Merge remote-tracking branch 'origin/master' into develop

Signed-off-by: snipe <snipe@snipe.net>

# Conflicts:
#	app/Http/Controllers/Api/AssetsController.php
#	app/Http/Transformers/AssetsTransformer.php
#	app/Importer/ConsumableImporter.php
#	app/Models/Consumable.php
#	config/version.php
#	package-lock.json
#	package.json
#	public/css/dist/all.css
#	public/css/dist/bootstrap-table.css
#	public/js/build/app.js
#	public/js/dist/all.js
#	public/js/dist/bootstrap-table.js
#	public/mix-manifest.json
#	resources/views/custom_fields/fieldsets/view.blade.php
#	resources/views/layouts/default.blade.php
#	routes/web.php
#	routes/web/fields.php
This commit is contained in:
snipe 2021-11-15 19:24:38 -08:00
commit f2f8f96991
14 changed files with 92 additions and 83 deletions

View file

@ -96,6 +96,8 @@ RUN \
&& rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \ && rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \
&& mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \ && mkdir -p "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \
&& ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \ && ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.cert" "/var/www/html/storage/ldap_client_tls.cert" \
&& ln -fs "/var/lib/snipeit/keys/ldap_client_tls.key" "/var/www/html/storage/ldap_client_tls.key" \
&& chown docker "/var/lib/snipeit/keys/" \ && chown docker "/var/lib/snipeit/keys/" \
&& chown -h docker "/var/www/html/storage/" \ && chown -h docker "/var/www/html/storage/" \
&& chmod +x /var/www/html/artisan \ && chmod +x /var/www/html/artisan \

View file

@ -171,6 +171,7 @@ class AssetsController extends Controller
// case we override with the actual count, so we should return 0 items. // case we override with the actual count, so we should return 0 items.
$offset = (($assets) && ($request->get('offset') > $assets->count())) ? $assets->count() : $request->get('offset', 0); $offset = (($assets) && ($request->get('offset') > $assets->count())) ? $assets->count() : $request->get('offset', 0);
// Check to make sure the limit is not higher than the max allowed // Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results'); ((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
@ -336,6 +337,7 @@ class AssetsController extends Controller
return (new $transformer)->transformAssets($assets, $total, $request); return (new $transformer)->transformAssets($assets, $total, $request);
} }
/** /**
* Returns JSON with information about an asset (by tag) for detail view. * Returns JSON with information about an asset (by tag) for detail view.
* *
@ -373,9 +375,19 @@ class AssetsController extends Controller
} }
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200); return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
$assets = Asset::with('assetstatus')->with('assignedTo');
if ($request->input('deleted', 'false') === 'true') {
$assets = $assets->withTrashed();
} }
$assets = $assets->where('serial', $serial)->get();
if ($assets) {
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
} else {
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
}
}
/** /**
* Returns JSON with information about an asset for detail view. * Returns JSON with information about an asset for detail view.
@ -677,6 +689,8 @@ class AssetsController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200); return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
} }
/** /**
* Restore a soft-deleted asset. * Restore a soft-deleted asset.
* *

View file

@ -114,25 +114,14 @@ class AssetsTransformer
} }
$permissions_array['available_actions'] = [ $permissions_array['available_actions'] = [
'checkout' => Gate::allows('checkout', Asset::class), 'checkout' => ($asset->deleted_at=='' && Gate::allows('checkout', Asset::class)) ? true : false,
'checkin' => Gate::allows('checkin', Asset::class), 'checkin' => ($asset->deleted_at=='' && Gate::allows('checkin', Asset::class)) ? true : false,
'clone' => false, 'clone' => Gate::allows('create', Asset::class) ? true : false,
'restore' => false, 'restore' => ($asset->deleted_at!='' && Gate::allows('create', Asset::class)) ? true : false,
'update' => (bool) Gate::allows('update', Asset::class), 'update' => ($asset->deleted_at=='' && Gate::allows('update', Asset::class)) ? true : false,
'delete' => ($asset->assigned_to == '' && Gate::allows('delete', Asset::class)), 'delete' => ($asset->deleted_at=='' && $asset->assigned_to =='' && Gate::allows('delete', Asset::class)) ? true : false,
]; ];
if ($asset->deleted_at != '') {
$permissions_array['available_actions'] = [
'checkout' => true,
'checkin' => false,
'clone' => Gate::allows('create', Asset::class),
'restore' => Gate::allows('create', Asset::class),
'update' => false,
'delete' => false,
];
}
if (request('components')=='true') { if (request('components')=='true') {

View file

@ -76,6 +76,7 @@ abstract class Importer
'department' => 'department', 'department' => 'department',
'manager_first_name' => 'manager first name', 'manager_first_name' => 'manager first name',
'manager_last_name' => 'manager last name', 'manager_last_name' => 'manager last name',
'min_amt' => 'minimum quantity',
]; ];
/** /**
* Map of item fields->csv names * Map of item fields->csv names
@ -196,11 +197,11 @@ abstract class Importer
$val = $default; $val = $default;
$key = $this->lookupCustomKey($key); $key = $this->lookupCustomKey($key);
// $this->log("Custom Key: ${key}"); $this->log("Custom Key: ${key}");
if (array_key_exists($key, $array)) { if (array_key_exists($key, $array)) {
$val = Encoding::toUTF8(trim($array[$key])); $val = Encoding::toUTF8(trim($array[$key]));
} }
// $this->log("${key}: ${val}"); $this->log("${key}: ${val}");
return $val; return $val;
} }

View file

@ -29,6 +29,7 @@
| serial number | serial | Asset, license | | serial number | serial | Asset, license |
| status | status | Asset ? All | | status | status | Asset ? All |
| supplier | supplier | Asset ? All | | supplier | supplier | Asset ? All |
| minimum quantity | min_amt | Consumable |
| termination date | termination_date | License | | termination date | termination_date | License |
| warranty months | warranty_months | Asset | | warranty months | warranty_months | Asset |
| User Related Fields | assigned_to | Asset | | User Related Fields | assigned_to | Asset |

View file

@ -68,6 +68,7 @@ class Consumable extends SnipeModel
'purchase_cost', 'purchase_cost',
'purchase_date', 'purchase_date',
'qty', 'qty',
'min_amt',
'requestable', 'requestable',
]; ];
@ -185,6 +186,7 @@ class Consumable extends SnipeModel
return $this->belongsTo(\App\Models\Category::class, 'category_id'); return $this->belongsTo(\App\Models\Category::class, 'category_id');
} }
/** /**
* Establishes the component -> action logs relationship * Establishes the component -> action logs relationship
* *
@ -209,8 +211,8 @@ class Consumable extends SnipeModel
if ($this->image) { if ($this->image) {
return Storage::disk('public')->url(app('consumables_upload_path').$this->image); return Storage::disk('public')->url(app('consumables_upload_path').$this->image);
} }
return false; return false;
} }
/** /**
@ -225,6 +227,7 @@ class Consumable extends SnipeModel
return $this->belongsToMany(\App\Models\User::class, 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps(); return $this->belongsToMany(\App\Models\User::class, 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps();
} }
/** /**
* Determine whether to send a checkin/checkout email based on * Determine whether to send a checkin/checkout email based on
* asset model category * asset model category

View file

@ -1,4 +1,4 @@
#!/usr/bin/env python #!/usr/bin/env python3
# A supervisor event listener which terminates supervisord if any of its child # A supervisor event listener which terminates supervisord if any of its child
# processes enter the FATAL state. # processes enter the FATAL state.
# https://stackoverflow.com/a/37527488/119527 # https://stackoverflow.com/a/37527488/119527

View file

@ -32,7 +32,7 @@
"bootstrap-colorpicker": "^2.5.3", "bootstrap-colorpicker": "^2.5.3",
"bootstrap-datepicker": "^1.9.0", "bootstrap-datepicker": "^1.9.0",
"bootstrap-less": "^3.3.8", "bootstrap-less": "^3.3.8",
"bootstrap-table": "^1.18.3", "bootstrap-table": "^1.19.1",
"chart.js": "^2.9.4", "chart.js": "^2.9.4",
"css-loader": "^3.6.0", "css-loader": "^3.6.0",
"ekko-lightbox": "^5.1.1", "ekko-lightbox": "^5.1.1",
@ -41,7 +41,7 @@
"imagemin": "^5.3.1", "imagemin": "^5.3.1",
"jquery-form-validator": "^2.3.79", "jquery-form-validator": "^2.3.79",
"jquery-slimscroll": "^1.3.8", "jquery-slimscroll": "^1.3.8",
"jquery-ui": "^1.12.1", "jquery-ui": "^1.13.0",
"jquery-ui-bundle": "^1.12.1", "jquery-ui-bundle": "^1.12.1",
"jquery.iframe-transport": "^1.0.0", "jquery.iframe-transport": "^1.0.0",
"less": "^4.1.1", "less": "^4.1.1",

Binary file not shown.

View file

@ -158,6 +158,7 @@
consumables: [ consumables: [
{id: 'item_no', text: "Item Number"}, {id: 'item_no', text: "Item Number"},
{id: 'model_number', text: "Model Number"}, {id: 'model_number', text: "Model Number"},
{id: 'min_amt', text: "Minimum Quantity"},
], ],
licenses: [ licenses: [
{id: 'asset_tag', text: 'Assigned To Asset'}, {id: 'asset_tag', text: 'Assigned To Asset'},
@ -216,6 +217,7 @@
.concat(this.columnOptions.accessories) .concat(this.columnOptions.accessories)
.sort(sorter); .sort(sorter);
case 'consumable': case 'consumable':
console.log('Returned consumable');
return this.columnOptions.general return this.columnOptions.general
.concat(this.columnOptions.consumables) .concat(this.columnOptions.consumables)
.sort(sorter); .sort(sorter);

View file

@ -57,21 +57,28 @@
<td>{{$field->element}}</td> <td>{{$field->element}}</td>
<td>{{ $field->field_encrypted=='1' ? trans('general.yes') : trans('general.no') }}</td> <td>{{ $field->field_encrypted=='1' ? trans('general.yes') : trans('general.no') }}</td>
<td> <td>
@if ($field->pivot->required) @if ($field->pivot->required)
<a href="{{ route('fields.optional', [$custom_fieldset->id, $field->id]) }}"> <form method="post" action="{{ route('fields.optional', [$custom_fieldset->id, $field->id]) }}">
<i class="fas fa-check text-success" aria-hidden="true"></i> @csrf
<span class="sr-only">Required - click to make optional</span> <button type="submit" class="btn btn-link"><i class="fa fa-check text-success" aria-hidden="true"></i></button>
</a> </form>
@else @else
<a href="{{ route('fields.required', [$custom_fieldset->id, $field->id]) }}">
<i class="fas fa-times text-danger" aria-hidden="true"></i> <form method="post" action="{{ route('fields.required', [$custom_fieldset->id, $field->id]) }}">
<span class="sr-only">Optional - click to make required</span> @csrf
</a> <button type="submit" class="btn btn-link"><i class="fa fa-times text-danger" aria-hidden="true"></i></button>
</form>
@endif @endif
</td> </td>
<td> <td>
@can('update', $custom_fieldset) @can('update', $custom_fieldset)
<a href="{{ route('fields.disassociate', [$field, $custom_fieldset->id]) }}" class="btn btn-sm btn-danger">Remove</a> <form method="post" action="{{ route('fields.disassociate', [$field, $custom_fieldset->id]) }}">
@csrf
<button type="submit" class="btn btn-sm btn-danger">Remove</button>
</form>
@endcan @endcan
</td> </td>
</tr> </tr>

View file

@ -109,14 +109,14 @@
@if ($snipeSettings->brand == '3') @if ($snipeSettings->brand == '3')
<a class="logo navbar-brand no-hover" href="{{ url('/') }}"> <a class="logo navbar-brand no-hover" href="{{ url('/') }}">
@if ($snipeSettings->logo!='') @if ($snipeSettings->logo!='')
<img class="navbar-brand-img" src="{{ Storage::disk('public')->url('/').e($snipeSettings->logo) }}" alt="{{ $snipeSettings->site_name }} logo"> <img class="navbar-brand-img" src="{{ Storage::disk('public')->url($snipeSettings->logo) }}" alt="{{ $snipeSettings->site_name }} logo">
@endif @endif
{{ $snipeSettings->site_name }} {{ $snipeSettings->site_name }}
</a> </a>
@elseif ($snipeSettings->brand == '2') @elseif ($snipeSettings->brand == '2')
<a class="logo navbar-brand no-hover" href="{{ url('/') }}"> <a class="logo navbar-brand no-hover" href="{{ url('/') }}">
@if ($snipeSettings->logo!='') @if ($snipeSettings->logo!='')
<img class="navbar-brand-img" src="{{ Storage::disk('public')->url('/').e($snipeSettings->logo) }}" alt="{{ $snipeSettings->site_name }} logo"> <img class="navbar-brand-img" src="{{ Storage::disk('public')->url($snipeSettings->logo) }}" alt="{{ $snipeSettings->site_name }} logo">
@endif @endif
<span class="sr-only">{{ $snipeSettings->site_name }}</span> <span class="sr-only">{{ $snipeSettings->site_name }}</span>
</a> </a>
@ -355,10 +355,17 @@
@endcan @endcan
<li class="divider"></li> <li class="divider"></li>
<li> <li>
<a href="{{ url('/logout') }}">
<i class="fas fa-sign-out-alt" aria-hidden="true"></i> <a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">
{{ trans('general.logout') }} <i class="fa fa-sign-out fa-fw"></i> {{ trans('general.logout') }}
{{ csrf_field() }}
</a> </a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
{{ csrf_field() }}
</form>
</li> </li>
</ul> </ul>
</li> </li>
@ -947,6 +954,7 @@
@endif @endif
@livewireScripts @livewireScripts
</body> </body>
</html> </html>

View file

@ -1,58 +1,40 @@
<?php <?php
use App\Http\Controllers\CustomFieldsController;
use App\Http\Controllers\CustomFieldsetsController;
use Illuminate\Support\Facades\Route;
/* /*
* Custom Fields Routes * Custom Fields Routes
*/ */
Route::group([ 'prefix' => 'fields','middleware' => ['auth'] ], function () { Route::group([ 'prefix' => 'fields','middleware' => ['auth'] ], function () {
Route::get( Route::post('required/{fieldset_id}/{field_id}',
'required/{fieldset_id}/{field_id}', ['uses' => 'CustomFieldsetsController@makeFieldRequired',
[ 'as' => 'fields.required']
CustomFieldsetsController::class, );
'makeFieldRequired'
]
)->name('fields.required');
Route::get( Route::post('optional/{fieldset_id}/{field_id}',
'optional/{fieldset_id}/{field_id}', ['uses' => 'CustomFieldsetsController@makeFieldOptional',
[ 'as' => 'fields.optional']
CustomFieldsetsController::class, );
'makeFieldOptional'
]
)->name('fields.optional');
Route::get( Route::post('{field_id}/fieldset/{fieldset_id}/disassociate',
'{field_id}/fieldset/{fieldset_id}/disassociate', ['uses' => 'CustomFieldsController@deleteFieldFromFieldset',
[ 'as' => 'fields.disassociate']
CustomFieldsetsController::class, );
'deleteFieldFromFieldset'
]
)->name('fields.disassociate');
Route::post( Route::post('fieldsets/{id}/associate',
'fieldsets/{id}/associate', ['uses' => 'CustomFieldsetsController@associate',
[ 'as' => 'fieldsets.associate']
CustomFieldsetsController::class, );
'associate'
]
)->name('fieldsets.associate');
Route::resource('fieldsets', CustomFieldsetsController::class, [ Route::resource('fieldsets', 'CustomFieldsetsController', [
'parameters' => ['fieldset' => 'field_id', 'field' => 'field_id'], 'parameters' => ['fieldset' => 'field_id', 'field' => 'field_id']
]); ]);
}); });
Route::resource('fields', 'CustomFieldsController', [
Route::resource('fields', CustomFieldsController::class, [ 'middleware' => ['auth'],
'parameters' => ['field' => 'field_id'], 'parameters' => ['field' => 'field_id', 'fieldset' => 'fieldset_id']
]); ]);