First pass at huge Actionlog refactor

This commit is contained in:
Brady Wetherington 2024-11-07 16:54:51 +00:00
parent 233ad92112
commit 5ce37eaa34
23 changed files with 271 additions and 760 deletions

13
app/Enums/ActionType.php Normal file
View file

@ -0,0 +1,13 @@
<?php
namespace App\Enums;
enum ActionType: string {
case Restore = 'restore';
case TwoFactorReset = '2FA reset';
case CheckinFrom = 'checkin from';
case RequestCanceled = 'request canceled';
case Requested = 'requested';
case DeleteSeats = 'delete seats';
case AddSeats = 'add seats';
}

View file

@ -217,15 +217,9 @@ class ManufacturersController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.manufacturer')])), 200); return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.manufacturer')])), 200);
} }
$manufacturer->setLogMessage('restore');
if ($manufacturer->restore()) { 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->created_by = auth()->id();
$logaction->logaction('restore');
return response()->json(Helper::formatStandardApiResponse('success', trans('admin/manufacturers/message.restore.success')), 200); return response()->json(Helper::formatStandardApiResponse('success', trans('admin/manufacturers/message.restore.success')), 200);
} }

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api; namespace App\Http\Controllers\Api;
use App\Enums\ActionType;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\SaveUserRequest; use App\Http\Requests\SaveUserRequest;
@ -701,17 +702,8 @@ class UsersController extends Controller
$this->authorize('update', $user); $this->authorize('update', $user);
$user->two_factor_secret = null; $user->two_factor_secret = null;
$user->two_factor_enrolled = 0; $user->two_factor_enrolled = 0;
$user->saveQuietly(); $user->setLogMessage(ActionType::TwoFactorReset);
$user->save();
// Log the reset
$logaction = new Actionlog();
$logaction->target_type = User::class;
$logaction->target_id = $user->id;
$logaction->item_type = User::class;
$logaction->item_id = $user->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('2FA reset');
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200); return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
} catch (\Exception $e) { } catch (\Exception $e) {
@ -754,15 +746,9 @@ class UsersController extends Controller
return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.user')])), 200); return response()->json(Helper::formatStandardApiResponse('error', trans('general.not_deleted', ['item_type' => trans('general.user')])), 200);
} }
$user->setLogMessage('restore');
if ($user->restore()) { 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->created_by = auth()->id();
$logaction->logaction('restore');
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.restored')), 200);
} }

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Enums\ActionType;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\StoreAssetModelRequest; use App\Http\Requests\StoreAssetModelRequest;
@ -224,14 +225,8 @@ class AssetModelsController extends Controller
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.asset_model')])); return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.asset_model')]));
} }
$model->setLogMessage(ActionType::Restore);
if ($model->restore()) { if ($model->restore()) {
$logaction = new Actionlog();
$logaction->item_type = AssetModel::class;
$logaction->item_id = $model->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index // Redirect them to the deleted page if there are more, otherwise the section index
$deleted_models = AssetModel::onlyTrashed()->count(); $deleted_models = AssetModel::onlyTrashed()->count();

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Enums\ActionType;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Asset; use App\Models\Asset;
@ -265,13 +266,8 @@ class LocationsController extends Controller
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.location')])); return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.location')]));
} }
$location->setLogMessage(ActionType::Restore);
if ($location->restore()) { if ($location->restore()) {
$logaction = new Actionlog();
$logaction->item_type = Location::class;
$logaction->item_id = $location->id;
$logaction->created_at = date('Y-m-d H:i:s');
$logaction->created_by = auth()->id();
$logaction->logaction('restore');
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success')); return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success'));
} }

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Enums\ActionType;
use App\Http\Requests\ImageUploadRequest; use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Manufacturer; use App\Models\Manufacturer;
@ -194,13 +195,8 @@ class ManufacturersController extends Controller
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.manufacturer')])); return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.manufacturer')]));
} }
$manufacturer->setLogMessage(ActionType::Restore);
if ($manufacturer->restore()) { 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->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index // Redirect them to the deleted page if there are more, otherwise the section index
$deleted_manufacturers = Manufacturer::onlyTrashed()->count(); $deleted_manufacturers = Manufacturer::onlyTrashed()->count();

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Users; namespace App\Http\Controllers\Users;
use App\Enums\ActionType;
use App\Events\UserMerged; use App\Events\UserMerged;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
@ -338,45 +339,35 @@ class BulkUsersController extends Controller
$logAction = new Actionlog(); $logAction = new Actionlog();
if ($itemType == License::class){ if ($itemType == License::class){
$item_id = $item->license_id; $item_id = $item->license_id; //FIXME - funkery happening here
} }
$logAction->item_id = $item_id; $item->setTarget($item->assignedTo); // will this work?!!?!?!?
// We can't rely on get_class here because the licenses/accessories fetched above are not eloquent models, but simply arrays. //$logAction->target_id = $item->assigned_to;
$logAction->item_type = $itemType; //$logAction->target_type = User::class;
$logAction->target_id = $item->assigned_to; $item->setNote('Bulk checkin items');
$logAction->target_type = User::class; $item->setLogMessage();
$logAction->created_by = auth()->id(); $item->logWithoutSave(ActionType::CheckinFrom);
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
} }
} }
private function logAccessoriesCheckin(Collection $accessoryUserRows): void private function logAccessoriesCheckin(Collection $accessoryUserRows): void
{ {
foreach ($accessoryUserRows as $accessoryUserRow) { foreach ($accessoryUserRows as $accessoryUserRow) {
$logAction = new Actionlog(); $accessory = Accessory::find($accessoryUserRow->accessory_id);
$logAction->item_id = $accessoryUserRow->accessory_id; $accessory->setTarget(User::find($accessoryUserRow->assignedTo));
$logAction->item_type = Accessory::class; $accessory->setNote('Bulk checkin items');
$logAction->target_id = $accessoryUserRow->assigned_to; $accessory->logWithoutSave(ActionType::CheckinFrom);
$logAction->target_type = User::class;
$logAction->created_at = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
} }
} }
private function logConsumablesCheckin(Collection $consumableUserRows): void private function logConsumablesCheckin(Collection $consumableUserRows): void
{ {
foreach ($consumableUserRows as $consumableUserRow) { foreach ($consumableUserRows as $consumableUserRow) {
$logAction = new Actionlog(); $consumable = Consumable::find($consumableUserRow->consumable_id);
$logAction->item_id = $consumableUserRow->consumable_id; $consumable->setTarget(auth()->user());
$logAction->item_type = Consumable::class; $consumable->setNote('Bulk checkin items');
$logAction->target_id = $consumableUserRow->assigned_to; $consumable->logWithoutSave(ActionType::CheckinFrom);
$logAction->target_type = User::class;
$logAction->created_at = auth()->id();
$logAction->note = 'Bulk checkin items';
$logAction->logaction('checkin from');
} }
} }

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers\Users; namespace App\Http\Controllers\Users;
use App\Enums\ActionType;
use App\Helpers\Helper; use App\Helpers\Helper;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use App\Http\Requests\DeleteUserRequest; use App\Http\Requests\DeleteUserRequest;
@ -358,14 +359,8 @@ class UsersController extends Controller
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.user')])); return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.user')]));
} }
$user->setLogMessage(ActionType::Restore);
if ($user->restore()) { 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->created_by = auth()->id();
$logaction->logaction('restore');
// Redirect them to the deleted page if there are more, otherwise the section index // Redirect them to the deleted page if there are more, otherwise the section index
$deleted_users = User::onlyTrashed()->count(); $deleted_users = User::onlyTrashed()->count();
if ($deleted_users > 0) { if ($deleted_users > 0) {

View file

@ -2,6 +2,7 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Enums\ActionType;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Asset; use App\Models\Asset;
use App\Models\AssetModel; use App\Models\AssetModel;
@ -93,17 +94,18 @@ class ViewAssetsController extends Controller
$user = auth()->user(); $user = auth()->user();
$logaction = new Actionlog(); //$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $item->id; //$logaction->item_id = $data['asset_id'] = $item->id;
$logaction->item_type = $fullItemType; //$logaction->item_type = $fullItemType;
$logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s'); //$logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
$data['requested_date'] = date('Y-m-d H:i:s');
if ($user->location_id) { if ($user->location_id) {
$logaction->location_id = $user->location_id; $item->setLocation($user->location);
} }
$logaction->target_id = $data['user_id'] = auth()->id(); $item->setTarget($user);
$logaction->target_type = User::class; //$logaction->target_id = $data['user_id'] = auth()->id();
//$logaction->target_type = User::class;
$data['item_quantity'] = $request->has('request-quantity') ? e($request->input('request-quantity')) : 1; $data['item_quantity'] = $request->has('request-quantity') ? e($request->input('request-quantity')) : 1;
$data['requested_by'] = $user->present()->fullName(); $data['requested_by'] = $user->present()->fullName();
@ -122,7 +124,7 @@ class ViewAssetsController extends Controller
if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) { if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) {
$item->cancelRequest($requestingUser); $item->cancelRequest($requestingUser);
$data['item_quantity'] = ($item_request) ? $item_request->qty : 1; $data['item_quantity'] = ($item_request) ? $item_request->qty : 1;
$logaction->logaction('request_canceled'); $item->logWithoutSave(ActionType::RequestCanceled);
if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) { if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) {
$settings->notify(new RequestAssetCancelation($data)); $settings->notify(new RequestAssetCancelation($data));
@ -130,9 +132,9 @@ class ViewAssetsController extends Controller
return redirect()->back()->with('success')->with('success', trans('admin/hardware/message.requests.canceled')); return redirect()->back()->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
} else { } else {
$item->request(); $item->request(); //!!!!!!!!!!!!!
if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) { if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) {
$logaction->logaction('requested'); $item->logWithoutSave(ActionType::Requested);
$settings->notify(new RequestAssetNotification($data)); $settings->notify(new RequestAssetNotification($data));
} }
@ -163,25 +165,23 @@ class ViewAssetsController extends Controller
$data['item_quantity'] = 1; $data['item_quantity'] = 1;
$settings = Setting::getSettings(); $settings = Setting::getSettings();
$logaction = new Actionlog(); //$logaction = new Actionlog();
$logaction->item_id = $data['asset_id'] = $asset->id; $data['asset_id'] = $asset->id;
$logaction->item_type = $data['item_type'] = Asset::class; $data['item_type'] = Asset::class;
$logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s'); $data['requested_date'] = date('Y-m-d H:i:s');
if ($user->location_id) { $asset->setLocation = $user->location;
$logaction->location_id = $user->location_id; $asset->setTarget($user);
} $data['user_id'] = auth()->id();
$logaction->target_id = $data['user_id'] = auth()->id();
$logaction->target_type = User::class;
// If it's already requested, cancel the request. // If it's already requested, cancel the request.
if ($asset->isRequestedBy(auth()->user())) { if ($asset->isRequestedBy(auth()->user())) {
$asset->cancelRequest(); $asset->cancelRequest(); //wait, what?
$asset->decrement('requests_counter', 1); $asset->decrement('requests_counter', 1); //this too
$logaction->logaction('request canceled'); $asset->logWithoutSave(ActionType::RequestCanceled);
try { try {
$settings->notify(new RequestAssetCancelation($data)); $settings->notify(new RequestAssetCancelation($data)); //and probably this
} catch (\Exception $e) { } catch (\Exception $e) {
Log::warning($e); Log::warning($e);
} }
@ -189,11 +189,11 @@ class ViewAssetsController extends Controller
->with('success')->with('success', trans('admin/hardware/message.requests.canceled')); ->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
} }
$logaction->logaction('requested'); $asset->logWithoutSave(ActionType::Requested); //ARGH
$asset->request(); $asset->request(); //HERE <-
$asset->increment('requests_counter', 1); $asset->increment('requests_counter', 1); //ARGH
try { try {
$settings->notify(new RequestAssetNotification($data)); $settings->notify(new RequestAssetNotification($data)); // ANd this.
} catch (\Exception $e) { } catch (\Exception $e) {
Log::warning($e); Log::warning($e);
} }

View file

@ -39,6 +39,65 @@ class Asset extends Depreciable
use Acceptable; use Acceptable;
public static function boot()
{
// handle incrementing of asset tags
self::created(function (Asset $asset) {
if ($settings = Setting::getSettings()) {
$tag = $asset->asset_tag;
$prefix = $settings->auto_increment_prefix;
$number = substr($tag, strlen($prefix));
// IF - auto_increment_assets is on, AND (there is no prefix OR the prefix matches the start of the tag)
// AND the rest of the string after the prefix is all digits, THEN...
if ($settings->auto_increment_assets && ($prefix == '' || strpos($tag, $prefix) === 0) && preg_match('/\d+/', $number) === 1) {
// new way of auto-trueing-up auto_increment ID's
$next_asset_tag = intval($number, 10) + 1;
// we had to use 'intval' because the $number could be '01234' and
// might get interpreted in Octal instead of decimal
// only modify the 'next' one if it's *bigger* than the stored base
//
if ($next_asset_tag > $settings->next_auto_tag_base && $next_asset_tag < PHP_INT_MAX) {
$settings->next_auto_tag_base = $next_asset_tag;
$settings->save();
}
} else {
// legacy method
$settings->increment('next_auto_tag_base');
$settings->save();
}
}
});
//calculate and update EOL as necessary
self::saving(function (Asset $asset) {
// determine if calculated eol and then calculate it - this should only happen on a new asset
if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && ($asset->model->eol > 0)) {
$asset->asset_eol_date = $asset->purchase_date->addMonths($asset->model->eol)->format('Y-m-d');
$asset->eol_explicit = false;
}
// determine if explicit and set eol_explicit to true
if (!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) {
if ($asset->model->eol > 0) {
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
if ($months != $asset->model->eol) {
$asset->eol_explicit = true;
}
}
} elseif (!is_null($asset->asset_eol_date) && is_null($asset->purchase_date)) {
$asset->eol_explicit = true;
}
if ((!is_null($asset->asset_eol_date)) && (!is_null($asset->purchase_date)) && (is_null($asset->model->eol) || ($asset->model->eol == 0))) {
$asset->eol_explicit = true;
}
});
parent::boot();
}
/** /**
* Run after the checkout acceptance was declined by the user * Run after the checkout acceptance was declined by the user
* *

View file

@ -11,6 +11,7 @@ use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
@ -48,6 +49,34 @@ class Consumable extends SnipeModel
'purchase_date' => 'date_format:Y-m-d|nullable', 'purchase_date' => 'date_format:Y-m-d|nullable',
]; ];
public static function boot()
{
self::deleting(function ($consumable) {
$consumable->users()->detach();
$uploads = $consumable->uploads;
foreach ($uploads as $file) {
try {
Storage::delete('private_uploads/consumables/'.$file->filename);
$file->delete();
} catch (\Exception $e) {
Log::info($e);
}
}
try {
Storage::disk('public')->delete('consumables/'.$consumable->image);
} catch (\Exception $e) {
Log::info($e);
}
$consumable->image = null;
});
parent::boot();
}
/** /**
* Whether the model should inject it's identifier to the unique * Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property * validation rules before attempting validation. If this property

View file

@ -12,6 +12,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\Session;
use Watson\Validating\ValidatingTrait; use Watson\Validating\ValidatingTrait;
use App\Enums\ActionType;
class License extends Depreciable class License extends Depreciable
{ {
@ -180,13 +181,8 @@ class License extends Depreciable
$seatsAvailableForDelete->pop()->delete(); $seatsAvailableForDelete->pop()->delete();
} }
// Log Deletion of seats. // Log Deletion of seats.
$logAction = new Actionlog; $license->setNote("deleted {$change} seats");
$logAction->item_type = self::class; $license->logWithoutSave(ActionType::DeleteSeats);
$logAction->item_id = $license->id;
$logAction->created_by = auth()->id() ?: 1; // We don't have an id while running the importer from CLI.
$logAction->note = "deleted {$change} seats";
$logAction->target_id = null;
$logAction->logaction('delete seats');
return true; return true;
} }
@ -212,13 +208,8 @@ class License extends Depreciable
// On initial create, we shouldn't log the addition of seats. // On initial create, we shouldn't log the addition of seats.
if ($license->id) { if ($license->id) {
//Log the addition of license to the log. //Log the addition of license to the log.
$logAction = new Actionlog(); $license->setNote("added {$change} seats");
$logAction->item_type = self::class; $license->logWithoutSave(ActionType::AddSeats);
$logAction->item_id = $license->id;
$logAction->created_by = auth()->id() ?: 1; // Importer.
$logAction->note = "added {$change} seats";
$logAction->target_id = null;
$logAction->logaction('add seats');
} }
return true; return true;

View file

@ -28,6 +28,7 @@ trait Requestable
public function request($qty = 1) public function request($qty = 1)
{ {
// THIS is where the requested log action thing should go, yeah? FIXME
$this->requests()->save( $this->requests()->save(
new CheckoutRequest(['user_id' => auth()->id(), 'qty' => $qty]) new CheckoutRequest(['user_id' => auth()->id(), 'qty' => $qty])
); );

View file

@ -74,6 +74,14 @@ class Setting extends Model
'require_checkinout_notes' => 'boolean', 'require_checkinout_notes' => 'boolean',
]; ];
public static function boot()
{
self::saved(function ($model) {
Cache::forget(Setting::SETUP_CHECK_KEY);
});
parent::boot();
}
/** /**
* Get the app settings. * Get the app settings.
* Cache is expired on Setting model saved in EventServiceProvider. * Cache is expired on Setting model saved in EventServiceProvider.

View file

@ -2,6 +2,7 @@
namespace App\Models\Traits; namespace App\Models\Traits;
use App\Enums\ActionType;
use App\Models\Actionlog; use App\Models\Actionlog;
use App\Models\Asset; use App\Models\Asset;
use App\Models\License; use App\Models\License;
@ -9,105 +10,119 @@ use App\Models\LicenseSeat;
use App\Models\Location; use App\Models\Location;
use App\Models\Setting; use App\Models\Setting;
use App\Notifications\AuditNotification; use App\Notifications\AuditNotification;
use Illuminate\Database\Eloquent\Model;
trait Loggable trait Loggable
{ {
// an attribute for setting whether or not the item was imported // an attribute for setting whether or not the item was imported
public ?bool $imported = false; public ?bool $imported = false;
private ?string $log_message = null;
private ?Model $item = null;
private array $log_meta = [];
private ?Model $target = null;
private ?string $note = null;
private ?Location $location = null;
static array $hide_changes = [];
public static function bootLoggable() public static function bootLoggable()
{ {
\Log::error("LOGGABLE IS BOOTING!!!!!!!!!!!"); \Log::error("LOGGABLE IS BOOTING!!!!!!!!!!!");
/**
* Listen to the Asset updating event. This fires automatically every time an existing asset is saved.
*
* @param Asset $asset
* @return void
*/
static::saving(function ($model) {
$attributes = $model->getAttributes();
$attributesOriginal = $model->getRawOriginal();
$same_checkout_counter = false;
$same_checkin_counter = false;
$restoring_or_deleting = false;
//these tiny methods just set up what the log message is going to be
// 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']));
}
if (array_key_exists('checkin_counter', $attributes) && array_key_exists('checkin_counter', $attributesOriginal)) {
$same_checkin_counter = (($attributes['checkin_counter'] == $attributesOriginal['checkin_counter']));
}
// 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'])
&& ($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']) && (!$restoring_or_deleting)) {
$changed = [];
foreach ($model->getRawOriginal() as $key => $value) {
if ($model->getRawOriginal()[$key] != $model->getAttributes()[$key]) {
$changed[$key]['old'] = $model->getRawOriginal()[$key];
$changed[$key]['new'] = $model->getAttributes()[$key];
}
}
if (empty($changed)) {
return;
}
$logAction = new Actionlog();
$logAction->item_type = self::class;
$logAction->item_id = $model->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->log_meta = json_encode($changed);
$logAction->logaction('update');
}
});
static::updating(function ($model) { static::updating(function ($model) {
$model->logMessage('update');
});
static::creating(function ($model) {
$model->logMessage('create');
}); });
/**
* Listen to the Asset deleting event.
*
* @param Asset $asset
* @return void
*/
static::deleting(function ($model) { static::deleting(function ($model) {
$logAction = new Actionlog(); $model->logMessage("delete");
$logAction->item_type = self::class;
$logAction->item_id = $model->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('delete');
}); });
/**
* Listen to the Asset deleting event.
*
* @param Asset $asset
* @return void
*/
static::restoring(function ($model) { static::restoring(function ($model) {
$logAction = new Actionlog(); $model->logMessage("restore");
$logAction->item_type = self::class;
$logAction->item_id = $model->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('restore');
}); });
// THIS sets up the transaction, and gets the 'diff' between the original for the model,
// and the way it's about to get saved to.
static::saving(function ($model) {
//possibly consider a "$this->saveWithoutTransaction" thing you can invoke?
// use "BEGIN" here?! TODO FIXME
foreach ($model->getRawOriginal() as $key => $value) {
if ($model->getRawOriginal()[$key] != $model->getAttributes()[$key]) {
$changed[$key]['old'] = $model->getRawOriginal()[$key];
$changed[$key]['new'] = $model->getAttributes()[$key];
}
if (in_array($key, self::$hide_changes)) {
$changed[$key]['old'] = '*************';
$changed[$key]['new'] = '*************';
}
}
$this->setLogMeta($changed);
});
// THIS is the whole enchilada, the MAIN thing that you've got to do to make things work.
//if we've set everything up correctly, this should pretty much do everything we want, all in one place
static::saved(function ($model) {
$model->logWithoutSave();
// DO COMMIT HERE? TODO FIXME
});
}
// and THIS is the main, primary logging system
// it *can* be called on its own, but in *general* you should let it trigger from the 'save'
public function logWithoutSave(ActionType $logaction = null)
{
if ($logaction) {
$this->setLogMessage($logaction);
}
$logAction = new Actionlog();
$logAction->item_type = self::class;
$logAction->item_id = $this->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if ($this->imported) {
$logAction->setActionSource('importer');
}
$logAction->log_meta = $this->log_meta ? json_encode($this->log_meta) : null;
if ($this->target) {
$logAction->target_type = $this->target::class;
$logAction->target_id = $this->target->id;
}
if ($this->note) {
$logAction->note = $this->note;
}
if ($this->location) {
$logAction->location_id = $this->location->id;
}
$logAction->logaction($this->log_message);
}
public function setLogMessage(ActionType $message)
{
$this->log_message = $message->value;
}
public function setLogMeta(array $changed)
{
$this->log_meta = $changed;
}
public function setTarget(Model $target)
{
$this->target = $target;
}
public function setNote(string $note)
{
$this->note = $note;
} }
/** /**

View file

@ -38,6 +38,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
protected $table = 'users'; protected $table = 'users';
protected $injectUniqueIdentifier = true; protected $injectUniqueIdentifier = true;
public static array $hide_changes = ['password', 'remember_token', 'two_factor_secret', 'reset_password_code'];
protected $fillable = [ protected $fillable = [
'activated', 'activated',
'address', 'address',

View file

@ -1,62 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Accessory;
use App\Models\Actionlog;
use Illuminate\Support\Facades\Auth;
class AccessoryObserver
{
/**
* Listen to the User created event.
*
* @param Accessory $accessory
* @return void
*/
public function updated(Accessory $accessory)
{
$logAction = new Actionlog();
$logAction->item_type = Accessory::class;
$logAction->item_id = $accessory->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('update');
}
/**
* Listen to the Accessory created event when
* a new accessory is created.
*
* @param Accessory $accessory
* @return void
*/
public function created(Accessory $accessory)
{
$logAction = new Actionlog();
$logAction->item_type = Accessory::class;
$logAction->item_id = $accessory->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if($accessory->imported) {
$logAction->setActionSource('importer');
}
$logAction->logaction('create');
}
/**
* Listen to the Accessory deleting event.
*
* @param Accessory $accessory
* @return void
*/
public function deleting(Accessory $accessory)
{
$logAction = new Actionlog();
$logAction->item_type = Accessory::class;
$logAction->item_id = $accessory->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('delete');
}
}

View file

@ -1,100 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Setting;
use Illuminate\Support\Facades\Auth;
use Carbon\Carbon;
class AssetObserver
{
/**
* Listen to the Asset created event, and increment
* the next_auto_tag_base value in the settings table when i
* a new asset is created.
*
* @param Asset $asset
* @return void
*/
public function created(Asset $asset)
{
if ($settings = Setting::getSettings()) {
$tag = $asset->asset_tag;
$prefix = (string)($settings->auto_increment_prefix ?? '');
$number = substr($tag, strlen($prefix));
// IF - auto_increment_assets is on, AND (there is no prefix OR the prefix matches the start of the tag)
// AND the rest of the string after the prefix is all digits, THEN...
if ($settings->auto_increment_assets && ($prefix=='' || strpos($tag, $prefix) === 0) && preg_match('/\d+/',$number) === 1) {
// new way of auto-trueing-up auto_increment ID's
$next_asset_tag = intval($number, 10) + 1;
// we had to use 'intval' because the $number could be '01234' and
// might get interpreted in Octal instead of decimal
// only modify the 'next' one if it's *bigger* than the stored base
//
if ($next_asset_tag > $settings->next_auto_tag_base && $next_asset_tag < PHP_INT_MAX) {
$settings->next_auto_tag_base = $next_asset_tag;
$settings->save();
}
} else {
// legacy method
$settings->increment('next_auto_tag_base');
$settings->save();
}
}
$logAction = new Actionlog();
$logAction->item_type = Asset::class; // can we instead say $logAction->item = $asset ?
$logAction->item_id = $asset->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if($asset->imported) {
$logAction->setActionSource('importer');
}
$logAction->logaction('create');
}
/**
* Executes every time an asset is saved.
*
* This matters specifically because any database fields affected here MUST already exist on
* the assets table (and/or any related models), or related migrations WILL fail.
*
* For example, if there is a database migration that's a bit older and modifies an asset, if the save
* fires before a field gets created in a later migration and that field in the later migration
* is used in this observer, it doesn't actually exist yet and the migration will break unless we
* use saveQuietly() in the migration which skips this observer.
*
* @see https://github.com/snipe/snipe-it/issues/13723#issuecomment-1761315938
*/
public function saving(Asset $asset)
{
// determine if calculated eol and then calculate it - this should only happen on a new asset
if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && ($asset->model->eol > 0)){
$asset->asset_eol_date = $asset->purchase_date->addMonths($asset->model->eol)->format('Y-m-d');
$asset->eol_explicit = false;
}
// determine if explicit and set eol_explicit to true
if (!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) {
if($asset->model->eol > 0) {
$months = Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date);
if($months != $asset->model->eol) {
$asset->eol_explicit = true;
}
}
} elseif (!is_null($asset->asset_eol_date) && is_null($asset->purchase_date)) {
$asset->eol_explicit = true;
}
if ((!is_null($asset->asset_eol_date)) && (!is_null($asset->purchase_date)) && (is_null($asset->model->eol) || ($asset->model->eol == 0))) {
$asset->eol_explicit = true;
}
}
}

View file

@ -1,62 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Actionlog;
use App\Models\Component;
use Illuminate\Support\Facades\Auth;
class ComponentObserver
{
/**
* Listen to the User created event.
*
* @param Component $component
* @return void
*/
public function updated(Component $component)
{
$logAction = new Actionlog();
$logAction->item_type = Component::class;
$logAction->item_id = $component->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('update');
}
/**
* Listen to the Component created event when
* a new component is created.
*
* @param Component $component
* @return void
*/
public function created(Component $component)
{
$logAction = new Actionlog();
$logAction->item_type = Component::class;
$logAction->item_id = $component->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if($component->imported) {
$logAction->setActionSource('importer');
}
$logAction->logaction('create');
}
/**
* Listen to the Component deleting event.
*
* @param Component $component
* @return void
*/
public function deleting(Component $component)
{
$logAction = new Actionlog();
$logAction->item_type = Component::class;
$logAction->item_id = $component->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('delete');
}
}

View file

@ -1,104 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Actionlog;
use App\Models\Consumable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
class ConsumableObserver
{
/**
* Listen to the User created event.
*
* @param Consumable $consumable
* @return void
*/
public function updated(Consumable $consumable)
{
$changed = [];
foreach ($consumable->getRawOriginal() as $key => $value) {
// Check and see if the value changed
if ($consumable->getRawOriginal()[$key] != $consumable->getAttributes()[$key]) {
$changed[$key]['old'] = $consumable->getRawOriginal()[$key];
$changed[$key]['new'] = $consumable->getAttributes()[$key];
}
}
if (count($changed) > 0) {
$logAction = new Actionlog();
$logAction->item_type = Consumable::class;
$logAction->item_id = $consumable->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->log_meta = json_encode($changed);
$logAction->logaction('update');
}
}
/**
* Listen to the Consumable created event when
* a new consumable is created.
*
* @param Consumable $consumable
* @return void
*/
public function created(Consumable $consumable)
{
$logAction = new Actionlog();
$logAction->item_type = Consumable::class;
$logAction->item_id = $consumable->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if($consumable->imported) {
$logAction->setActionSource('importer');
}
$logAction->logaction('create');
}
/**
* Listen to the Consumable deleting event.
*
* @param Consumable $consumable
* @return void
*/
public function deleting(Consumable $consumable)
{
$consumable->users()->detach();
$uploads = $consumable->uploads;
foreach ($uploads as $file) {
try {
Storage::delete('private_uploads/consumables/'.$file->filename);
$file->delete();
} catch (\Exception $e) {
Log::info($e);
}
}
try {
Storage::disk('public')->delete('consumables/'.$consumable->image);
} catch (\Exception $e) {
Log::info($e);
}
$consumable->image = null;
$consumable->save();
$logAction = new Actionlog();
$logAction->item_type = Consumable::class;
$logAction->item_id = $consumable->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('delete');
}
}

View file

@ -1,62 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Actionlog;
use App\Models\License;
use Illuminate\Support\Facades\Auth;
class LicenseObserver
{
/**
* Listen to the User created event.
*
* @param License $license
* @return void
*/
public function updated(License $license)
{
$logAction = new Actionlog();
$logAction->item_type = License::class;
$logAction->item_id = $license->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('update');
}
/**
* Listen to the License created event when
* a new license is created.
*
* @param License $license
* @return void
*/
public function created(License $license)
{
$logAction = new Actionlog();
$logAction->item_type = License::class;
$logAction->item_id = $license->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
if($license->imported) {
$logAction->setActionSource('importer');
}
$logAction->logaction('create');
}
/**
* Listen to the License deleting event.
*
* @param License $license
* @return void
*/
public function deleting(License $license)
{
$logAction = new Actionlog();
$logAction->item_type = License::class;
$logAction->item_id = $license->id;
$logAction->created_at = date('Y-m-d H:i:s');
$logAction->created_by = auth()->id();
$logAction->logaction('delete');
}
}

View file

@ -1,21 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Setting;
use Illuminate\Support\Facades\Cache;
class SettingObserver
{
/**
* Listen to the Setting saved event.
*
* @param Setting $setting
*
* @return void
*/
public function saved(Setting $setting)
{
Cache::forget(Setting::SETUP_CHECK_KEY);
}
}

View file

@ -1,149 +0,0 @@
<?php
namespace App\Observers;
use App\Models\Actionlog;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
class UserObserver
{
/**
* Listen to the User updating event. This fires automatically every time an existing asset is saved.
*
* @param User $user
* @return void
*/
public function updating(User $user)
{
// ONLY allow these fields to be stored
$allowed_fields = [
'email',
'activated',
'first_name',
'last_name',
'website',
'country',
'gravatar',
'location_id',
'phone',
'jobtitle',
'manager_id',
'employee_num',
'username',
'notes',
'company_id',
'ldap_import',
'locale',
'two_factor_enrolled',
'two_factor_optin',
'department_id',
'address',
'address2',
'city',
'state',
'zip',
'remote',
'start_date',
'end_date',
'autoassign_licenses',
'vip',
'password'
];
$changed = [];
foreach ($user->getRawOriginal() as $key => $value) {
// Make sure the info is in the allow fields array
if (in_array($key, $allowed_fields)) {
// Check and see if the value changed
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'] = '*************';
}
}
}
}
if (count($changed) > 0) {
$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->created_by = 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->created_by = 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->created_by = 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->created_by = auth()->id();
$logAction->logaction('restore');
}
}