mirror of
https://github.com/snipe/snipe-it.git
synced 2024-12-27 14:39:49 -08:00
Merge remote-tracking branch 'origin/develop'
Signed-off-by: snipe <snipe@snipe.net> # Conflicts: # public/js/dist/all-defer.js # public/mix-manifest.json
This commit is contained in:
commit
3dfd471fa4
|
@ -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');
|
||||
|
|
|
@ -70,8 +70,6 @@ class AssetModelsFilesController extends Controller
|
|||
}
|
||||
|
||||
$file = 'private_uploads/assetmodels/'.$log->filename;
|
||||
\Log::debug('Checking for '.$file);
|
||||
|
||||
|
||||
if (! Storage::exists($file)) {
|
||||
return response('File '.$file.' not found on server', 404)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ class AssetFilesController extends Controller
|
|||
}
|
||||
|
||||
$file = 'private_uploads/assets/'.$log->filename;
|
||||
\Log::debug('Checking for '.$file);
|
||||
|
||||
if ($log->action_type == 'audit') {
|
||||
$file = 'private_uploads/audits/'.$log->filename;
|
||||
|
|
|
@ -293,7 +293,7 @@ class AssetsController extends Controller
|
|||
*
|
||||
* @param int $assetId
|
||||
* @return \Illuminate\Http\RedirectResponse|Redirect
|
||||
*@since [v1.0]
|
||||
* @since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function update(ImageUploadRequest $request, $assetId = null)
|
||||
|
|
|
@ -13,7 +13,9 @@ use App\Models\Setting;
|
|||
use App\View\Label;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use App\Http\Requests\AssetCheckoutRequest;
|
||||
|
@ -189,7 +191,6 @@ class BulkAssetsController extends Controller
|
|||
* Save bulk edits
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @return Redirect
|
||||
* @internal param array $assets
|
||||
* @since [v2.0]
|
||||
*/
|
||||
|
@ -214,7 +215,7 @@ class BulkAssetsController extends Controller
|
|||
}
|
||||
|
||||
|
||||
$assets = Asset::whereIn('id', array_keys($request->input('ids')))->get();
|
||||
$assets = Asset::whereIn('id', $request->input('ids'))->get();
|
||||
|
||||
|
||||
|
||||
|
@ -379,28 +380,30 @@ class BulkAssetsController extends Controller
|
|||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
|
||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($field->field_encrypted == '1')) {
|
||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||
if (Gate::allows('admin')) {
|
||||
$decrypted_old = Helper::gracefulDecrypt($field, $asset->{$field->db_column});
|
||||
|
||||
/*
|
||||
* Check if the decrypted existing value is different from one we just submitted
|
||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||
* different times will have different values, so it will *look* like it was updated
|
||||
* but it wasn't.
|
||||
*/
|
||||
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
||||
$asset->{$field->db_column} = \Crypt::encrypt($this->update_array[$field->db_column]);
|
||||
} else {
|
||||
/*
|
||||
* Remove the encrypted custom field from the update_array, since nothing changed
|
||||
* Check if the decrypted existing value is different from one we just submitted
|
||||
* and if not, pull it out of the object since it shouldn't really be updating at all.
|
||||
* If we don't do this, it will try to re-encrypt it, and the same value encrypted two
|
||||
* different times will have different values, so it will *look* like it was updated
|
||||
* but it wasn't.
|
||||
*/
|
||||
unset($this->update_array[$field->db_column]);
|
||||
unset($asset->{$field->db_column});
|
||||
}
|
||||
if ($decrypted_old != $this->update_array[$field->db_column]) {
|
||||
$asset->{$field->db_column} = Crypt::encrypt($this->update_array[$field->db_column]);
|
||||
} else {
|
||||
/*
|
||||
* Remove the encrypted custom field from the update_array, since nothing changed
|
||||
*/
|
||||
unset($this->update_array[$field->db_column]);
|
||||
unset($asset->{$field->db_column});
|
||||
}
|
||||
|
||||
/*
|
||||
* These custom fields aren't encrypted, just carry on as usual
|
||||
*/
|
||||
/*
|
||||
* These custom fields aren't encrypted, just carry on as usual
|
||||
*/
|
||||
}
|
||||
} else {
|
||||
|
||||
if ((array_key_exists($field->db_column, $this->update_array)) && ($asset->{$field->db_column} != $this->update_array[$field->db_column])) {
|
||||
|
|
|
@ -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']);
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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'] = "************";
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
@ -307,7 +302,6 @@ final class Company extends SnipeModel
|
|||
*/
|
||||
public static function scopeCompanyableChildren(array $companyable_names, $query)
|
||||
{
|
||||
\Log::debug('Company Names in scopeCompanyableChildren: '.print_r($companyable_names, true));
|
||||
|
||||
if (count($companyable_names) == 0) {
|
||||
throw new Exception('No Companyable Children to scope');
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -363,6 +363,15 @@ class AssetFactory extends Factory
|
|||
});
|
||||
}
|
||||
|
||||
public function hasMultipleCustomFields(array $fields = null): self
|
||||
{
|
||||
return $this->state(function () use ($fields) {
|
||||
return [
|
||||
'model_id' => AssetModel::factory()->hasMultipleCustomFields($fields),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This allows bypassing model level validation if you want to purposefully
|
||||
|
|
|
@ -439,4 +439,13 @@ class AssetModelFactory extends Factory
|
|||
];
|
||||
});
|
||||
}
|
||||
|
||||
public function hasMultipleCustomFields(array $fields = null)
|
||||
{
|
||||
return $this->state(function () use ($fields) {
|
||||
return [
|
||||
'fieldset_id' => CustomFieldset::factory()->hasMultipleCustomFields($fields),
|
||||
];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,4 +53,23 @@ class CustomFieldsetFactory extends Factory
|
|||
$fieldset->fields()->attach($field, ['order' => '1', 'required' => false]);
|
||||
});
|
||||
}
|
||||
|
||||
public function hasMultipleCustomFields(array $fields = null): self
|
||||
{
|
||||
return $this->afterCreating(function (CustomFieldset $fieldset) use ($fields) {
|
||||
if (empty($fields)) {
|
||||
$mac_address = CustomField::factory()->macAddress()->create();
|
||||
$ram = CustomField::factory()->ram()->create();
|
||||
$cpu = CustomField::factory()->cpu()->create();
|
||||
|
||||
$fieldset->fields()->attach($mac_address, ['order' => '1', 'required' => false]);
|
||||
$fieldset->fields()->attach($ram, ['order' => '2', 'required' => false]);
|
||||
$fieldset->fields()->attach($cpu, ['order' => '3', 'required' => false]);
|
||||
} else {
|
||||
foreach ($fields as $field) {
|
||||
$fieldset->fields()->attach($field, ['order' => '1', 'required' => false]);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddNoteToCheckoutAcceptanceTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->text('note')->after('signature_filename')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('checkout_acceptances', function (Blueprint $table) {
|
||||
$table->dropColumn('note');
|
||||
});
|
||||
}
|
||||
}
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
7
public/.well-known/security.txt
Normal file
7
public/.well-known/security.txt
Normal file
|
@ -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
|
|
@ -49,6 +49,7 @@ return [
|
|||
'default_eula_text' => 'Default EULA',
|
||||
'default_language' => 'Default Language',
|
||||
'default_eula_help_text' => 'You can also associate custom EULAs to specific asset categories.',
|
||||
'acceptance_note' => 'Add a note for your decision (Optional)',
|
||||
'display_asset_name' => 'Display Asset Name',
|
||||
'display_checkout_date' => 'Display Checkout Date',
|
||||
'display_eol' => 'Display EOL in table view',
|
||||
|
|
|
@ -295,6 +295,7 @@ return [
|
|||
'user' => 'User',
|
||||
'accepted' => 'accepted',
|
||||
'declined' => 'declined',
|
||||
'declined_note' => 'Declined Notes',
|
||||
'unassigned' => 'Unassigned',
|
||||
'unaccepted_asset_report' => 'Unaccepted Assets',
|
||||
'users' => 'Users',
|
||||
|
|
|
@ -64,6 +64,15 @@
|
|||
</label>
|
||||
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<br>
|
||||
<div class="col-md-12" style="display:block;">
|
||||
<label id="note_label" for="note" style="text-align:center;" >{{trans('admin/settings/general.acceptance_note')}}</label>
|
||||
</div>
|
||||
<div class="col-md-12">
|
||||
<textarea id="note" name="note" rows="4" cols="50" value="note" style="width:100%" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($snipeSettings->require_accept_signature=='1')
|
||||
<div class="col-md-12">
|
||||
|
@ -133,5 +142,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
@stop
|
|
@ -196,8 +196,8 @@
|
|||
|
||||
@include("models/custom_fields_form_bulk_edit",["models" => $models])
|
||||
|
||||
@foreach ($assets as $key => $value)
|
||||
<input type="hidden" name="ids[{{ $value }}]" value="1">
|
||||
@foreach($assets as $asset)
|
||||
<input type="hidden" name="ids[]" value="{{ $asset }}">
|
||||
@endforeach
|
||||
</div> <!--/.box-body-->
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
208
tests/Feature/Assets/AssetsBulkEditTest.php
Normal file
208
tests/Feature/Assets/AssetsBulkEditTest.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
namespace Tests\Feature\Assets;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AssetsBulkEditTest extends TestCase
|
||||
{
|
||||
public function testUserWithPermissionsCanAccessPage()
|
||||
{
|
||||
$user = User::factory()->viewAssets()->editAssets()->create();
|
||||
$assets = Asset::factory()->count(2)->create();
|
||||
|
||||
$id_array = $assets->pluck('id')->toArray();
|
||||
|
||||
$this->actingAs($user)->post('/hardware/bulkedit', [
|
||||
'ids' => $id_array,
|
||||
'order' => 'asc',
|
||||
'bulk_actions' => 'edit',
|
||||
'sort' => 'id'
|
||||
])->assertStatus(200);
|
||||
}
|
||||
|
||||
public function testStandardUserCannotAccessPage()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$assets = Asset::factory()->count(2)->create();
|
||||
|
||||
$id_array = $assets->pluck('id')->toArray();
|
||||
|
||||
$this->actingAs($user)->post('/hardware/bulkedit', [
|
||||
'ids' => $id_array,
|
||||
'order' => 'asc',
|
||||
'bulk_actions' => 'edit',
|
||||
'sort' => 'id'
|
||||
])->assertStatus(403);
|
||||
}
|
||||
|
||||
public function testBulkEditAssetsAcceptsAllPossibleAttributes()
|
||||
{
|
||||
// sets up all needed models and attributes on the assets
|
||||
// this test does not deal with custom fields - will be dealt with in separate cases
|
||||
$status1 = Statuslabel::factory()->create();
|
||||
$status2 = Statuslabel::factory()->create();
|
||||
$model1 = AssetModel::factory()->create();
|
||||
$model2 = AssetModel::factory()->create();
|
||||
$supplier1 = Supplier::factory()->create();
|
||||
$supplier2 = Supplier::factory()->create();
|
||||
$company1 = Company::factory()->create();
|
||||
$company2 = Company::factory()->create();
|
||||
$assets = Asset::factory()->count(10)->create([
|
||||
'purchase_date' => '2023-01-01',
|
||||
'expected_checkin' => '2023-01-01',
|
||||
'status_id' => $status1->id,
|
||||
'model_id' => $model1->id,
|
||||
// skipping locations on this test, it deserves it's own test
|
||||
'purchase_cost' => 1234.90,
|
||||
'supplier_id' => $supplier1->id,
|
||||
'company_id' => $company1->id,
|
||||
'order_number' => '123456',
|
||||
'warranty_months' => 24,
|
||||
'next_audit_date' => '2024-06-01',
|
||||
'requestable' => false
|
||||
]);
|
||||
|
||||
// gets the ids together to submit to the endpoint
|
||||
$id_array = $assets->pluck('id')->toArray();
|
||||
|
||||
// submits the ids and new values for each attribute
|
||||
$this->actingAs(User::factory()->editAssets()->create())->post(route('hardware/bulksave'), [
|
||||
'ids' => $id_array,
|
||||
'purchase_date' => '2024-01-01',
|
||||
'expected_checkin' => '2024-01-01',
|
||||
'status_id' => $status2->id,
|
||||
'model_id' => $model2->id,
|
||||
'purchase_cost' => 5678.92,
|
||||
'supplier_id' => $supplier2->id,
|
||||
'company_id' => $company2->id,
|
||||
'order_number' => '7890',
|
||||
'warranty_months' => 36,
|
||||
'next_audit_date' => '2025-01-01',
|
||||
'requestable' => true
|
||||
])
|
||||
->assertStatus(302)
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
// asserts that each asset has the updated values
|
||||
Asset::findMany($id_array)->each(function (Asset $asset) use ($status2, $model2, $supplier2, $company2) {
|
||||
$this->assertEquals('2024-01-01', $asset->purchase_date->format('Y-m-d'));
|
||||
$this->assertEquals('2024-01-01', $asset->expected_checkin->format('Y-m-d'));
|
||||
$this->assertEquals($status2->id, $asset->status_id);
|
||||
$this->assertEquals($model2->id, $asset->model_id);
|
||||
$this->assertEquals(5678.92, $asset->purchase_cost);
|
||||
$this->assertEquals($supplier2->id, $asset->supplier_id);
|
||||
$this->assertEquals($company2->id, $asset->company_id);
|
||||
$this->assertEquals(7890, $asset->order_number);
|
||||
$this->assertEquals(36, $asset->warranty_months);
|
||||
$this->assertEquals('2025-01-01', $asset->next_audit_date->format('Y-m-d'));
|
||||
// shouldn't requestable be cast as a boolean??? it's not.
|
||||
$this->assertEquals(1, $asset->requestable);
|
||||
});
|
||||
}
|
||||
|
||||
public function testBulkEditAssetsAcceptsAndUpdatesUnencryptedCustomFields()
|
||||
{
|
||||
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
|
||||
|
||||
CustomField::factory()->ram()->create();
|
||||
CustomField::factory()->cpu()->create();
|
||||
|
||||
// when getting the custom field directly from the factory the field has not been fully created yet
|
||||
// so we have to do a query afterwards to get the actual model :shrug:
|
||||
|
||||
$ram = CustomField::where('name', 'RAM')->first();
|
||||
$cpu = CustomField::where('name', 'CPU')->first();
|
||||
|
||||
$assets = Asset::factory()->count(10)->hasMultipleCustomFields([$ram, $cpu])->create([
|
||||
$ram->db_column => 8,
|
||||
$cpu->db_column => '2.1',
|
||||
]);
|
||||
|
||||
$id_array = $assets->pluck('id')->toArray();
|
||||
|
||||
$this->actingAs(User::factory()->editAssets()->create())->post(route('hardware/bulksave'), [
|
||||
'ids' => $id_array,
|
||||
$ram->db_column => 16,
|
||||
$cpu->db_column => '4.1',
|
||||
])->assertStatus(302);
|
||||
|
||||
Asset::findMany($id_array)->each(function (Asset $asset) use ($ram, $cpu) {
|
||||
$this->assertEquals(16, $asset->{$ram->db_column});
|
||||
$this->assertEquals('4.1', $asset->{$cpu->db_column});
|
||||
});
|
||||
}
|
||||
|
||||
public function testBulkEditAssetsAcceptsAndUpdatesEncryptedCustomFields()
|
||||
{
|
||||
$this->markIncompleteIfMySQL('Custom Fields tests do not work on MySQL');
|
||||
|
||||
CustomField::factory()->testEncrypted()->create();
|
||||
|
||||
$encrypted = CustomField::where('name', 'Test Encrypted')->first();
|
||||
|
||||
$assets = Asset::factory()->count(10)->hasEncryptedCustomField($encrypted)->create([
|
||||
$encrypted->db_column => Crypt::encrypt('Original Encrypted Text'),
|
||||
]);
|
||||
|
||||
$id_array = $assets->pluck('id')->toArray();
|
||||
|
||||
$this->actingAs(User::factory()->admin()->create())->post(route('hardware/bulksave'), [
|
||||
'ids' => $id_array,
|
||||
$encrypted->db_column => 'New Encrypted Text',
|
||||
])->assertStatus(302);
|
||||
|
||||
Asset::findMany($id_array)->each(function (Asset $asset) use ($encrypted) {
|
||||
$this->assertEquals('New Encrypted Text', Crypt::decrypt($asset->{$encrypted->db_column}));
|
||||
});
|
||||
}
|
||||
|
||||
public function testBulkEditAssetsRequiresAdminUserToUpdateEncryptedCustomFields()
|
||||
{
|
||||
$this->markIncompleteIfMySQL('Custom Fields tests do not work on mysql');
|
||||
$edit_user = User::factory()->editAssets()->create();
|
||||
$admin_user = User::factory()->admin()->create();
|
||||
|
||||
CustomField::factory()->testEncrypted()->create();
|
||||
|
||||
$encrypted = CustomField::where('name', 'Test Encrypted')->first();
|
||||
|
||||
$admin_assets = Asset::factory()->count(5)->hasEncryptedCustomField($encrypted)->create([
|
||||
$encrypted->db_column => Crypt::encrypt('Original Encrypted Text'),
|
||||
]);
|
||||
|
||||
$standard_assets = Asset::factory()->count(5)->hasEncryptedCustomField($encrypted)->create([
|
||||
$encrypted->db_column => Crypt::encrypt('Original Encrypted Text'),
|
||||
]);
|
||||
|
||||
$admin_id_array = $admin_assets->pluck('id')->toArray();
|
||||
$standard_id_array = $standard_assets->pluck('id')->toArray();
|
||||
|
||||
$this->actingAs($admin_user)->post(route('hardware/bulksave'), [
|
||||
'ids' => $admin_id_array,
|
||||
$encrypted->db_column => 'New Encrypted Text',
|
||||
])->assertStatus(302);
|
||||
|
||||
// do we want to return an error when this happens???
|
||||
$this->actingAs($edit_user)->post(route('hardware/bulksave'), [
|
||||
'ids' => $standard_id_array,
|
||||
$encrypted->db_column => 'New Encrypted Text',
|
||||
])->assertStatus(302);
|
||||
|
||||
Asset::findMany($admin_id_array)->each(function (Asset $asset) use ($encrypted) {
|
||||
$this->assertEquals('New Encrypted Text', Crypt::decrypt($asset->{$encrypted->db_column}));
|
||||
});
|
||||
|
||||
Asset::findMany($standard_id_array)->each(function (Asset $asset) use ($encrypted) {
|
||||
$this->assertEquals('Original Encrypted Text', Crypt::decrypt($asset->{$encrypted->db_column}));
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue