Merge branch 'develop' into chore/sc-24808

This commit is contained in:
Marcus Moore
2024-02-21 12:33:06 -08:00
112 changed files with 1262 additions and 286811 deletions
@@ -36,7 +36,8 @@ class AssetMaintenancesController extends Controller
{
$this->authorize('view', Asset::class);
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'admin');
$maintenances = AssetMaintenance::select('asset_maintenances.*')
->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'asset.assetstatus', 'admin');
if ($request->filled('search')) {
$maintenances = $maintenances->TextSearch($request->input('search'));
@@ -47,7 +48,7 @@ class AssetMaintenancesController extends Controller
}
if ($request->filled('supplier_id')) {
$maintenances->where('supplier_id', '=', $request->input('supplier_id'));
$maintenances->where('asset_maintenances.supplier_id', '=', $request->input('supplier_id'));
}
if ($request->filled('asset_maintenance_type')) {
@@ -70,10 +71,13 @@ class AssetMaintenancesController extends Controller
'notes',
'asset_tag',
'asset_name',
'serial',
'user_id',
'supplier',
'is_warranty',
'status_label',
];
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
@@ -90,6 +94,12 @@ class AssetMaintenancesController extends Controller
case 'asset_name':
$maintenances = $maintenances->OrderByAssetName($order);
break;
case 'serial':
$maintenances = $maintenances->OrderByAssetSerial($order);
break;
case 'status_label':
$maintenances = $maintenances->OrderStatusName($order);
break;
default:
$maintenances = $maintenances->orderBy($sort, $order);
break;
@@ -903,6 +903,13 @@ class AssetsController extends Controller
$originalValues['action_date'] = $checkin_at;
}
if(!empty($asset->licenseseats->all())){
foreach ($asset->licenseseats as $seat){
$seat->assigned_to = null;
$seat->save();
}
}
if ($asset->save()) {
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
@@ -25,9 +25,27 @@ class LocationsController extends Controller
{
$this->authorize('view', Location::class);
$allowed_columns = [
'id', 'name', 'address', 'address2', 'city', 'state', 'country', 'zip', 'created_at',
'updated_at', 'manager_id', 'image',
'assigned_assets_count', 'users_count', 'assets_count','assigned_assets_count', 'assets_count', 'rtd_assets_count', 'currency', 'ldap_ou', ];
'id',
'name',
'address',
'address2',
'city',
'state',
'country',
'zip',
'created_at',
'updated_at',
'manager_id',
'image',
'assigned_assets_count',
'users_count',
'assets_count',
'assigned_assets_count',
'assets_count',
'rtd_assets_count',
'currency',
'ldap_ou',
];
$locations = Location::with('parent', 'manager', 'children')->select([
'locations.id',
@@ -50,6 +68,7 @@ class LocationsController extends Controller
])->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count');
if ($request->filled('search')) {
@@ -80,6 +99,10 @@ class LocationsController extends Controller
$locations->where('locations.country', '=', $request->input('country'));
}
if ($request->filled('manager_id')) {
$locations->where('locations.manager_id', '=', $request->input('manager_id'));
}
// Make sure the offset and limit are actually integers and do not exceed system limits
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
$limit = app('api_limit_value');
@@ -33,7 +33,12 @@ class ReportsController extends Controller
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
$actionlogs = $actionlogs->where('item_id', '=', $request->input('item_id'))
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')))
->orWhere(function($query) use ($request)
{
$query->where('target_id', '=', $request->input('item_id'))
->where('target_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
});
}
if ($request->filled('action_type')) {
@@ -148,7 +148,7 @@ class SettingsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v3.0]
* @return Redirect
* @return JsonResponse
*/
public function ajaxTestEmail()
{
@@ -170,7 +170,7 @@ class SettingsController extends Controller
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0.0]
* @return Response
* @return JsonResponse
*/
public function purgeBarcodes()
{
@@ -211,7 +211,7 @@ class SettingsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v5.0.0]
* @param \Illuminate\Http\Request $request
* @return array
* @return array | JsonResponse
*/
public function showLoginAttempts(Request $request)
{
@@ -229,6 +229,12 @@ class SettingsController extends Controller
}
/**
* Lists backup files
*
* @author [A. Gianotto]
* @return array | JsonResponse
*/
public function listBackups() {
$settings = Setting::getSettings();
$path = 'app/backups';
@@ -249,12 +255,12 @@ class SettingsController extends Controller
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
'modified_value' => $file_timestamp,
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
'backup_url' => config('app.url').'/settings/backups/download/'.basename($backup_files[$f]),
];
$count++;
}
}
}
@@ -264,15 +270,56 @@ class SettingsController extends Controller
}
/**
* Downloads a backup file.
* We use response()->download() here instead of Storage::download() because Storage::download()
* exhausts memory on larger files.
*
* @author [A. Gianotto]
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function downloadBackup($file) {
$path = 'app/backups';
if (Storage::exists($path.'/'.$file)) {
$path = storage_path('app/backups');
if (Storage::exists('app/backups/'.$file)) {
$headers = ['ContentType' => 'application/zip'];
return Storage::download($path.'/'.$file, $file, $headers);
return response()->download($path.'/'.$file, $file, $headers);
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
}
}
/**
* Determines and downloads the latest backup
*
* @author [A. Gianotto]
* @since [v6.3.1]
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function downloadLatestBackup() {
$fileData = collect();
foreach (Storage::files('app/backups') as $file) {
if (pathinfo($file, PATHINFO_EXTENSION) == 'zip') {
$fileData->push([
'file' => $file,
'date' => Storage::lastModified($file)
]);
}
}
$newest = $fileData->sortByDesc('date')->first();
if (Storage::exists($newest['file'])) {
$headers = ['ContentType' => 'application/zip'];
return response()->download(storage_path($newest['file']), basename($newest['file']), $headers);
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
}
}
}
@@ -274,11 +274,6 @@ class UsersController extends Controller
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
$limit = app('api_limit_value');
\Log::debug('Requested offset: '. $request->input('offset'));
\Log::debug('App offset: '. app('api_offset_value'));
\Log::debug('Actual offset: '. $offset);
\Log::debug('Limit: '. $limit);
$total = $users->count();
$users = $users->skip($offset)->take($limit)->get();
@@ -148,30 +148,20 @@ class AssetMaintenancesController extends Controller
*/
public function edit($assetMaintenanceId = null)
{
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
$this->authorize('update', Asset::class);
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the improvement management page
return redirect()->route('maintenances.index')
->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif (! $assetMaintenance->asset) {
return redirect()->route('maintenances.index')
->with('error', 'The asset associated with this maintenance does not exist.');
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
if ($assetMaintenance->completion_date == '0000-00-00') {
$assetMaintenance->completion_date = null;
}
if ($assetMaintenance->start_date == '0000-00-00') {
$assetMaintenance->start_date = null;
}
if ($assetMaintenance->cost == '0.00') {
$assetMaintenance->cost = null;
}
// Prepare Improvement Type List
$assetMaintenanceType = [
@@ -203,8 +193,10 @@ class AssetMaintenancesController extends Controller
// Check if the asset maintenance exists
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')
->with('error', trans('admin/asset_maintenances/message.not_found'));
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
// Redirect to the asset maintenance management page
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
return static::getInsufficientPermissionsRedirect();
}
@@ -442,7 +442,6 @@ class AssetModelsController extends Controller
$del_count = 0;
foreach ($models as $model) {
\Log::debug($model->id);
if ($model->assets_count > 0) {
$del_error_count++;
@@ -452,8 +451,6 @@ class AssetModelsController extends Controller
}
}
\Log::debug($del_count);
\Log::debug($del_error_count);
if ($del_error_count == 0) {
return redirect()->route('models.index')
+92 -2
View File
@@ -8,6 +8,7 @@ use App\Models\Location;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Request;
/**
* This controller handles all actions related to Locations for
@@ -168,7 +169,7 @@ class LocationsController extends Controller
{
$this->authorize('delete', Location::class);
if (is_null($location = Location::find($locationId))) {
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.not_found'));
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist'));
}
if ($location->users()->count() > 0) {
@@ -238,7 +239,7 @@ class LocationsController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net>]
* @param int $locationId
* @since [v6.0.14]
* @return View
* @return \Illuminate\Contracts\View\View
*/
public function getClone($locationId = null)
{
@@ -272,8 +273,97 @@ class LocationsController extends Controller
}
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
}
/**
* Returns a view that allows the user to bulk delete locations
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.3.1]
* @return \Illuminate\Contracts\View\View
*/
public function postBulkDelete(Request $request)
{
$locations_raw_array = $request->input('ids');
// Make sure some IDs have been selected
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {
$locations = Location::whereIn('id', $locations_raw_array)
->withCount('assignedAssets as assigned_assets_count')
->withCount('assets as assets_count')
->withCount('rtd_assets as rtd_assets_count')
->withCount('children as children_count')
->withCount('users as users_count')->get();
$valid_count = 0;
foreach ($locations as $location) {
if ($location->isDeletable()) {
$valid_count++;
}
}
return view('locations/bulk-delete', compact('locations'))->with('valid_count', $valid_count);
}
return redirect()->route('models.index')
->with('error', 'You must select at least one model to edit.');
}
/**
* Checks that locations can be deleted and deletes them if they can
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @since [v6.3.1]
* @return \Illuminate\Http\RedirectResponse
*/
public function postBulkDeleteStore(Request $request) {
$locations_raw_array = $request->input('ids');
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {
$locations = Location::whereIn('id', $locations_raw_array)->get();
$success_count = 0;
$error_count = 0;
foreach ($locations as $location) {
// Can we delete this location?
if ($location->isDeletable()) {
$location->delete();
$success_count++;
} else {
$error_count++;
}
}
\Log::debug('Success count: '.$success_count);
\Log::debug('Error count: '.$error_count);
// Complete success
if ($success_count == count($locations_raw_array)) {
return redirect()
->route('locations.index')
->with('success', trans_choice('general.bulk.delete.success', $success_count,
['object_type' => trans_choice('general.location_plural', $success_count), 'count' => $success_count]
));
}
// Partial success
if ($error_count > 0) {
return redirect()
->route('locations.index')
->with('warning', trans('general.bulk.partial_success',
['success' => $success_count, 'error' => $error_count, 'object_type' => trans('general.locations')]
));
}
}
// Nothing was selected - return to the index
return redirect()
->route('locations.index')
->with('error', trans('general.bulk.nothing_selected',
['object_type' => trans('general.locations')]
));
}
}
+2 -2
View File
@@ -296,8 +296,8 @@ class ReportsController extends Controller
e($actionlog->itemType()),
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
($actionlog->item) ? $actionlog->item->serial : null,
($actionlog->item->model) ? htmlspecialchars($actionlog->item->model->name, ENT_NOQUOTES) : null,
($actionlog->item->model) ? $actionlog->item->model->model_number : null,
(($actionlog->item) && ($actionlog->item->model)) ? htmlspecialchars($actionlog->item->model->name, ENT_NOQUOTES) : null,
(($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null,
$target_name,
($actionlog->note) ? e($actionlog->note) : '',
$actionlog->log_meta,
+51 -52
View File
@@ -425,65 +425,64 @@ class SettingsController extends Controller
if (! config('app.lock_passwords')) {
$setting->site_name = $request->input('site_name');
$setting->custom_css = $request->input('custom_css');
}
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
if ('1' == $request->input('clear_logo')) {
if ('1' == $request->input('clear_logo')) {
Storage::disk('public')->delete($setting->logo);
$setting->logo = null;
$setting->logo = null;
$setting->brand = 1;
}
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
if ('1' == $request->input('clear_email_logo')) {
Storage::disk('public')->delete($setting->email_logo);
$setting->email_logo = null;
// If they are uploading an image, validate it and upload it
}
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
if ('1' == $request->input('clear_label_logo')) {
Storage::disk('public')->delete($setting->label_logo);
$setting->label_logo = null;
}
// If the user wants to clear the favicon...
if ($request->hasFile('favicon')) {
$favicon_image = $favicon_upload = $request->file('favicon');
$favicon_ext = $favicon_image->getClientOriginalExtension();
$setting->favicon = $favicon_file_name = 'favicon-uploaded.'.$favicon_ext;
if (($favicon_image->getClientOriginalExtension() != 'ico') && ($favicon_image->getClientOriginalExtension() != 'svg')) {
$favicon_upload = Image::make($favicon_image->getRealPath())->resize(null, 36, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
// This requires a string instead of an object, so we use ($string)
Storage::disk('public')->put($favicon_file_name, (string) $favicon_upload->encode());
} else {
Storage::disk('public')->put($favicon_file_name, file_get_contents($request->file('favicon')));
}
// Remove Current image if exists
if (($setting->favicon) && (file_exists($favicon_file_name))) {
Storage::disk('public')->delete($favicon_file_name);
}
} elseif ('1' == $request->input('clear_favicon')) {
Storage::disk('public')->delete($setting->clear_favicon);
$setting->favicon = null;
$setting = $request->handleImages($setting, 600, 'email_logo', '', 'email_logo');
// If they are uploading an image, validate it and upload it
}
if ('1' == $request->input('clear_email_logo')) {
Storage::disk('public')->delete($setting->email_logo);
$setting->email_logo = null;
// If they are uploading an image, validate it and upload it
}
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
if ('1' == $request->input('clear_label_logo')) {
Storage::disk('public')->delete($setting->label_logo);
$setting->label_logo = null;
}
// If the user wants to clear the favicon...
if ($request->hasFile('favicon')) {
$favicon_image = $favicon_upload = $request->file('favicon');
$favicon_ext = $favicon_image->getClientOriginalExtension();
$setting->favicon = $favicon_file_name = 'favicon-uploaded.'.$favicon_ext;
if (($favicon_image->getClientOriginalExtension() != 'ico') && ($favicon_image->getClientOriginalExtension() != 'svg')) {
$favicon_upload = Image::make($favicon_image->getRealPath())->resize(null, 36, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
// This requires a string instead of an object, so we use ($string)
Storage::disk('public')->put($favicon_file_name, (string) $favicon_upload->encode());
} else {
Storage::disk('public')->put($favicon_file_name, file_get_contents($request->file('favicon')));
}
// Remove Current image if exists
if (($setting->favicon) && (file_exists($favicon_file_name))) {
Storage::disk('public')->delete($favicon_file_name);
}
} elseif ('1' == $request->input('clear_favicon')) {
Storage::disk('public')->delete($setting->clear_favicon);
$setting->favicon = null;
// If they are uploading an image, validate it and upload it
}
}
if ($setting->save()) {
return redirect()->route('settings.index')
+1 -1
View File
@@ -97,7 +97,7 @@ class ImageUploadRequest extends Request
if (!config('app.lock_passwords')) {
$ext = $image->getClientOriginalExtension();
$ext = $image->guessExtension();
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
\Log::info('File name will be: '.$file_name);
@@ -28,12 +28,20 @@ class AssetMaintenancesTransformer
'id' => (int) $assetmaintenance->asset->id,
'name'=> ($assetmaintenance->asset->name) ? e($assetmaintenance->asset->name) : null,
'asset_tag'=> e($assetmaintenance->asset->asset_tag),
'serial'=> e($assetmaintenance->asset->serial),
'deleted_at'=> e($assetmaintenance->asset->deleted_at),
'created_at'=> e($assetmaintenance->asset->created_at),
] : null,
'model' => (($assetmaintenance->asset) && ($assetmaintenance->asset->model)) ? [
'id' => (int) $assetmaintenance->asset->model->id,
'name'=> ($assetmaintenance->asset->model->name) ? e($assetmaintenance->asset->model->name).' '.e($assetmaintenance->asset->model->model_number) : null,
] : null,
'status_label' => ($assetmaintenance->asset->assetstatus) ? [
'id' => (int) $assetmaintenance->asset->assetstatus->id,
'name'=> e($assetmaintenance->asset->assetstatus->name),
'status_type'=> e($assetmaintenance->asset->assetstatus->getStatuslabelType()),
'status_meta' => e($assetmaintenance->asset->present()->statusMeta),
] : null,
'company' => (($assetmaintenance->asset) && ($assetmaintenance->asset->company)) ? [
'id' => (int) $assetmaintenance->asset->company->id,
'name'=> ($assetmaintenance->asset->company->name) ? e($assetmaintenance->asset->company->name) : null,
@@ -64,7 +72,7 @@ class AssetMaintenancesTransformer
];
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Asset::class),
'update' => (Gate::allows('update', Asset::class) && ($assetmaintenance->asset->deleted_at=='')) ? true : false,
'delete' => Gate::allows('delete', Asset::class),
];
@@ -65,6 +65,9 @@ class LocationsTransformer
$permissions_array['available_actions'] = [
'update' => Gate::allows('update', Location::class) ? true : false,
'delete' => $location->isDeletable(),
'bulk_selectable' => [
'delete' => $location->isDeletable()
],
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
];