diff --git a/.env.example b/.env.example index f8e1df2987..fd90391973 100644 --- a/.env.example +++ b/.env.example @@ -86,6 +86,7 @@ COOKIE_DOMAIN=null SECURE_COOKIES=false API_TOKEN_EXPIRATION_YEARS=15 BS_TABLE_STORAGE=cookieStorage +BS_TABLE_DEEPLINK=true # -------------------------------------------- # OPTIONAL: SECURITY HEADER SETTINGS diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 1b671386ab..38f1356812 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -592,6 +592,11 @@ class AssetsController extends Controller } } } + if ($field->element == 'checkbox') { + if(is_array($field_val)) { + $field_val = implode(',', $field_val); + } + } $asset->{$field->db_column} = $field_val; @@ -614,7 +619,7 @@ class AssetsController extends Controller $asset->image = $asset->getImageUrl(); } - return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success'))); + return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.create.success'))); } return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200); @@ -642,26 +647,35 @@ class AssetsController extends Controller } /** - * this is here just legacy reasons. Api\AssetController - * used image_source once to allow encoded image uploads. - */ + * this is here just legacy reasons. Api\AssetController + * used image_source once to allow encoded image uploads. + */ if ($request->has('image_source')) { $request->offsetSet('image', $request->offsetGet('image_source')); - } + } $asset = $request->handleImages($asset); $model = $asset->model; - + // Update custom fields if (($model) && (isset($model->fieldset))) { foreach ($model->fieldset->fields as $field) { + $field_val = $request->input($field->db_column, null); + if ($request->has($field->db_column)) { if ($field->field_encrypted == '1') { if (Gate::allows('admin')) { - $asset->{$field->db_column} = Crypt::encrypt($request->input($field->db_column)); + $asset->{$field->db_column} = Crypt::encrypt($field_val); } - } else { - $asset->{$field->db_column} = $request->input($field->db_column); + } + if ($field->element == 'checkbox') { + if(is_array($field_val)) { + $field_val = implode(',', $field_val); + $asset->{$field->db_column} = $field_val; + } + } + else { + $asset->{$field->db_column} = $field_val; } } } @@ -686,7 +700,7 @@ class AssetsController extends Controller if ($asset->image) { $asset->image = $asset->getImageUrl(); } - return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.update.success'))); + return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset), trans('admin/hardware/message.update.success'))); } return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200); } diff --git a/app/Http/Controllers/Api/ReportsController.php b/app/Http/Controllers/Api/ReportsController.php index a91d8a9bcc..3c1faa1031 100644 --- a/app/Http/Controllers/Api/ReportsController.php +++ b/app/Http/Controllers/Api/ReportsController.php @@ -45,6 +45,10 @@ class ReportsController extends Controller $actionlogs = $actionlogs->where('action_type', '=', $request->input('action_type'))->orderBy('created_at', 'desc'); } + if ($request->filled('user_id')) { + $actionlogs = $actionlogs->where('user_id', '=', $request->input('user_id')); + } + if ($request->filled('action_source')) { $actionlogs = $actionlogs->where('action_source', '=', $request->input('action_source'))->orderBy('created_at', 'desc'); } diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 6d32e8b6f2..5ef45ee4d9 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -560,7 +560,26 @@ class UsersController extends Controller { $this->authorize('view', User::class); $this->authorize('view', Asset::class); - $assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model')->get(); + $assets = Asset::where('assigned_to', '=', $id)->where('assigned_type', '=', User::class)->with('model'); + + + // Filter on category ID + if ($request->filled('category_id')) { + $assets = $assets->InCategory($request->input('category_id')); + } + + + // Filter on model ID + if ($request->filled('model_id')) { + + $model_ids = $request->input('model_id'); + if (!is_array($model_ids)) { + $model_ids = array($model_ids); + } + $assets = $assets->InModelList($model_ids); + } + + $assets = $assets->get(); return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request); } @@ -661,7 +680,17 @@ class UsersController extends Controller $user = User::find($request->get('id')); $user->two_factor_secret = null; $user->two_factor_enrolled = 0; - $user->save(); + $user->saveQuietly(); + + // Log the reset + $logaction = new Actionlog(); + $logaction->target_type = User::class; + $logaction->target_id = $user->id; + $logaction->item_type = User::class; + $logaction->item_id = $user->id; + $logaction->created_at = date('Y-m-d H:i:s'); + $logaction->user_id = Auth::user()->id; + $logaction->logaction('2FA reset'); return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200); } catch (\Exception $e) { diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index 484a2e2f85..8d387f968f 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -7,6 +7,7 @@ use App\Http\Requests\ImageUploadRequest; use App\Models\Actionlog; use App\Models\Asset; use App\Models\AssetModel; +use App\Models\CustomField; use App\Models\User; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; @@ -486,11 +487,11 @@ class AssetModelsController extends Controller * @param array $defaultValues * @return void */ - private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues) + private function assignCustomFieldsDefaultValues(AssetModel $model, array $defaultValues): bool { $data = array(); foreach ($defaultValues as $customFieldId => $defaultValue) { - $customField = \App\Models\CustomField::find($customFieldId); + $customField = CustomField::find($customFieldId); $data[$customField->db_column] = $defaultValue; } diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 0683a54e3a..6054718e6b 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -102,6 +102,10 @@ class AssetsController extends Controller { $this->authorize(Asset::class); + // There are a lot more rules to add here but prevents + // errors around `asset_tags` not being present below. + $this->validate($request, ['asset_tags' => ['required', 'array']]); + // Handle asset tags - there could be one, or potentially many. // This is only necessary on create, not update, since bulk editing is handled // differently diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index ffe5eceec2..23ea9da34b 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -260,7 +260,7 @@ class CustomFieldsController extends Controller $field->name = trim(e($request->get("name"))); $field->element = e($request->get("element")); - $field->field_values = e($request->get("field_values")); + $field->field_values = $request->get("field_values"); $field->user_id = Auth::id(); $field->help_text = $request->get("help_text"); $field->show_in_email = $show_in_email; diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index b1cb620a83..dbb6f66222 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -20,6 +20,7 @@ use DB; use enshrined\svgSanitize\Sanitizer; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; +use Illuminate\Validation\Rule; use Image; use Input; use Redirect; @@ -499,6 +500,19 @@ class SettingsController extends Controller */ public function postSecurity(Request $request) { + $this->validate($request, [ + 'pwd_secure_complexity' => 'array', + 'pwd_secure_complexity.*' => [ + Rule::in([ + 'disallow_same_pwd_as_user_fields', + 'letters', + 'numbers', + 'symbols', + 'case_diff', + ]) + ] + ]); + if (is_null($setting = Setting::getSettings())) { return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error')); } diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 74988b6c62..8e7559673e 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -4,6 +4,8 @@ namespace App\Http\Requests; use App\Models\Asset; use App\Models\Company; +use Carbon\Carbon; +use Carbon\Exceptions\InvalidFormatException; use Illuminate\Support\Facades\Gate; class StoreAssetRequest extends ImageUploadRequest @@ -27,6 +29,8 @@ class StoreAssetRequest extends ImageUploadRequest ? Company::getIdForCurrentUser($this->company_id) : $this->company_id; + $this->parseLastAuditDate(); + $this->merge([ 'asset_tag' => $this->asset_tag ?? Asset::autoincrement_asset(), 'company_id' => $idForCurrentUser, @@ -48,4 +52,21 @@ class StoreAssetRequest extends ImageUploadRequest return $rules; } + + private function parseLastAuditDate(): void + { + if ($this->input('last_audit_date')) { + try { + $lastAuditDate = Carbon::parse($this->input('last_audit_date')); + + $this->merge([ + 'last_audit_date' => $lastAuditDate->startOfDay()->format('Y-m-d H:i:s'), + ]); + } catch (InvalidFormatException $e) { + // we don't need to do anything here... + // we'll keep the provided date in an + // invalid format so validation picks it up later + } + } + } } diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 112c79aee6..f9c9ce15ee 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -90,27 +90,29 @@ class Asset extends Depreciable ]; protected $rules = [ - 'model_id' => 'required|integer|exists:models,id,deleted_at,NULL|not_array', - 'status_id' => 'required|integer|exists:status_labels,id', - 'asset_tag' => 'required|min:1|max:255|unique_undeleted:assets,asset_tag|not_array', - 'name' => 'nullable|max:255', - 'company_id' => 'nullable|integer|exists:companies,id', - 'warranty_months' => 'nullable|numeric|digits_between:0,240', - 'last_checkout' => 'nullable|date_format:Y-m-d H:i:s', + 'model_id' => 'required|integer|exists:models,id,deleted_at,NULL|not_array', + 'status_id' => 'required|integer|exists:status_labels,id', + 'asset_tag' => 'required|min:1|max:255|unique_undeleted:assets,asset_tag|not_array', + 'name' => 'nullable|max:255', + 'company_id' => 'nullable|integer|exists:companies,id', + 'warranty_months' => 'nullable|numeric|digits_between:0,240', + 'last_checkout' => 'nullable|date_format:Y-m-d H:i:s', 'expected_checkin' => 'nullable|date', - 'location_id' => 'nullable|exists:locations,id', - 'rtd_location_id' => 'nullable|exists:locations,id', - 'purchase_date' => 'nullable|date|date_format:Y-m-d', - 'serial' => 'nullable|unique_undeleted:assets,serial', - 'purchase_cost' => 'nullable|numeric|gte:0', - 'supplier_id' => 'nullable|exists:suppliers,id', - 'asset_eol_date' => 'nullable|date', - 'eol_explicit' => 'nullable|boolean', - 'byod' => 'nullable|boolean', - 'order_number' => 'nullable|string|max:191', - 'notes' => 'nullable|string|max:65535', - 'assigned_to' => 'nullable|integer', - 'requestable' => 'nullable|boolean', + 'last_audit_date' => 'nullable|date_format:Y-m-d H:i:s', + 'next_audit_date' => 'nullable|date|after:last_audit_date', + 'location_id' => 'nullable|exists:locations,id', + 'rtd_location_id' => 'nullable|exists:locations,id', + 'purchase_date' => 'nullable|date|date_format:Y-m-d', + 'serial' => 'nullable|unique_undeleted:assets,serial', + 'purchase_cost' => 'nullable|numeric|gte:0', + 'supplier_id' => 'nullable|exists:suppliers,id', + 'asset_eol_date' => 'nullable|date', + 'eol_explicit' => 'nullable|boolean', + 'byod' => 'nullable|boolean', + 'order_number' => 'nullable|string|max:191', + 'notes' => 'nullable|string|max:65535', + 'assigned_to' => 'nullable|integer', + 'requestable' => 'nullable|boolean', ]; /** diff --git a/app/Models/CustomFieldset.php b/app/Models/CustomFieldset.php index a62f96d631..71be28e8a3 100644 --- a/app/Models/CustomFieldset.php +++ b/app/Models/CustomFieldset.php @@ -5,6 +5,8 @@ namespace App\Models; use Gate; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Log; +use Illuminate\Validation\Rule; use Watson\Validating\ValidatingTrait; class CustomFieldset extends Model @@ -92,8 +94,19 @@ class CustomFieldset extends Model array_push($rule, $field->attributes['format']); $rules[$field->db_column_name()] = $rule; - //add not_array to rules for all fields - $rules[$field->db_column_name()][] = 'not_array'; + + // add not_array to rules for all fields but checkboxes + if ($field->element != 'checkbox') { + $rules[$field->db_column_name()][] = 'not_array'; + } + + if ($field->element == 'checkbox') { + $rules[$field->db_column_name()][] = 'checkboxes'; + } + + if ($field->element == 'radio') { + $rules[$field->db_column_name()][] = 'radio_buttons'; + } } return $rules; diff --git a/app/Models/Labels/Tapes/Dymo/LabelWriter_1933081.php b/app/Models/Labels/Tapes/Dymo/LabelWriter_1933081.php new file mode 100644 index 0000000000..9b56012f7a --- /dev/null +++ b/app/Models/Labels/Tapes/Dymo/LabelWriter_1933081.php @@ -0,0 +1,89 @@ +getPrintableArea(); + + $currentX = $pa->x1; + $currentY = $pa->y1; + $usableWidth = $pa->w; + + $barcodeSize = $pa->h - self::TAG_SIZE; + + if ($record->has('barcode2d')) { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'C', + $barcodeSize, self::TAG_SIZE, true, 0 + ); + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $currentX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + self::BARCODE_MARGIN; + $usableWidth -= $barcodeSize + self::BARCODE_MARGIN; + } else { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'R', + $usableWidth, self::TAG_SIZE, true, 0 + ); + } + + if ($record->has('title')) { + static::writeText( + $pdf, $record->get('title'), + $currentX, $currentY, + 'freesans', 'b', self::TITLE_SIZE, 'L', + $usableWidth, self::TITLE_SIZE, true, 0 + ); + $currentY += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $field) { + static::writeText( + $pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'], + $currentX, $currentY, + 'freesans', '', self::FIELD_SIZE, 'L', + $usableWidth, self::FIELD_SIZE, true, 0, 0.3 + ); + $currentY += self::FIELD_SIZE + self::FIELD_MARGIN; + } + + if ($record->has('barcode1d')) { + static::write1DBarcode( + $pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type, + $currentX, $barcodeSize + self::BARCODE_MARGIN, $usableWidth - self::TAG_SIZE, self::TAG_SIZE + ); + } + } + +} diff --git a/app/Models/Labels/Tapes/Dymo/LabelWriter_2112283.php b/app/Models/Labels/Tapes/Dymo/LabelWriter_2112283.php new file mode 100644 index 0000000000..e1305bd068 --- /dev/null +++ b/app/Models/Labels/Tapes/Dymo/LabelWriter_2112283.php @@ -0,0 +1,89 @@ +getPrintableArea(); + + $currentX = $pa->x1; + $currentY = $pa->y1; + $usableWidth = $pa->w; + + $barcodeSize = $pa->h - self::TAG_SIZE; + + if ($record->has('barcode2d')) { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'C', + $barcodeSize, self::TAG_SIZE, true, 0 + ); + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $currentX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + self::BARCODE_MARGIN; + $usableWidth -= $barcodeSize + self::BARCODE_MARGIN; + } else { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'R', + $usableWidth, self::TAG_SIZE, true, 0 + ); + } + + if ($record->has('title')) { + static::writeText( + $pdf, $record->get('title'), + $currentX, $currentY, + 'freesans', 'b', self::TITLE_SIZE, 'L', + $usableWidth, self::TITLE_SIZE, true, 0 + ); + $currentY += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $field) { + static::writeText( + $pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'], + $currentX, $currentY, + 'freesans', '', self::FIELD_SIZE, 'L', + $usableWidth, self::FIELD_SIZE, true, 0, 0.3 + ); + $currentY += self::FIELD_SIZE + self::FIELD_MARGIN; + } + + if ($record->has('barcode1d')) { + static::write1DBarcode( + $pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type, + $currentX, $barcodeSize + self::BARCODE_MARGIN, $usableWidth - self::TAG_SIZE, self::TAG_SIZE + ); + } + } + +} diff --git a/app/Presenters/AccessoryPresenter.php b/app/Presenters/AccessoryPresenter.php index cc4f9badfc..fd6122cab7 100644 --- a/app/Presenters/AccessoryPresenter.php +++ b/app/Presenters/AccessoryPresenter.php @@ -41,6 +41,7 @@ class AccessoryPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('general.name'), 'formatter' => 'accessoriesLinkFormatter', ], [ diff --git a/app/Presenters/ActionlogPresenter.php b/app/Presenters/ActionlogPresenter.php index ddff10864e..2794b6c5fb 100644 --- a/app/Presenters/ActionlogPresenter.php +++ b/app/Presenters/ActionlogPresenter.php @@ -38,10 +38,14 @@ class ActionlogPresenter extends Presenter public function icon() { - + // User related icons if ($this->itemType() == 'user') { + if ($this->actionType()=='2fa reset') { + return 'fa-solid fa-mobile-screen'; + } + if ($this->actionType()=='create new') { return 'fa-solid fa-user-plus'; } @@ -61,6 +65,7 @@ class ActionlogPresenter extends Presenter if ($this->actionType()=='update') { return 'fa-solid fa-user-pen'; } + return 'fa-solid fa-user'; } diff --git a/app/Presenters/AssetMaintenancesPresenter.php b/app/Presenters/AssetMaintenancesPresenter.php index 5f9694b44c..3908720dc3 100644 --- a/app/Presenters/AssetMaintenancesPresenter.php +++ b/app/Presenters/AssetMaintenancesPresenter.php @@ -85,6 +85,7 @@ class AssetMaintenancesPresenter extends Presenter 'field' => 'title', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('admin/asset_maintenances/form.title'), ], [ 'field' => 'start_date', diff --git a/app/Presenters/AssetModelPresenter.php b/app/Presenters/AssetModelPresenter.php index 85a0fa58ec..da93092b91 100644 --- a/app/Presenters/AssetModelPresenter.php +++ b/app/Presenters/AssetModelPresenter.php @@ -35,6 +35,7 @@ class AssetModelPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'visible' => true, 'title' => trans('general.name'), 'formatter' => 'modelsLinkFormatter', diff --git a/app/Presenters/AssetPresenter.php b/app/Presenters/AssetPresenter.php index dd88b07fde..5f900a6a83 100644 --- a/app/Presenters/AssetPresenter.php +++ b/app/Presenters/AssetPresenter.php @@ -55,6 +55,7 @@ class AssetPresenter extends Presenter 'field' => 'asset_tag', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('admin/hardware/table.asset_tag'), 'visible' => true, 'formatter' => 'hardwareLinkFormatter', @@ -316,7 +317,7 @@ class AssetPresenter extends Presenter 'field' => 'checkincheckout', 'searchable' => false, 'sortable' => false, - 'switchable' => true, + 'switchable' => false, 'title' => trans('general.checkin').'/'.trans('general.checkout'), 'visible' => true, 'formatter' => 'hardwareInOutFormatter', diff --git a/app/Presenters/CategoryPresenter.php b/app/Presenters/CategoryPresenter.php index e9276a3417..fbf431637c 100644 --- a/app/Presenters/CategoryPresenter.php +++ b/app/Presenters/CategoryPresenter.php @@ -25,6 +25,7 @@ class CategoryPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('general.name'), 'visible' => true, 'formatter' => 'categoriesLinkFormatter', diff --git a/app/Presenters/CompanyPresenter.php b/app/Presenters/CompanyPresenter.php index ec2e7cfc5a..7603191fc1 100644 --- a/app/Presenters/CompanyPresenter.php +++ b/app/Presenters/CompanyPresenter.php @@ -25,7 +25,7 @@ class CompanyPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, - 'switchable' => true, + 'switchable' => false, 'title' => trans('admin/companies/table.name'), 'visible' => true, 'formatter' => 'companiesLinkFormatter', diff --git a/app/Presenters/ComponentPresenter.php b/app/Presenters/ComponentPresenter.php index c7468911a1..d142d7abc2 100644 --- a/app/Presenters/ComponentPresenter.php +++ b/app/Presenters/ComponentPresenter.php @@ -126,7 +126,7 @@ class ComponentPresenter extends Presenter 'field' => 'checkincheckout', 'searchable' => false, 'sortable' => false, - 'switchable' => true, + 'switchable' => false, 'title' => trans('general.checkin').'/'.trans('general.checkout'), 'visible' => true, 'formatter' => 'componentsInOutFormatter', diff --git a/app/Presenters/ConsumablePresenter.php b/app/Presenters/ConsumablePresenter.php index abb599de4f..d3e73de1cf 100644 --- a/app/Presenters/ConsumablePresenter.php +++ b/app/Presenters/ConsumablePresenter.php @@ -35,6 +35,7 @@ class ConsumablePresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('general.name'), 'visible' => true, 'formatter' => 'consumablesLinkFormatter', diff --git a/app/Presenters/DepreciationPresenter.php b/app/Presenters/DepreciationPresenter.php index 2a293a46ff..9df1fe1322 100644 --- a/app/Presenters/DepreciationPresenter.php +++ b/app/Presenters/DepreciationPresenter.php @@ -25,6 +25,7 @@ class DepreciationPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('general.name'), 'visible' => true, 'formatter' => 'depreciationsLinkFormatter', diff --git a/app/Presenters/DepreciationReportPresenter.php b/app/Presenters/DepreciationReportPresenter.php index ea88342372..50a8b73b54 100644 --- a/app/Presenters/DepreciationReportPresenter.php +++ b/app/Presenters/DepreciationReportPresenter.php @@ -34,6 +34,7 @@ class DepreciationReportPresenter extends Presenter "field" => "name", "searchable" => true, "sortable" => true, + 'switchable' => false, "title" => trans('admin/hardware/form.name'), "visible" => false, ], [ diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php index c5c8982664..8ca8e120f2 100644 --- a/app/Presenters/LicensePresenter.php +++ b/app/Presenters/LicensePresenter.php @@ -33,6 +33,7 @@ class LicensePresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('general.name'), 'formatter' => 'licensesLinkFormatter', ], [ @@ -186,7 +187,7 @@ class LicensePresenter extends Presenter 'field' => 'checkincheckout', 'searchable' => false, 'sortable' => false, - 'switchable' => true, + 'switchable' => false, 'title' => trans('general.checkin').'/'.trans('general.checkout'), 'visible' => true, 'formatter' => 'licensesInOutFormatter', @@ -280,7 +281,7 @@ class LicensePresenter extends Presenter 'field' => 'checkincheckout', 'searchable' => false, 'sortable' => false, - 'switchable' => true, + 'switchable' => false, 'title' => trans('general.checkin').'/'.trans('general.checkout'), 'visible' => true, 'formatter' => 'licenseSeatInOutFormatter', diff --git a/app/Presenters/LocationPresenter.php b/app/Presenters/LocationPresenter.php index 6a9bc0b568..56d710ac96 100644 --- a/app/Presenters/LocationPresenter.php +++ b/app/Presenters/LocationPresenter.php @@ -31,6 +31,7 @@ class LocationPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('admin/locations/table.name'), 'visible' => true, 'formatter' => 'locationsLinkFormatter', diff --git a/app/Presenters/ManufacturerPresenter.php b/app/Presenters/ManufacturerPresenter.php index ad6b5443bf..3e36cbcde0 100644 --- a/app/Presenters/ManufacturerPresenter.php +++ b/app/Presenters/ManufacturerPresenter.php @@ -27,6 +27,7 @@ class ManufacturerPresenter extends Presenter 'field' => 'name', 'searchable' => true, 'sortable' => true, + 'switchable' => false, 'title' => trans('admin/manufacturers/table.name'), 'visible' => true, 'formatter' => 'manufacturersLinkFormatter', diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index 211057c548..4726205c72 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -38,7 +38,7 @@ class UserPresenter extends Presenter 'searchable' => false, 'sortable' => false, 'switchable' => true, - 'title' => 'Avatar', + 'title' => trans('general.importer.avatar'), 'visible' => false, 'formatter' => 'imageFormatter', ], @@ -175,7 +175,7 @@ class UserPresenter extends Presenter 'field' => 'username', 'searchable' => true, 'sortable' => true, - 'switchable' => true, + 'switchable' => false, 'title' => trans('admin/users/table.username'), 'visible' => true, 'formatter' => 'usersLinkFormatter', diff --git a/app/Providers/ValidationServiceProvider.php b/app/Providers/ValidationServiceProvider.php index bf9f5c55cf..7b9c9902c1 100644 --- a/app/Providers/ValidationServiceProvider.php +++ b/app/Providers/ValidationServiceProvider.php @@ -2,9 +2,12 @@ namespace App\Providers; +use App\Models\CustomField; use App\Models\Department; use App\Models\Setting; use DB; +use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Facades\Log; use Illuminate\Support\ServiceProvider; use Illuminate\Validation\Rule; use Validator; @@ -293,6 +296,39 @@ class ValidationServiceProvider extends ServiceProvider Validator::extend('not_array', function ($attribute, $value, $parameters, $validator) { return !is_array($value); }); + + // This is only used in Models/CustomFieldset.php - it does automatic validation for checkboxes by making sure + // that the submitted values actually exist in the options. + Validator::extend('checkboxes', function ($attribute, $value, $parameters, $validator){ + $field = CustomField::where('db_column', $attribute)->first(); + $options = $field->formatFieldValuesAsArray(); + + if(is_array($value)) { + $invalid = array_diff($value, $options); + if(count($invalid) > 0) { + return false; + } + } + + // for legacy, allows users to submit a comma separated string of options + elseif(!is_array($value)) { + $exploded = array_map('trim', explode(',', $value)); + $invalid = array_diff($exploded, $options); + if(count($invalid) > 0) { + return false; + } + } + + return true; + }); + + // Validates that a radio button option exists + Validator::extend('radio_buttons', function ($attribute, $value) { + $field = CustomField::where('db_column', $attribute)->first(); + $options = $field->formatFieldValuesAsArray(); + + return in_array($value, $options); + }); } /** diff --git a/config/session.php b/config/session.php index a47294a8cb..5c6cb27a9f 100644 --- a/config/session.php +++ b/config/session.php @@ -174,4 +174,17 @@ return [ 'bs_table_storage' => env('BS_TABLE_STORAGE', 'cookieStorage'), + + /* + |-------------------------------------------------------------------------- + | Bootstrap Table Enable Deeplinking + |-------------------------------------------------------------------------- + | + | Use deeplinks to directly link to search results, sorting, and pagination + | + | More info: https://github.com/generals-space/bootstrap-table-addrbar/blob/master/readme(EN).md + */ + + 'bs_table_addrbar' => env('BS_TABLE_DEEPLINK', true), + ]; diff --git a/config/version.php b/config/version.php index a1d26453da..4812c3368e 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v6.3.3', - 'full_app_version' => 'v6.3.3 - build 12903-g0f63fa23e', - 'build_version' => '12903', + 'full_app_version' => 'v6.3.3 - build 13056-gb34156ca2', + 'build_version' => '13056', 'prerelease_version' => '', - 'hash_version' => 'g0f63fa23e', - 'full_hash' => 'v6.3.3-67-g0f63fa23e', + 'hash_version' => 'gb34156ca2', + 'full_hash' => 'v6.3.3-151-gb34156ca2', 'branch' => 'develop', ); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3a81578e6a..37902c1ffa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2379,9 +2379,9 @@ } }, "alpinejs": { - "version": "3.13.5", - "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.5.tgz", - "integrity": "sha512-1d2XeNGN+Zn7j4mUAKXtAgdc4/rLeadyTMWeJGXF5DzwawPBxwTiBhFFm6w/Ei8eJxUZeyNWWSD9zknfdz1kEw==", + "version": "3.13.7", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.7.tgz", + "integrity": "sha512-rcTyjTANbsePq1hb7eSekt3qjI94HLGeO6JaRjCssCVbIIc+qBrc7pO5S/+2JB6oojIibjM6FA+xRI3zhGPZIg==", "requires": { "@vue/reactivity": "~3.1.1" } diff --git a/package.json b/package.json index f02b78db0b..fab86d9d2c 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "acorn-import-assertions": "^1.9.0", "admin-lte": "^2.4.18", "ajv": "^6.12.6", - "alpinejs": "^3.13.5", + "alpinejs": "^3.13.6", "blueimp-file-upload": "^9.34.0", "bootstrap": "^3.4.1", "bootstrap-colorpicker": "^2.5.3", diff --git a/public/js/dist/all-defer.js b/public/js/dist/all-defer.js index 50470c93f9..5d43f61e37 100644 Binary files a/public/js/dist/all-defer.js and b/public/js/dist/all-defer.js differ diff --git a/public/js/dist/bootstrap-table.js b/public/js/dist/bootstrap-table.js index 7d45dced5d..69d67d52e7 100644 Binary files a/public/js/dist/bootstrap-table.js and b/public/js/dist/bootstrap-table.js differ diff --git a/public/mix-manifest.json b/public/mix-manifest.json index 6c7fa0e60f..0c7d2c8a80 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -31,9 +31,9 @@ "/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=e11465c0eff0549edd4e8ea6bbcf242f", "/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=99c395f0bab5966f32f63f4e55899e64", "/js/build/vendor.js": "/js/build/vendor.js?id=a2b971da417306a63385c8098acfe4af", - "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=d0eb38da8b772a21b827b7df208dc4fe", + "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=857da5daffd13e0553510e5ccd410c79", "/js/dist/all.js": "/js/dist/all.js?id=13bdb521e0c745d7f81dae3fb110b650", - "/js/dist/all-defer.js": "/js/dist/all-defer.js?id=19ccc62a8f1ea103dede4808837384d4", + "/js/dist/all-defer.js": "/js/dist/all-defer.js?id=18d36546bdad8285c229008df799b343", "/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=0a82a6ae6bb4e58fe62d162c4fb50397", "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=d419cb63a12dc175d71645c876bfc2ab", "/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb", diff --git a/resources/lang/en-US/admin/settings/general.php b/resources/lang/en-US/admin/settings/general.php index 33cfd7b416..71fb8eb2c6 100644 --- a/resources/lang/en-US/admin/settings/general.php +++ b/resources/lang/en-US/admin/settings/general.php @@ -261,7 +261,7 @@ return [ 'two_factor_enrollment' => 'Two-Factor Enrollment', 'two_factor_enabled_text' => 'Enable Two Factor', 'two_factor_reset' => 'Reset Two-Factor Secret', - 'two_factor_reset_help' => 'This will force the user to enroll their device with Google Authenticator again. This can be useful if their currently enrolled device is lost or stolen. ', + 'two_factor_reset_help' => 'This will force the user to enroll their device with their authenticator app again. This can be useful if their currently enrolled device is lost or stolen. ', 'two_factor_reset_success' => 'Two factor device successfully reset', 'two_factor_reset_error' => 'Two factor device reset failed', 'two_factor_enabled_warning' => 'Enabling two-factor if it is not currently enabled will immediately force you to authenticate with a Google Auth enrolled device. You will have the ability to enroll your device if one is not currently enrolled.', diff --git a/resources/lang/en-US/general.php b/resources/lang/en-US/general.php index bf17024844..9f9a0e08c7 100644 --- a/resources/lang/en-US/general.php +++ b/resources/lang/en-US/general.php @@ -1,6 +1,7 @@ '2FA reset', 'accessories' => 'Accessories', 'activated' => 'Activated', 'accepted_date' => 'Date Accepted', diff --git a/resources/lang/en-US/validation.php b/resources/lang/en-US/validation.php index 1c6ad8a148..05374e23af 100644 --- a/resources/lang/en-US/validation.php +++ b/resources/lang/en-US/validation.php @@ -105,6 +105,8 @@ return [ 'gte' => [ 'numeric' => 'Value cannot be negative' ], + 'checkboxes' => ':attribute contains invalid options.', + 'radio_buttons' => ':attribute is invalid.', /* @@ -151,4 +153,10 @@ return [ 'attributes' => [], + /* + |-------------------------------------------------------------------------- + | Generic Validation Messages + |-------------------------------------------------------------------------- + */ + 'invalid_value_in_field' => 'Invalid value included in this field', ]; diff --git a/resources/views/custom_fields/fields/edit.blade.php b/resources/views/custom_fields/fields/edit.blade.php index 504b556faa..e21e9fba48 100644 --- a/resources/views/custom_fields/fields/edit.blade.php +++ b/resources/views/custom_fields/fields/edit.blade.php @@ -135,7 +135,7 @@ @if (!$field->id) -
+
- @endif @@ -298,11 +297,16 @@ }).change(); // Only display the field element if the type is not text + // and don't display encryption option for checkbox or radio $(".field_element").change(function(){ $(this).find("option:selected").each(function(){ if (($(this).attr("value")!="text") && ($(this).attr("value")!="textarea")){ $("#field_values_text").show(); + if ($(this).attr("value") == "checkbox" || $(this).attr("value") == "radio") { + $("#encryption_section").hide(); + } } else{ + $("#encryption_section").show(); $("#field_values_text").hide(); } }); diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index a32503d7ea..550359eb0b 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -904,27 +904,18 @@ @endcan @can('delete', $asset) - @if ($asset->deleted_at=='') -
- +
+ @if ($asset->deleted_at=='') + {{ trans('general.delete') }} -
- @endif + @else +
+ @csrf + +
+ @endif @endcan - @if ($asset->deleted_at!='') -
-
- @csrf - -
-
- @endif - - @if ($snipeSettings->qr_code=='1') - QR code for {{ $asset->getDisplayNameAttribute() }} - @endif - @if (($asset->assignedTo) && ($asset->deleted_at==''))

{{ trans('admin/hardware/form.checkedout_to') }}

@@ -982,9 +973,17 @@
@endif + + @if ($snipeSettings->qr_code=='1') +
+ QR code for {{ $asset->getDisplayNameAttribute() }} +
+ @endif +
+
diff --git a/resources/views/licenses/view.blade.php b/resources/views/licenses/view.blade.php index b23023f489..4f47055c27 100755 --- a/resources/views/licenses/view.blade.php +++ b/resources/views/licenses/view.blade.php @@ -174,23 +174,56 @@ @endif - @if ($license->supplier_id) -
-
- - {{ trans('general.supplier') }} - -
-
- @if ($license->supplier) - + @if ($license->supplier) +
+
+ {{ trans('general.supplier') }} +
+
+ @can('view', \App\Models\Supplier::class) + + {{ $license->supplier->name }} + + @else {{ $license->supplier->name }} - - @else - {{ trans('general.deleted') }} - @endif + @endcan + + @if ($license->supplier->url) +
{{ $license->supplier->url }} + @endif + + @if ($license->supplier->phone) +
+ {{ $license->supplier->phone }} + @endif + + @if ($license->supplier->email) +
{{ $license->supplier->email }} + @endif + + @if ($license->supplier->address) +
{{ $license->supplier->address }} + @endif + @if ($license->supplier->address2) +
{{ $license->supplier->address2 }} + @endif + @if ($license->supplier->city) +
{{ $license->supplier->city }}, + @endif + @if ($license->supplier->state) + {{ $license->supplier->state }} + @endif + @if ($license->supplier->country) + {{ $license->supplier->country }} + @endif + @if ($license->supplier->zip) + {{ $license->supplier->zip }} + @endif + +
-
+ @else + {{ trans('general.deleted') }} @endif diff --git a/resources/views/models/custom_fields_form.blade.php b/resources/views/models/custom_fields_form.blade.php index bae98373e4..3c49ef8f7e 100644 --- a/resources/views/models/custom_fields_form.blade.php +++ b/resources/views/models/custom_fields_form.blade.php @@ -9,7 +9,7 @@ @if ($field->element=='listbox') {{ Form::select($field->db_column_name(), $field->formatFieldValuesAsArray(), - Request::old($field->db_column_name(),(isset($item) ? Helper::gracefulDecrypt($field, htmlspecialchars($item->{$field->db_column_name()}, ENT_QUOTES)) : $field->defaultValue($model->id))), ['class'=>'format select2 form-control']) }} + Request::old($field->db_column_name(),(isset($item) ? Helper::gracefulDecrypt($field, $item->{$field->db_column_name()}) : $field->defaultValue($model->id))), ['class'=>'format select2 form-control']) }} @elseif ($field->element=='textarea') diff --git a/resources/views/models/custom_fields_form_bulk_edit.blade.php b/resources/views/models/custom_fields_form_bulk_edit.blade.php index f30c60d331..dc0ad1f88a 100644 --- a/resources/views/models/custom_fields_form_bulk_edit.blade.php +++ b/resources/views/models/custom_fields_form_bulk_edit.blade.php @@ -25,7 +25,7 @@ @if ($field->element=='listbox') {{ Form::select($field->db_column_name(), $field->formatFieldValuesAsArray(), - Request::old($field->db_column_name(),(isset($item) ? Helper::gracefulDecrypt($field, htmlspecialchars($item->{$field->db_column_name()}, ENT_QUOTES)) : $field->defaultValue($model->id))), ['class'=>'format select2 form-control']) }} + Request::old($field->db_column_name(),(isset($item) ? Helper::gracefulDecrypt($field, $item->{$field->db_column_name()}) : $field->defaultValue($model->id))), ['class'=>'format select2 form-control']) }} @elseif ($field->element=='textarea') @if($field->is_unique) diff --git a/resources/views/models/view.blade.php b/resources/views/models/view.blade.php index 91f112d8aa..76d3322998 100755 --- a/resources/views/models/view.blade.php +++ b/resources/views/models/view.blade.php @@ -236,6 +236,12 @@ @endif + @if ($model->created_at) +
  • {{ trans('general.created_at') }}: + {{ Helper::getFormattedDateObject($model->created_at, 'datetime', false) }} +
  • + @endif + @if ($model->min_amt)
  • {{ trans('general.min_amt') }}: {{$model->min_amt }} @@ -313,11 +319,6 @@
  • @endif - - - @if ($model->deleted_at!='') -

  • {{ trans('admin/models/general.restore') }}
  • - @endif @if ($model->note) @@ -337,22 +338,32 @@ @can('create', \App\Models\AssetModel::class) @endcan @can('delete', \App\Models\AssetModel::class) @if ($model->assets_count > 0) -
    - +
    @else -
    - - {{ trans('general.delete') }} -
    + @endif + + +
    + @if ($model->deleted_at!='') +
    + @csrf + +
    + @else + + {{ trans('general.delete') }} + @endif +
    + @endcan
    diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 95f2785b61..a3d6b6df2d 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -46,16 +46,19 @@ stickyHeader: true, stickyHeaderOffsetLeft: parseInt($('body').css('padding-left'), 10), stickyHeaderOffsetRight: parseInt($('body').css('padding-right'), 10), - locale: locale, + locale: '{{ app()->getLocale() }}', undefinedText: '', iconsPrefix: 'fa', cookieStorage: '{{ config('session.bs_table_storage') }}', cookie: true, cookieExpire: '2y', + showColumnsToggleAll: true, + minimumCountColumns: 2, mobileResponsive: true, maintainSelected: true, trimOnSearch: false, showSearchClearButton: true, + addrbar: {{ (config('session.bs_table_addrbar') == 'true') ? 'true' : 'false'}}, // deeplink search phrases, sorting, etc paginationFirstText: "{{ trans('general.first') }}", paginationLastText: "{{ trans('general.last') }}", paginationPreText: "{{ trans('general.previous') }}", @@ -85,7 +88,7 @@ export: 'fa-download', clearSearch: 'fa-times' }, - exportOptions: export_options, + exportOptions: export_options, exportTypes: ['xlsx', 'excel', 'csv', 'pdf','json', 'xml', 'txt', 'sql', 'doc' ], onLoadSuccess: function () { $('[data-tooltip="true"]').tooltip(); // Needed to attach tooltips after ajax call diff --git a/resources/views/settings/security.blade.php b/resources/views/settings/security.blade.php index a23b8cece9..f108683dc3 100644 --- a/resources/views/settings/security.blade.php +++ b/resources/views/settings/security.blade.php @@ -74,12 +74,11 @@ -
    +
    {{ Form::label('pwd_secure_complexity', trans('admin/settings/general.pwd_secure_complexity')) }}
    - + @if ($errors->has('pwd_secure_complexity.*')) + {{ trans('validation.invalid_value_in_field') }} + @endif

    {{ trans('admin/settings/general.pwd_secure_complexity_help') }}

    diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 8d24e440b8..9a2a039af7 100755 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -499,18 +499,21 @@
    @endif - -
    -
    - {{ trans('admin/settings/general.two_factor_reset') }} - - - + @if ((Auth::user()->isSuperUser()) && ($user->two_factor_active_and_enrolled()) && ($snipeSettings->two_factor_enabled!='0') && ($snipeSettings->two_factor_enabled!='')) + +
    + +
    +

    {{ trans('admin/settings/general.two_factor_reset_help') }}

    +
    -
    -

    {{ trans('admin/settings/general.two_factor_reset_help') }}

    -
    -
    + @endif + @endif @@ -702,7 +705,7 @@ $(document).ready(function() { $("#two_factor_resetrow").removeClass('success'); $("#two_factor_resetrow").removeClass('danger'); $("#two_factor_resetstatus").html(''); - $("#two_factor_reseticon").html(''); + $("#two_factor_reseticon").html(' '); $.ajax({ url: '{{ route('api.users.two_factor_reset', ['id'=> $user->id]) }}', type: 'POST', @@ -715,13 +718,12 @@ $(document).ready(function() { success: function (data) { $("#two_factor_reseticon").html(''); - $("#two_factor_resetstatus").html('' + data.message); + $("#two_factor_resetstatus").html(' ' + data.message + ''); }, error: function (data) { $("#two_factor_reseticon").html(''); - $("#two_factor_reseticon").html(''); - $('#two_factor_resetstatus').text(data.message); + $("#two_factor_resetstatus").html(' ' + data.message + ''); } diff --git a/resources/views/users/print.blade.php b/resources/views/users/print.blade.php index 324fda1b0f..2c9b4719f2 100644 --- a/resources/views/users/print.blade.php +++ b/resources/views/users/print.blade.php @@ -110,6 +110,7 @@ {{ trans('general.name') }} {{ trans('general.category') }} {{ trans('admin/hardware/form.model') }} + {{ trans('admin/hardware/form.default_location') }} {{ trans('general.location') }} {{ trans('admin/hardware/form.serial') }} {{ trans('admin/hardware/table.checkout_date') }} @@ -129,6 +130,7 @@ {{ $asset->name }} {{ (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : trans('general.invalid_category') }} {{ ($asset->model) ? $asset->model->name : trans('general.invalid_model') }} + {{ ($asset->defaultLoc) ? $asset->defaultLoc->name : '' }} {{ ($asset->location) ? $asset->location->name : '' }} {{ $asset->serial }} @@ -155,6 +157,7 @@ {{ $asset->asset_tag }} {{ $asset->name }} {{ $asset->model->category->name }} + {{ ($asset->defaultLoc) ? $asset->defaultLoc->name : '' }} {{ ($asset->location) ? $asset->location->name : '' }} {{ $asset->model->name }} {{ $asset->serial }} diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index a8c24b9321..3dbd9ff531 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -597,7 +597,7 @@
    - @if ((Auth::user()->isSuperUser()) && ($snipeSettings->two_factor_enabled!='0') && ($snipeSettings->two_factor_enabled!='')) + @if ((Auth::user()->isSuperUser()) && ($user->two_factor_active_and_enrolled()) && ($snipeSettings->two_factor_enabled!='0') && ($snipeSettings->two_factor_enabled!=''))
    diff --git a/tests/Feature/Api/Accessories/AccessoryCheckoutTest.php b/tests/Feature/Api/Accessories/AccessoryCheckoutTest.php index d65a3ad613..854a96ada2 100644 --- a/tests/Feature/Api/Accessories/AccessoryCheckoutTest.php +++ b/tests/Feature/Api/Accessories/AccessoryCheckoutTest.php @@ -7,13 +7,10 @@ use App\Models\Actionlog; use App\Models\User; use App\Notifications\CheckoutAccessoryNotification; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AccessoryCheckoutTest extends TestCase { - use InteractsWithSettings; - public function testCheckingOutAccessoryRequiresCorrectPermission() { $this->actingAsForApi(User::factory()->create()) diff --git a/tests/Feature/Api/Assets/AssetCheckinTest.php b/tests/Feature/Api/Assets/AssetCheckinTest.php index 6f8daf5691..add90a067d 100644 --- a/tests/Feature/Api/Assets/AssetCheckinTest.php +++ b/tests/Feature/Api/Assets/AssetCheckinTest.php @@ -11,13 +11,10 @@ use App\Models\Statuslabel; use App\Models\User; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Event; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetCheckinTest extends TestCase { - use InteractsWithSettings; - public function testCheckingInAssetRequiresCorrectPermission() { $this->actingAsForApi(User::factory()->create()) diff --git a/tests/Feature/Api/Assets/AssetIndexTest.php b/tests/Feature/Api/Assets/AssetIndexTest.php index 778483c1c9..3175db6953 100644 --- a/tests/Feature/Api/Assets/AssetIndexTest.php +++ b/tests/Feature/Api/Assets/AssetIndexTest.php @@ -6,13 +6,10 @@ use App\Models\Asset; use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetIndexTest extends TestCase { - use InteractsWithSettings; - public function testAssetIndexReturnsExpectedAssets() { Asset::factory()->count(3)->create(); diff --git a/tests/Feature/Api/Assets/AssetStoreTest.php b/tests/Feature/Api/Assets/AssetStoreTest.php index 92a58a5006..e98da36cf9 100644 --- a/tests/Feature/Api/Assets/AssetStoreTest.php +++ b/tests/Feature/Api/Assets/AssetStoreTest.php @@ -9,15 +9,11 @@ use App\Models\Location; use App\Models\Statuslabel; use App\Models\Supplier; use App\Models\User; -use Carbon\Carbon; use Illuminate\Testing\Fluent\AssertableJson; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetStoreTest extends TestCase { - use InteractsWithSettings; - public function testRequiresPermissionToCreateAsset() { $this->actingAsForApi(User::factory()->create()) @@ -69,8 +65,7 @@ class AssetStoreTest extends TestCase $this->assertEquals('random_string', $asset->asset_tag); $this->assertEquals($userAssigned->id, $asset->assigned_to); $this->assertTrue($asset->company->is($company)); - // I don't see this on the GUI side either, but it's in the docs so I'm guessing that's a mistake? It wasn't in the controller. - // $this->assertEquals('2023-09-03', $asset->last_audit_date); + $this->assertEquals('2023-09-03 00:00:00', $asset->last_audit_date->format('Y-m-d H:i:s')); $this->assertTrue($asset->location->is($location)); $this->assertTrue($asset->model->is($model)); $this->assertEquals('A New Asset', $asset->name); @@ -86,6 +81,52 @@ class AssetStoreTest extends TestCase $this->assertEquals(10, $asset->warranty_months); } + public function testSetsLastAuditDateToMidnightOfProvidedDate() + { + $response = $this->actingAsForApi(User::factory()->superuser()->create()) + ->postJson(route('api.assets.store'), [ + 'last_audit_date' => '2023-09-03 12:23:45', + 'asset_tag' => '1234', + 'model_id' => AssetModel::factory()->create()->id, + 'status_id' => Statuslabel::factory()->create()->id, + ]) + ->assertOk() + ->assertStatusMessageIs('success'); + + $asset = Asset::find($response['payload']['id']); + $this->assertEquals('00:00:00', $asset->last_audit_date->format('H:i:s')); + } + + public function testLastAuditDateCanBeNull() + { + $response = $this->actingAsForApi(User::factory()->superuser()->create()) + ->postJson(route('api.assets.store'), [ + // 'last_audit_date' => '2023-09-03 12:23:45', + 'asset_tag' => '1234', + 'model_id' => AssetModel::factory()->create()->id, + 'status_id' => Statuslabel::factory()->create()->id, + ]) + ->assertOk() + ->assertStatusMessageIs('success'); + + $asset = Asset::find($response['payload']['id']); + $this->assertNull($asset->last_audit_date); + } + + public function testNonDateUsedForLastAuditDateReturnsValidationError() + { + $response = $this->actingAsForApi(User::factory()->superuser()->create()) + ->postJson(route('api.assets.store'), [ + 'last_audit_date' => 'this-is-not-valid', + 'asset_tag' => '1234', + 'model_id' => AssetModel::factory()->create()->id, + 'status_id' => Statuslabel::factory()->create()->id, + ]) + ->assertStatusMessageIs('error'); + + $this->assertNotNull($response->json('messages.last_audit_date')); + } + public function testArchivedDepreciateAndPhysicalCanBeNull() { $model = AssetModel::factory()->ipadModel()->create(); diff --git a/tests/Feature/Api/Assets/AssetsForSelectListTest.php b/tests/Feature/Api/Assets/AssetsForSelectListTest.php index cccae38d38..3c5e1e4e7c 100644 --- a/tests/Feature/Api/Assets/AssetsForSelectListTest.php +++ b/tests/Feature/Api/Assets/AssetsForSelectListTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; use App\Models\Company; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetsForSelectListTest extends TestCase { - use InteractsWithSettings; - public function testAssetsCanBeSearchedForByAssetTag() { Asset::factory()->create(['asset_tag' => '0001']); diff --git a/tests/Feature/Api/Assets/RequestableAssetsTest.php b/tests/Feature/Api/Assets/RequestableAssetsTest.php index 8649b1b00b..d90e45f223 100644 --- a/tests/Feature/Api/Assets/RequestableAssetsTest.php +++ b/tests/Feature/Api/Assets/RequestableAssetsTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Assets; use App\Models\Asset; use App\Models\Company; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class RequestableAssetsTest extends TestCase { - use InteractsWithSettings; - public function testViewingRequestableAssetsRequiresCorrectPermission() { $this->actingAsForApi(User::factory()->create()) diff --git a/tests/Feature/Api/Components/ComponentIndexTest.php b/tests/Feature/Api/Components/ComponentIndexTest.php index ee83b7a46d..517724a499 100644 --- a/tests/Feature/Api/Components/ComponentIndexTest.php +++ b/tests/Feature/Api/Components/ComponentIndexTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Components; use App\Models\Company; use App\Models\Component; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ComponentIndexTest extends TestCase { - use InteractsWithSettings; - public function testComponentIndexAdheresToCompanyScoping() { [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/Api/Consumables/ConsumableCheckoutTest.php b/tests/Feature/Api/Consumables/ConsumableCheckoutTest.php index 103be96ac2..1528e65aa3 100644 --- a/tests/Feature/Api/Consumables/ConsumableCheckoutTest.php +++ b/tests/Feature/Api/Consumables/ConsumableCheckoutTest.php @@ -7,13 +7,10 @@ use App\Models\Consumable; use App\Models\User; use App\Notifications\CheckoutConsumableNotification; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumableCheckoutTest extends TestCase { - use InteractsWithSettings; - public function testCheckingOutConsumableRequiresCorrectPermission() { $this->actingAsForApi(User::factory()->create()) diff --git a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php index 33c10ed078..00fa43da27 100644 --- a/tests/Feature/Api/Consumables/ConsumablesIndexTest.php +++ b/tests/Feature/Api/Consumables/ConsumablesIndexTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Consumables; use App\Models\Company; use App\Models\Consumable; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumablesIndexTest extends TestCase { - use InteractsWithSettings; - public function testConsumableIndexAdheresToCompanyScoping() { [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/Api/Departments/DepartmentIndexTest.php b/tests/Feature/Api/Departments/DepartmentIndexTest.php index 1a3884308f..11ab5df9bc 100644 --- a/tests/Feature/Api/Departments/DepartmentIndexTest.php +++ b/tests/Feature/Api/Departments/DepartmentIndexTest.php @@ -5,15 +5,11 @@ namespace Tests\Feature\Api\Departments; use App\Models\Company; use App\Models\Department; use App\Models\User; -use Illuminate\Routing\Route; use Illuminate\Testing\Fluent\AssertableJson; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DepartmentIndexTest extends TestCase { - use InteractsWithSettings; - public function testViewingDepartmentIndexRequiresAuthentication() { $this->getJson(route('api.departments.index'))->assertRedirect(); diff --git a/tests/Feature/Api/Groups/GroupStoreTest.php b/tests/Feature/Api/Groups/GroupStoreTest.php index 9ffba51913..31a69fb469 100644 --- a/tests/Feature/Api/Groups/GroupStoreTest.php +++ b/tests/Feature/Api/Groups/GroupStoreTest.php @@ -4,13 +4,10 @@ namespace Tests\Feature\Api\Groups; use App\Models\Group; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class GroupStoreTest extends TestCase { - use InteractsWithSettings; - public function testStoringGroupRequiresSuperAdminPermission() { $this->actingAsForApi(User::factory()->create()) diff --git a/tests/Feature/Api/Licenses/LicensesIndexTest.php b/tests/Feature/Api/Licenses/LicensesIndexTest.php index a21a27da73..603002a095 100644 --- a/tests/Feature/Api/Licenses/LicensesIndexTest.php +++ b/tests/Feature/Api/Licenses/LicensesIndexTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Licenses; use App\Models\Company; use App\Models\License; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LicensesIndexTest extends TestCase { - use InteractsWithSettings; - public function testLicensesIndexAdheresToCompanyScoping() { [$companyA, $companyB] = Company::factory()->count(2)->create(); diff --git a/tests/Feature/Api/Locations/LocationsForSelectListTest.php b/tests/Feature/Api/Locations/LocationsForSelectListTest.php index 4170cfc7f7..bfc7fc5374 100644 --- a/tests/Feature/Api/Locations/LocationsForSelectListTest.php +++ b/tests/Feature/Api/Locations/LocationsForSelectListTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Locations; use App\Models\Location; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LocationsForSelectListTest extends TestCase { - use InteractsWithSettings; - public function testGettingLocationListRequiresProperPermission() { $this->actingAsForApi(User::factory()->create()) diff --git a/tests/Feature/Api/Users/UpdateUserApiTest.php b/tests/Feature/Api/Users/UpdateUserApiTest.php index 0786b171e4..f58aae4a05 100644 --- a/tests/Feature/Api/Users/UpdateUserApiTest.php +++ b/tests/Feature/Api/Users/UpdateUserApiTest.php @@ -3,13 +3,10 @@ namespace Tests\Feature\Api\Users; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UpdateUserApiTest extends TestCase { - use InteractsWithSettings; - public function testApiUsersCanBeActivatedWithNumber() { $admin = User::factory()->superuser()->create(); diff --git a/tests/Feature/Api/Users/UsersForSelectListTest.php b/tests/Feature/Api/Users/UsersForSelectListTest.php index 8cdf700f04..1ebfcf72eb 100644 --- a/tests/Feature/Api/Users/UsersForSelectListTest.php +++ b/tests/Feature/Api/Users/UsersForSelectListTest.php @@ -6,13 +6,10 @@ use App\Models\Company; use App\Models\User; use Illuminate\Testing\Fluent\AssertableJson; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UsersForSelectListTest extends TestCase { - use InteractsWithSettings; - public function testUsersAreReturned() { $users = User::factory()->superuser()->count(3)->create(); diff --git a/tests/Feature/Api/Users/UsersSearchTest.php b/tests/Feature/Api/Users/UsersSearchTest.php index 723a115db1..72f23017f5 100644 --- a/tests/Feature/Api/Users/UsersSearchTest.php +++ b/tests/Feature/Api/Users/UsersSearchTest.php @@ -5,13 +5,10 @@ namespace Tests\Feature\Api\Users; use App\Models\Company; use App\Models\User; use Laravel\Passport\Passport; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UsersSearchTest extends TestCase { - use InteractsWithSettings; - public function testCanSearchByUserFirstAndLastName() { User::factory()->create(['first_name' => 'Luke', 'last_name' => 'Skywalker']); diff --git a/tests/Feature/Api/Users/UsersUpdateTest.php b/tests/Feature/Api/Users/UsersUpdateTest.php index 953a671cf1..d6e0f9e46b 100644 --- a/tests/Feature/Api/Users/UsersUpdateTest.php +++ b/tests/Feature/Api/Users/UsersUpdateTest.php @@ -8,13 +8,10 @@ use App\Models\Group; use App\Models\Location; use App\Models\User; use Illuminate\Support\Facades\Hash; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UsersUpdateTest extends TestCase { - use InteractsWithSettings; - public function testCanUpdateUserViaPatch() { $admin = User::factory()->superuser()->create(); diff --git a/tests/Feature/Checkins/AccessoryCheckinTest.php b/tests/Feature/Checkins/AccessoryCheckinTest.php index 25cd5d0d87..56030991e2 100644 --- a/tests/Feature/Checkins/AccessoryCheckinTest.php +++ b/tests/Feature/Checkins/AccessoryCheckinTest.php @@ -8,13 +8,10 @@ use App\Models\User; use App\Notifications\CheckinAccessoryNotification; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AccessoryCheckinTest extends TestCase { - use InteractsWithSettings; - public function testCheckingInAccessoryRequiresCorrectPermission() { $accessory = Accessory::factory()->checkedOutToUser()->create(); diff --git a/tests/Feature/Checkins/AssetCheckinTest.php b/tests/Feature/Checkins/AssetCheckinTest.php index fb6d21a6ac..1e6d2b995b 100644 --- a/tests/Feature/Checkins/AssetCheckinTest.php +++ b/tests/Feature/Checkins/AssetCheckinTest.php @@ -11,13 +11,10 @@ use App\Models\Statuslabel; use App\Models\User; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Event; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetCheckinTest extends TestCase { - use InteractsWithSettings; - public function testCheckingInAssetRequiresCorrectPermission() { $this->actingAs(User::factory()->create()) diff --git a/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php b/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php index a49b1167cb..bdaf0e780f 100644 --- a/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php +++ b/tests/Feature/CheckoutAcceptances/AccessoryAcceptanceTest.php @@ -7,13 +7,10 @@ use App\Models\CheckoutAcceptance; use App\Notifications\AcceptanceAssetAcceptedNotification; use App\Notifications\AcceptanceAssetDeclinedNotification; use Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AccessoryAcceptanceTest extends TestCase { - use InteractsWithSettings; - /** * This can be absorbed into a bigger test */ diff --git a/tests/Feature/Checkouts/AccessoryCheckoutTest.php b/tests/Feature/Checkouts/AccessoryCheckoutTest.php index cbe9801cc0..11224e4d1f 100644 --- a/tests/Feature/Checkouts/AccessoryCheckoutTest.php +++ b/tests/Feature/Checkouts/AccessoryCheckoutTest.php @@ -7,13 +7,10 @@ use App\Models\Actionlog; use App\Models\User; use App\Notifications\CheckoutAccessoryNotification; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AccessoryCheckoutTest extends TestCase { - use InteractsWithSettings; - public function testCheckingOutAccessoryRequiresCorrectPermission() { $this->actingAs(User::factory()->create()) diff --git a/tests/Feature/Checkouts/ConsumableCheckoutTest.php b/tests/Feature/Checkouts/ConsumableCheckoutTest.php index 5785d0572b..e38ae96c83 100644 --- a/tests/Feature/Checkouts/ConsumableCheckoutTest.php +++ b/tests/Feature/Checkouts/ConsumableCheckoutTest.php @@ -7,13 +7,10 @@ use App\Models\Consumable; use App\Models\User; use App\Notifications\CheckoutConsumableNotification; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ConsumableCheckoutTest extends TestCase { - use InteractsWithSettings; - public function testCheckingOutConsumableRequiresCorrectPermission() { $this->actingAs(User::factory()->create()) diff --git a/tests/Feature/Checkouts/LicenseCheckoutTest.php b/tests/Feature/Checkouts/LicenseCheckoutTest.php index 978fac28f2..2f4f51d4ac 100644 --- a/tests/Feature/Checkouts/LicenseCheckoutTest.php +++ b/tests/Feature/Checkouts/LicenseCheckoutTest.php @@ -6,13 +6,10 @@ use App\Models\Asset; use App\Models\License; use App\Models\LicenseSeat; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class LicenseCheckoutTest extends TestCase { - use InteractsWithSettings; - public function testNotesAreStoredInActionLogOnCheckoutToAsset() { $admin = User::factory()->superuser()->create(); diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index 4e9459fb06..4690a13901 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -3,13 +3,10 @@ namespace Tests\Feature; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DashboardTest extends TestCase { - use InteractsWithSettings; - public function testUsersWithoutAdminAccessAreRedirected() { $this->actingAs(User::factory()->create()) diff --git a/tests/Feature/Notifications/Email/EmailNotificationsUponCheckinTest.php b/tests/Feature/Notifications/Email/EmailNotificationsUponCheckinTest.php index dbe79c5727..4ae415f1ee 100644 --- a/tests/Feature/Notifications/Email/EmailNotificationsUponCheckinTest.php +++ b/tests/Feature/Notifications/Email/EmailNotificationsUponCheckinTest.php @@ -7,7 +7,6 @@ use App\Models\Asset; use App\Models\User; use App\Notifications\CheckinAssetNotification; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; /** @@ -15,8 +14,6 @@ use Tests\TestCase; */ class EmailNotificationsUponCheckinTest extends TestCase { - use InteractsWithSettings; - protected function setUp(): void { parent::setUp(); diff --git a/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckinTest.php b/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckinTest.php index b6bb7801a7..29bf06d9dc 100644 --- a/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckinTest.php +++ b/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckinTest.php @@ -14,7 +14,6 @@ use App\Notifications\CheckinAssetNotification; use App\Notifications\CheckinLicenseSeatNotification; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; /** @@ -22,8 +21,6 @@ use Tests\TestCase; */ class SlackNotificationsUponCheckinTest extends TestCase { - use InteractsWithSettings; - protected function setUp(): void { parent::setUp(); diff --git a/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckoutTest.php b/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckoutTest.php index 550f7c5b18..048448cad7 100644 --- a/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckoutTest.php +++ b/tests/Feature/Notifications/Webhooks/SlackNotificationsUponCheckoutTest.php @@ -16,7 +16,6 @@ use App\Notifications\CheckoutConsumableNotification; use App\Notifications\CheckoutLicenseSeatNotification; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; /** @@ -24,8 +23,6 @@ use Tests\TestCase; */ class SlackNotificationsUponCheckoutTest extends TestCase { - use InteractsWithSettings; - protected function setUp(): void { parent::setUp(); diff --git a/tests/Feature/Reports/CustomReportTest.php b/tests/Feature/Reports/CustomReportTest.php index dd3199212e..d90e4cb2a0 100644 --- a/tests/Feature/Reports/CustomReportTest.php +++ b/tests/Feature/Reports/CustomReportTest.php @@ -8,14 +8,10 @@ use App\Models\User; use Illuminate\Testing\TestResponse; use League\Csv\Reader; use PHPUnit\Framework\Assert; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; - class CustomReportTest extends TestCase { - use InteractsWithSettings; - protected function setUp(): void { parent::setUp(); diff --git a/tests/Feature/Users/UpdateUserTest.php b/tests/Feature/Users/UpdateUserTest.php index 92245059ef..934fbce2b8 100644 --- a/tests/Feature/Users/UpdateUserTest.php +++ b/tests/Feature/Users/UpdateUserTest.php @@ -3,13 +3,10 @@ namespace Tests\Feature\Users; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class UpdateUserTest extends TestCase { - use InteractsWithSettings; - public function testUsersCanBeActivatedWithNumber() { $admin = User::factory()->superuser()->create(); diff --git a/tests/Support/InteractsWithSettings.php b/tests/Support/InitializesSettings.php similarity index 90% rename from tests/Support/InteractsWithSettings.php rename to tests/Support/InitializesSettings.php index a8c0070188..7c08e6f897 100644 --- a/tests/Support/InteractsWithSettings.php +++ b/tests/Support/InitializesSettings.php @@ -4,7 +4,7 @@ namespace Tests\Support; use App\Models\Setting; -trait InteractsWithSettings +trait InitializesSettings { protected Settings $settings; diff --git a/tests/TestCase.php b/tests/TestCase.php index 535f9a3e21..0c5ecc37e8 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -9,7 +9,7 @@ use RuntimeException; use Tests\Support\AssertsAgainstSlackNotifications; use Tests\Support\CustomTestMacros; use Tests\Support\InteractsWithAuthentication; -use Tests\Support\InteractsWithSettings; +use Tests\Support\InitializesSettings; abstract class TestCase extends BaseTestCase { @@ -17,6 +17,7 @@ abstract class TestCase extends BaseTestCase use CreatesApplication; use CustomTestMacros; use InteractsWithAuthentication; + use InitializesSettings; use LazilyRefreshDatabase; private array $globallyDisabledMiddleware = [ @@ -25,20 +26,23 @@ abstract class TestCase extends BaseTestCase protected function setUp(): void { - if (!file_exists(realpath(__DIR__ . '/../') . '/.env.testing')) { - throw new RuntimeException( - '.env.testing file does not exist. Aborting to avoid wiping your local database' - ); - } + $this->guardAgainstMissingEnv(); parent::setUp(); + $this->registerCustomMacros(); + $this->withoutMiddleware($this->globallyDisabledMiddleware); - if (collect(class_uses_recursive($this))->contains(InteractsWithSettings::class)) { - $this->initializeSettings(); - } + $this->initializeSettings(); + } - $this->registerCustomMacros(); + private function guardAgainstMissingEnv(): void + { + if (!file_exists(realpath(__DIR__ . '/../') . '/.env.testing')) { + throw new RuntimeException( + '.env.testing file does not exist. Aborting to avoid wiping your local database.' + ); + } } } diff --git a/tests/Unit/AssetMaintenanceTest.php b/tests/Unit/AssetMaintenanceTest.php index 69c4c30938..46a0efdd7c 100644 --- a/tests/Unit/AssetMaintenanceTest.php +++ b/tests/Unit/AssetMaintenanceTest.php @@ -2,14 +2,10 @@ namespace Tests\Unit; use App\Models\AssetMaintenance; -use Carbon\Carbon; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetMaintenanceTest extends TestCase { - use InteractsWithSettings; - public function testZerosOutWarrantyIfBlank() { $c = new AssetMaintenance; diff --git a/tests/Unit/AssetModelTest.php b/tests/Unit/AssetModelTest.php index aec8edf692..4cc62e20a0 100644 --- a/tests/Unit/AssetModelTest.php +++ b/tests/Unit/AssetModelTest.php @@ -4,13 +4,10 @@ namespace Tests\Unit; use App\Models\Asset; use App\Models\Category; use App\Models\AssetModel; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetModelTest extends TestCase { - use InteractsWithSettings; - public function testAnAssetModelContainsAssets() { $category = Category::factory()->create([ diff --git a/tests/Unit/AssetTest.php b/tests/Unit/AssetTest.php index d3d9a90114..9c3a76af69 100644 --- a/tests/Unit/AssetTest.php +++ b/tests/Unit/AssetTest.php @@ -5,13 +5,10 @@ use App\Models\Asset; use App\Models\AssetModel; use App\Models\Category; use Carbon\Carbon; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class AssetTest extends TestCase { - use InteractsWithSettings; - public function testAutoIncrement() { $this->settings->enableAutoIncrement(); diff --git a/tests/Unit/CategoryTest.php b/tests/Unit/CategoryTest.php index e5c98a67ad..c3c9b0de8e 100644 --- a/tests/Unit/CategoryTest.php +++ b/tests/Unit/CategoryTest.php @@ -4,13 +4,10 @@ namespace Tests\Unit; use App\Models\Category; use App\Models\AssetModel; use App\Models\Asset; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class CategoryTest extends TestCase { - use InteractsWithSettings; - public function testFailsEmptyValidation() { // An Asset requires a name, a qty, and a category_id. diff --git a/tests/Unit/CompanyScopingTest.php b/tests/Unit/CompanyScopingTest.php index 669dd5ed41..3923dd9f7d 100644 --- a/tests/Unit/CompanyScopingTest.php +++ b/tests/Unit/CompanyScopingTest.php @@ -12,13 +12,10 @@ use App\Models\License; use App\Models\LicenseSeat; use App\Models\User; use Illuminate\Database\Eloquent\Model; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class CompanyScopingTest extends TestCase { - use InteractsWithSettings; - public function models(): array { return [ diff --git a/tests/Unit/ComponentTest.php b/tests/Unit/ComponentTest.php index 8f71057bfc..df8f64771f 100644 --- a/tests/Unit/ComponentTest.php +++ b/tests/Unit/ComponentTest.php @@ -5,13 +5,10 @@ use App\Models\Category; use App\Models\Company; use App\Models\Component; use App\Models\Location; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class ComponentTest extends TestCase { - use InteractsWithSettings; - public function testAComponentBelongsToACompany() { $component = Component::factory() diff --git a/tests/Unit/DepreciationTest.php b/tests/Unit/DepreciationTest.php index ed033cf442..4dd8422276 100644 --- a/tests/Unit/DepreciationTest.php +++ b/tests/Unit/DepreciationTest.php @@ -5,13 +5,10 @@ use App\Models\Depreciation; use App\Models\Category; use App\Models\License; use App\Models\AssetModel; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class DepreciationTest extends TestCase { - use InteractsWithSettings; - public function testADepreciationHasModels() { $depreciation = Depreciation::factory()->create(); diff --git a/tests/Unit/LdapTest.php b/tests/Unit/LdapTest.php index c286b38496..6beb0d2118 100644 --- a/tests/Unit/LdapTest.php +++ b/tests/Unit/LdapTest.php @@ -3,8 +3,6 @@ namespace Tests\Unit; use App\Models\Ldap; -use Exception; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; /** @@ -12,7 +10,6 @@ use Tests\TestCase; */ class LdapTest extends TestCase { - use InteractsWithSettings; use \phpmock\phpunit\PHPMock; public function testConnect() diff --git a/tests/Unit/Models/Company/GetIdForCurrentUserTest.php b/tests/Unit/Models/Company/GetIdForCurrentUserTest.php index 1ca88d7cac..6d77c88731 100644 --- a/tests/Unit/Models/Company/GetIdForCurrentUserTest.php +++ b/tests/Unit/Models/Company/GetIdForCurrentUserTest.php @@ -4,13 +4,10 @@ namespace Tests\Unit\Models\Company; use App\Models\Company; use App\Models\User; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class GetIdForCurrentUserTest extends TestCase { - use InteractsWithSettings; - public function testReturnsProvidedValueWhenFullCompanySupportDisabled() { $this->settings->disableMultipleFullCompanySupport(); diff --git a/tests/Unit/NotificationTest.php b/tests/Unit/NotificationTest.php index 64cf8afb0a..8005759a1e 100644 --- a/tests/Unit/NotificationTest.php +++ b/tests/Unit/NotificationTest.php @@ -8,13 +8,10 @@ use App\Models\Category; use Carbon\Carbon; use App\Notifications\CheckoutAssetNotification; use Illuminate\Support\Facades\Notification; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class NotificationTest extends TestCase { - use InteractsWithSettings; - public function testAUserIsEmailedIfTheyCheckoutAnAssetWithEULA() { $admin = User::factory()->superuser()->create(); diff --git a/tests/Unit/SnipeModelTest.php b/tests/Unit/SnipeModelTest.php index ad4231010f..2bc81da61b 100644 --- a/tests/Unit/SnipeModelTest.php +++ b/tests/Unit/SnipeModelTest.php @@ -2,13 +2,10 @@ namespace Tests\Unit; use App\Models\SnipeModel; -use Tests\Support\InteractsWithSettings; use Tests\TestCase; class SnipeModelTest extends TestCase { - use InteractsWithSettings; - public function testSetsPurchaseDatesAppropriately() { $c = new SnipeModel; diff --git a/webpack.mix.js b/webpack.mix.js index fdda6618ab..cbf7fe1231 100644 --- a/webpack.mix.js +++ b/webpack.mix.js @@ -183,11 +183,11 @@ mix [ "./resources/assets/js/dragtable.js", './node_modules/bootstrap-table/dist/bootstrap-table.js', - "./resources/assets/js/bootstrap-table-reorder-columns.js", './node_modules/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.js', './node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.js', './node_modules/bootstrap-table/dist/extensions/cookie/bootstrap-table-cookie.js', './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.js', + './node_modules/bootstrap-table/dist/extensions/addrbar/bootstrap-table-addrbar.js', './resources/assets/js/extensions/jquery.base64.js', './node_modules/tableexport.jquery.plugin/tableExport.min.js', './node_modules/tableexport.jquery.plugin/libs/jsPDF/jspdf.umd.min.js',