diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php index 030e069bd2..b33d83cdd0 100644 --- a/app/Http/Controllers/Account/AcceptanceController.php +++ b/app/Http/Controllers/Account/AcceptanceController.php @@ -223,6 +223,7 @@ class AcceptanceController extends Controller 'item_model' => $display_model, 'item_serial' => $item->serial, 'eula' => $item->getEula(), + 'note' => $request->input('note'), 'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'), 'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'), 'assigned_to' => $assigned_to, @@ -238,7 +239,7 @@ class AcceptanceController extends Controller Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output()); } - $acceptance->accept($sig_filename, $item->getEula(), $pdf_filename); + $acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note')); $acceptance->notify(new AcceptanceAssetAcceptedNotification($data)); event(new CheckoutAccepted($acceptance)); @@ -306,10 +307,12 @@ class AcceptanceController extends Controller $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; break; } + $data = [ 'item_tag' => $item->asset_tag, 'item_model' => $display_model, 'item_serial' => $item->serial, + 'note' => $request->input('note'), 'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'), 'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null, 'assigned_to' => $assigned_to, @@ -323,7 +326,7 @@ class AcceptanceController extends Controller Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output()); } - $acceptance->decline($sig_filename); + $acceptance->decline($sig_filename, $request->input('note')); $acceptance->notify(new AcceptanceAssetDeclinedNotification($data)); event(new CheckoutDeclined($acceptance)); $return_msg = trans('admin/users/message.declined'); diff --git a/app/Http/Controllers/AssetModelsFilesController.php b/app/Http/Controllers/AssetModelsFilesController.php index 91cb525d77..2a0a23a9f2 100644 --- a/app/Http/Controllers/AssetModelsFilesController.php +++ b/app/Http/Controllers/AssetModelsFilesController.php @@ -71,7 +71,6 @@ class AssetModelsFilesController extends Controller $file = 'private_uploads/assetmodels/'.$log->filename; - if (! Storage::exists($file)) { return response('File '.$file.' not found on server', 404) ->header('Content-Type', 'text/plain'); diff --git a/app/Http/Controllers/Assets/AssetCheckoutController.php b/app/Http/Controllers/Assets/AssetCheckoutController.php index a096f16678..aa282b443d 100644 --- a/app/Http/Controllers/Assets/AssetCheckoutController.php +++ b/app/Http/Controllers/Assets/AssetCheckoutController.php @@ -62,7 +62,7 @@ class AssetCheckoutController extends Controller $this->authorize('checkout', $asset); $admin = Auth::user(); - $target = $this->determineCheckoutTarget($asset); + $target = $this->determineCheckoutTarget(); $asset = $this->updateAssetLocation($asset, $target); diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php index 9316c2dec4..b0874cb569 100755 --- a/app/Http/Controllers/Users/UsersController.php +++ b/app/Http/Controllers/Users/UsersController.php @@ -293,8 +293,15 @@ class UsersController extends Controller $user->password = bcrypt($request->input('password')); } + + // Update the location of any assets checked out to this user + Asset::where('assigned_type', User::class) + ->where('assigned_to', $user->id) + ->update(['location_id' => $user->location_id]); + $permissions_array = $request->input('permission'); + // Strip out the superuser permission if the user isn't a superadmin if (! Auth::user()->isSuperUser()) { unset($permissions_array['superuser']); diff --git a/app/Http/Requests/ImageUploadRequest.php b/app/Http/Requests/ImageUploadRequest.php index 9677111059..59af9259f4 100644 --- a/app/Http/Requests/ImageUploadRequest.php +++ b/app/Http/Requests/ImageUploadRequest.php @@ -86,12 +86,8 @@ class ImageUploadRequest extends Request if ($this->offsetGet($form_fieldname) instanceof UploadedFile) { $image = $this->offsetGet($form_fieldname); - \Log::debug('Image is an instance of UploadedFile'); } elseif ($this->hasFile($form_fieldname)) { $image = $this->file($form_fieldname); - \Log::debug('Just use regular upload for '.$form_fieldname); - } else { - \Log::debug('No image found for form fieldname: '.$form_fieldname); } if (isset($image)) { diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index d99e570810..ca0f6296ee 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -85,20 +85,23 @@ class ActionlogsTransformer $enc_old = ''; $enc_new = ''; - try { - $enc_old = \Crypt::decryptString($this->clean_field($fieldata->old)); - } catch (\Exception $e) { - \Log::debug('Could not decrypt field - maybe the key changed?'); + if ($this->clean_field($fieldata->old!='')) { + try { + $enc_old = \Crypt::decryptString($this->clean_field($fieldata->old)); + } catch (\Exception $e) { + \Log::debug('Could not decrypt old field value - maybe the key changed?'); + } } - try { - $enc_new = \Crypt::decryptString($this->clean_field($fieldata->new)); - } catch (\Exception $e) { - \Log::debug('Could not decrypt field - maybe the key changed?'); + if ($this->clean_field($fieldata->new!='')) { + try { + $enc_new = \Crypt::decryptString($this->clean_field($fieldata->new)); + } catch (\Exception $e) { + \Log::debug('Could not decrypt new field value - maybe the key changed?'); + } } if ($enc_old != $enc_new) { - \Log::debug('custom fields do not match'); $clean_meta[$fieldname]['old'] = "************"; $clean_meta[$fieldname]['new'] = "************"; diff --git a/app/Listeners/LogListener.php b/app/Listeners/LogListener.php index 4b584c668b..0345ac1341 100644 --- a/app/Listeners/LogListener.php +++ b/app/Listeners/LogListener.php @@ -62,6 +62,7 @@ class LogListener $logaction->target()->associate($event->acceptance->assignedTo); $logaction->accept_signature = $event->acceptance->signature_filename; $logaction->filename = $event->acceptance->stored_eula_file; + $logaction->note = $event->acceptance->note; $logaction->action_type = 'accepted'; // TODO: log the actual license seat that was checked out @@ -78,6 +79,7 @@ class LogListener $logaction->item()->associate($event->acceptance->checkoutable); $logaction->target()->associate($event->acceptance->assignedTo); $logaction->accept_signature = $event->acceptance->signature_filename; + $logaction->note = $event->acceptance->note; $logaction->action_type = 'declined'; // TODO: log the actual license seat that was checked out diff --git a/app/Models/CheckoutAcceptance.php b/app/Models/CheckoutAcceptance.php index 4a4360c40a..9c501aaf63 100644 --- a/app/Models/CheckoutAcceptance.php +++ b/app/Models/CheckoutAcceptance.php @@ -80,12 +80,13 @@ class CheckoutAcceptance extends Model * * @param string $signature_filename */ - public function accept($signature_filename, $eula = null, $filename = null) + public function accept($signature_filename, $eula = null, $filename = null, $note = null) { $this->accepted_at = now(); $this->signature_filename = $signature_filename; $this->stored_eula = $eula; $this->stored_eula_file = $filename; + $this->note = $note; $this->save(); /** @@ -99,9 +100,10 @@ class CheckoutAcceptance extends Model * * @param string $signature_filename */ - public function decline($signature_filename) + public function decline($signature_filename, $note = null) { $this->declined_at = now(); + $this->note = $note; $this->signature_filename = $signature_filename; $this->save(); diff --git a/app/Models/Company.php b/app/Models/Company.php index 8f8e71ff5c..aac002bdcd 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -262,7 +262,6 @@ final class Company extends SnipeModel if (! static::isFullMultipleCompanySupportEnabled() || (Auth::check() && Auth::user()->isSuperUser()) || (! Auth::check())) { return $query; } else { - \Log::debug('Fire scopeCompanyablesDirectly.'); return static::scopeCompanyablesDirectly($query, $column, $table_name); } } @@ -275,7 +274,6 @@ final class Company extends SnipeModel { // Get the company ID of the logged in user, or set it to null if there is no company assicoated with the user if (Auth::user()) { - \Log::debug('Admin company is: '.Auth::user()->company_id); $company_id = Auth::user()->company_id; } else { $company_id = null; @@ -283,9 +281,6 @@ final class Company extends SnipeModel // Dynamically get the table name if it's not passed in, based on the model we're querying against $table = ($table_name) ? $table_name."." : $query->getModel()->getTable()."."; - \Log::debug('Model is: '.$query->getModel()); - - \Log::debug('Table is: '.$table); // If the column exists in the table, use it to scope the query if (\Schema::hasColumn($query->getModel()->getTable(), $column)) { diff --git a/app/Notifications/AcceptanceAssetAcceptedNotification.php b/app/Notifications/AcceptanceAssetAcceptedNotification.php index ca016acd34..db1555b574 100644 --- a/app/Notifications/AcceptanceAssetAcceptedNotification.php +++ b/app/Notifications/AcceptanceAssetAcceptedNotification.php @@ -26,6 +26,7 @@ class AcceptanceAssetAcceptedNotification extends Notification $this->item_serial = $params['item_serial']; $this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false); $this->assigned_to = $params['assigned_to']; + $this->note = $params['note']; $this->company_name = $params['company_name']; $this->settings = Setting::getSettings(); @@ -64,6 +65,7 @@ class AcceptanceAssetAcceptedNotification extends Notification 'item_tag' => $this->item_tag, 'item_model' => $this->item_model, 'item_serial' => $this->item_serial, + 'note' => $this->note, 'accepted_date' => $this->accepted_date, 'assigned_to' => $this->assigned_to, 'company_name' => $this->company_name, diff --git a/app/Notifications/AcceptanceAssetDeclinedNotification.php b/app/Notifications/AcceptanceAssetDeclinedNotification.php index 11b022e095..abdfbbf0c0 100644 --- a/app/Notifications/AcceptanceAssetDeclinedNotification.php +++ b/app/Notifications/AcceptanceAssetDeclinedNotification.php @@ -25,6 +25,7 @@ class AcceptanceAssetDeclinedNotification extends Notification $this->item_model = $params['item_model']; $this->item_serial = $params['item_serial']; $this->declined_date = Helper::getFormattedDateObject($params['declined_date'], 'date', false); + $this->note = $params['note']; $this->assigned_to = $params['assigned_to']; $this->company_name = $params['company_name']; $this->settings = Setting::getSettings(); @@ -62,6 +63,7 @@ class AcceptanceAssetDeclinedNotification extends Notification 'item_tag' => $this->item_tag, 'item_model' => $this->item_model, 'item_serial' => $this->item_serial, + 'note' => $this->note, 'declined_date' => $this->declined_date, 'assigned_to' => $this->assigned_to, 'company_name' => $this->company_name, diff --git a/database/migrations/2024_03_18_164714_add_note_to_checkout_acceptance_table.php b/database/migrations/2024_03_18_164714_add_note_to_checkout_acceptance_table.php new file mode 100644 index 0000000000..75d251b60d --- /dev/null +++ b/database/migrations/2024_03_18_164714_add_note_to_checkout_acceptance_table.php @@ -0,0 +1,32 @@ +text('note')->after('signature_filename')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('checkout_acceptances', function (Blueprint $table) { + $table->dropColumn('note'); + }); + } +} diff --git a/package-lock.json b/package-lock.json index 1a61476f90..e444bbb02f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2379,9 +2379,9 @@ } }, "alpinejs": { - "version": "3.13.5", - "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.5.tgz", - "integrity": "sha512-1d2XeNGN+Zn7j4mUAKXtAgdc4/rLeadyTMWeJGXF5DzwawPBxwTiBhFFm6w/Ei8eJxUZeyNWWSD9zknfdz1kEw==", + "version": "3.13.10", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.10.tgz", + "integrity": "sha512-86RB307VWICex0vG15Eq0x058cNNsvS57ohrjN6n/TJAVSFV+zXOK/E34nNHDHc6Poq+yTNCLqEzPqEkRBTMRQ==", "requires": { "@vue/reactivity": "~3.1.1" } diff --git a/package.json b/package.json index 0526d5370b..13bfc8a25f 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "acorn-import-assertions": "^1.9.0", "admin-lte": "^2.4.18", "ajv": "^6.12.6", - "alpinejs": "3.13.5", + "alpinejs": "^3.13.10", "blueimp-file-upload": "^9.34.0", "bootstrap": "^3.4.1", "bootstrap-colorpicker": "^2.5.3", diff --git a/public/.well-known/security.txt b/public/.well-known/security.txt new file mode 100644 index 0000000000..5b8d0c144a --- /dev/null +++ b/public/.well-known/security.txt @@ -0,0 +1,7 @@ +Contact: mailto:security@snipeitapp.com +Expires: 2025-05-16T11:30:00.000Z +Acknowledgments: https://snipeitapp.com/thanks +Preferred-Languages: en-US, pt-PT, de-DE +Canonical: https://github.com/snipe/snipe-it/blob/master/public/.well-known/security.txt +Policy: https://snipeitapp.com/security +Hiring: https://snipeitapp.com/company/careers \ No newline at end of file diff --git a/public/js/dist/all-defer.js b/public/js/dist/all-defer.js index 50470c93f9..7480ea7c6d 100644 --- a/public/js/dist/all-defer.js +++ b/public/js/dist/all-defer.js @@ -104,120 +104,6 @@ return () => release(effectReference); } - // packages/alpinejs/src/utils/dispatch.js - function dispatch(el, name, detail = {}) { - el.dispatchEvent( - new CustomEvent(name, { - detail, - bubbles: true, - // Allows events to pass the shadow DOM barrier. - composed: true, - cancelable: true - }) - ); - } - - // packages/alpinejs/src/utils/walk.js - function walk(el, callback) { - if (typeof ShadowRoot === "function" && el instanceof ShadowRoot) { - Array.from(el.children).forEach((el2) => walk(el2, callback)); - return; - } - let skip = false; - callback(el, () => skip = true); - if (skip) - return; - let node = el.firstElementChild; - while (node) { - walk(node, callback, false); - node = node.nextElementSibling; - } - } - - // packages/alpinejs/src/utils/warn.js - function warn(message, ...args) { - console.warn(`Alpine Warning: ${message}`, ...args); - } - - // packages/alpinejs/src/lifecycle.js - var started = false; - function start() { - if (started) - warn("Alpine has already been initialized on this page. Calling Alpine.start() more than once can cause problems."); - started = true; - if (!document.body) - warn("Unable to initialize. Trying to load Alpine before `` is available. Did you forget to add `defer` in Alpine's ` @stop \ No newline at end of file diff --git a/resources/views/notifications/markdown/asset-acceptance.blade.php b/resources/views/notifications/markdown/asset-acceptance.blade.php index 50191d4a37..93292375a5 100644 --- a/resources/views/notifications/markdown/asset-acceptance.blade.php +++ b/resources/views/notifications/markdown/asset-acceptance.blade.php @@ -13,6 +13,9 @@ @if (isset($declined_date)) | **{{ ucfirst(trans('general.declined')) }}** | {{ $declined_date }} | @endif +@if (isset($note)) +| **{{ trans('general.notes') }}** | {{ $note }} | +@endif @if ((isset($item_tag)) && ($item_tag!='')) | **{{ trans('mail.asset_tag') }}** | {{ $item_tag }} | @endif diff --git a/resources/views/partials/label2-field-definitions.blade.php b/resources/views/partials/label2-field-definitions.blade.php index b701ffe69a..2a44fbf257 100644 --- a/resources/views/partials/label2-field-definitions.blade.php +++ b/resources/views/partials/label2-field-definitions.blade.php @@ -209,7 +209,9 @@ array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]); }, - get valueString() { return this.toString(this.fields); }, + get valueString() { + return this.getCombinedString(this.fields); + }, onTest: function(a) { console.log('test', a); }, @@ -229,7 +231,7 @@ }) })); }, - toString: function(fields) { + getCombinedString: function (fields) { return fields .map(field => field.options .map(option => option.label + '=' + option.datasource)