diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 21a4779b4..24152670e 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -754,34 +754,24 @@ class AssetsController extends Controller */ public function restore(Request $request, $assetId = null) { - // Get asset information - $asset = Asset::withTrashed()->find($assetId); - $this->authorize('delete', $asset); - if (isset($asset->id)) { + if ($asset = Asset::withTrashed()->find($assetId)) { + $this->authorize('delete', $asset); - if ($asset->deleted_at=='') { - $message = 'Asset was not deleted. No data was changed.'; - - } else { - - $message = trans('admin/hardware/message.restore.success'); - // Restore the asset - Asset::withTrashed()->where('id', $assetId)->restore(); - - $logaction = new Actionlog(); - $logaction->item_type = Asset::class; - $logaction->item_id = $asset->id; - $logaction->created_at = date("Y-m-d H:i:s"); - $logaction->user_id = Auth::user()->id; - $logaction->logaction('restored'); + if ($asset->deleted_at == '') { + return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.asset')])), 200); } - return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset, $request), $message)); - + if ($asset->restore()) { + return response()->json(Helper::formatStandardApiResponse('success', trans('admin/hardware/message.restore.success')), 200); + } + // Check validation to make sure we're not restoring an asset with the same asset tag (or unique attribute) as an existing asset + return response()->json(Helper::formatStandardApiResponse('error', trans('general.could_not_restore', ['item_type' => trans('general.asset'), 'error' => $asset->getErrors()->first()])), 200); } + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200); + } /** diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php index dadef87e2..6b5a13022 100644 --- a/app/Http/Controllers/Api/ManufacturersController.php +++ b/app/Http/Controllers/Api/ManufacturersController.php @@ -6,9 +6,11 @@ use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Transformers\ManufacturersTransformer; use App\Http\Transformers\SelectlistTransformer; +use App\Models\Actionlog; use App\Models\Manufacturer; use Illuminate\Http\Request; use App\Http\Requests\ImageUploadRequest; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Storage; class ManufacturersController extends Controller @@ -159,6 +161,44 @@ class ManufacturersController extends Controller } + /** + * Restore a given Manufacturer (mark as un-deleted) + * + * @author [A. Gianotto] [] + * @since [v6.3.4] + * @param int $id + * @return \Illuminate\Http\JsonResponse + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + public function restore($id) + { + $this->authorize('delete', Manufacturer::class); + + if ($manufacturer = Manufacturer::withTrashed()->find($id)) { + + if ($manufacturer->deleted_at == '') { + return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.manufacturer')])), 200); + } + + if ($manufacturer->restore()) { + + $logaction = new Actionlog(); + $logaction->item_type = Manufacturer::class; + $logaction->item_id = $manufacturer->id; + $logaction->created_at = date('Y-m-d H:i:s'); + $logaction->user_id = Auth::user()->id; + $logaction->logaction('restore'); + + return response()->json(Helper::formatStandardApiResponse('success', trans('admin/manufacturers/message.restore.success')), 200); + } + + // Check validation to make sure we're not restoring an item with the same unique attributes as a non-deleted one + return response()->json(Helper::formatStandardApiResponse('error', trans('general.could_not_restore', ['item_type' => trans('general.manufacturer'), 'error' => $manufacturer->getErrors()->first()])), 200); + } + + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/manufacturers/message.does_not_exist'))); + } + /** * Gets a paginated collection for the select2 menus * diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 5a2cd7dcf..913fe0f5a 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -11,6 +11,7 @@ use App\Http\Transformers\ConsumablesTransformer; use App\Http\Transformers\LicensesTransformer; use App\Http\Transformers\SelectlistTransformer; use App\Http\Transformers\UsersTransformer; +use App\Models\Actionlog; use App\Models\Asset; use App\Models\Company; use App\Models\License; @@ -688,17 +689,31 @@ class UsersController extends Controller */ public function restore($userId = null) { - // Get asset information - $user = User::withTrashed()->find($userId); - $this->authorize('delete', $user); - if (isset($user->id)) { - // Restore the user - User::withTrashed()->where('id', $userId)->restore(); - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored'))); + if ($user = User::withTrashed()->find($userId)) { + $this->authorize('delete', $user); + + if ($user->deleted_at == '') { + return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.user')])), 200); + } + + if ($user->restore()) { + + $logaction = new Actionlog(); + $logaction->item_type = User::class; + $logaction->item_id = $user->id; + $logaction->created_at = date('Y-m-d H:i:s'); + $logaction->user_id = Auth::user()->id; + $logaction->logaction('restore'); + + return response()->json(Helper::formatStandardApiResponse('success', trans('admin/users/message.restore.success')), 200); + } + + // Check validation to make sure we're not restoring a user with the same username as an existing user + return response()->json(Helper::formatStandardApiResponse('error', trans('general.could_not_restore', ['item_type' => trans('general.user'), 'error' => $user->getErrors()->first()])), 200); } - - $id = $userId; - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))), 200); + + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')), 200); + } } diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index 1783b3392..a3afc4f00 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -4,7 +4,10 @@ namespace App\Http\Controllers; use App\Helpers\Helper; use App\Http\Requests\ImageUploadRequest; +use App\Models\Actionlog; +use App\Models\Asset; use App\Models\AssetModel; +use App\Models\User; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Input; @@ -209,7 +212,7 @@ class AssetModelsController extends Controller $this->authorize('delete', AssetModel::class); // Check if the model exists if (is_null($model = AssetModel::find($modelId))) { - return redirect()->route('models.index')->with('error', trans('admin/models/message.not_found')); + return redirect()->route('models.index')->with('error', trans('admin/models/message.does_not_exist')); } if ($model->assets()->count() > 0) { @@ -237,22 +240,42 @@ class AssetModelsController extends Controller * * @author [A. Gianotto] [] * @since [v1.0] - * @param int $modelId + * @param int $id * @return Redirect * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function getRestore($modelId = null) + public function getRestore($id) { $this->authorize('create', AssetModel::class); - // Get user information - $model = AssetModel::withTrashed()->find($modelId); - if (isset($model->id)) { - $model->restore(); + if ($model = AssetModel::withTrashed()->find($id)) { - return redirect()->route('models.index')->with('success', trans('admin/models/message.restore.success')); + if ($model->deleted_at == '') { + return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.asset_model')])); + } + + if ($model->restore()) { + $logaction = new Actionlog(); + $logaction->item_type = User::class; + $logaction->item_id = $model->id; + $logaction->created_at = date('Y-m-d H:i:s'); + $logaction->user_id = Auth::user()->id; + $logaction->logaction('restore'); + + + // Redirect them to the deleted page if there are more, otherwise the section index + $deleted_models = AssetModel::onlyTrashed()->count(); + if ($deleted_models > 0) { + return redirect()->back()->with('success', trans('admin/models/message.restore.success')); + } + return redirect()->route('models.index')->with('success', trans('admin/models/message.restore.success')); + } + + // Check validation + return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.asset_model'), 'error' => $model->getErrors()->first()])); } - return redirect()->back()->with('error', trans('admin/models/message.not_found')); + + return redirect()->back()->with('error', trans('admin/models/message.does_not_exist')); } diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 28d7906cd..aa7d182ff 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -6,6 +6,7 @@ use App\Helpers\Helper; use App\Http\Controllers\Controller; use App\Http\Requests\ImageUploadRequest; use App\Models\Actionlog; +use App\Models\Manufacturer; use Illuminate\Support\Facades\Log; use App\Models\Asset; use App\Models\AssetModel; @@ -794,21 +795,24 @@ class AssetsController extends Controller */ public function getRestore($assetId = null) { - // Get asset information - $asset = Asset::withTrashed()->find($assetId); - $this->authorize('delete', $asset); - if (isset($asset->id)) { - // Restore the asset - Asset::withTrashed()->where('id', $assetId)->restore(); + if ($asset = Asset::withTrashed()->find($assetId)) { + $this->authorize('delete', $asset); - $logaction = new Actionlog(); - $logaction->item_type = Asset::class; - $logaction->item_id = $asset->id; - $logaction->created_at = date('Y-m-d H:i:s'); - $logaction->user_id = Auth::user()->id; - $logaction->logaction('restored'); + if ($asset->deleted_at == '') { + return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.asset')])); + } - return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success')); + if ($asset->restore()) { + // Redirect them to the deleted page if there are more, otherwise the section index + $deleted_assets = Asset::onlyTrashed()->count(); + if ($deleted_assets > 0) { + return redirect()->back()->with('success', trans('admin/hardware/message.restore.success')); + } + return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.restore.success')); + } + + // Check validation to make sure we're not restoring an asset with the same asset tag (or unique attribute) as an existing asset + return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.asset'), 'error' => $asset->getErrors()->first()])); } return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist')); diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php index e98644f46..c927a5aff 100755 --- a/app/Http/Controllers/ManufacturersController.php +++ b/app/Http/Controllers/ManufacturersController.php @@ -2,8 +2,12 @@ namespace App\Http\Controllers; +use App\Helpers\Helper; use App\Http\Requests\ImageUploadRequest; +use App\Models\Actionlog; +use App\Models\Asset; use App\Models\Manufacturer; +use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Storage; @@ -218,22 +222,37 @@ class ManufacturersController extends Controller * @return Redirect * @throws \Illuminate\Auth\Access\AuthorizationException */ - public function restore($manufacturers_id) + public function restore($id) { - $this->authorize('create', Manufacturer::class); - $manufacturer = Manufacturer::onlyTrashed()->where('id', $manufacturers_id)->first(); + $this->authorize('delete', Manufacturer::class); - if ($manufacturer) { + if ($manufacturer = Manufacturer::withTrashed()->find($id)) { + + if ($manufacturer->deleted_at == '') { + return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.manufacturer')])); + } - // Not sure why this is necessary - it shouldn't fail validation here, but it fails without this, so.... - $manufacturer->setValidating(false); if ($manufacturer->restore()) { + $logaction = new Actionlog(); + $logaction->item_type = Manufacturer::class; + $logaction->item_id = $manufacturer->id; + $logaction->created_at = date('Y-m-d H:i:s'); + $logaction->user_id = Auth::user()->id; + $logaction->logaction('restore'); + + // Redirect them to the deleted page if there are more, otherwise the section index + $deleted_manufacturers = Manufacturer::onlyTrashed()->count(); + if ($deleted_manufacturers > 0) { + return redirect()->back()->with('success', trans('admin/manufacturers/message.success.restored')); + } return redirect()->route('manufacturers.index')->with('success', trans('admin/manufacturers/message.restore.success')); } - return redirect()->back()->with('error', 'Could not restore.'); + // Check validation to make sure we're not restoring an asset with the same asset tag (or unique attribute) as an existing asset + return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.manufacturer'), 'error' => $manufacturer->getErrors()->first()])); } - return redirect()->back()->with('error', trans('admin/manufacturers/message.does_not_exist')); + return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.does_not_exist')); + } } diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php index 25a64e5cb..2655e50f7 100755 --- a/app/Http/Controllers/Users/UsersController.php +++ b/app/Http/Controllers/Users/UsersController.php @@ -7,10 +7,10 @@ use App\Http\Controllers\Controller; use App\Http\Controllers\UserNotFoundException; use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\SaveUserRequest; +use App\Models\Actionlog; use App\Models\Asset; use App\Models\Company; use App\Models\Group; -use App\Models\Ldap; use App\Models\Setting; use App\Models\User; use App\Notifications\WelcomeNotification; @@ -385,18 +385,35 @@ class UsersController extends Controller */ public function getRestore($id = null) { - $this->authorize('update', User::class); - // Get user information - if (! User::onlyTrashed()->find($id)) { - return redirect()->route('users.index')->with('error', trans('admin/users/messages.user_not_found')); + if ($user = User::withTrashed()->find($id)) { + $this->authorize('delete', $user); + + if ($user->deleted_at == '') { + return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.user')])); + } + + if ($user->restore()) { + $logaction = new Actionlog(); + $logaction->item_type = User::class; + $logaction->item_id = $user->id; + $logaction->created_at = date('Y-m-d H:i:s'); + $logaction->user_id = Auth::user()->id; + $logaction->logaction('restore'); + + // Redirect them to the deleted page if there are more, otherwise the section index + $deleted_users = User::onlyTrashed()->count(); + if ($deleted_users > 0) { + return redirect()->back()->with('success', trans('admin/users/message.success.restored')); + } + return redirect()->route('users.index')->with('success', trans('admin/users/message.success.restored')); + + } + + // Check validation to make sure we're not restoring a user with the same username as an existing user + return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.user'), 'error' => $user->getErrors()->first()])); } - // Restore the user - if (User::withTrashed()->where('id', $id)->restore()) { - return redirect()->route('users.index')->with('success', trans('admin/users/message.success.restored')); - } - - return redirect()->route('users.index')->with('error', 'User could not be restored.'); + return redirect()->route('users.index')->with('error', trans('admin/users/message.does_not_exist')); } /** diff --git a/app/Http/Transformers/AssetModelsTransformer.php b/app/Http/Transformers/AssetModelsTransformer.php index ff0a13048..a7b1c6a49 100644 --- a/app/Http/Transformers/AssetModelsTransformer.php +++ b/app/Http/Transformers/AssetModelsTransformer.php @@ -73,7 +73,7 @@ class AssetModelsTransformer $permissions_array['available_actions'] = [ 'update' => (Gate::allows('update', AssetModel::class) && ($assetmodel->deleted_at == '')), - 'delete' => (Gate::allows('delete', AssetModel::class) && ($assetmodel->assets_count == 0)), + 'delete' => $assetmodel->isDeletable(), 'clone' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at == '')), 'restore' => (Gate::allows('create', AssetModel::class) && ($assetmodel->deleted_at != '')), ]; diff --git a/app/Http/Transformers/AssetsTransformer.php b/app/Http/Transformers/AssetsTransformer.php index d38eac241..f5d5ae12b 100644 --- a/app/Http/Transformers/AssetsTransformer.php +++ b/app/Http/Transformers/AssetsTransformer.php @@ -147,7 +147,7 @@ class AssetsTransformer 'clone' => Gate::allows('create', Asset::class) ? true : false, 'restore' => ($asset->deleted_at!='' && Gate::allows('create', Asset::class)) ? true : false, 'update' => ($asset->deleted_at=='' && Gate::allows('update', Asset::class)) ? true : false, - 'delete' => ($asset->deleted_at=='' && $asset->assigned_to =='' && Gate::allows('delete', Asset::class)) ? true : false, + 'delete' => ($asset->deleted_at=='' && $asset->assigned_to =='' && Gate::allows('delete', Asset::class) && ($asset->deleted_at == '')) ? true : false, ]; diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index 45de50fa7..0ebaca269 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -79,7 +79,7 @@ class UsersTransformer $permissions_array['available_actions'] = [ 'update' => (Gate::allows('update', User::class) && ($user->deleted_at == '')), - 'delete' => (Gate::allows('delete', User::class) && ($user->assets_count == 0) && ($user->licenses_count == 0) && ($user->accessories_count == 0)), + 'delete' => $user->isDeletable(), 'clone' => (Gate::allows('create', User::class) && ($user->deleted_at == '')), 'restore' => (Gate::allows('create', User::class) && ($user->deleted_at != '')), ]; diff --git a/app/Models/AssetModel.php b/app/Models/AssetModel.php index f94c6f8ea..d0e47e1cf 100755 --- a/app/Models/AssetModel.php +++ b/app/Models/AssetModel.php @@ -6,6 +6,7 @@ use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; +use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; @@ -188,6 +189,21 @@ class AssetModel extends SnipeModel return false; } + + /** + * Checks if the model is deletable + * + * @author A. Gianotto + * @since [v6.3.4] + * @return bool + */ + public function isDeletable() + { + return Gate::allows('delete', $this) + && ($this->assets_count == 0) + && ($this->deleted_at == ''); + } + /** * Get uploads for this model * diff --git a/app/Models/Category.php b/app/Models/Category.php index d880ba899..17e41da1f 100755 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -100,7 +100,8 @@ class Category extends SnipeModel { return Gate::allows('delete', $this) - && ($this->itemCount() == 0); + && ($this->itemCount() == 0) + && ($this->deleted_at == ''); } /** diff --git a/app/Models/Manufacturer.php b/app/Models/Manufacturer.php index da4f26b02..5408d50c3 100755 --- a/app/Models/Manufacturer.php +++ b/app/Models/Manufacturer.php @@ -77,7 +77,8 @@ class Manufacturer extends SnipeModel && ($this->assets()->count() === 0) && ($this->licenses()->count() === 0) && ($this->consumables()->count() === 0) - && ($this->accessories()->count() === 0); + && ($this->accessories()->count() === 0) + && ($this->deleted_at == ''); } public function assets() diff --git a/app/Models/User.php b/app/Models/User.php index 8011f94ff..85a17b16d 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -17,6 +17,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\Access\Authorizable; use Illuminate\Notifications\Notifiable; +use Illuminate\Support\Facades\Gate; use Laravel\Passport\HasApiTokens; use Watson\Validating\ValidatingTrait; @@ -201,6 +202,23 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo return $this->checkPermissionSection('superuser'); } + /** + * Checks if the user is deletable + * + * @author A. Gianotto + * @since [v6.3.4] + * @return bool + */ + public function isDeletable() + { + return Gate::allows('delete', $this) + && ($this->assets()->count() === 0) + && ($this->licenses()->count() === 0) + && ($this->consumables()->count() === 0) + && ($this->accessories()->count() === 0) + && ($this->deleted_at == ''); + } + /** * Establishes the user -> company relationship diff --git a/app/Observers/AssetObserver.php b/app/Observers/AssetObserver.php index f42b041fa..2b0955fde 100644 --- a/app/Observers/AssetObserver.php +++ b/app/Observers/AssetObserver.php @@ -22,6 +22,13 @@ class AssetObserver $attributesOriginal = $asset->getRawOriginal(); $same_checkout_counter = false; $same_checkin_counter = false; + $restoring_or_deleting = false; + + + // This is a gross hack to prevent the double logging when restoring an asset + if (array_key_exists('deleted_at', $attributes) && array_key_exists('deleted_at', $attributesOriginal)){ + $restoring_or_deleting = (($attributes['deleted_at'] != $attributesOriginal['deleted_at'])); + } if (array_key_exists('checkout_counter', $attributes) && array_key_exists('checkout_counter', $attributesOriginal)){ $same_checkout_counter = (($attributes['checkout_counter'] == $attributesOriginal['checkout_counter'])); @@ -33,10 +40,10 @@ class AssetObserver // If the asset isn't being checked out or audited, log the update. // (Those other actions already create log entries.) - if (($attributes['assigned_to'] == $attributesOriginal['assigned_to']) + if (($attributes['assigned_to'] == $attributesOriginal['assigned_to']) && ($same_checkout_counter) && ($same_checkin_counter) && ((isset( $attributes['next_audit_date']) ? $attributes['next_audit_date'] : null) == (isset($attributesOriginal['next_audit_date']) ? $attributesOriginal['next_audit_date']: null)) - && ($attributes['last_checkout'] == $attributesOriginal['last_checkout'])) + && ($attributes['last_checkout'] == $attributesOriginal['last_checkout']) && (!$restoring_or_deleting)) { $changed = []; @@ -121,6 +128,22 @@ class AssetObserver $logAction->logaction('delete'); } + /** + * Listen to the Asset deleting event. + * + * @param Asset $asset + * @return void + */ + public function restoring(Asset $asset) + { + $logAction = new Actionlog(); + $logAction->item_type = Asset::class; + $logAction->item_id = $asset->id; + $logAction->created_at = date('Y-m-d H:i:s'); + $logAction->user_id = Auth::id(); + $logAction->logaction('restore'); + } + /** * Executes every time an asset is saved. * diff --git a/app/Observers/UserObserver.php b/app/Observers/UserObserver.php new file mode 100644 index 000000000..5691cb5a6 --- /dev/null +++ b/app/Observers/UserObserver.php @@ -0,0 +1,113 @@ +getRawOriginal() as $key => $value) { + + if ($user->getRawOriginal()[$key] != $user->getAttributes()[$key]) { + + $changed[$key]['old'] = $user->getRawOriginal()[$key]; + $changed[$key]['new'] = $user->getAttributes()[$key]; + + // Do not store the hashed password in changes + if ($key == 'password') { + $changed['password']['old'] = '*************'; + $changed['password']['new'] = '*************'; + } + + // Do not store last login in changes + if ($key == 'last_login') { + unset($changed['last_login']); + unset($changed['last_login']); + } + + if ($key == 'permissions') { + unset($changed['permissions']); + unset($changed['permissions']); + } + } + } + + $logAction = new Actionlog(); + $logAction->item_type = User::class; + $logAction->item_id = $user->id; + $logAction->target_type = User::class; // can we instead say $logAction->item = $asset ? + $logAction->target_id = $user->id; + $logAction->created_at = date('Y-m-d H:i:s'); + $logAction->user_id = Auth::id(); + $logAction->log_meta = json_encode($changed); + $logAction->logaction('update'); + } + + /** + * Listen to the User created event, and increment + * the next_auto_tag_base value in the settings table when i + * a new asset is created. + * + * @param User $user + * @return void + */ + public function created(User $user) + { + $logAction = new Actionlog(); + $logAction->item_type = User::class; // can we instead say $logAction->item = $asset ? + $logAction->item_id = $user->id; + $logAction->created_at = date('Y-m-d H:i:s'); + $logAction->user_id = Auth::id(); + $logAction->logaction('create'); + } + + /** + * Listen to the User deleting event. + * + * @param User $user + * @return void + */ + public function deleting(User $user) + { + $logAction = new Actionlog(); + $logAction->item_type = User::class; + $logAction->item_id = $user->id; + $logAction->target_type = User::class; // can we instead say $logAction->item = $asset ? + $logAction->target_id = $user->id; + $logAction->created_at = date('Y-m-d H:i:s'); + $logAction->user_id = Auth::id(); + $logAction->logaction('delete'); + } + + /** + * Listen to the User deleting event. + * + * @param User $user + * @return void + */ + public function restoring(User $user) + { + $logAction = new Actionlog(); + $logAction->item_type = User::class; + $logAction->item_id = $user->id; + $logAction->target_type = User::class; // can we instead say $logAction->item = $asset ? + $logAction->target_id = $user->id; + $logAction->created_at = date('Y-m-d H:i:s'); + $logAction->user_id = Auth::id(); + $logAction->logaction('restore'); + } + + +} diff --git a/app/Presenters/ActionlogPresenter.php b/app/Presenters/ActionlogPresenter.php index cd581d33c..ddff10864 100644 --- a/app/Presenters/ActionlogPresenter.php +++ b/app/Presenters/ActionlogPresenter.php @@ -38,22 +38,63 @@ class ActionlogPresenter extends Presenter public function icon() { - $itemicon = 'fas fa-paperclip'; + + // User related icons + if ($this->itemType() == 'user') { - if ($this->itemType() == 'asset') { - return 'fas fa-barcode'; - } elseif ($this->itemType() == 'accessory') { - return 'far fa-keyboard'; - } elseif ($this->itemType() == 'consumable') { - return 'fas fa-tint'; - } elseif ($this->itemType() == 'license') { - return 'far fa-save'; - } elseif ($this->itemType() == 'component') { - return 'far fa-hdd'; - } elseif ($this->itemType() == 'user') { - return 'fa-solid fa-people-arrows'; + if ($this->actionType()=='create new') { + return 'fa-solid fa-user-plus'; + } + + if ($this->actionType()=='merged') { + return 'fa-solid fa-people-arrows'; + } + + if ($this->actionType()=='delete') { + return 'fa-solid fa-user-minus'; + } + + if ($this->actionType()=='delete') { + return 'fa-solid fa-user-minus'; + } + + if ($this->actionType()=='update') { + return 'fa-solid fa-user-pen'; + } + return 'fa-solid fa-user'; } + // Everything else + if ($this->actionType()=='create new') { + return 'fa-solid fa-plus'; + } + + if ($this->actionType()=='delete') { + return 'fa-solid fa-user-xmark'; + } + + if ($this->actionType()=='update') { + return 'fa-solid fa-pen'; + } + + if ($this->actionType()=='restore') { + return 'fa-solid fa-trash-arrow-up'; + } + + if ($this->actionType()=='upload') { + return 'fas fa-paperclip'; + } + + if ($this->actionType()=='checkout') { + return 'fa-solid fa-rotate-left'; + } + + if ($this->actionType()=='checkin from') { + return 'fa-solid fa-rotate-right'; + } + + return 'fa-solid fa-rotate-right'; + } public function actionType() diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 325fb8ad1..dcd8d0127 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -7,10 +7,12 @@ use App\Models\Asset; use App\Models\Component; use App\Models\Consumable; use App\Models\License; +use App\Models\User; use App\Models\Setting; use App\Models\SnipeSCIMConfig; use App\Observers\AccessoryObserver; use App\Observers\AssetObserver; +use App\Observers\UserObserver; use App\Observers\ComponentObserver; use App\Observers\ConsumableObserver; use App\Observers\LicenseObserver; @@ -58,6 +60,7 @@ class AppServiceProvider extends ServiceProvider Schema::defaultStringLength(191); Asset::observe(AssetObserver::class); + User::observe(UserObserver::class); Accessory::observe(AccessoryObserver::class); Component::observe(ComponentObserver::class); Consumable::observe(ConsumableObserver::class); diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 2deb8cb55..a568e0043 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -72,6 +72,8 @@ return [ 'consumable' => 'Consumable', 'consumables' => 'Consumables', 'country' => 'Country', + 'could_not_restore' => 'Error restoring :item_type: :error', + 'not_deleted' => 'The :item_type is not deleted so it cannot be restored', 'create' => 'Create New', 'created' => 'Item Created', 'created_asset' => 'created asset', diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index 0122096f8..74abfa24b 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -279,7 +279,11 @@ + ' data-title="{{ trans('general.delete') }}" onClick="return false;">' + '{{ trans('general.delete') }} '; } else { - actions += ' '; + // Do not show the delete button on things that are already deleted + if ((row.available_actions) && (row.available_actions.restore != true)) { + actions += ' '; + } + } diff --git a/routes/api.php b/routes/api.php index 2ae1bfe55..d10d90fbe 100644 --- a/routes/api.php +++ b/routes/api.php @@ -706,6 +706,13 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi ] )->name('api.manufacturers.selectlist'); + Route::post('{id}/restore', + [ + Api\ManufacturersController::class, + 'restore' + ] + )->name('api.manufacturers.restore'); + }); Route::resource('manufacturers', @@ -742,6 +749,13 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'throttle:api']], functi ] )->name('api.models.assets'); + Route::post('{id}/restore', + [ + Api\AssetModelsController::class, + 'restore' + ] + )->name('api.models.restore'); + }); Route::resource('models',