Merge branch 'develop' into bug/sc-15034

This commit is contained in:
Marcus Moore 2023-03-30 16:17:42 -07:00
commit 621d8500eb
No known key found for this signature in database
21 changed files with 154 additions and 43 deletions

View file

@ -66,8 +66,11 @@ Since the release of the JSON REST API, several third-party developers have been
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
- [Snipe-IT Kubernetes Helm Chart](https://github.com/t3n/helm-charts/tree/master/snipeit) - For more information, [click here](https://hub.helm.sh/charts/t3n/snipeit).
- [Snipe-IT Bulk Edit](https://github.com/bricelabelle/snipe-it-bulkedit) - Google Script files to use Google Sheets as a bulk checkout/checkin/edit tool for Snipe-it.
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@RodneyLeeBrands](https://github.com/RodneyLeeBrands) - Python script to synchronize information between Mosyle and Snipe-IT
- [MosyleSnipeSync](https://github.com/RodneyLeeBrands/MosyleSnipeSync) by [@Karpadiem](https://github.com/Karpadiem) - Python script to synchronize information between Mosyle and Snipe-IT
- [WWW::SnipeIT](https://github.com/SEDC/perl-www-snipeit) by [@SEDC](https://github.com/SEDC) - perl module for accessing the API
- [UniFi to Snipe-IT](https://github.com/RodneyLeeBrands/UnifiSnipeSync) by [@karpadiem](https://github.com/karpadiem) - Python script that synchronizes UniFi devices with Snipe-IT.
- [Kandji2Snipe](https://github.com/grokability/kandji2snipe) by [@briangoldstein](https://github.com/briangoldstein) - Python script that synchronizes Kandji with Snipe-IT.
- [SnipeAgent](https://github.com/ReticentRobot/SnipeAgent) by @ReticentRobot - Windows agent for Snipe-IT
As these were created by third-parties, Snipe-IT cannot provide support for these project, and you should contact the developers directly if you need assistance. Additionally, Snipe-IT makes no guarantees as to the reliability, accuracy or maintainability of these libraries. Use at your own risk. :)

View file

@ -463,7 +463,7 @@ class AssetsController extends Controller
{
$this->authorize('view', Asset::class);
$this->authorize('view', License::class);
$asset = Asset::where('id', $id)->withTrashed()->first();
$asset = Asset::where('id', $id)->withTrashed()->firstorfail();
$licenses = $asset->licenses()->get();
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
@ -832,7 +832,6 @@ class AssetsController extends Controller
} elseif (request('checkout_to_type') == 'asset') {
$target = Asset::where('id', '!=', $asset_id)->find(request('assigned_asset'));
$asset->location_id = $target->rtd_location_id;
// Override with the asset's location_id if it has one
$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
$error_payload['target_id'] = $request->input('assigned_asset');

View file

@ -49,6 +49,7 @@ class BulkAssetsController extends Controller
->with('settings', Setting::getSettings())
->with('bulkedit', true)
->with('count', 0);
case 'delete':
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
$assets->each(function ($asset) {
@ -56,6 +57,15 @@ class BulkAssetsController extends Controller
});
return view('hardware/bulk-delete')->with('assets', $assets);
case 'restore':
$assets = Asset::withTrashed()->find($asset_ids);
$assets->each(function ($asset) {
$this->authorize('delete', $asset);
});
return view('hardware/bulk-restore')->with('assets', $assets);
case 'edit':
return view('hardware/bulk')
->with('assets', $asset_ids)
@ -320,5 +330,18 @@ class BulkAssetsController extends Controller
} catch (ModelNotFoundException $e) {
return redirect()->route('hardware.bulkcheckout.show')->with('error', $e->getErrors());
}
}
public function restore(Request $request) {
$assetIds = $request->get('ids');
if (empty($assetIds)) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.restore.nothing_updated'));
} else {
foreach ($assetIds as $key => $assetId) {
$asset = Asset::withTrashed()->find($assetId);
$asset->restore();
}
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success'));
}
}
}

View file

@ -92,7 +92,7 @@ class GroupsController extends Controller
return view('groups.edit', compact('group', 'permissions', 'selected_array', 'groupPermissions'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found'));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
}
/**
@ -107,7 +107,7 @@ class GroupsController extends Controller
public function update(Request $request, $id = null)
{
if (! $group = Group::find($id)) {
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
}
$group->name = $request->input('name');
$group->permissions = json_encode($request->input('permission'));
@ -133,14 +133,13 @@ class GroupsController extends Controller
* @return \Illuminate\Http\RedirectResponse
* @throws \Exception
*/
public function destroy($id = null)
public function destroy($id)
{
if (! config('app.lock_passwords')) {
if (! $group = Group::find($id)) {
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
}
$group->delete();
// Redirect to the group management page
return redirect()->route('groups.index')->with('success', trans('admin/groups/message.success.delete'));
}
@ -164,6 +163,6 @@ class GroupsController extends Controller
return view('groups/view', compact('group'));
}
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', compact('id')));
return redirect()->route('groups.index')->with('error', trans('admin/groups/message.group_not_found', ['id' => $id]));
}
}

View file

@ -198,8 +198,8 @@ class Importer extends Component
public function updating($name, $new_import_type)
{
if ($name == "activeFile.import_type") {
\Log::info("WE ARE CHANGING THE import_type!!!!! TO: " . $new_import_type);
\Log::info("so, what's \$this->>field_map at?: " . print_r($this->field_map, true));
\Log::debug("WE ARE CHANGING THE import_type!!!!! TO: " . $new_import_type);
\Log::debug("so, what's \$this->>field_map at?: " . print_r($this->field_map, true));
// go through each header, find a matching field to try and map it to.
foreach ($this->activeFile->header_row as $i => $header) {
// do we have something mapped already?
@ -252,7 +252,7 @@ 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::info("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk
\Log::debug("Hey, we are calling MOUNT (in the importer-file) !!!!!!!!"); //fcuk
$this->importTypes = [
'asset' => trans('general.assets'),
'accessory' => trans('general.accessories'),
@ -273,8 +273,8 @@ class Importer extends Component
public function selectFile($id)
{
\Log::info("TOGGLE EVENT FIRED!");
\Log::error("The ID we are trying to find is AS FOLLOWS: ".$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) {
@ -288,7 +288,7 @@ class Importer extends Component
$this->file_id = $id;
$this->import_errors = null;
$this->statusText = null;
\Log::error("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type);
\Log::debug("The import type we are about to try and load up is gonna be this: ".$this->activeFile->import_type);
}

View file

@ -60,7 +60,7 @@ class AssetImporter extends ItemImporter
$asset_tag = Asset::autoincrement_asset();
}
$asset = Asset::where(['asset_tag'=> $asset_tag])->first();
$asset = Asset::where(['asset_tag'=> (string) $asset_tag])->first();
if ($asset) {
if (! $this->updating) {
$this->log('A matching Asset '.$asset_tag.' already exists');

View file

@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v6.0.14',
'full_app_version' => 'v6.0.14 - build 9715-g8b70a7f21',
'build_version' => '9715',
'app_version' => 'v6.1.0-pre',
'full_app_version' => 'v6.1.0-pre - build 10030-gdcbd216e2',
'build_version' => '10030',
'prerelease_version' => '',
'hash_version' => 'g8b70a7f21',
'full_hash' => 'v6.0.14-671-g8b70a7f21',
'hash_version' => 'gdcbd216e2',
'full_hash' => 'v6.1.0-pre-986-gdcbd216e2',
'branch' => 'develop',
);

View file

@ -3,7 +3,7 @@
return array(
'group_exists' => 'Group already exists!',
'group_not_found' => 'Group [:id] does not exist.',
'group_not_found' => 'Group ID :id does not exist.',
'group_name_required' => 'The name field is required',
'success' => array(

View file

@ -2,8 +2,11 @@
return [
'bulk_delete' => 'Confirm Bulk Delete Assets',
'bulk_restore' => 'Confirm Bulk Restore Assets',
'bulk_delete_help' => 'Review the assets for bulk deletion below. Once deleted, these assets can be restored, but they will no longer be associated with any users they are currently assigned to.',
'bulk_restore_help' => 'Review the assets for bulk restoration below. Once restored, these assets will not be associated with any users they were previously assigned to.',
'bulk_delete_warn' => 'You are about to delete :asset_count assets.',
'bulk_restore_warn' => 'You are about to restore :asset_count assets.',
'bulk_update' => 'Bulk Update Assets',
'bulk_update_help' => 'This form allows you to update multiple assets at once. Only fill in the fields you need to change. Any fields left blank will remain unchanged. ',
'bulk_update_warn' => 'You are about to edit the properties of a single asset.|You are about to edit the properties of :asset_count assets.',

View file

@ -23,6 +23,8 @@ return [
'restore' => [
'error' => 'Asset was not restored, please try again',
'success' => 'Asset restored successfully.',
'bulk_success' => 'Asset restored successfully.',
'nothing_updated' => 'No assets were selected, so nothing was restored.',
],
'audit' => [

View file

@ -422,6 +422,8 @@ return [
'merged_log_this_user_from' => 'Merged user ID :from_id (:from_username) into this user (ID :to_id - :to_username)',
'clear_and_save' => 'Clear & Save',
'update_existing_values' => 'Update Existing Values?',
'auto_incrementing_asset_tags_disabled_so_tags_required' => 'Generating auto-incrementing asset tags is disabled so all rows need to have the "Asset Tag" column populated.',
'auto_incrementing_asset_tags_enabled_so_now_assets_will_be_created' => 'Note: Generating auto-incrementing asset tags is enabled so assets will be created for rows that do not have "Asset Tag" populated. Rows that do have "Asset Tag" populated will be updated with the provided information.',
'send_welcome_email_to_users' => ' Send Welcome Email for new Users?',
'back_before_importing' => 'Backup before importing?',
'csv_header_field' => 'CSV Header Field',
@ -433,4 +435,7 @@ return [
'errors_importing' => 'Some Errors occurred while importing: ',
'warning' => 'WARNING: :warning',
'success_redirecting' => '"Success... Redirecting.',
'setup_successful_migrations' => 'Your database tables have been created',
'setup_migration_output' => 'Migration output:',
'setup_migration_create_user' => 'Next: Create User',
];

View file

@ -2,7 +2,7 @@
{{-- Page title --}}
@section('title')
{{ trans('general.accept_assets', array('name' => $user->present()->fullName())) }}
{{ trans('general.accept_assets', array('name' => empty($user) ? '' : $user->present()->full_name)) }}
@parent
@stop

View file

@ -113,7 +113,7 @@
<td>
@can('view', \App\Models\AssetModel::class)
<a href="{{ url('/') }}'/models/'.{{ $requestableModel->id }}) }}">{{ $requestableModel->name }}</a>
<a href="{{ route('models.show', ['model' => $requestableModel->id]) }}">{{ $requestableModel->name }}</a>
@else
{{ $requestableModel->name }}
@endcan

View file

@ -43,7 +43,7 @@
<tr>
<th data-switchable="true" data-sortable="true" data-field="id" data-visible="false">{{ trans('general.id') }}</th>
<th data-switchable="true" data-sortable="true" data-field="name" data-formatter="groupsAdminLinkFormatter" data-visible="true">{{ trans('admin/groups/table.name') }}</th>
<th data-switchable="true" data-sortable="true" data-field="users_count" data-visible="true">{{ trans('admin/groups/table.users') }}</th>
<th data-switchable="true" data-sortable="true" data-field="users_count" data-visible="true"><i class="fas fa-user" aria-hidden="true"></i><span class="sr-only">{{ trans('admin/groups/table.users') }}</span></th>
<th data-switchable="true" data-sortable="true" data-field="created_at" data-visible="true" data-formatter="dateDisplayFormatter">{{ trans('general.created_at') }}</th>
<th data-switchable="false" data-searchable="false" data-sortable="false" data-field="actions" data-formatter="groupsActionsFormatter">{{ trans('table.actions') }}</th>
</tr>

View file

@ -0,0 +1,62 @@
@extends('layouts/default')
{{-- Page title --}}
@section('title')
{{ trans('admin/hardware/form.bulk_restore') }}
@parent
@stop
@section('header_right')
<a href="{{ URL::previous() }}" class="btn btn-primary pull-right">
{{ trans('general.back') }}</a>
@stop
{{-- Page content --}}
@section('content')
<div class="row">
<!-- left column -->
<div class="col-md-12">
<p>{{ trans('admin/hardware/form.bulk_restore_help') }}</p>
<form class="form-horizontal" method="post" action="{{ route('hardware/bulkrestore') }}" autocomplete="off" role="form">
{{csrf_field()}}
<div class="box box-default">
<div class="box-header with-border">
<h2 class="box-title" style="color: red">{{ trans('admin/hardware/form.bulk_restore_warn', ['asset_count' => count($assets)]) }}</h2>
</div>
<div class="box-body">
<table class="table table-striped table-condensed">
<thead>
<tr>
<td></td>
<td>{{ trans('admin/hardware/table.id') }}</td>
<td>{{ trans('admin/hardware/table.name') }}</td>
<td>{{ trans('admin/hardware/table.location')}}</td>
</tr>
</thead>
<tbody>
@foreach ($assets as $asset)
<tr>
<td><input type="checkbox" name="ids[]" value="{{ $asset->id }}" checked="checked"></td>
<td>{{ $asset->id }}</td>
<td>{{ $asset->present()->name() }}</td>
<td>
@if ($asset->location)
{{ $asset->location->name }}
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
</div><!-- /.box-body -->
<div class="box-footer text-right">
<a class="btn btn-link" href="{{ URL::previous() }}" method="post" enctype="multipart/form-data">{{ trans('button.cancel') }}</a>
<button type="submit" class="btn btn-success" id="submit-button"><i class="fas fa-check icon-white" aria-hidden="true"></i> {{ trans('button.restore') }}</button>
</div><!-- /.box-footer -->
</div><!-- /.box -->
</form>
</div> <!-- .col-md-12-->
</div><!--.row-->
@stop

View file

@ -63,13 +63,7 @@
<div class="row">
<div class="col-md-12">
@if (Request::get('status')!='Deleted')
@include('partials.asset-bulk-actions')
@endif
@include('partials.asset-bulk-actions', ['status' => Request::get('status')])
<table
data-advanced-search="true"

View file

@ -597,7 +597,7 @@
@if ($asset->serial && $asset->model->manufacturer)
@if ((strtolower($asset->model->manufacturer->name) == "apple") || (str_starts_with(str_replace(' ','',strtolower($asset->model->manufacturer->name)),"appleinc")))
<a href="https://checkcoverage.apple.com/us/{{ \App\Models\Setting::getSettings()->locale }}/?sn={{ $asset->serial }}" target="_blank">
<a href="https://checkcoverage.apple.com/?locale={{ (str_replace('-','_',\App\Models\Setting::getSettings()->locale)) }}" target="_blank">
<i class="fa-brands fa-apple" aria-hidden="true"><span class="sr-only">{{ trans('hardware/general.mfg_warranty_lookup') }}</span></i>
</a>
@elseif ((strtolower($asset->model->manufacturer->name) == "dell") || (str_starts_with(str_replace(' ','',strtolower($asset->model->manufacturer->name)),"dellinc")))

View file

@ -156,26 +156,36 @@
'data-minimum-results-for-search' => '-1', // Remove this if the list gets long enough that we need to search
'data-livewire-component' => $_instance->id
]) }}
@if ($activeFile->import_type === 'asset' && $snipeSettings->auto_increment_assets == 0)
<span class="help-block">
{{ trans('general.auto_incrementing_asset_tags_disabled_so_tags_required') }}
</span>
@endif
</div>
</div>
<div class="form-group col-md-12">
<label for="update" class="col-md-9 col-md-offset-3 col-xs-12" wire:ignore>
<input type="checkbox" class="minimal livewire-icheck" name="update" data-livewire-component="{{ $_instance->id }}">
<label for="update" class="col-md-9 col-md-offset-3 col-xs-12">
<input type="checkbox" class="minimal livewire-icheck" name="update" data-livewire-component="{{ $_instance->id }}" wire:model="update">
{{ trans('general.update_existing_values') }}
@if ($activeFile->import_type === 'asset' && $snipeSettings->auto_increment_assets == 1 && $update)
<span class="help-block">
{{ trans('general.auto_incrementing_asset_tags_enabled_so_now_assets_will_be_created') }}
</span>
@endif
</label>
</div>
<div class="form-group col-md-12">
<label for="send_welcome" class="col-md-9 col-md-offset-3 col-xs-12" wire:ignore>
<input type="checkbox" class="minimal livewire-icheck" name="send_welcome" data-livewire-component="{{ $_instance->id }}">
<label for="send_welcome" class="col-md-9 col-md-offset-3 col-xs-12">
<input type="checkbox" class="minimal livewire-icheck" name="send_welcome" data-livewire-component="{{ $_instance->id }}" wire:model="send_welcome">
{{ trans('general.send_welcome_email_to_users') }}
</label>
</div>
<div class="form-group col-md-12">
<label for="run_backup" class="col-md-9 col-md-offset-3 col-xs-12" wire:ignore>
<input type="checkbox" class="minimal livewire-icheck" name="run_backup" data-livewire-component="{{ $_instance->id }}">
<label for="run_backup" class="col-md-9 col-md-offset-3 col-xs-12">
<input type="checkbox" class="minimal livewire-icheck" name="run_backup" data-livewire-component="{{ $_instance->id }}" wire:model="run_backup">
{{ trans('general.back_before_importing') }}
</label>
</div>

View file

@ -13,6 +13,11 @@
</span>
</label>
<select name="bulk_actions" class="form-control select2" aria-label="bulk_actions" style="min-width: 350px;">
@if((isset($status)) && ($status == 'Deleted'))
@can('delete', \App\Models\Asset::class)
<option value="restore">{{trans('button.restore')}}</option>
@endcan
@else
@can('update', \App\Models\Asset::class)
<option value="edit">{{ trans('button.edit') }}</option>
@endcan
@ -20,6 +25,7 @@
<option value="delete">{{ trans('button.delete') }}</option>
@endcan
<option value="labels" accesskey="l">{{ trans_choice('button.generate_labels', 2) }}</option>
@endif
</select>
<button class="btn btn-primary" id="{{ (isset($id_button)) ? $id_button : 'bulkAssetEditButton' }}" disabled>{{ trans('button.go') }}</button>

View file

@ -32,7 +32,7 @@
@section('button')
<form action="{{ route('setup.user') }}" method="GET">
<button class="btn btn-primary">{{ trans('general.setup_migrations_create_user') }}</button>
<button class="btn btn-primary">{{ trans('general.setup_migration_create_user') }}</button>
</form>
@parent
@stop

View file

@ -160,6 +160,11 @@ Route::group(
[BulkAssetsController::class, 'destroy']
)->name('hardware/bulkdelete');
Route::post(
'bulkrestore',
[BulkAssetsController::class, 'restore']
)->name('hardware/bulkrestore');
Route::post(
'bulksave',
[BulkAssetsController::class, 'update']