diff --git a/.chipperci.yml b/.chipperci.yml new file mode 100644 index 000000000..fa3b3fd92 --- /dev/null +++ b/.chipperci.yml @@ -0,0 +1,59 @@ +version: 1 + +environment: + php: 8.0 + node: 12 + +services: + - mysql: 5.7 + - dusk: + +on: + push: + branches: + - master + - develop + +pipeline: + - name: Setup + cmd: | + cp -v .env.example .env + + composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Generate Key + cmd: | + php artisan key:generate --force + + - name: Passport Keys + cmd: | + php artisan passport:keys + + - name: Run Migrations + cmd: | + # php artisan migrate --force + + - name: PHPUnit Unit Tests + cmd: | + # php artisan test --testsuite Unit + + - name: PHPUnit Feature Tests + cmd: | + # php artisan test --testsuite Feature + + - name: Browser Tests + cmd: | + cp -v .env.dusk.example .env.dusk.ci + sed -i "s@APP_ENV=.*@APP_ENV=ci@g" .env.dusk.ci + sed -i "s@APP_URL=.*@APP_URL=http://$BUILD_HOST:8000@g" .env.dusk.ci + #sed -i "s@DB_HOST=.*@DB_HOST=mysql@g" .env.dusk.ci + sed -i "s@DB_HOST=.*@DB_HOST=$DB_HOST@g" .env.dusk.ci + sed -i "s@DB_USERNAME=.*@DB_USERNAME=chipperci@g" .env.dusk.ci + sed -i "s@DB_DATABASE=.*@DB_DATABASE=chipperci@g" .env.dusk.ci + sed -i "s@DB_PASSWORD=.*@DB_PASSWORD=secret@g" .env.dusk.ci + + php -S [::0]:8000 -t public 2>server.log & + sleep 2 + php artisan dusk:chrome-driver $CHROME_DRIVER + php artisan dusk --env=ci + diff --git a/.env.example b/.env.example index c523ef0c0..fbf5c4cff 100644 --- a/.env.example +++ b/.env.example @@ -175,6 +175,15 @@ REQUIRE_SAML=false API_THROTTLE_PER_MINUTE=120 CSV_ESCAPE_FORMULAS=true +# -------------------------------------------- +# OPTIONAL: HASHING +# -------------------------------------------- +HASHING_DRIVER='bcrypt' +BCRYPT_ROUNDS=10 +ARGON_MEMORY=1024 +ARGON_THREADS=2 +ARGON_TIME=2 + # -------------------------------------------- # OPTIONAL: SCIM # -------------------------------------------- diff --git a/app/Console/Commands/SystemBackup.php b/app/Console/Commands/SystemBackup.php index b7ca52605..3b51bcc73 100644 --- a/app/Console/Commands/SystemBackup.php +++ b/app/Console/Commands/SystemBackup.php @@ -11,7 +11,7 @@ class SystemBackup extends Command * * @var string */ - protected $name = 'snipeit:backup'; + protected $signature = 'snipeit:backup {--filename=}'; /** * The console command description. @@ -37,7 +37,18 @@ class SystemBackup extends Command */ public function handle() { - // - $this->call('backup:run'); + if ($this->option('filename')) { + $filename = $this->option('filename'); + + // Make sure the filename ends in .zip + if (!ends_with($filename, '.zip')) { + $filename = $filename.'.zip'; + } + + $this->call('backup:run', ['--filename' => $filename]); + } else { + $this->call('backup:run'); + } + } } diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php index 726e164ba..645e2624b 100644 --- a/app/Http/Controllers/Account/AcceptanceController.php +++ b/app/Http/Controllers/Account/AcceptanceController.php @@ -121,7 +121,6 @@ class AcceptanceController extends Controller $pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf'; $sig_filename=''; - if ($request->input('asset_acceptance') == 'accepted') { /** @@ -153,12 +152,14 @@ class AcceptanceController extends Controller } } - // this is horrible switch($acceptance->checkoutable_type){ case 'App\Models\Asset': $pdf_view_route ='account.accept.accept-asset-eula'; $asset_model = AssetModel::find($item->model_id); + if (!$asset_model) { + return redirect()->back()->with('error', trans('admin/models/message.does_not_exist')); + } $display_model = $asset_model->name; $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; @@ -167,7 +168,7 @@ class AcceptanceController extends Controller $pdf_view_route ='account.accept.accept-accessory-eula'; $accessory = Accessory::find($item->id); $display_model = $accessory->name; - $assigned_to = User::find($item->assignedTo); + $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; case 'App\Models\LicenseSeat': @@ -250,11 +251,15 @@ class AcceptanceController extends Controller // This is the most horriblest switch($acceptance->checkoutable_type){ case 'App\Models\Asset': + $asset_model = AssetModel::find($item->model_id); + $display_model = $asset_model->name; $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; case 'App\Models\Accessory': - $assigned_to = User::find($item->assignedTo); + $accessory = Accessory::find($item->id); + $display_model = $accessory->name; + $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; case 'App\Models\LicenseSeat': @@ -266,6 +271,8 @@ class AcceptanceController extends Controller break; case 'App\Models\Consumable': + $consumable = Consumable::find($item->id); + $display_model = $consumable->name; $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; } @@ -289,4 +296,4 @@ class AcceptanceController extends Controller return redirect()->to('account/accept')->with('success', $return_msg); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Api/AssetMaintenancesController.php b/app/Http/Controllers/Api/AssetMaintenancesController.php index ab5635ec3..b2870792f 100644 --- a/app/Http/Controllers/Api/AssetMaintenancesController.php +++ b/app/Http/Controllers/Api/AssetMaintenancesController.php @@ -36,7 +36,7 @@ class AssetMaintenancesController extends Controller { $this->authorize('view', Asset::class); - $maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'supplier', 'asset.company', 'admin'); + $maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'admin'); if ($request->filled('search')) { $maintenances = $maintenances->TextSearch($request->input('search')); diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 1816fc9f6..ced1f013c 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -573,6 +573,7 @@ class AssetsController extends Controller // Update custom fields in the database. // Validation for these fields is handled through the AssetRequest form request $model = AssetModel::find($request->get('model_id')); + if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { diff --git a/app/Http/Controllers/Api/CustomFieldsetsController.php b/app/Http/Controllers/Api/CustomFieldsetsController.php index 27da7733c..df0fc940c 100644 --- a/app/Http/Controllers/Api/CustomFieldsetsController.php +++ b/app/Http/Controllers/Api/CustomFieldsetsController.php @@ -7,6 +7,7 @@ use App\Http\Controllers\Controller; use App\Http\Transformers\CustomFieldsetsTransformer; use App\Http\Transformers\CustomFieldsTransformer; use App\Models\CustomFieldset; +use App\Models\CustomField; use Illuminate\Http\Request; use Redirect; use View; @@ -94,6 +95,18 @@ class CustomFieldsetsController extends Controller $fieldset->fill($request->all()); if ($fieldset->save()) { + // Sync fieldset with auto_add_to_fieldsets + $fields = CustomField::select('id')->where('auto_add_to_fieldsets', '=', '1')->get(); + + if ($fields->count() > 0) { + + foreach ($fields as $field) { + $field_ids[] = $field->id; + } + + $fieldset->fields()->sync($field_ids); + } + return response()->json(Helper::formatStandardApiResponse('success', $fieldset, trans('admin/custom_fields/message.fieldset.create.success'))); } diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index 6f5fc05ff..2d7e2f7d7 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -160,7 +160,7 @@ class ImportController extends Controller // Run a backup immediately before processing if ($request->get('run-backup')) { \Log::debug('Backup manually requested via importer'); - Artisan::call('backup:run'); + Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]); } else { \Log::debug('NO BACKUP requested via importer'); } @@ -193,6 +193,9 @@ class ImportController extends Controller case 'user': $redirectTo = 'users.index'; break; + case 'location': + $redirectTo = 'locations.index'; + break; } if ($errors) { //Failure diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php index f3183238b..9ff0a0c20 100644 --- a/app/Http/Controllers/Api/ManufacturersController.php +++ b/app/Http/Controllers/Api/ManufacturersController.php @@ -23,10 +23,10 @@ class ManufacturersController extends Controller public function index(Request $request) { $this->authorize('view', Manufacturer::class); - $allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count']; + $allowed_columns = ['id', 'name', 'url', 'support_url', 'support_email', 'warranty_lookup_url', 'support_phone', 'created_at', 'updated_at', 'image', 'assets_count', 'consumables_count', 'components_count', 'licenses_count']; $manufacturers = Manufacturer::select( - ['id', 'name', 'url', 'support_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'deleted_at'] + ['id', 'name', 'url', 'support_url', 'warranty_lookup_url', 'support_email', 'support_phone', 'created_at', 'updated_at', 'image', 'deleted_at'] )->withCount('assets as assets_count')->withCount('licenses as licenses_count')->withCount('consumables as consumables_count')->withCount('accessories as accessories_count'); if ($request->input('deleted') == 'true') { @@ -49,6 +49,10 @@ class ManufacturersController extends Controller $manufacturers->where('support_url', '=', $request->input('support_url')); } + if ($request->filled('warranty_lookup_url')) { + $manufacturers->where('warranty_lookup_url', '=', $request->input('warranty_lookup_url')); + } + if ($request->filled('support_phone')) { $manufacturers->where('support_phone', '=', $request->input('support_phone')); } diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index e29cbaa3f..bbc3790d6 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -7,6 +7,7 @@ use App\Http\Requests\CustomFieldRequest; use App\Models\CustomField; use App\Models\CustomFieldset; use Illuminate\Support\Facades\Auth; +use Illuminate\Http\Request; use Redirect; /** @@ -45,7 +46,7 @@ class CustomFieldsController extends Controller * @see CustomFieldsController::storeField() * @author [A. Gianotto] [] * @since [v5.1.5] - * @return Redirect + * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ public function show() @@ -63,14 +64,17 @@ class CustomFieldsController extends Controller * @return \Illuminate\Support\Facades\View * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function create() + public function create(Request $request) { $this->authorize('create', CustomField::class); + $fieldsets = CustomFieldset::get(); return view('custom_fields.fields.edit', [ 'predefinedFormats' => Helper::predefined_formats(), - 'customFormat' => '', - ])->with('field', new CustomField()); + 'customFormat' => '', + 'fieldsets' => $fieldsets, + 'field' => new CustomField(), + ]); } /** @@ -79,7 +83,7 @@ class CustomFieldsController extends Controller * @see CustomFieldsController::createField() * @author [Brady Wetherington] [] * @since [v1.8] - * @return Redirect + * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ public function store(CustomFieldRequest $request) @@ -104,6 +108,7 @@ class CustomFieldsController extends Controller "show_in_email" => $show_in_email, "is_unique" => $request->get("is_unique", 0), "display_in_user_view" => $display_in_user_view, + "auto_add_to_fieldsets" => $request->get("auto_add_to_fieldsets", 0), "user_id" => Auth::id() ]); @@ -115,10 +120,20 @@ class CustomFieldsController extends Controller } if ($field->save()) { + + // Sync fields with fieldsets + $fieldset_array = $request->input('associate_fieldsets'); + if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) { + $field->fieldset()->sync(array_keys($fieldset_array)); + } else { + $field->fieldset()->sync([]); + } + + return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/message.field.create.success')); } - return redirect()->back()->withInput() + return redirect()->back()->with('selected_fieldsets', $request->input('associate_fieldsets'))->withInput() ->with('error', trans('admin/custom_fields/message.field.create.error')); } @@ -128,7 +143,7 @@ class CustomFieldsController extends Controller * * @author [A. Gianotto] [] * @since [v3.0] - * @return Redirect + * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ public function deleteFieldFromFieldset($field_id, $fieldset_id) @@ -147,8 +162,7 @@ class CustomFieldsController extends Controller ->with('success', trans('admin/custom_fields/message.field.delete.success')); } else { return redirect()->back()->withErrors(['message' => "Field is in use and cannot be deleted."]); - } - + } } return redirect()->back()->withErrors(['message' => "Error deleting field from fieldset"]); @@ -161,7 +175,7 @@ class CustomFieldsController extends Controller * * @author [Brady Wetherington] [] * @since [v1.8] - * @return Redirect + * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ public function destroy($field_id) @@ -190,12 +204,12 @@ class CustomFieldsController extends Controller * @return \Illuminate\Support\Facades\View * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function edit($id) + public function edit(Request $request, $id) { if ($field = CustomField::find($id)) { $this->authorize('update', $field); - + $fieldsets = CustomFieldset::get(); $customFormat = ''; if ((stripos($field->format, 'regex') === 0) && ($field->format !== CustomField::PREDEFINED_FORMATS['MAC'])) { $customFormat = $field->format; @@ -204,6 +218,7 @@ class CustomFieldsController extends Controller return view('custom_fields.fields.edit', [ 'field' => $field, 'customFormat' => $customFormat, + 'fieldsets' => $fieldsets, 'predefinedFormats' => Helper::predefined_formats(), ]); } @@ -222,7 +237,7 @@ class CustomFieldsController extends Controller * @author [A. Gianotto] [] * @param int $id * @since [v4.0] - * @return Redirect + * @return \Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ public function update(CustomFieldRequest $request, $id) @@ -249,6 +264,7 @@ class CustomFieldsController extends Controller $field->show_in_email = $show_in_email; $field->is_unique = $request->get("is_unique", 0); $field->display_in_user_view = $display_in_user_view; + $field->auto_add_to_fieldsets = $request->get("auto_add_to_fieldsets", 0); if ($request->get('format') == 'CUSTOM REGEX') { $field->format = e($request->get('custom_format')); @@ -256,11 +272,21 @@ class CustomFieldsController extends Controller $field->format = e($request->get('format')); } - if($field->element == 'checkbox' || $field->element == 'radio'){ + if ($field->element == 'checkbox' || $field->element == 'radio'){ $field->format = 'ANY'; } if ($field->save()) { + + + // Sync fields with fieldsets + $fieldset_array = $request->input('associate_fieldsets'); + if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) { + $field->fieldset()->sync(array_keys($fieldset_array)); + } else { + $field->fieldset()->sync([]); + } + return redirect()->route('fields.index')->with('success', trans('admin/custom_fields/message.field.update.success')); } diff --git a/app/Http/Controllers/CustomFieldsetsController.php b/app/Http/Controllers/CustomFieldsetsController.php index 8c1450228..dbee97b77 100644 --- a/app/Http/Controllers/CustomFieldsetsController.php +++ b/app/Http/Controllers/CustomFieldsetsController.php @@ -93,16 +93,27 @@ class CustomFieldsetsController extends Controller { $this->authorize('create', CustomField::class); - $cfset = new CustomFieldset([ + $fieldset = new CustomFieldset([ 'name' => e($request->get('name')), 'user_id' => Auth::user()->id, ]); - $validator = Validator::make($request->all(), $cfset->rules); - if ($validator->passes()) { - $cfset->save(); + $validator = Validator::make($request->all(), $fieldset->rules); - return redirect()->route('fieldsets.show', [$cfset->id]) + if ($validator->passes()) { + $fieldset->save(); + + // Sync fieldset with auto_add_to_fieldsets + $fields = CustomField::select('id')->where('auto_add_to_fieldsets', '=', '1')->get(); + if ($fields->count() > 0) { + foreach ($fields as $field) { + $field_ids[] = $field->id; + } + + $fieldset->fields()->sync($field_ids); + } + + return redirect()->route('fieldsets.show', [$fieldset->id]) ->with('success', trans('admin/custom_fields/message.fieldset.create.success')); } diff --git a/app/Http/Controllers/GoogleAuthController.php b/app/Http/Controllers/GoogleAuthController.php new file mode 100644 index 000000000..84e428af3 --- /dev/null +++ b/app/Http/Controllers/GoogleAuthController.php @@ -0,0 +1,73 @@ + config('app.url').'/google/callback']); + config(['services.google.client_id' => $setting->google_client_id]); + config(['services.google.client_secret' => $setting->google_client_secret]); + } + + public function redirectToGoogle() + { + return Socialite::driver('google')->redirect(); + } + + public function handleGoogleCallback() + { + try { + $socialUser = Socialite::driver('google')->user(); + \Log::debug('Google user found'); + } catch (InvalidStateException $exception) { + \Log::debug('Google user NOT found'); + return redirect()->route('login') + ->withErrors( + [ + 'username' => [ + trans('auth/general.google_login_failed') + ], + ] + ); + } + + + $user = User::where('username', $socialUser->getEmail())->first(); + + + if ($user) { + + $user->update([ + 'avatar' => $socialUser->avatar, + ]); + + Auth::login($user, true); + return redirect()->route('home'); + } + + return redirect()->route('login') + ->withErrors( + [ + 'username' => [ + trans('admin/users/message.user_not_found'), + ], + ] + ); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php index 1f7d2f2c0..e98644f46 100755 --- a/app/Http/Controllers/ManufacturersController.php +++ b/app/Http/Controllers/ManufacturersController.php @@ -68,6 +68,7 @@ class ManufacturersController extends Controller $manufacturer->user_id = Auth::id(); $manufacturer->url = $request->input('url'); $manufacturer->support_url = $request->input('support_url'); + $manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url'); $manufacturer->support_phone = $request->input('support_phone'); $manufacturer->support_email = $request->input('support_email'); $manufacturer = $request->handleImages($manufacturer); @@ -123,10 +124,11 @@ class ManufacturersController extends Controller return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist')); } - // Save the data + // Save the data $manufacturer->name = $request->input('name'); $manufacturer->url = $request->input('url'); $manufacturer->support_url = $request->input('support_url'); + $manufacturer->warranty_lookup_url = $request->input('warranty_lookup_url'); $manufacturer->support_phone = $request->input('support_phone'); $manufacturer->support_email = $request->input('support_email'); diff --git a/app/Http/Controllers/ReportsController.php b/app/Http/Controllers/ReportsController.php index 9764df923..80fe24255 100644 --- a/app/Http/Controllers/ReportsController.php +++ b/app/Http/Controllers/ReportsController.php @@ -641,6 +641,9 @@ class ReportsController extends Controller if (($request->filled('created_start')) && ($request->filled('created_end'))) { $assets->whereBetween('assets.created_at', [$request->input('created_start'), $request->input('created_end')]); } + if (($request->filled('checkout_date_start')) && ($request->filled('checkout_date_end'))) { + $assets->whereBetween('assets.last_checkout', [$request->input('checkout_date_start'), $request->input('checkout_date_end')]); + } if (($request->filled('expected_checkin_start')) && ($request->filled('expected_checkin_end'))) { $assets->whereBetween('assets.expected_checkin', [$request->input('expected_checkin_start'), $request->input('expected_checkin_end')]); @@ -898,12 +901,8 @@ class ReportsController extends Controller public function getAssetMaintenancesReport() { $this->authorize('reports.view'); - // Grab all the improvements - $assetMaintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company') - ->orderBy('created_at', 'DESC') - ->get(); - return view('reports/asset_maintenances', compact('assetMaintenances')); + return view('reports.asset_maintenances'); } /** diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index c65dbc7d2..fbb7f4e4c 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -1039,6 +1039,48 @@ class SettingsController extends Controller return $pdf_branding; } + + /** + * Show Google login settings form + * + * @author [A. Gianotto] [] + * @since [v6.1.1] + * @return View + */ + public function getGoogleLoginSettings() + { + $setting = Setting::getSettings(); + return view('settings.google', compact('setting')); + } + + /** + * ShSaveow Google login settings form + * + * @author [A. Gianotto] [] + * @since [v6.1.1] + * @return View + */ + public function postGoogleLoginSettings(Request $request) + { + if (!config('app.lock_passwords')) { + $setting = Setting::getSettings(); + + $setting->google_login = $request->input('google_login', 0); + $setting->google_client_id = $request->input('google_client_id'); + $setting->google_client_secret = $request->input('google_client_secret'); + + if ($setting->save()) { + return redirect()->route('settings.index') + ->with('success', trans('admin/settings/message.update.success')); + } + + return redirect()->back()->withInput()->withErrors($setting->getErrors()); + } + + return redirect()->back()->with('error', trans('general.feature_disabled')); + } + + /** * Show the listing of backups. * @@ -1094,7 +1136,7 @@ class SettingsController extends Controller public function postBackups() { if (! config('app.lock_passwords')) { - Artisan::call('backup:run'); + Artisan::call('snipeit:backup', ['--filename' => 'manual-backup-'.date('Y-m-d-H:i:s')]); $output = Artisan::output(); // Backup completed diff --git a/app/Http/Livewire/Importer.php b/app/Http/Livewire/Importer.php index 784d3b298..7a37b00d1 100644 --- a/app/Http/Livewire/Importer.php +++ b/app/Http/Livewire/Importer.php @@ -67,7 +67,6 @@ class Importer extends Component 'location' => 'Location', 'maintained' => 'Maintained', 'manufacturer' => 'Manufacturer', - 'notes' => 'Notes', 'order_number' => 'Order Number', 'purchase_cost' => 'Purchase Cost', 'purchase_date' => 'Purchase Date', @@ -81,11 +80,14 @@ class Importer extends Component static $accessories = [ 'model_number' => 'Model Number', + 'notes' => 'Notes', ]; static $assets = [ 'asset_tag' => 'Asset Tag', 'asset_model' => 'Model Name', + 'asset_notes' => 'Asset Notes', + 'model_notes' => 'Model Notes', 'byod' => 'BYOD', 'checkout_class' => 'Checkout Type', 'checkout_location' => 'Checkout Location', @@ -99,6 +101,7 @@ class Importer extends Component static $consumables = [ 'item_no' => "Item Number", 'model_number' => "Model Number", + 'notes' => 'Notes', 'min_amt' => "Minimum Quantity", ]; @@ -111,13 +114,15 @@ class Importer extends Component 'purchase_order' => 'Purchase Order', 'reassignable' => 'Reassignable', 'seats' => 'Seats', + 'notes' => 'Notes', ]; static $users = [ 'employee_num' => 'Employee Number', 'first_name' => 'First Name', - 'jobtitle' => 'Job Title', 'last_name' => 'Last Name', + 'notes' => 'Notes', + 'jobtitle' => 'Job Title', 'phone_number' => 'Phone Number', 'manager_first_name' => 'Manager First Name', 'manager_last_name' => 'Manager Last Name', @@ -126,7 +131,25 @@ class Importer extends Component 'city' => 'City', 'state' => 'State', 'country' => 'Country', - 'vip' => 'VIP' + 'zip' => 'Zip', + 'vip' => 'VIP', + 'remote' => 'Remote', + ]; + + static $locations = [ + 'name' => 'Name', + 'address' => 'Address', + 'address2' => 'Address 2', + 'city' => 'City', + 'state' => 'State', + 'country' => 'Country', + 'zip' => 'Zip', + 'currency' => 'Currency', + 'ldap_ou' => 'LDAP OU', + 'manager_username' => 'Manager Username', + 'manager' => 'Manager', + 'parent_location' => 'Parent Location', + 'notes' => 'Notes', ]; //array of "real fieldnames" to a list of aliases for that field @@ -150,6 +173,11 @@ class Importer extends Component 'QTY', 'Quantity' ], + 'zip' => + [ + 'Postal Code', + 'Post Code' + ], 'min_amt' => [ 'Min Amount', @@ -159,6 +187,31 @@ class Importer extends Component [ 'Next Audit', ], + 'address2' => + [ + 'Address 2', + 'Address2', + ], + 'ldap_ou' => + [ + 'LDAP OU', + 'OU', + ], + 'parent_location' => + [ + 'Parent', + 'Parent Location', + ], + 'manager' => + [ + 'Managed By', + 'Manager Name', + 'Manager Full Name', + ], + 'manager_username' => + [ + 'Manager Username', + ], ]; @@ -181,6 +234,9 @@ class Importer extends Component case 'user': $results = self::$general + self::$users; break; + case 'location': + $results = self::$general + self::$locations; + break; default: $results = self::$general; } @@ -252,7 +308,6 @@ class Importer extends Component $this->authorize('import'); $this->progress = -1; // '-1' means 'don't show the progressbar' $this->progress_bar_class = 'progress-bar-warning'; - \Log::debug("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk $this->importTypes = [ 'asset' => trans('general.assets'), 'accessory' => trans('general.accessories'), @@ -260,6 +315,7 @@ class Importer extends Component 'component' => trans('general.components'), 'license' => trans('general.licenses'), 'user' => trans('general.users'), + 'location' => trans('general.locations'), ]; $this->columnOptions[''] = $this->getColumns(''); //blank mode? I don't know what this is supposed to mean @@ -273,8 +329,7 @@ class Importer extends Component public function selectFile($id) { - \Log::debug("TOGGLE EVENT FIRED!"); - \Log::debug("The ID we are trying to find is AS FOLLOWS: ".$id); + $this->activeFile = Import::find($id); $this->field_map = null; foreach($this->activeFile->header_row as $element) { @@ -284,11 +339,9 @@ class Importer extends Component $this->field_map[] = null; // re-inject the 'nulls' if a file was imported with some 'Do Not Import' settings } } - //$this->field_map = $this->activeFile->field_map ? array_values($this->activeFile->field_map) : []; // this is wrong $this->file_id = $id; $this->import_errors = null; $this->statusText = null; - \Log::debug("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type); } diff --git a/app/Http/Requests/CustomFieldRequest.php b/app/Http/Requests/CustomFieldRequest.php index 7c6ba1e97..0c2ec0ae6 100644 --- a/app/Http/Requests/CustomFieldRequest.php +++ b/app/Http/Requests/CustomFieldRequest.php @@ -26,6 +26,8 @@ class CustomFieldRequest extends FormRequest { $rules = []; + $rules['associate_fieldsets.*'] = 'nullable|integer|exists:custom_fieldsets,id'; + switch ($this->method()) { // Brand new @@ -54,4 +56,11 @@ class CustomFieldRequest extends FormRequest return $rules; } + + public function messages() + { + return [ + 'associate_fieldsets.*.exists' => trans('admin/custom_fields/message/does_not_exist'), + ]; + } } diff --git a/app/Http/Transformers/CategoriesTransformer.php b/app/Http/Transformers/CategoriesTransformer.php index faf05f7f4..d5e1ceb51 100644 --- a/app/Http/Transformers/CategoriesTransformer.php +++ b/app/Http/Transformers/CategoriesTransformer.php @@ -38,6 +38,9 @@ class CategoriesTransformer case 'component': $category->item_count = $category->components_count; break; + case 'license': + $category->item_count = $category->licenses_count; + break; default: $category->item_count = 0; } diff --git a/app/Http/Transformers/CustomFieldsTransformer.php b/app/Http/Transformers/CustomFieldsTransformer.php index 9ada5183a..db467be0b 100644 --- a/app/Http/Transformers/CustomFieldsTransformer.php +++ b/app/Http/Transformers/CustomFieldsTransformer.php @@ -48,6 +48,7 @@ class CustomFieldsTransformer 'type' => e($field->element), 'required' => (($field->pivot) && ($field->pivot->required=='1')) ? true : false, 'display_in_user_view' => ($field->display_in_user_view =='1') ? true : false, + 'auto_add_to_fieldsets' => ($field->auto_add_to_fieldsets == '1') ? true : false, 'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'), ]; diff --git a/app/Http/Transformers/ManufacturersTransformer.php b/app/Http/Transformers/ManufacturersTransformer.php index bbcbda12b..9c84fd50f 100644 --- a/app/Http/Transformers/ManufacturersTransformer.php +++ b/app/Http/Transformers/ManufacturersTransformer.php @@ -29,6 +29,7 @@ class ManufacturersTransformer 'url' => e($manufacturer->url), 'image' => ($manufacturer->image) ? Storage::disk('public')->url('manufacturers/'.e($manufacturer->image)) : null, 'support_url' => e($manufacturer->support_url), + 'warranty_lookup_url' => e($manufacturer->warranty_lookup_url), 'support_phone' => e($manufacturer->support_phone), 'support_email' => e($manufacturer->support_email), 'assets_count' => (int) $manufacturer->assets_count, diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index 1ee90b399..dfc808466 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -65,19 +65,22 @@ abstract class Importer 'email' => 'email', 'username' => 'username', 'address' => 'address', + 'address2' => 'address2', 'city' => 'city', 'state' => 'state', 'country' => 'country', + 'zip' => 'zip', 'jobtitle' => 'job title', 'employee_num' => 'employee number', 'phone_number' => 'phone number', 'first_name' => 'first name', 'last_name' => 'last name', 'department' => 'department', - 'manager_first_name' => 'manager first name', - 'manager_last_name' => 'manager last name', + 'manager_name' => 'manager full name', + 'manager_username' => 'manager username', 'min_amt' => 'minimum quantity', 'remote' => 'remote', + 'vip' => 'vip', ]; /** * Map of item fields->csv names @@ -119,7 +122,7 @@ abstract class Importer } else { $this->csv = Reader::createFromString($file); } - $this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 20); + $this->tempPassword = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 40); } // Cached Values for import lookups @@ -198,11 +201,11 @@ abstract class Importer $val = $default; $key = $this->lookupCustomKey($key); - $this->log("Custom Key: ${key}"); + // $this->log("Custom Key: ${key}"); if (array_key_exists($key, $array)) { $val = Encoding::toUTF8(trim($array[$key])); } - $this->log("${key}: ${val}"); + //$this->log("${key}: ${val}"); return $val; } @@ -280,8 +283,9 @@ abstract class Importer * @return User Model w/ matching name * @internal param array $user_array User details parsed from csv */ - protected function createOrFetchUser($row) + protected function createOrFetchUser($row, $type = 'user') { + $user_array = [ 'full_name' => $this->findCsvMatch($row, 'full_name'), 'email' => $this->findCsvMatch($row, 'email'), @@ -292,31 +296,36 @@ abstract class Importer 'remote' => $this->fetchHumanBoolean(($this->findCsvMatch($row, 'remote'))), ]; - // Maybe we're lucky and the user already exists. - if ($user = User::where('username', $user_array['username'])->first()) { - $this->log('User '.$user_array['username'].' already exists'); - return $user; + if ($type == 'manager') { + $user_array['full_name'] = $this->findCsvMatch($row, 'manager'); + $user_array['username'] = $this->findCsvMatch($row, 'manager_username'); } - // If the full name is empty, bail out--we need this to extract first name (at the very least) - if (empty($user_array['full_name'])) { - $this->log('Insufficient user data provided (Full name is required)- skipping user creation, just adding asset'); + // Maybe we're lucky and the username was passed and it already exists. + if (!empty($user_array['username'])) { + if ($user = User::where('username', $user_array['username'])->first()) { + $this->log('User '.$user_array['username'].' already exists'); + return $user; + } + } + + // If the full name and username is empty, bail out--we need this to extract first name (at the very least) + if ((empty($user_array['username'])) && (empty($user_array['full_name']))) { + $this->log('Insufficient user data provided (Full name or username is required) - skipping user creation.'); + \Log::debug(print_r($user_array, true)); + \Log::debug(print_r($row, true)); return false; } - // Is the user actually an ID? - if ($user = $this->findUserByNumber($user_array['full_name'])) { - return $user; - } - $this->log('User does not appear to be an id with number: '.$user_array['full_name'].'. Continuing through our processes'); // Populate email if it does not exist. if (empty($user_array['email'])) { $user_array['email'] = User::generateEmailFromFullName($user_array['full_name']); } + // Get some fields for first name and last name based off of full name $user_formatted_array = User::generateFormattedNameFromFullName($user_array['full_name'], Setting::getSettings()->username_format); $user_array['first_name'] = $user_formatted_array['first_name']; $user_array['last_name'] = $user_formatted_array['last_name']; @@ -326,14 +335,12 @@ abstract class Importer if ($this->usernameFormat == 'email') { $user_array['username'] = $user_array['email']; } - } - // Does this ever actually fire?? - // Check for a matching user after trying to guess username. - if ($user = User::where('username', $user_array['username'])->first()) { - $this->log('User '.$user_array['username'].' already exists'); - - return $user; + // Check for a matching username one more time after trying to guess username. + if ($user = User::where('username', $user_array['username'])->first()) { + $this->log('User '.$user_array['username'].' already exists'); + return $user; + } } // If at this point we have not found a username or first name, bail out in shame. @@ -341,7 +348,7 @@ abstract class Importer return false; } - // No Luck, let's create one. + // No luck finding a user on username or first name, let's create one. $user = new User; $user->first_name = $user_array['first_name']; $user->last_name = $user_array['last_name']; @@ -356,9 +363,9 @@ abstract class Importer if ($user->save()) { $this->log('User '.$user_array['username'].' created'); - return $user; } + $this->logError($user, 'User "'.$user_array['username'].'" was not able to be created.'); return false; diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php index 7848ec6b8..f989457dc 100644 --- a/app/Importer/ItemImporter.php +++ b/app/Importer/ItemImporter.php @@ -60,8 +60,8 @@ class ItemImporter extends Importer $this->item['department_id'] = $this->createOrFetchDepartment($item_department); } - $item_manager_first_name = $this->findCsvMatch($row, 'manage_first_name'); - $item_manager_last_name = $this->findCsvMatch($row, 'manage_last_name'); + $item_manager_first_name = $this->findCsvMatch($row, 'manager_first_name'); + $item_manager_last_name = $this->findCsvMatch($row, 'manager_last_name'); if ($this->shouldUpdateField($item_manager_first_name)) { $this->item['manager_id'] = $this->fetchManager($item_manager_first_name, $item_manager_last_name); @@ -112,6 +112,10 @@ class ItemImporter extends Importer return $this->createOrFetchUser($row); } + if (get_class($this) != LocationImporter::class) { + return; + } + if (strtolower($this->item['checkout_class']) === 'location' && $this->findCsvMatch($row, 'checkout_location') != null ) { return Location::findOrFail($this->createOrFetchLocation($this->findCsvMatch($row, 'checkout_location'))); } diff --git a/app/Importer/LocationImporter.php b/app/Importer/LocationImporter.php new file mode 100644 index 000000000..25140abe0 --- /dev/null +++ b/app/Importer/LocationImporter.php @@ -0,0 +1,102 @@ +createLocationIfNotExists($row); + } + + /** + * Create a location if a duplicate does not exist. + * @todo Investigate how this should interact with Importer::createLocationIfNotExists + * + * @author A. Gianotto + * @since 6.1.0 + * @param array $row + */ + public function createLocationIfNotExists(array $row) + { + + $editingLocation = false; + $location = Location::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); + + if ($location) { + if (! $this->updating) { + $this->log('A matching Location '.$this->item['name'].' already exists'); + return; + } + + $this->log('Updating Location'); + $editingLocation = true; + } else { + $this->log('No Matching Location, Create a new one'); + $location = new Location; + } + + // Pull the records from the CSV to determine their values + $this->item['name'] = $this->findCsvMatch($row, 'name'); + $this->item['address'] = $this->findCsvMatch($row, 'address'); + $this->item['address2'] = $this->findCsvMatch($row, 'address2'); + $this->item['city'] = $this->findCsvMatch($row, 'city'); + $this->item['state'] = $this->findCsvMatch($row, 'state'); + $this->item['country'] = $this->findCsvMatch($row, 'country'); + $this->item['zip'] = $this->findCsvMatch($row, 'zip'); + $this->item['currency'] = $this->findCsvMatch($row, 'currency'); + $this->item['ldap_ou'] = $this->findCsvMatch($row, 'ldap_ou'); + $this->item['manager'] = $this->findCsvMatch($row, 'manager'); + $this->item['manager_username'] = $this->findCsvMatch($row, 'manager_username'); + $this->item['user_id'] = \Auth::user()->id; + + if ($this->findCsvMatch($row, 'parent_location')) { + $this->item['parent_id'] = $this->createOrFetchLocation($this->findCsvMatch($row, 'parent_location')); + } + + if (!empty($this->item['manager'])) { + if ($manager = $this->createOrFetchUser($row, 'manager')) { + $this->item['manager_id'] = $manager->id; + } + } + + \Log::debug('Item array is: '); + \Log::debug(print_r($this->item, true)); + + + if ($editingLocation) { + \Log::debug('Updating existing location'); + $location->update($this->sanitizeItemForUpdating($location)); + } else { + \Log::debug('Creating location'); + $location->fill($this->sanitizeItemForStoring($location)); + } + + if ($location->save()) { + $this->log('Location '.$location->name.' created or updated from CSV import'); + return $location; + + } else { + \Log::debug($location->getErrors()); + return $location->errors; + } + + + } +} \ No newline at end of file diff --git a/app/Models/Asset.php b/app/Models/Asset.php index a5211e800..ac431253b 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -90,7 +90,7 @@ class Asset extends Depreciable protected $rules = [ 'name' => 'max:255|nullable', - 'model_id' => 'required|integer|exists:models,id', + 'model_id' => 'required|integer|exists:models,id,deleted_at,NULL', 'status_id' => 'required|integer|exists:status_labels,id', 'company_id' => 'integer|nullable', 'warranty_months' => 'numeric|nullable|digits_between:0,240', @@ -909,7 +909,13 @@ class Asset extends Depreciable return false; } - + public function getComponentCost(){ + $cost = 0; + foreach($this->components as $component) { + $cost += $component->pivot->assigned_qty*$component->purchase_cost; + } + return $cost; + } /** * ----------------------------------------------- diff --git a/app/Models/CheckoutAcceptance.php b/app/Models/CheckoutAcceptance.php index c3c34b057..4a4360c40 100644 --- a/app/Models/CheckoutAcceptance.php +++ b/app/Models/CheckoutAcceptance.php @@ -3,13 +3,14 @@ namespace App\Models; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Notifications\Notifiable; class CheckoutAcceptance extends Model { - use SoftDeletes, Notifiable; + use HasFactory, SoftDeletes, Notifiable; protected $casts = [ 'accepted_at' => 'datetime', diff --git a/app/Models/CustomField.php b/app/Models/CustomField.php index fcab5b25f..b39650e74 100644 --- a/app/Models/CustomField.php +++ b/app/Models/CustomField.php @@ -52,6 +52,7 @@ class CustomField extends Model 'name' => 'required|unique:custom_fields', 'element' => 'required|in:text,listbox,textarea,checkbox,radio', 'field_encrypted' => 'nullable|boolean', + 'auto_add_to_fieldsets' => 'boolean', ]; /** @@ -69,6 +70,8 @@ class CustomField extends Model 'show_in_email', 'is_unique', 'display_in_user_view', + 'auto_add_to_fieldsets', + ]; /** diff --git a/app/Models/Location.php b/app/Models/Location.php index 8cea9bda1..2f4e78dcc 100755 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -26,11 +26,12 @@ class Location extends SnipeModel protected $table = 'locations'; protected $rules = [ 'name' => 'required|min:2|max:255|unique_undeleted', - 'city' => 'min:2|max:255|nullable', - 'country' => 'min:2|max:255|nullable', - 'address' => 'max:80|nullable', - 'address2' => 'max:80|nullable', - 'zip' => 'min:3|max:10|nullable', + 'address' => 'max:191|nullable', + 'address2' => 'max:191|nullable', + 'city' => 'max:191|nullable', + 'state' => 'min:2|max:191|nullable', + 'country' => 'min:2|max:191|nullable', + 'zip' => 'max:10|nullable', 'manager_id' => 'exists:users,id|nullable', 'parent_id' => 'non_circular:locations,id', ]; diff --git a/app/Models/Manufacturer.php b/app/Models/Manufacturer.php index 5f01c3c27..da4f26b02 100755 --- a/app/Models/Manufacturer.php +++ b/app/Models/Manufacturer.php @@ -23,8 +23,9 @@ class Manufacturer extends SnipeModel protected $rules = [ 'name' => 'required|min:2|max:255|unique:manufacturers,name,NULL,id,deleted_at,NULL', 'url' => 'url|nullable', - 'support_url' => 'url|nullable', 'support_email' => 'email|nullable', + 'support_url' => 'nullable|url', + 'warranty_lookup_url' => 'nullable|starts_with:http://,https://,afp://,facetime://,file://,irc://' ]; protected $hidden = ['user_id']; @@ -51,6 +52,7 @@ class Manufacturer extends SnipeModel 'support_phone', 'support_url', 'url', + 'warranty_lookup_url', ]; use Searchable; diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 61be790e0..6c95d6b01 100755 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -76,6 +76,7 @@ class Setting extends Model 'audit_interval' => 'numeric|nullable', 'custom_forgot_pass_url' => 'url|nullable', 'privacy_policy_link' => 'nullable|url', + 'google_client_id' => 'nullable|ends_with:apps.googleusercontent.com' ]; protected $fillable = [ @@ -86,6 +87,9 @@ class Setting extends Model 'webhook_endpoint', 'webhook_channel', 'webhook_botname', + 'google_login', + 'google_client_id', + 'google_client_secret', ]; /** diff --git a/app/Models/Supplier.php b/app/Models/Supplier.php index fa00fbad2..e198d10c1 100755 --- a/app/Models/Supplier.php +++ b/app/Models/Supplier.php @@ -16,17 +16,17 @@ class Supplier extends SnipeModel protected $table = 'suppliers'; protected $rules = [ - 'name' => 'required|min:1|max:255|unique_undeleted', - 'address' => 'max:250|nullable', - 'address2' => 'max:250|nullable', - 'city' => 'max:255|nullable', - 'state' => 'max:32|nullable', - 'country' => 'max:3|nullable', + 'name' => 'required|min:1|max:255|unique_undeleted', 'fax' => 'min:7|max:35|nullable', 'phone' => 'min:7|max:35|nullable', 'contact' => 'max:100|nullable', 'notes' => 'max:191|nullable', // Default string length is 191 characters.. 'email' => 'email|max:150|nullable', + 'address' => 'max:250|nullable', + 'address2' => 'max:250|nullable', + 'city' => 'max:191|nullable', + 'state' => 'min:2|max:191|nullable', + 'country' => 'min:2|max:191|nullable', 'zip' => 'max:10|nullable', 'url' => 'sometimes|nullable|string|max:250', ]; diff --git a/app/Models/User.php b/app/Models/User.php index 36e1c8ac4..1e63ebad7 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -98,6 +98,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo 'start_date' => 'nullable|date_format:Y-m-d', 'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:start_date', 'autoassign_licenses' => 'boolean', + 'address' => 'max:191|nullable', + 'city' => 'max:191|nullable', + 'state' => 'min:2|max:191|nullable', + 'country' => 'min:2|max:191|nullable', + 'zip' => 'max:10|nullable', ]; /** diff --git a/app/Presenters/AssetPresenter.php b/app/Presenters/AssetPresenter.php index 4be0f5601..ce476d082 100644 --- a/app/Presenters/AssetPresenter.php +++ b/app/Presenters/AssetPresenter.php @@ -534,6 +534,18 @@ class AssetPresenter extends Presenter return false; } + /** + * Used to take user created warranty URL and dynamically fill in the needed values per asset + * @return string + */ + public function dynamicWarrantyUrl() + { + $warranty_lookup_url = $this->model->model->manufacturer->warranty_lookup_url; + $url = (str_replace('{LOCALE}',\App\Models\Setting::getSettings()->locale,$warranty_lookup_url)); + $url = (str_replace('{SERIAL}',$this->model->serial,$url)); + return $url; + } + /** * Url to view this item. * @return string diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php index 5a44bf52a..f2d54549e 100644 --- a/app/Presenters/LicensePresenter.php +++ b/app/Presenters/LicensePresenter.php @@ -151,6 +151,21 @@ class LicensePresenter extends Presenter 'visible' => false, 'title' => trans('general.order_number'), ], [ + 'field' => 'created_at', + 'searchable' => false, + 'sortable' => true, + 'visible' => false, + 'title' => trans('general.created_at'), + 'formatter' => 'dateDisplayFormatter', + ], [ + 'field' => 'updated_at', + 'searchable' => false, + 'sortable' => true, + 'visible' => false, + 'title' => trans('general.updated_at'), + 'formatter' => 'dateDisplayFormatter', + ], + [ 'field' => 'notes', 'searchable' => true, 'sortable' => true, diff --git a/app/Presenters/ManufacturerPresenter.php b/app/Presenters/ManufacturerPresenter.php index 5b44a7693..f5c15f1fe 100644 --- a/app/Presenters/ManufacturerPresenter.php +++ b/app/Presenters/ManufacturerPresenter.php @@ -47,7 +47,7 @@ class ManufacturerPresenter extends Presenter 'switchable' => true, 'title' => trans('admin/manufacturers/table.url'), 'visible' => true, - 'formatter' => 'linkFormatter', + 'formatter' => 'externalLinkFormatter', ], [ 'field' => 'support_url', @@ -56,7 +56,7 @@ class ManufacturerPresenter extends Presenter 'switchable' => true, 'title' => trans('admin/manufacturers/table.support_url'), 'visible' => true, - 'formatter' => 'linkFormatter', + 'formatter' => 'externalLinkFormatter', ], [ @@ -78,6 +78,15 @@ class ManufacturerPresenter extends Presenter 'visible' => true, 'formatter' => 'emailFormatter', ], + [ + 'field' => 'warranty_lookup_url', + 'searchable' => true, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('admin/manufacturers/table.warranty_lookup_url'), + 'visible' => false, + 'formatter' => 'externalLinkFormatter', + ], [ 'field' => 'assets_count', diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index fbb41a4d5..080a2d10e 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -7,6 +7,7 @@ use App\Models\Setting; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Str; /** * Class UserPresenter @@ -399,17 +400,25 @@ class UserPresenter extends Presenter public function gravatar() { if ($this->avatar) { + + // Check if it's a google avatar or some external avatar + if (Str::startsWith($this->avatar, ['http://', 'https://'])) { + return $this->avatar; + } + + // Otherwise assume it's an uploaded image return Storage::disk('public')->url('avatars/'.e($this->avatar)); } if (Setting::getSettings()->load_remote == '1') { if ($this->model->gravatar != '') { + $gravatar = md5(strtolower(trim($this->model->gravatar))); - return '//gravatar.com/avatar/'.$gravatar; - } elseif ($this->email != '') { - $gravatar = md5(strtolower(trim($this->email))); + } elseif ($this->email != '') { + + $gravatar = md5(strtolower(trim($this->email))); return '//gravatar.com/avatar/'.$gravatar; } } diff --git a/composer.json b/composer.json index 2f1007fa7..165a4a08f 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ } ], "require": { - "php": ">=7.4 <8.3", + "php": ">=7.4.3 <8.2", "ext-curl": "*", "ext-fileinfo": "*", "ext-json": "*", @@ -46,6 +46,7 @@ "laravel/helpers": "^1.4", "laravel/passport": "^10.1", "laravel/slack-notification-channel": "^2.3", + "laravel/socialite": "^5.6", "laravel/tinker": "^2.6", "laravel/ui": "^3.3", "laravelcollective/html": "^6.2", diff --git a/composer.lock b/composer.lock index c34d46ce6..1ef75690a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "590171872e4a6a29c78efde99fbbf00e", + "content-hash": "4c82b2e171fb02a3ef024906db5d74c9", "packages": [ { "name": "alek13/slack", @@ -2673,6 +2673,7 @@ "type": "github" } ], + "abandoned": true, "time": "2022-02-23T14:25:13+00:00" }, { @@ -3604,6 +3605,75 @@ }, "time": "2022-01-12T18:07:54+00:00" }, + { + "name": "laravel/socialite", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/socialite.git", + "reference": "a14a177f2cc71d8add71e2b19e00800e83bdda09" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/socialite/zipball/a14a177f2cc71d8add71e2b19e00800e83bdda09", + "reference": "a14a177f2cc71d8add71e2b19e00800e83bdda09", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0", + "league/oauth1-client": "^1.10.1", + "php": "^7.2|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0", + "phpunit/phpunit": "^8.0|^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Socialite\\SocialiteServiceProvider" + ], + "aliases": { + "Socialite": "Laravel\\Socialite\\Facades\\Socialite" + } + } + }, + "autoload": { + "psr-4": { + "Laravel\\Socialite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.", + "homepage": "https://laravel.com", + "keywords": [ + "laravel", + "oauth" + ], + "support": { + "issues": "https://github.com/laravel/socialite/issues", + "source": "https://github.com/laravel/socialite" + }, + "time": "2023-01-20T15:42:35+00:00" + }, { "name": "laravel/tinker", "version": "v2.7.2", @@ -3803,6 +3873,7 @@ "issues": "https://github.com/LaravelCollective/html/issues", "source": "https://github.com/LaravelCollective/html" }, + "abandoned": "spatie/laravel-html", "time": "2022-02-08T21:02:54+00:00" }, { @@ -4532,6 +4603,82 @@ ], "time": "2022-04-17T13:12:02+00:00" }, + { + "name": "league/oauth1-client", + "version": "v1.10.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth1-client.git", + "reference": "d6365b901b5c287dd41f143033315e2f777e1167" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/d6365b901b5c287dd41f143033315e2f777e1167", + "reference": "d6365b901b5c287dd41f143033315e2f777e1167", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=7.1||>=8.0" + }, + "require-dev": { + "ext-simplexml": "*", + "friendsofphp/php-cs-fixer": "^2.17", + "mockery/mockery": "^1.3.3", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5||9.5" + }, + "suggest": { + "ext-simplexml": "For decoding XML-based responses." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev", + "dev-develop": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth1\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Corlett", + "email": "bencorlett@me.com", + "homepage": "http://www.webcomm.com.au", + "role": "Developer" + } + ], + "description": "OAuth 1.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "bitbucket", + "identity", + "idp", + "oauth", + "oauth1", + "single sign on", + "trello", + "tumblr", + "twitter" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth1-client/issues", + "source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.1" + }, + "time": "2022-04-15T14:02:14+00:00" + }, { "name": "league/oauth2-server", "version": "8.3.5", @@ -5007,6 +5154,10 @@ "source": "https://github.com/maennchen/ZipStream-PHP/tree/2.2.1" }, "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + }, { "url": "https://opencollective.com/zipstream", "type": "open_collective" @@ -13984,6 +14135,7 @@ "type": "github" } ], + "abandoned": true, "time": "2020-12-07T05:51:20+00:00" }, { @@ -16410,7 +16562,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.4 <8.3", + "php": ">=7.4.3 <8.2", "ext-curl": "*", "ext-fileinfo": "*", "ext-json": "*", diff --git a/config/app.php b/config/app.php index 8833ea2ae..2559b8012 100755 --- a/config/app.php +++ b/config/app.php @@ -216,7 +216,8 @@ return [ */ 'require_saml' => env('REQUIRE_SAML', false), - + + /* |-------------------------------------------------------------------------- | Demo Mode Lockdown @@ -294,6 +295,7 @@ return [ Laravel\Tinker\TinkerServiceProvider::class, Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class, + Laravel\Socialite\SocialiteServiceProvider::class, /* * Application Service Providers... @@ -366,6 +368,7 @@ return [ 'Image' => Intervention\Image\ImageServiceProvider::class, 'Carbon' => Carbon\Carbon::class, 'Helper' => App\Helpers\Helper::class, // makes it much easier to use 'Helper::blah' in blades (which is where we usually use this) + 'Socialite' => Laravel\Socialite\Facades\Socialite::class, ], diff --git a/config/hashing.php b/config/hashing.php index d3c8e2fb2..06f18a0c6 100644 --- a/config/hashing.php +++ b/config/hashing.php @@ -15,7 +15,7 @@ return [ | */ - 'driver' => 'bcrypt', + 'driver' => env('HASHING_DRIVER', 'bcrypt'), /* |-------------------------------------------------------------------------- @@ -44,9 +44,9 @@ return [ */ 'argon' => [ - 'memory' => 1024, - 'threads' => 2, - 'time' => 2, + 'memory' => env('ARGON_MEMORY', 1024), + 'threads' => env('ARGON_THREADS', 2), + 'time' => env('ARGON_TIME', 2), ], ]; diff --git a/config/mail.php b/config/mail.php index d47d182ed..f650cf538 100755 --- a/config/mail.php +++ b/config/mail.php @@ -140,8 +140,8 @@ return [ | */ - 'sendmail' => '/usr/sbin/sendmail -bs', - + 'sendmail' => env('SENDMAIL_PATH', ini_get('sendmail_path')), + 'markdown' => [ 'theme' => 'default', 'paths' => [ diff --git a/config/version.php b/config/version.php index f8c297c9c..4f60d6090 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v6.1.0', - 'full_app_version' => 'v6.1.0 - build 10161-ga8ca3ad2a', - 'build_version' => '10161', + 'app_version' => 'v6.1.1-pre', + 'full_app_version' => 'v6.1.1-pre - build 10534-g609b1646e', + 'build_version' => '10534', 'prerelease_version' => '', - 'hash_version' => 'ga8ca3ad2a', - 'full_hash' => 'v6.1.0-127-ga8ca3ad2a', + 'hash_version' => 'g609b1646e', + 'full_hash' => 'v6.1.1-pre-292-g609b1646e', 'branch' => 'develop', ); \ No newline at end of file diff --git a/database/factories/CheckoutAcceptanceFactory.php b/database/factories/CheckoutAcceptanceFactory.php new file mode 100644 index 000000000..b5744527f --- /dev/null +++ b/database/factories/CheckoutAcceptanceFactory.php @@ -0,0 +1,41 @@ + Asset::class, + 'checkoutable_id' => Asset::factory(), + 'assigned_to_id' => User::factory(), + ]; + } + + public function forAccessory() + { + return $this->state([ + 'checkoutable_type' => Accessory::class, + 'checkoutable_id' => Accessory::factory(), + ]); + } + + public function pending() + { + return $this->state([ + 'accepted_at' => null, + 'declined_at' => null, + ]); + } +} diff --git a/database/factories/CustomFieldFactory.php b/database/factories/CustomFieldFactory.php index bfa41b4d8..adcca9cae 100644 --- a/database/factories/CustomFieldFactory.php +++ b/database/factories/CustomFieldFactory.php @@ -25,6 +25,7 @@ class CustomFieldFactory extends Factory 'name' => $this->faker->catchPhrase(), 'format' => '', 'element' => 'text', + 'auto_add_to_fieldsets' => '0', ]; } diff --git a/database/factories/ManufacturerFactory.php b/database/factories/ManufacturerFactory.php index ab22262a7..4e736b8d8 100644 --- a/database/factories/ManufacturerFactory.php +++ b/database/factories/ManufacturerFactory.php @@ -38,6 +38,7 @@ class ManufacturerFactory extends Factory 'name' => 'Apple', 'url' => 'https://apple.com', 'support_url' => 'https://support.apple.com', + 'warranty_lookup_url' => 'https://checkcoverage.apple.com', 'image' => 'apple.jpg', ]; }); @@ -50,6 +51,7 @@ class ManufacturerFactory extends Factory 'name' => 'Microsoft', 'url' => 'https://microsoft.com', 'support_url' => 'https://support.microsoft.com', + 'warranty_lookup_url' => 'https://account.microsoft.com/devices', 'image' => 'microsoft.png', ]; }); @@ -62,6 +64,7 @@ class ManufacturerFactory extends Factory 'name' => 'Dell', 'url' => 'https://dell.com', 'support_url' => 'https://support.dell.com', + 'warranty_lookup_url' => 'https://www.dell.com/support/home/en-us/Products/?app=warranty', 'image' => 'dell.png', ]; }); diff --git a/database/migrations/2023_04_25_085912_add_autoadd_to_customfields.php b/database/migrations/2023_04_25_085912_add_autoadd_to_customfields.php new file mode 100644 index 000000000..918bec9c5 --- /dev/null +++ b/database/migrations/2023_04_25_085912_add_autoadd_to_customfields.php @@ -0,0 +1,34 @@ +boolean('auto_add_to_fieldsets')->nullable()->default(0); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('custom_fields', function (Blueprint $table) { + if (Schema::hasColumn('custom_fields', 'auto_add_to_fieldsets')) { + $table->dropColumn('auto_add_to_fieldsets'); + } + }); + } +} diff --git a/database/migrations/2023_04_26_160235_add_warranty_url_to_manufacturers.php b/database/migrations/2023_04_26_160235_add_warranty_url_to_manufacturers.php new file mode 100644 index 000000000..52a655f2e --- /dev/null +++ b/database/migrations/2023_04_26_160235_add_warranty_url_to_manufacturers.php @@ -0,0 +1,32 @@ +string('warranty_lookup_url')->after('support_url')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('manufacturers', function (Blueprint $table) { + $table->dropColumn('warranty_lookup_url'); + }); + } +} diff --git a/database/migrations/2023_05_08_132921_increase_state_to_more_than_3.php b/database/migrations/2023_05_08_132921_increase_state_to_more_than_3.php new file mode 100644 index 000000000..7ffc0c386 --- /dev/null +++ b/database/migrations/2023_05_08_132921_increase_state_to_more_than_3.php @@ -0,0 +1,40 @@ +string('state', 191)->nullable()->default(null)->change(); + }); + + Schema::table('suppliers', function (Blueprint $table) { + $table->string('state', 191)->nullable()->default(null)->change(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users', function (Blueprint $table) { + $table->string('state', 3)->nullable()->default(null)->change(); + }); + + Schema::table('suppliers', function (Blueprint $table) { + $table->string('state', 32)->nullable()->default(null)->change(); + }); + } +} diff --git a/database/migrations/2023_05_10_001836_add_google_auth_to_settings.php b/database/migrations/2023_05_10_001836_add_google_auth_to_settings.php new file mode 100644 index 000000000..7f15e0d6e --- /dev/null +++ b/database/migrations/2023_05_10_001836_add_google_auth_to_settings.php @@ -0,0 +1,37 @@ +boolean('google_login')->nullable()->default(0); + $table->string('google_client_id')->nullable()->default(null); + $table->string('google_client_secret')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('google_login'); + $table->dropColumn('google_client_id'); + $table->dropColumn('google_client_secret'); + + }); + } +} diff --git a/package.json b/package.json index 5d8cfd622..0026531e7 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,6 @@ "tableexport.jquery.plugin": "1.27.0", "tether": "^1.4.0", "vue-resource": "^1.5.2", - "webpack": "^5.77.0" + "webpack": "^5.78.0" } } diff --git a/public/css/build/app.css b/public/css/build/app.css index 8ab54a325..623ae2df1 100644 --- a/public/css/build/app.css +++ b/public/css/build/app.css @@ -501,6 +501,9 @@ a.accordion-header { .btn-info.btn-outline { color: #5bc0de; } +.btn-warning { + background-color: #f39c12 !important; +} .btn-warning.btn-outline { color: #f0ad4e; } diff --git a/public/css/build/overrides.css b/public/css/build/overrides.css index 296136c7a..2c4f57f85 100644 --- a/public/css/build/overrides.css +++ b/public/css/build/overrides.css @@ -134,6 +134,9 @@ a.accordion-header { .btn-info.btn-outline { color: #5bc0de; } +.btn-warning { + background-color: #f39c12 !important; +} .btn-warning.btn-outline { color: #f0ad4e; } diff --git a/public/css/dist/all.css b/public/css/dist/all.css index d5383def4..6db24038e 100644 --- a/public/css/dist/all.css +++ b/public/css/dist/all.css @@ -23267,6 +23267,9 @@ a.accordion-header { .btn-info.btn-outline { color: #5bc0de; } +.btn-warning { + background-color: #f39c12 !important; +} .btn-warning.btn-outline { color: #f0ad4e; } @@ -24490,6 +24493,9 @@ a.accordion-header { .btn-info.btn-outline { color: #5bc0de; } +.btn-warning { + background-color: #f39c12 !important; +} .btn-warning.btn-outline { color: #f0ad4e; } diff --git a/public/css/dist/skins/skin-black-dark.css b/public/css/dist/skins/skin-black-dark.css index c9f573c75..3e1773560 100644 --- a/public/css/dist/skins/skin-black-dark.css +++ b/public/css/dist/skins/skin-black-dark.css @@ -201,6 +201,9 @@ a:visited { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -212,6 +215,23 @@ a:visited { .pagination > .active > a:hover { background-color: var(--hover-link); } +.tasks-menu > .dropdown-menu > li .menu > li > a:hover .progress { + background-color: var(--background); +} +a:hover > h2.task_menu { + color: var(--header); +} +h2.task_menu { + color: var(--link); +} +.navbar-custom-menu > .navbar-nav > li > .dropdown-menu { + background-color: var(--back-main); + color: var(--link); +} +.navbar-custom-menu > .navbar-nav > li > .dropdown-menu > li.header { + background-color: var(--header); + color: var(--link); +} .main-header .navbar, .main-header .logo { background-color: var(--header); diff --git a/public/css/dist/skins/skin-black-dark.min.css b/public/css/dist/skins/skin-black-dark.min.css index c9f573c75..3e1773560 100644 --- a/public/css/dist/skins/skin-black-dark.min.css +++ b/public/css/dist/skins/skin-black-dark.min.css @@ -201,6 +201,9 @@ a:visited { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -212,6 +215,23 @@ a:visited { .pagination > .active > a:hover { background-color: var(--hover-link); } +.tasks-menu > .dropdown-menu > li .menu > li > a:hover .progress { + background-color: var(--background); +} +a:hover > h2.task_menu { + color: var(--header); +} +h2.task_menu { + color: var(--link); +} +.navbar-custom-menu > .navbar-nav > li > .dropdown-menu { + background-color: var(--back-main); + color: var(--link); +} +.navbar-custom-menu > .navbar-nav > li > .dropdown-menu > li.header { + background-color: var(--header); + color: var(--link); +} .main-header .navbar, .main-header .logo { background-color: var(--header); diff --git a/public/css/dist/skins/skin-blue-dark.css b/public/css/dist/skins/skin-blue-dark.css index c728a5af2..c4f267293 100644 --- a/public/css/dist/skins/skin-blue-dark.css +++ b/public/css/dist/skins/skin-blue-dark.css @@ -196,6 +196,9 @@ a:visited { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -482,6 +485,12 @@ a:hover { a:visited { color: var(--visited-link); } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/public/css/dist/skins/skin-blue-dark.min.css b/public/css/dist/skins/skin-blue-dark.min.css index c728a5af2..c4f267293 100644 --- a/public/css/dist/skins/skin-blue-dark.min.css +++ b/public/css/dist/skins/skin-blue-dark.min.css @@ -196,6 +196,9 @@ a:visited { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -482,6 +485,12 @@ a:hover { a:visited { color: var(--visited-link); } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/public/css/dist/skins/skin-green-dark.css b/public/css/dist/skins/skin-green-dark.css index 5bf1b300d..8e5430e5c 100644 --- a/public/css/dist/skins/skin-green-dark.css +++ b/public/css/dist/skins/skin-green-dark.css @@ -196,6 +196,9 @@ a:visited { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -240,9 +243,6 @@ h2.task_menu { background-color: var(--back-main); color: var(--text-main); } -a:link { - color: var(--link); -} .btn-primary.hover { color: var(--nav-link); } @@ -472,6 +472,12 @@ a:hover { a:visited { color: var(--visited-link); } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/public/css/dist/skins/skin-green-dark.min.css b/public/css/dist/skins/skin-green-dark.min.css index 5bf1b300d..8e5430e5c 100644 --- a/public/css/dist/skins/skin-green-dark.min.css +++ b/public/css/dist/skins/skin-green-dark.min.css @@ -196,6 +196,9 @@ a:visited { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -240,9 +243,6 @@ h2.task_menu { background-color: var(--back-main); color: var(--text-main); } -a:link { - color: var(--link); -} .btn-primary.hover { color: var(--nav-link); } @@ -472,6 +472,12 @@ a:hover { a:visited { color: var(--visited-link); } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/public/css/dist/skins/skin-orange-dark.css b/public/css/dist/skins/skin-orange-dark.css index 5f4e71929..1ec2c0701 100644 --- a/public/css/dist/skins/skin-orange-dark.css +++ b/public/css/dist/skins/skin-orange-dark.css @@ -190,6 +190,9 @@ li.dropdown-item-marker { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -470,6 +473,12 @@ input[type=search] { .box-header.with-border { border-bottom: #000; } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/public/css/dist/skins/skin-orange-dark.min.css b/public/css/dist/skins/skin-orange-dark.min.css index 5f4e71929..1ec2c0701 100644 --- a/public/css/dist/skins/skin-orange-dark.min.css +++ b/public/css/dist/skins/skin-orange-dark.min.css @@ -190,6 +190,9 @@ li.dropdown-item-marker { #ldapad_test_results.well.well-sm { color: var(--back-main); } +a.actions { + color: #fff !important; +} .pagination > li > a { color: var(--light-link); background-color: var(--back-main); @@ -470,6 +473,12 @@ input[type=search] { .box-header.with-border { border-bottom: #000; } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/public/css/dist/skins/skin-red-dark.css b/public/css/dist/skins/skin-red-dark.css index bcce285ed..5ae17e15d 100644 --- a/public/css/dist/skins/skin-red-dark.css +++ b/public/css/dist/skins/skin-red-dark.css @@ -244,12 +244,12 @@ h2.task_menu { a:link { color: var(--link); } -a:visited { - color: var(--nav-link); -} a:hover { color: var(--hover-link); } +a:visited { + color: var(--nav-link); +} .far fa-life-ring { color: var(--link); } @@ -462,7 +462,6 @@ input[type=search] { } .table-striped > tbody > tr:nth-of-type(even) { background-color: var(--back-sub-alt); - color: var(--text-alt); } #webui > div > div > div > div > div > table > tbody > tr > td > a > i.fa, .box-body, @@ -477,14 +476,20 @@ a { color: var(--link); } a:link { - color: var(--link); + color: var(--nav-link); } a:hover { - color: var(--hover-link); + color: var(--nav-link); text-decoration: underline; } a:visited { - color: var(--visited-link); + color: var(--nav-link); +} +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; } .row-striped { vertical-align: top; diff --git a/public/css/dist/skins/skin-red-dark.min.css b/public/css/dist/skins/skin-red-dark.min.css index bcce285ed..5ae17e15d 100644 --- a/public/css/dist/skins/skin-red-dark.min.css +++ b/public/css/dist/skins/skin-red-dark.min.css @@ -244,12 +244,12 @@ h2.task_menu { a:link { color: var(--link); } -a:visited { - color: var(--nav-link); -} a:hover { color: var(--hover-link); } +a:visited { + color: var(--nav-link); +} .far fa-life-ring { color: var(--link); } @@ -462,7 +462,6 @@ input[type=search] { } .table-striped > tbody > tr:nth-of-type(even) { background-color: var(--back-sub-alt); - color: var(--text-alt); } #webui > div > div > div > div > div > table > tbody > tr > td > a > i.fa, .box-body, @@ -477,14 +476,20 @@ a { color: var(--link); } a:link { - color: var(--link); + color: var(--nav-link); } a:hover { - color: var(--hover-link); + color: var(--nav-link); text-decoration: underline; } a:visited { - color: var(--visited-link); + color: var(--nav-link); +} +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets'] { + background-color: transparent; } .row-striped { vertical-align: top; diff --git a/public/css/dist/skins/skin-yellow-dark.css b/public/css/dist/skins/skin-yellow-dark.css index fddcde6fa..1f1654075 100644 --- a/public/css/dist/skins/skin-yellow-dark.css +++ b/public/css/dist/skins/skin-yellow-dark.css @@ -101,10 +101,6 @@ border-bottom-right-radius: 2px; border-bottom-left-radius: 0; } -.btn, -.btn:hover { - color: #000; -} .btn.btn-primary, .btn:hover.btn-primary, .btn .btn-primary:link, @@ -129,6 +125,9 @@ background-color: var(--hover-link); color: #545454; } +a.actions { + color: #fff !important; +} /** The dropdown is white, so use a darker color */ @@ -211,7 +210,7 @@ a.btn.btn-default { color: var(--nav-link); } .bootstrap-table .fixed-table-container .table thead th .sortable { - color: var(--nav-link); + color: var(--text-main); } .bootstrap-table .fixed-table-toolbar .columns label { color: #000; @@ -423,14 +422,9 @@ input[type=search] { .skin-yellow-dark .main-header .navbar .dropdown-menu li a { color: var(--header); } -div.th-inner { +tr th div.th-inner { color: var(--text-main); } -.fixed-table-body thead th .th-inner, -.skin-yellow-dark, -.skin-yellow { - background-color: var(--header) !important; -} .tab-content, .tab-pane { background-color: var(--back-main); diff --git a/public/css/dist/skins/skin-yellow-dark.min.css b/public/css/dist/skins/skin-yellow-dark.min.css index fddcde6fa..1f1654075 100644 --- a/public/css/dist/skins/skin-yellow-dark.min.css +++ b/public/css/dist/skins/skin-yellow-dark.min.css @@ -101,10 +101,6 @@ border-bottom-right-radius: 2px; border-bottom-left-radius: 0; } -.btn, -.btn:hover { - color: #000; -} .btn.btn-primary, .btn:hover.btn-primary, .btn .btn-primary:link, @@ -129,6 +125,9 @@ background-color: var(--hover-link); color: #545454; } +a.actions { + color: #fff !important; +} /** The dropdown is white, so use a darker color */ @@ -211,7 +210,7 @@ a.btn.btn-default { color: var(--nav-link); } .bootstrap-table .fixed-table-container .table thead th .sortable { - color: var(--nav-link); + color: var(--text-main); } .bootstrap-table .fixed-table-toolbar .columns label { color: #000; @@ -423,14 +422,9 @@ input[type=search] { .skin-yellow-dark .main-header .navbar .dropdown-menu li a { color: var(--header); } -div.th-inner { +tr th div.th-inner { color: var(--text-main); } -.fixed-table-body thead th .th-inner, -.skin-yellow-dark, -.skin-yellow { - background-color: var(--header) !important; -} .tab-content, .tab-pane { background-color: var(--back-main); diff --git a/public/mix-manifest.json b/public/mix-manifest.json index cafa72644..931a6156e 100644 --- a/public/mix-manifest.json +++ b/public/mix-manifest.json @@ -1,24 +1,24 @@ { "/js/build/app.js": "/js/build/app.js?id=7caeae38608edd96421f8ef59d33f5f6", "/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=f677207c6cf9678eb539abecb408c374", - "/css/build/overrides.css": "/css/build/overrides.css?id=ce20eefb1895545e882840c480bca0dc", - "/css/build/app.css": "/css/build/app.css?id=3afc900b0a697567f8285f46aded1c89", + "/css/build/overrides.css": "/css/build/overrides.css?id=97a58ce3a89cd0043a1c54ecf63d4686", + "/css/build/app.css": "/css/build/app.css?id=02dbcc25fce08e9b9a9b285883821805", "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=dc383f8560a8d4adb51d44fb4043e03b", "/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=6f0563e726c2fe4fab4026daaa5bfdf2", - "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=ca38553d041220a4296dda555940e056", - "/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=032f18fdd48936784cfcfe70712a68ae", - "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=e5b6ec4691d8fd647d38722886f983e6", + "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=e6e53eef152bba01a4c666a4d8b01117", + "/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=07273f6ca3c698a39e8fc2075af4fa07", + "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=7c4badf178b44a4489dac90c0f772908", "/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=7b315b9612b8fde8f9c5b0ddb6bba690", "/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=7d92dea45d94be7e1d4e427c728d335d", "/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=6fe68325d5356197672c27bc77cedcb4", - "/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=218c6d947f73c767d23a663a9859d97e", - "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=87c6506e9aac3ebc68dfd99b6f983602", + "/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=d6086232485d2b9661b7f83ed482355e", + "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=bdfc704731682c67645a2248b0b8d2d7", "/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=76482123f6c70e866d6b971ba91de7bb", - "/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=28b36223cf7b1d6e5f236859a4ef2b45", + "/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=e36e83c2aa3c3afdbb8ebe2c0309e91d", "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=0a82a6ae6bb4e58fe62d162c4fb50397", "/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=da6c7997d9de2f8329142399f0ce50da", "/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=44bf834f2110504a793dadec132a5898", - "/css/dist/all.css": "/css/dist/all.css?id=41d8a74912c3b0d17cc508361530c597", + "/css/dist/all.css": "/css/dist/all.css?id=999cf8c1432f7baff31b61a04a9a8485", "/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7", "/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=e2e2b1797606a266ed55549f5bb5a179", @@ -34,18 +34,18 @@ "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=a0e44dba789031b34ef150a01318b865", "/js/dist/all.js": "/js/dist/all.js?id=97b1034b75e3ac29a2eb9770d66c3370", "/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=28b36223cf7b1d6e5f236859a4ef2b45", + "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=e36e83c2aa3c3afdbb8ebe2c0309e91d", "/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=76482123f6c70e866d6b971ba91de7bb", - "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=87c6506e9aac3ebc68dfd99b6f983602", + "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=bdfc704731682c67645a2248b0b8d2d7", "/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=f677207c6cf9678eb539abecb408c374", - "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=032f18fdd48936784cfcfe70712a68ae", + "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=07273f6ca3c698a39e8fc2075af4fa07", "/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=7b315b9612b8fde8f9c5b0ddb6bba690", - "/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=e5b6ec4691d8fd647d38722886f983e6", + "/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=7c4badf178b44a4489dac90c0f772908", "/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=44bf834f2110504a793dadec132a5898", - "/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=218c6d947f73c767d23a663a9859d97e", + "/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=d6086232485d2b9661b7f83ed482355e", "/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=6fe68325d5356197672c27bc77cedcb4", "/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=7d92dea45d94be7e1d4e427c728d335d", "/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=6f0563e726c2fe4fab4026daaa5bfdf2", - "/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=ca38553d041220a4296dda555940e056", + "/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=e6e53eef152bba01a4c666a4d8b01117", "/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=da6c7997d9de2f8329142399f0ce50da" } diff --git a/resources/assets/less/overrides.less b/resources/assets/less/overrides.less index 60a75358f..e8dc67ce3 100644 --- a/resources/assets/less/overrides.less +++ b/resources/assets/less/overrides.less @@ -195,6 +195,9 @@ a.accordion-header { .btn-info.btn-outline { color: #5bc0de; } +.btn-warning{ + background-color:#f39c12 !important; +} .btn-warning.btn-outline { color: #f0ad4e; @@ -499,14 +502,14 @@ h4 { background: #FFFFFF; border-top: 1px solid #dddddd; display: table-row; - + } .row-new-striped > .row:nth-of-type(odd) { background-color: #F8F8F8; border-top: 1px solid #dddddd; display: table-row; - + } .row-new-striped div { @@ -740,7 +743,7 @@ input[type="checkbox"] { input[type="checkbox"]::before { -/** If you want to use the non-checkbox, filled square, use this instead **/ + /** If you want to use the non-checkbox, filled square, use this instead **/ content: ""; width: 1em; height: 1em; diff --git a/resources/assets/less/skins/skin-black-dark.less b/resources/assets/less/skins/skin-black-dark.less index e914d2c0a..69a393e80 100644 --- a/resources/assets/less/skins/skin-black-dark.less +++ b/resources/assets/less/skins/skin-black-dark.less @@ -135,6 +135,9 @@ a { #ldapad_test_results.well.well-sm{ color: var(--back-main); } +a.actions { + color:#fff !important; +} //pagination .pagination > li >a{ color: var(--light-link); @@ -147,6 +150,23 @@ a { .pagination > .active > a:hover{ background-color: var(--hover-link); } +.tasks-menu > .dropdown-menu > li .menu > li > a:hover .progress{ + background-color: var(--background); +} +a:hover > h2.task_menu{ + color:var(--header); +} +h2.task_menu{ + color:var(--link); +} +.navbar-custom-menu > .navbar-nav > li > .dropdown-menu{ + background-color:var(--back-main); + color:var(--link); +} +.navbar-custom-menu > .navbar-nav > li > .dropdown-menu > li.header{ + background-color:var(--header); + color:var(--link); +} .main-header .navbar, .main-header .logo { background-color: var(--header); diff --git a/resources/assets/less/skins/skin-blue-dark.less b/resources/assets/less/skins/skin-blue-dark.less index e886b24f9..6c502b178 100644 --- a/resources/assets/less/skins/skin-blue-dark.less +++ b/resources/assets/less/skins/skin-blue-dark.less @@ -132,6 +132,9 @@ a { #ldapad_test_results.well.well-sm{ color: var(--back-main); } +a.actions { + color:#fff !important; +} //pagination .pagination > li >a{ color: var(--light-link); @@ -394,6 +397,12 @@ a { color: var(--visited-link) } } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets']{ + background-color: transparent; +} .row-striped { vertical-align: top; diff --git a/resources/assets/less/skins/skin-green-dark.less b/resources/assets/less/skins/skin-green-dark.less index 518146cdb..a69f918ac 100644 --- a/resources/assets/less/skins/skin-green-dark.less +++ b/resources/assets/less/skins/skin-green-dark.less @@ -131,6 +131,9 @@ a { #ldapad_test_results.well.well-sm{ color: var(--back-main); } +a.actions { + color:#fff !important; +} //pagination .pagination > li >a{ color: var(--light-link); @@ -180,10 +183,6 @@ h2.task_menu{ color: var(--text-main); } -a:link { - color: var(--link); -} - .btn-primary.hover { color: var(--nav-link); } @@ -385,6 +384,12 @@ a { color: var(--visited-link) } } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets']{ + background-color: transparent; +} .row-striped { vertical-align: top; diff --git a/resources/assets/less/skins/skin-orange-dark.less b/resources/assets/less/skins/skin-orange-dark.less index bd1386d1e..98925b475 100644 --- a/resources/assets/less/skins/skin-orange-dark.less +++ b/resources/assets/less/skins/skin-orange-dark.less @@ -119,6 +119,9 @@ li.dropdown-item-marker { #ldapad_test_results.well.well-sm{ color: var(--back-main); } +a.actions { + color:#fff !important; +} //pagination .pagination > li >a{ color: var(--light-link); @@ -378,6 +381,12 @@ input[type=text], input[type=search] { .box-header.with-border { border-bottom: #000; } +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets']{ + background-color: transparent; +} .row-striped { vertical-align: top; diff --git a/resources/assets/less/skins/skin-red-dark.less b/resources/assets/less/skins/skin-red-dark.less index dbb002369..8d75bbc79 100644 --- a/resources/assets/less/skins/skin-red-dark.less +++ b/resources/assets/less/skins/skin-red-dark.less @@ -58,8 +58,6 @@ } } - - .btn, .btn:hover { color: #fff; @@ -134,6 +132,7 @@ a { #ldapad_test_results.well.well-sm{ color: var(--back-main); } + //pagination .pagination > li >a{ color: var(--light-link); @@ -186,14 +185,12 @@ h2.task_menu{ a:link { color: var(--link); } - -a:visited { - color: var(--nav-link); -} - a:hover { color: var(--hover-link); } +a:visited { + color: var(--nav-link); +} .far fa-life-ring{ color:var(--link); } @@ -380,7 +377,6 @@ input[type=text], input[type=search] { } .table-striped>tbody>tr:nth-of-type(even){ background-color: var(--back-sub-alt); - color: var(--text-alt); } #webui>div>div>div>div>div>table>tbody>tr>td>a>i.fa, .box-body, .box-footer, .box-header { color: var(--text-main); @@ -394,16 +390,22 @@ a { color: var(--link); &:link { - color: var(--link) } + color: var(--nav-link); + } &:hover { - color: var(--hover-link); + color: var(--nav-link); text-decoration: underline; } &:visited { - color: var(--visited-link) + color: var(--nav-link); } } - +#customFieldsTable a[href*='/models'] { + color: var(--back-sub); +} +#customFieldsTable a[href*='/fieldsets']{ + background-color: transparent; +} .row-striped { vertical-align: top; line-height: 2.6; diff --git a/resources/assets/less/skins/skin-yellow-dark.less b/resources/assets/less/skins/skin-yellow-dark.less index 99678e774..2718eb638 100644 --- a/resources/assets/less/skins/skin-yellow-dark.less +++ b/resources/assets/less/skins/skin-yellow-dark.less @@ -52,7 +52,6 @@ } .btn, .btn:hover { - color: #000; &.btn-primary, .btn-primary:link { background-color: var(--button-default); @@ -60,7 +59,6 @@ color: #545454; } - &a.btn-primary:hover { background-color: var(--button-hover); border-color: var(--button-hover); @@ -77,6 +75,9 @@ color: #545454; } } +a.actions { + color:#fff !important; +} /** The dropdown is white, so use a darker color @@ -165,7 +166,7 @@ a.btn.btn-default{ color:var(--nav-link); } .bootstrap-table .fixed-table-container .table thead th .sortable { - color: var(--nav-link); + color: var(--text-main); } .bootstrap-table .fixed-table-toolbar .columns label { color:#000; @@ -355,12 +356,9 @@ input[type=text], input[type=search] { .skin-yellow-dark .main-header .navbar .dropdown-menu li a { color: var(--header); } -div.th-inner{ +tr th div.th-inner { color:var(--text-main); } -.fixed-table-body thead th .th-inner, .skin-yellow-dark, .skin-yellow { - background-color: var(--header)!important; -} .tab-content, .tab-pane { background-color: var(--back-main); color: var(--text-main); diff --git a/resources/lang/en/admin/accessories/general.php b/resources/lang/en/admin/accessories/general.php index 84a3e8338..bed7f38fa 100644 --- a/resources/lang/en/admin/accessories/general.php +++ b/resources/lang/en/admin/accessories/general.php @@ -17,5 +17,6 @@ return array( 'use_default_eula' => 'Use the primary default EULA instead.', 'use_default_eula_disabled' => 'Use the primary default EULA instead. No primary default EULA is set. Please add one in Settings.', 'clone' => 'Clone Accessory', + 'delete_disabled' => 'This accessory cannot be deleted yet because some items are still checked out.', ); diff --git a/resources/lang/en/admin/custom_fields/general.php b/resources/lang/en/admin/custom_fields/general.php index 9dae380aa..1923aa7f4 100644 --- a/resources/lang/en/admin/custom_fields/general.php +++ b/resources/lang/en/admin/custom_fields/general.php @@ -49,4 +49,6 @@ return [ 'unique' => 'Unique', 'display_in_user_view' => 'Allow the checked out user to view these values in their View Assigned Assets page', 'display_in_user_view_table' => 'Visible to User', + 'auto_add_to_fieldsets' => 'Automatically add this to every new fieldset', + 'add_to_preexisting_fieldsets' => 'Add to any existing fieldsets', ]; diff --git a/resources/lang/en/admin/hardware/table.php b/resources/lang/en/admin/hardware/table.php index 6166ba804..10629fd22 100644 --- a/resources/lang/en/admin/hardware/table.php +++ b/resources/lang/en/admin/hardware/table.php @@ -8,6 +8,7 @@ return [ 'change' => 'In/Out', 'checkout_date' => 'Checkout Date', 'checkoutto' => 'Checked Out', + 'components_cost' => 'Total Components Cost', 'current_value' => 'Current Value', 'diff' => 'Diff', 'dl_csv' => 'Download CSV', diff --git a/resources/lang/en/admin/manufacturers/message.php b/resources/lang/en/admin/manufacturers/message.php index 21a4bc5aa..d6656683a 100644 --- a/resources/lang/en/admin/manufacturers/message.php +++ b/resources/lang/en/admin/manufacturers/message.php @@ -2,6 +2,7 @@ return array( + 'support_url_help' => 'Use {LOCALE} and {SERIAL} in your URL as variables to have those values auto-populate when viewing assets.', 'does_not_exist' => 'Manufacturer does not exist.', 'assoc_users' => 'This manufacturer is currently associated with at least one model and cannot be deleted. Please update your models to no longer reference this manufacturer and try again. ', diff --git a/resources/lang/en/admin/manufacturers/table.php b/resources/lang/en/admin/manufacturers/table.php index 4e3ea9904..38cab6fd9 100644 --- a/resources/lang/en/admin/manufacturers/table.php +++ b/resources/lang/en/admin/manufacturers/table.php @@ -10,6 +10,7 @@ return array( 'support_email' => 'Support Email', 'support_phone' => 'Support Phone', 'support_url' => 'Support URL', + 'warranty_lookup_url' => 'Warranty Lookup URL', 'update' => 'Update Manufacturer', 'url' => 'URL', diff --git a/resources/lang/en/admin/settings/general.php b/resources/lang/en/admin/settings/general.php index c69c94457..92faf85c5 100644 --- a/resources/lang/en/admin/settings/general.php +++ b/resources/lang/en/admin/settings/general.php @@ -330,4 +330,9 @@ return [ 'setup_migration_create_user' => 'Next: Create User', 'ldap_settings_link' => 'LDAP Settings Page', 'slack_test' => 'Test Integration', + 'google_callback_help' => 'This should be entered as the callback URL in your Google OAuth app settings in your organization's Google developer console .', + 'google_login' => 'Google Workspace Login Settings', + 'enable_google_login' => 'Enable users to login with Google Workspace', + 'enable_google_login_help' => 'Users will not be automatically provisioned. They must have an existing account here AND in Google Workspace, and their username here must match their Google Workspace email address. ', + ]; diff --git a/resources/lang/en/auth/general.php b/resources/lang/en/auth/general.php index 78b678092..4486f090b 100644 --- a/resources/lang/en/auth/general.php +++ b/resources/lang/en/auth/general.php @@ -12,5 +12,8 @@ return [ 'remember_me' => 'Remember Me', 'username_help_top' => 'Enter your username to be emailed a password reset link.', 'username_help_bottom' => 'Your username and email address may be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator.

Usernames without an associated email address will not be emailed a password reset link. ', - ]; + 'google_login' => 'Or login with Google Workspace', + 'google_login_failed' => 'Google Login failed, please try again.', + +]; diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 4874158bc..674dec6e4 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -91,6 +91,8 @@ return [ 'debug_warning' => 'Warning!', 'debug_warning_text' => 'This application is running in production mode with debugging enabled. This can expose sensitive data if your application is accessible to the outside world. Disable debug mode by setting the APP_DEBUG value in your .env file to false.', 'delete' => 'Delete', + 'delete_confirm' => 'Are you sure you wish to delete :item?', + 'delete_confirm_no_undo' => 'Are you sure you wish to delete :item? This can not be undone.', 'deleted' => 'Deleted', 'delete_seats' => 'Deleted Seats', 'deletion_failed' => 'Deletion failed', diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php index 31c9dcd85..df514da6f 100644 --- a/resources/lang/en/validation.php +++ b/resources/lang/en/validation.php @@ -67,6 +67,8 @@ return [ 'array' => 'The :attribute must have at least :min items.', ], 'starts_with' => 'The :attribute must start with one of the following: :values.', + 'ends_with' => 'The :attribute must end with one of the following: :values.', + 'not_in' => 'The selected :attribute is invalid.', 'numeric' => 'The :attribute must be a number.', 'present' => 'The :attribute field must be present.', diff --git a/resources/views/accessories/view.blade.php b/resources/views/accessories/view.blade.php index a34cf572c..b3798697b 100644 --- a/resources/views/accessories/view.blade.php +++ b/resources/views/accessories/view.blade.php @@ -12,43 +12,6 @@ @parent @stop -{{-- Right header --}} -@section('header_right') - @can('manage', \App\Models\Accessory::class) - - @endcan -@stop - {{-- Page content --}} @section('content') {{-- Page content --}} @@ -136,7 +99,7 @@ - +
@@ -271,13 +234,13 @@
-
- - @endcan - - - + + @endcan + + + + @@ -294,10 +257,10 @@ @if ($accessory->company)
-
+
{{ trans('general.company')}}
- @@ -306,10 +269,10 @@ @if ($accessory->category)
-
+
{{ trans('general.category')}}
- @@ -317,88 +280,75 @@ @if ($accessory->notes) - -
+
+
{{ trans('general.notes') }}
-
+
{!! nl2br(e($accessory->notes)) !!}
+
@endif
-
+
{{ trans('admin/accessories/general.remaining') }}
-
+
{{ $accessory->numRemaining() }}
-
+
{{ trans('general.checked_out') }}
-
+
{{ $accessory->users_count }}
+
+
+ @can('checkout', \App\Models\Accessory::class) + + @endcan + @can('update', \App\Models\Accessory::class) + + @endcan + @can('update', \App\Models\Accessory::class) + + @endcan - - @can('checkout', \App\Models\Accessory::class) - - @endcan - - -
-
-
- - - - - - - - - - - - @if ($snipeSettings->require_accept_signature=='1') - - @endif - - -
{{ trans('general.record_created') }}{{ trans('general.admin') }}{{ trans('general.action') }}{{ trans('general.item') }}{{ trans('general.target') }}{{ trans('general.notes') }}{{ trans('general.date') }}{{ trans('general.signature') }}
-
-
-
-
-
+ @can('delete', $accessory) + @if ($accessory->users_count == 0) +
+ +
+ @else + + @endif + @endcan +
+
@@ -411,5 +361,13 @@ @section('moar_scripts') + @include ('partials.bootstrap-table') @stop diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 330d7bf50..8d9f648a9 100755 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -64,7 +64,7 @@
@if (!config('app.require_saml') && $snipeSettings->saml_enabled) -
+ -
+ @if ($snipeSettings->custom_forgot_pass_url) - {{ trans('auth/general.forgot_password') }} + @elseif (!config('app.require_saml')) - {{ trans('auth/general.forgot_password') }} + @endif -
+
+ @if (($snipeSettings->google_login=='1') && ($snipeSettings->google_client_id!='') && ($snipeSettings->google_client_secret!='')) + + + {{ trans('auth/general.google_login') }} + + @endif +
diff --git a/resources/views/custom_fields/fields/edit.blade.php b/resources/views/custom_fields/fields/edit.blade.php index 8e025e4b6..9d5113844 100644 --- a/resources/views/custom_fields/fields/edit.blade.php +++ b/resources/views/custom_fields/fields/edit.blade.php @@ -1,8 +1,8 @@ -@php - use App\Models\CustomField; -@endphp +@extends('layouts/default', [ + 'helpText' => trans('admin/custom_fields/general.about_fieldsets_text'), + 'helpPosition' => 'right', +]) -@extends('layouts/default') {{-- Page title --}} @section('title') @@ -21,24 +21,31 @@ {{-- Page content --}} @section('content') -
-
- @if ($field->id) - {{ Form::open(['route' => ['fields.update', $field->id], 'class'=>'form-horizontal']) }} - {{ method_field('PUT') }} - @else - {{ Form::open(['route' => 'fields.store', 'class'=>'form-horizontal']) }} - @endif + @if ($field->id) + {{ Form::open(['route' => ['fields.update', $field->id], 'class'=>'form-horizontal']) }} + {{ method_field('PUT') }} + @else + {{ Form::open(['route' => 'fields.store', 'class'=>'form-horizontal']) }} + @endif + @csrf +
+
+
+ +
+ +
+
-