diff --git a/app/Actions/CheckoutRequests/CancelCheckoutRequestAction.php b/app/Actions/CheckoutRequests/CancelCheckoutRequestAction.php
index 2d6dd68a0837..8ffe5fc8fd8c 100644
--- a/app/Actions/CheckoutRequests/CancelCheckoutRequestAction.php
+++ b/app/Actions/CheckoutRequests/CancelCheckoutRequestAction.php
@@ -2,6 +2,7 @@
namespace App\Actions\CheckoutRequests;
+use App\Enums\ActionType;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\Company;
@@ -9,6 +10,7 @@
use App\Models\User;
use App\Notifications\RequestAssetCancelation;
use Illuminate\Auth\Access\AuthorizationException;
+use Illuminate\Support\Facades\Auth;
class CancelCheckoutRequestAction
{
@@ -18,7 +20,7 @@ public static function run(Asset $asset, User $user)
throw new AuthorizationException();
}
- $asset->cancelRequest();
+ $asset->cancelRequest(); //TODO - should the below logic just be here?
$asset->decrement('requests_counter', 1);
@@ -27,14 +29,8 @@ public static function run(Asset $asset, User $user)
$data['item_quantity'] = 1;
$settings = Setting::getSettings();
- $logaction = new Actionlog();
- $logaction->item_id = $data['asset_id'] = $asset->id;
- $logaction->item_type = $data['item_type'] = Asset::class;
- $logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
- $logaction->target_id = $data['user_id'] = auth()->id();
- $logaction->target_type = User::class;
- $logaction->location_id = $user->location_id ?? null;
- $logaction->logaction('request canceled');
+ $asset->setLogTarget(Auth::user());
+ $asset->logAndSaveIfNeeded(ActionType::RequestCanceled);
try {
$settings->notify(new RequestAssetCancelation($data));
diff --git a/app/Actions/CheckoutRequests/CreateCheckoutRequestAction.php b/app/Actions/CheckoutRequests/CreateCheckoutRequestAction.php
index 6870cfba2d4f..0f08ba3c3fef 100644
--- a/app/Actions/CheckoutRequests/CreateCheckoutRequestAction.php
+++ b/app/Actions/CheckoutRequests/CreateCheckoutRequestAction.php
@@ -2,6 +2,7 @@
namespace App\Actions\CheckoutRequests;
+use App\Enums\ActionType;
use App\Exceptions\AssetNotRequestable;
use App\Models\Actionlog;
use App\Models\Asset;
@@ -10,6 +11,7 @@
use App\Models\User;
use App\Notifications\RequestAssetNotification;
use Illuminate\Auth\Access\AuthorizationException;
+use Illuminate\Support\Facades\Auth;
use Log;
class CreateCheckoutRequestAction
@@ -32,17 +34,11 @@ public static function run(Asset $asset, User $user): string
$data['item_quantity'] = 1;
$settings = Setting::getSettings();
- $logaction = new Actionlog();
- $logaction->item_id = $data['asset_id'] = $asset->id;
- $logaction->item_type = $data['item_type'] = Asset::class;
- $logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
- $logaction->target_id = $data['user_id'] = auth()->id();
- $logaction->target_type = User::class;
- $logaction->location_id = $user->location_id ?? null;
- $logaction->logaction('requested');
+ $asset->setLogTarget(Auth::user());
+ $asset->logAndSaveIfNeeded(ActionType::Requested);
- $asset->request();
- $asset->increment('requests_counter', 1);
+ $asset->request(); // TODO: could argue that the above stuff belongs here? This
+ $asset->increment('requests_counter', 1); // TODO - would rather hit the DB once, but we don't yet have transaction safety
try {
$settings->notify(new RequestAssetNotification($data));
} catch (\Exception $e) {
diff --git a/app/Console/Commands/CheckinLicensesFromAllUsers.php b/app/Console/Commands/CheckinLicensesFromAllUsers.php
index 5e02bffb7b53..8a79c9aa7378 100644
--- a/app/Console/Commands/CheckinLicensesFromAllUsers.php
+++ b/app/Console/Commands/CheckinLicensesFromAllUsers.php
@@ -73,15 +73,13 @@ public function handle()
$this->info($seat->user->username.' has a license seat for '.$license->name);
$seat->assigned_to = null;
- if ($seat->save()) {
+ $seat->setLogNote('Checked in via cli tool');
+ if ($seat->checkInAndSave()) {
// Override the email address so we don't notify on checkin
if (! $notify) {
- $seat->user->email = null;
+ $seat->user->email = null; //FIXME - this is probably not implemented just yet? maybe hoist this above the checkin?
}
-
- // Log the checkin
- $seat->logCheckin($seat->user, 'Checked in via cli tool');
}
}
}
diff --git a/app/Console/Commands/MergeUsersByUsername.php b/app/Console/Commands/MergeUsersByUsername.php
index 0c5e966ab912..3fdff9bf5bb9 100644
--- a/app/Console/Commands/MergeUsersByUsername.php
+++ b/app/Console/Commands/MergeUsersByUsername.php
@@ -2,7 +2,6 @@
namespace App\Console\Commands;
-use App\Events\UserMerged;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
@@ -59,72 +58,7 @@ public function handle()
foreach ($bad_users as $bad_user) {
$this->info($bad_user->username.' ('.$bad_user->id.') will be merged into '.$user->username.' ('.$user->id.') ');
-
- // Walk the list of assets
- foreach ($bad_user->assets as $asset) {
- $this->info('Updating asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id);
- $asset->assigned_to = $user->id;
- if (! $asset->save()) {
- $this->error('Could not update assigned_to field on asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id);
- $this->error('Error saving: '.$asset->getErrors());
- }
- }
-
- // Walk the list of licenses
- foreach ($bad_user->licenses as $license) {
- $this->info('Updating license '.$license->name.' '.$license->id.' to user '.$user->id);
- $bad_user->licenses()->updateExistingPivot($license->id, ['assigned_to' => $user->id]);
- }
-
- // Walk the list of consumables
- foreach ($bad_user->consumables as $consumable) {
- $this->info('Updating consumable '.$consumable->id.' to user '.$user->id);
- $bad_user->consumables()->updateExistingPivot($consumable->id, ['assigned_to' => $user->id]);
- }
-
- // Walk the list of accessories
- foreach ($bad_user->accessories as $accessory) {
- $this->info('Updating accessory '.$accessory->id.' to user '.$user->id);
- $bad_user->accessories()->updateExistingPivot($accessory->id, ['assigned_to' => $user->id]);
- }
-
- // Walk the list of logs
- foreach ($bad_user->userlog as $log) {
- $this->info('Updating action log record '.$log->id.' to user '.$user->id);
- $log->target_id = $user->id;
- $log->save();
- }
-
- // Update any manager IDs
- $this->info('Updating managed user records to user '.$user->id);
- User::where('manager_id', '=', $bad_user->id)->update(['manager_id' => $user->id]);
-
- // Update location manager IDs
- foreach ($bad_user->managedLocations as $managedLocation) {
- $this->info('Updating managed location record '.$managedLocation->name.' to manager '.$user->id);
- $managedLocation->manager_id = $user->id;
- $managedLocation->save();
- }
-
- foreach ($bad_user->uploads as $upload) {
- $this->info('Updating upload log record '.$upload->id.' to user '.$user->id);
- $upload->item_id = $user->id;
- $upload->save();
- }
-
- foreach ($bad_user->acceptances as $acceptance) {
- $this->info('Updating acceptance log record '.$acceptance->id.' to user '.$user->id);
- $acceptance->item_id = $user->id;
- $acceptance->save();
- }
-
- // Mark the user as deleted
- $this->info('Marking the user as deleted');
- $bad_user->deleted_at = Carbon::now()->timestamp;
- $bad_user->save();
-
- event(new UserMerged($bad_user, $user, null));
-
+ $user->merge($bad_user); //THAT's IT!
}
}
diff --git a/app/Enums/ActionType.php b/app/Enums/ActionType.php
new file mode 100644
index 000000000000..09084cdcd510
--- /dev/null
+++ b/app/Enums/ActionType.php
@@ -0,0 +1,23 @@
+acceptance = $acceptance;
- }
-}
diff --git a/app/Events/CheckoutDeclined.php b/app/Events/CheckoutDeclined.php
deleted file mode 100644
index 01d84b30f371..000000000000
--- a/app/Events/CheckoutDeclined.php
+++ /dev/null
@@ -1,23 +0,0 @@
-acceptance = $acceptance;
- }
-}
diff --git a/app/Events/UserMerged.php b/app/Events/UserMerged.php
deleted file mode 100644
index 3a7f4d6a2c38..000000000000
--- a/app/Events/UserMerged.php
+++ /dev/null
@@ -1,24 +0,0 @@
-merged_from = $from_user;
- $this->merged_to = $to_user;
- $this->admin = $admin;
- }
-}
diff --git a/app/Http/Controllers/Accessories/AccessoriesFilesController.php b/app/Http/Controllers/Accessories/AccessoriesFilesController.php
index 9dbb16d83aed..4f5cf54ea2f4 100644
--- a/app/Http/Controllers/Accessories/AccessoriesFilesController.php
+++ b/app/Http/Controllers/Accessories/AccessoriesFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Accessories;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
@@ -47,7 +48,10 @@ public function store(UploadFileRequest $request, $accessoryId = null) : Redirec
$file_name = $request->handleFile('private_uploads/accessories/', 'accessory-'.$accessory->id, $file);
//Log the upload to the log
- $accessory->logUpload($file_name, e($request->input('notes')));
+ $accessory->setLogFilename($file_name);
+ $accessory->setLogNote(e($request->input('notes')));
+ $accessory->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$accessory->logUpload($file_name, e($request->input('notes')));
}
diff --git a/app/Http/Controllers/Accessories/AccessoryCheckinController.php b/app/Http/Controllers/Accessories/AccessoryCheckinController.php
index e36f8a240db8..d794d0e02669 100644
--- a/app/Http/Controllers/Accessories/AccessoryCheckinController.php
+++ b/app/Http/Controllers/Accessories/AccessoryCheckinController.php
@@ -8,6 +8,7 @@
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use App\Models\User;
+use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use \Illuminate\Contracts\View\View;
@@ -56,12 +57,12 @@ public function store(Request $request, $accessoryCheckoutId = null, $backto = n
$checkin_hours = date('H:i:s');
$checkin_at = date('Y-m-d H:i:s');
if ($request->filled('checkin_at')) {
- $checkin_at = $request->input('checkin_at').' '.$checkin_hours;
+ $accessory->setLogDate(new Carbon($request->input('checkin_at').' '.$checkin_hours));
}
+ $accessory->setLogTarget($accessory_checkout);
// Was the accessory updated?
- if ($accessory_checkout->delete()) {
- event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at));
+ if ($accessory->checkInAndSave()) {
session()->put(['redirect_option' => $request->get('redirect_option')]);
diff --git a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php
index 58ce78724566..d09d7b7ce795 100644
--- a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php
+++ b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php
@@ -67,34 +67,21 @@ public function create($id) : View | RedirectResponse
*/
public function store(AccessoryCheckoutRequest $request, Accessory $accessory) : RedirectResponse
{
-
$this->authorize('checkout', $accessory);
- $target = $this->determineCheckoutTarget();
-
- $accessory->checkout_qty = $request->input('checkout_qty', 1);
-
- for ($i = 0; $i < $accessory->checkout_qty; $i++) {
-
- $accessory_checkout = new AccessoryCheckout([
- 'accessory_id' => $accessory->id,
- 'created_at' => Carbon::now(),
- 'assigned_to' => $target->id,
- 'assigned_type' => $target::class,
- 'note' => $request->input('note'),
- ]);
-
- $accessory_checkout->created_by = auth()->id();
- $accessory_checkout->save();
- }
+ $accessory->setLogTarget($this->determineCheckoutTarget());
+
+ $accessory->setLogQuantity($request->input('checkout_qty', 1));
+ $accessory->setLogNote($request->input('note'));
- event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
+ event(new CheckoutableCheckedOut($accessory, $accessory->getLogTarget(), auth()->user(), $accessory->getLogNote()));
$request->request->add(['checkout_to_type' => request('checkout_to_type')]);
- $request->request->add(['assigned_to' => $target->id]);
+ $request->request->add(['assigned_to' => $accessory->getLogTarget()->id]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
+ $accessory->checkOutAndSave();
// Redirect to the new accessory page
return redirect()->to(Helper::getRedirectOption($request, $accessory->id, 'Accessories'))
diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php
index b20f7d97e8ed..1e2ba43ea0ff 100644
--- a/app/Http/Controllers/Account/AcceptanceController.php
+++ b/app/Http/Controllers/Account/AcceptanceController.php
@@ -2,8 +2,7 @@
namespace App\Http\Controllers\Account;
-use App\Events\CheckoutAccepted;
-use App\Events\CheckoutDeclined;
+use App\Enums\ActionType;
use App\Events\ItemAccepted;
use App\Events\ItemDeclined;
use App\Http\Controllers\Controller;
@@ -12,6 +11,7 @@
use App\Models\CheckoutAcceptance;
use App\Models\Company;
use App\Models\Contracts\Acceptable;
+use App\Models\LicenseSeat;
use App\Models\Setting;
use App\Models\User;
use App\Models\AssetModel;
@@ -240,12 +240,26 @@ public function store(Request $request, $id) : RedirectResponse
}
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
+ // so, *this* is the key element here - accept will also call accept on the thing that was accepted
+ // (which currently does _nothing_)
try {
$acceptance->notify(new AcceptanceAssetAcceptedNotification($data));
} catch (\Exception $e) {
Log::warning($e);
}
- event(new CheckoutAccepted($acceptance));
+ //this came from the previous 'listener' thing
+ Log::debug('event passed to the onCheckoutAccepted listener:'); //[sic]
+ $acceptance->checkoutable->setLogTarget(User::find($acceptance->assigned_to));
+ $acceptance->checkoutable->setLogFilename($acceptance->stored_eula_file);
+ $acceptance->checkoutable->setLogAcceptSignature($acceptance->signature_filename);
+ $acceptance->checkoutable->setLogNote($acceptance->note);
+
+ //// TODO: log the actual license seat that was checked out
+ //if ($acceptance->checkoutable instanceof LicenseSeat) {
+ // $logaction->item()->associate($acceptance->checkoutable->license);
+ //} // FIXME - confirm this is already handled within Loggable!
+
+ $acceptance->checkoutable->logAndSaveIfNeeded(ActionType::Accepted);
$return_msg = trans('admin/users/message.accepted');
@@ -333,7 +347,19 @@ public function store(Request $request, $id) : RedirectResponse
$acceptance->decline($sig_filename, $request->input('note'));
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
- event(new CheckoutDeclined($acceptance));
+ // The below is from the former event(new CheckoutDeclined($acceptance));
+
+ $acceptance->checkoutable->setLogTarget(User::find($acceptance->assigned_to));
+ $acceptance->checkoutable->setLogAcceptSignature($acceptance->signature_filename);
+ $acceptance->checkoutable->setLogNote($acceptance->note);
+
+ //// TODO: log the actual license seat that was checked out
+ //if ($acceptance->checkoutable instanceof LicenseSeat) {
+ // $logaction->item()->associate($acceptance->checkoutable->license);
+ //} //FIXME - confirm this actually works automatically
+
+ $acceptance->checkoutable->logAndSaveIfNeeded(ActionType::Declined);
+
$return_msg = trans('admin/users/message.declined');
}
diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php
index 76e69591d4f1..41384e2b3a82 100644
--- a/app/Http/Controllers/Api/AccessoriesController.php
+++ b/app/Http/Controllers/Api/AccessoriesController.php
@@ -274,27 +274,14 @@ public function destroy($id)
*/
public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory)
{
+ //\Log::error("Am I even in the right place?!");
$this->authorize('checkout', $accessory);
- $target = $this->determineCheckoutTarget();
- $accessory->checkout_qty = $request->input('checkout_qty', 1);
-
- for ($i = 0; $i < $accessory->checkout_qty; $i++) {
-
- $accessory_checkout = new AccessoryCheckout([
- 'accessory_id' => $accessory->id,
- 'created_at' => Carbon::now(),
- 'assigned_to' => $target->id,
- 'assigned_type' => $target::class,
- 'note' => $request->input('note'),
- ]);
-
- $accessory_checkout->created_by = auth()->id();
- $accessory_checkout->save();
- }
-
- // Set this value to be able to pass the qty through to the event
- event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
-
+ $accessory->setLogTarget($this->determineCheckoutTarget());
+ $accessory->setLogQuantity($request->input('checkout_qty', 1));
+ $accessory->setLogNote($request->input('note'));
+ //$accessory->checkout_qty = ;
+ //dump($accessory->getLogTarget());
+ $accessory->checkOutAndSave();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
}
@@ -319,13 +306,11 @@ public function checkin(Request $request, $accessoryUserId = null)
$accessory = Accessory::find($accessory_checkout->accessory_id);
$this->authorize('checkin', $accessory);
- $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'));
+ $accessory->setLogNote($request->input('note'));
+ $accessory->setLogTarget($accessory_checkout); //need to do some 'magic' to convert this to a user (or location), elsewhere.
// Was the accessory updated?
- if ($accessory_checkout->delete()) {
- if (! is_null($accessory_checkout->assigned_to)) {
- $user = User::find($accessory_checkout->assigned_to);
- }
+ if ($accessory->checkInAndSave()) {
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
}
diff --git a/app/Http/Controllers/Api/AssetFilesController.php b/app/Http/Controllers/Api/AssetFilesController.php
index 4369d287d5c2..8adb06a95a2f 100644
--- a/app/Http/Controllers/Api/AssetFilesController.php
+++ b/app/Http/Controllers/Api/AssetFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use Illuminate\Support\Facades\Storage;
use App\Helpers\Helper;
@@ -53,8 +54,11 @@ public function store(UploadFileRequest $request, $assetId = null) : JsonRespons
// Loop over the attached files and add them to the asset
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
-
- $asset->logUpload($file_name, e($request->get('notes')));
+
+ $asset->setLogFilename($file_name);
+ $asset->setLogNote(e($request->input('notes')));
+ $asset->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$asset->logUpload($file_name, e($request->get('notes')));
}
// All done - report success
diff --git a/app/Http/Controllers/Api/AssetModelFilesController.php b/app/Http/Controllers/Api/AssetModelFilesController.php
index 7f0f06c63514..0449cee0a682 100644
--- a/app/Http/Controllers/Api/AssetModelFilesController.php
+++ b/app/Http/Controllers/Api/AssetModelFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use Illuminate\Support\Facades\Storage;
use App\Helpers\Helper;
@@ -54,8 +55,11 @@ public function store(UploadFileRequest $request, $assetModelId = null) : JsonRe
// Loop over the attached files and add them to the asset
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$assetModel->id, $file);
-
- $assetModel->logUpload($file_name, e($request->get('notes')));
+
+ $assetModel->setLogFilename($file_name);
+ $assetModel->setLogNote(e($request->input('notes')));
+ $assetModel->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$assetModel->logUpload($file_name, e($request->get('notes')));
}
// All done - report success
diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php
index d780bd8bde38..47304288ed50 100644
--- a/app/Http/Controllers/Api/AssetsController.php
+++ b/app/Http/Controllers/Api/AssetsController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api;
+use App\Enums\ActionType;
use App\Events\CheckoutableCheckedIn;
use App\Http\Requests\StoreAssetRequest;
use App\Http\Requests\UpdateAssetRequest;
@@ -687,7 +688,13 @@ public function store(StoreAssetRequest $request): JsonResponse
$target = Location::find(request('assigned_location'));
}
if (isset($target)) {
- $asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset creation', e($request->get('name')));
+ $asset->setLogTarget($target);
+ $asset->setLogNote('Checked out on asset creation');
+ if ($request->validated('location_id')) {
+ \Log::error("OKAY - we are OVERRIDING the location for the checkoutandsave I guess? to:" . $request->validated('location_id'));
+ $asset->setLogLocationOverride(Location::find($request->validated('location_id'))); //TODO - weird behavior in different contexts
+ }
+ $asset->checkOutAndSave();
}
if ($asset->image) {
@@ -774,7 +781,12 @@ public function update(UpdateAssetRequest $request, Asset $asset): JsonResponse
}
if (isset($target)) {
- $asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), '', 'Checked out on asset update', e($request->get('name')), $location);
+ $asset->setLogTarget($target);
+ if ($location) {
+ //$asset->setLocationOverride(Location::find($location)); //TODO - weird location override
+ }
+ $asset->setLogNote('Checked out on asset update');
+ $asset->checkOutAndSave();
}
if ($asset->image) {
@@ -897,39 +909,46 @@ public function checkout(AssetCheckoutRequest $request, $asset_id): JsonResponse
'asset_tag' => $asset->asset_tag,
];
+ $error_payload['target_type'] = request('checkout_to_type');
// This item is checked out to a location
if (request('checkout_to_type') == 'location') {
- $target = Location::find(request('assigned_location'));
- $asset->location_id = ($target) ? $target->id : '';
+ $asset->setLogTarget(Location::find(request('assigned_location')));
+ //$asset->location_id = ($target) ? $target->id : '';
$error_payload['target_id'] = $request->input('assigned_location');
- $error_payload['target_type'] = 'location';
} elseif (request('checkout_to_type') == 'asset') {
- $target = Asset::where('id', '!=', $asset_id)->find(request('assigned_asset'));
+ $asset->setLogTarget(Asset::where('id', '!=', $asset_id)->find(request('assigned_asset')));
// Override with the asset's location_id if it has one
- $asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
+ //$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
$error_payload['target_id'] = $request->input('assigned_asset');
- $error_payload['target_type'] = 'asset';
} elseif (request('checkout_to_type') == 'user') {
// Fetch the target and set the asset's new location_id
- $target = User::find(request('assigned_user'));
- $asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
+ $asset->setLogTarget(User::find(request('assigned_user')));
+ //$asset->location_id = (($target) && (isset($target->location_id))) ? $target->location_id : '';
$error_payload['target_id'] = $request->input('assigned_user');
- $error_payload['target_type'] = 'user';
+ } else {
+ //FIXME - return error - bad checkout_to_type ?
+ \Log::error("FAILED in terms of checkout_to_type!!! it's: ".request('checkout_to_type'));
}
if ($request->filled('status_id')) {
$asset->status_id = $request->get('status_id');
}
- if (! isset($target)) {
+ if (!$asset->getLogTarget()) {
+ \Log::error("no target set for checkout so we're aborting it now with a json error");
return response()->json(Helper::formatStandardApiResponse('error', $error_payload, 'Checkout target for asset ' . e($asset->asset_tag) . ' is invalid - ' . $error_payload['target_type'] . ' does not exist.'));
}
- $checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
- $expected_checkin = request('expected_checkin', null);
- $note = request('note', null);
+ if ($request->has('checkout_at')) {
+ $asset->setLogDate(new Carbon($request->get('checkout_at')));
+ }
+ //$checkout_at = request('checkout_at', date('Y-m-d H:i:s')); // WHERE TO PUT THIS!
+ $asset->expected_checkin = $request->get('expected_checkin', null);
+ $asset->setLogNote($request->get('note', null));
// Using `->has` preserves the asset name if the name parameter was not included in request.
- $asset_name = request()->has('name') ? request('name') : $asset->name;
+ if ($request->has('name')) {
+ $asset->name = $request->get('name');
+ }
// Set the location ID to the RTD location id if there is one
// Wait, why are we doing this? This overrides the stuff we set further up, which makes no sense.
@@ -940,7 +959,7 @@ public function checkout(AssetCheckoutRequest $request, $asset_id): JsonResponse
// $asset->location_id = $target->rtd_location_id;
// }
- if ($asset->checkOut($target, auth()->user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id)) {
+ if ($asset->checkOutAndSave()) {
return response()->json(Helper::formatStandardApiResponse('success', ['asset' => e($asset->asset_tag)], trans('admin/hardware/message.checkout.success')));
}
@@ -979,9 +998,9 @@ public function checkin(Request $request, $asset_id): JsonResponse
$asset->name = $request->input('name');
}
- $this->migrateLegacyLocations($asset);
+ $this->migrateLegacyLocations($asset); //FIXME - hrm.
- $asset->location_id = $asset->rtd_location_id;
+ $asset->location_id = $asset->rtd_location_id; //FIXME this seems like it should be in Asset?
if ($request->filled('location_id')) {
$asset->location_id = $request->input('location_id');
@@ -994,34 +1013,18 @@ public function checkin(Request $request, $asset_id): JsonResponse
if ($request->filled('status_id')) {
$asset->status_id = $request->input('status_id');
}
-
- $checkin_at = $request->filled('checkin_at') ? $request->input('checkin_at') . ' ' . date('H:i:s') : date('Y-m-d H:i:s');
- $originalValues = $asset->getRawOriginal();
-
+
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
- $originalValues['action_date'] = $checkin_at;
+ \Log::error("Setting checkin time of ".$request->get('checkin_at')." because that's not today which is: ".date('Y-m-d'));
+ $asset->setLogDate(new Carbon($request->get('checkin_at')));
}
- $asset->licenseseats->each(function (LicenseSeat $seat) {
- $seat->update(['assigned_to' => null]);
- });
-
- // Get all pending Acceptances for this asset and delete them
- CheckoutAcceptance::pending()
- ->whereHasMorph(
- 'checkoutable',
- [Asset::class],
- function (Builder $query) use ($asset) {
- $query->where('id', $asset->id);
- }
- )
- ->get()
- ->map(function ($acceptance) {
- $acceptance->delete();
- });
+ if ($request->filled('note')) {
+ $asset->setLogNote($request->input('note'));
+ }
- if ($asset->save()) {
- event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
+ if ($asset->checkInAndSave()) {
+ //event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
return response()->json(Helper::formatStandardApiResponse('success', [
'asset_tag' => e($asset->asset_tag),
@@ -1086,22 +1089,6 @@ public function audit(Request $request): JsonResponse
if ($asset) {
- /**
- * Even though we do a save() further down, we don't want to log this as a "normal" asset update,
- * which would trigger the Asset Observer and would log an asset *update* log entry (because the
- * de-normed fields like next_audit_date on the asset itself will change on save()) *in addition* to
- * the audit log entry we're creating through this controller.
- *
- * To prevent this double-logging (one for update and one for audit), we skip the observer and bypass
- * that de-normed update log entry by using unsetEventDispatcher(), BUT invoking unsetEventDispatcher()
- * will bypass normal model-level validation that's usually handled at the observer )
- *
- * We handle validation on the save() by checking if the asset is valid via the ->isValid() method,
- * which manually invokes Watson Validating to make sure the asset's model is valid.
- *
- * @see \App\Observers\AssetObserver::updating()
- */
- $asset->unsetEventDispatcher();
$asset->next_audit_date = $dt;
if ($request->filled('next_audit_date')) {
@@ -1116,12 +1103,10 @@ public function audit(Request $request): JsonResponse
$asset->last_audit_date = date('Y-m-d H:i:s');
- /**
- * Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
- * We have to invoke this manually because of the unsetEventDispatcher() above.)
- */
- if ($asset->isValid() && $asset->save()) {
- $asset->logAudit(request('note'), request('location_id'));
+ $asset->setLogNote($request->input('note'));
+
+ if ($asset->AuditAndSave()) {
+ //$asset->logAudit(request('note'), request('location_id'));
return response()->json(Helper::formatStandardApiResponse('success', [
'asset_tag' => e($asset->asset_tag),
diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php
index 200951886289..93f9ed2dbbfe 100644
--- a/app/Http/Controllers/Api/ComponentsController.php
+++ b/app/Http/Controllers/Api/ComponentsController.php
@@ -12,6 +12,9 @@
use App\Models\Asset;
use Illuminate\Support\Facades\Validator;
use Illuminate\Database\Query\Builder;
+use Illuminate\Database\Eloquent\Builder as RealBuilder;
+
+//FIXME what the F is this?
use Illuminate\Support\Facades\Log;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
@@ -285,18 +288,12 @@ public function checkout(Request $request, $componentId) : JsonResponse
if ($component->numRemaining() >= $request->get('assigned_qty')) {
$asset = Asset::find($request->input('assigned_to'));
- $component->assigned_to = $request->input('assigned_to');
-
- $component->assets()->attach($component->id, [
- 'component_id' => $component->id,
- 'created_at' => Carbon::now(),
- 'assigned_qty' => $request->get('assigned_qty', 1),
- 'created_by' => auth()->id(),
- 'asset_id' => $request->get('assigned_to'),
- 'note' => $request->get('note'),
- ]);
+ $component->setLogTarget($asset);
+
+ $component->setLogQuantity($request->input('assigned_qty'));
+ $component->setLogNote($request->input('note'));
+ $component->checkOutAndSave();
- $component->logCheckout($request->input('note'), $asset);
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkout.success')));
}
@@ -314,6 +311,13 @@ public function checkout(Request $request, $componentId) : JsonResponse
*/
public function checkin(Request $request, $component_asset_id) : JsonResponse
{
+ //$component_asset = Component::whereHas('assets', function (RealBuilder $query) use ($component_asset_id) {
+ // $query->where('components_assets.id', $component_asset_id);
+ //})->get();
+ //\Log::error(Component::whereHas('assets', function (RealBuilder $query) use ($component_asset_id) {
+ // $query->where('components_assets.id', $component_asset_id);
+ //})->toSql());
+ //dump($component_asset);
if ($component_assets = DB::table('components_assets')->find($component_asset_id)) {
if (is_null($component = Component::find($component_assets->component_id))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.not_found')));
@@ -331,26 +335,11 @@ public function checkin(Request $request, $component_asset_id) : JsonResponse
return response()->json(Helper::formatStandardApiResponse('error', null, 'Checkin quantity must be between 1 and ' . $max_to_checkin));
}
- // Validation passed, so let's figure out what we have to do here.
- $qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty', 1));
-
- // We have to modify the record to reflect the new qty that's
- // actually checked out.
- $component_assets->assigned_qty = $qty_remaining_in_checkout;
-
- Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
-
- DB::table('components_assets')->where('id', $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
-
- // If the checked-in qty is exactly the same as the assigned_qty,
- // we can simply delete the associated components_assets record
- if ($qty_remaining_in_checkout === 0) {
- DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
- }
-
- $asset = Asset::find($component_assets->asset_id);
-
- event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
+ $component->setLogTarget($component_assets); //FIXME TODO - hrm. This is 'weird'. okay, now it's _very_ weird.
+ //$component->log_target =
+ $component->setLogQuantity($request->input('checkin_qty', 1));
+ $component->setLogNote($request->input('note'));
+ $component->checkInAndSave();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkin.success')));
}
diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php
index 7ff676c7bef3..2a1bb535bb0b 100644
--- a/app/Http/Controllers/Api/ConsumablesController.php
+++ b/app/Http/Controllers/Api/ConsumablesController.php
@@ -258,7 +258,7 @@ public function checkout(Request $request, $id) : JsonResponse
$this->authorize('checkout', $consumable);
- $consumable->checkout_qty = $request->input('checkout_qty', 1);
+ $consumable->setLogQuantity($request->input('checkout_qty', 1));
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0) {
@@ -273,7 +273,7 @@ public function checkout(Request $request, $id) : JsonResponse
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0 || $consumable->checkout_qty > $consumable->numRemaining()) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.checkout.unavailable', ['requested' => $consumable->checkout_qty, 'remaining' => $consumable->numRemaining() ])));
- }
+ } //FIXME - this is consumables logic, not here
@@ -283,22 +283,11 @@ public function checkout(Request $request, $id) : JsonResponse
return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found'));
}
- // Update the consumable data
- $consumable->assigned_to = $request->input('assigned_to');
-
- for ($i = 0; $i < $consumable->checkout_qty; $i++) {
- $consumable->users()->attach($consumable->id,
- [
- 'consumable_id' => $consumable->id,
- 'created_by' => $user->id,
- 'assigned_to' => $request->input('assigned_to'),
- 'note' => $request->input('note'),
- ]
- );
+ if ($request->has('note')) {
+ $consumable->setLogNote($request->input('note'));
}
-
-
- event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
+ $consumable->setLogTarget($user);
+ $consumable->checkoutAndSave();
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
diff --git a/app/Http/Controllers/Api/LicenseSeatsController.php b/app/Http/Controllers/Api/LicenseSeatsController.php
index 2ed709732236..5a206299cecf 100644
--- a/app/Http/Controllers/Api/LicenseSeatsController.php
+++ b/app/Http/Controllers/Api/LicenseSeatsController.php
@@ -132,19 +132,18 @@ public function update(Request $request, $licenseId, $seatId) : JsonResponse | a
if (is_null($target)){
return response()->json(Helper::formatStandardApiResponse('error', null, 'Target not found'));
}
+ $licenseSeat->setLogTarget($target);
+ $licenseSeat->setLogNote($request->input('note'));
- if ($licenseSeat->save()) {
-
- if ($is_checkin) {
- $licenseSeat->logCheckin($target, $request->input('note'));
-
+ //since we are, effectively, going seat-by-seat here, should this really live on the licenseSeat itself?
+ if ($is_checkin) {
+ if ($licenseSeat->checkInAndSave()) {
+ return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
+ }
+ } else {
+ if ($licenseSeat->checkOutAndSave()) {
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
-
- // in this case, relevant fields are touched but it's not a checkin operation. so it must be a checkout operation.
- $licenseSeat->logCheckout($request->input('note'), $target);
-
- return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
}
return Helper::formatStandardApiResponse('error', null, $licenseSeat->getErrors());
diff --git a/app/Http/Controllers/Api/ManufacturersController.php b/app/Http/Controllers/Api/ManufacturersController.php
index 652fad1cfc6b..5dd3c19435af 100644
--- a/app/Http/Controllers/Api/ManufacturersController.php
+++ b/app/Http/Controllers/Api/ManufacturersController.php
@@ -218,14 +218,7 @@ public function restore($id) : JsonResponse
}
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);
}
diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php
index 1d34f90a39e5..78571d726562 100644
--- a/app/Http/Controllers/Api/UsersController.php
+++ b/app/Http/Controllers/Api/UsersController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Api;
+use App\Enums\ActionType;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\SaveUserRequest;
@@ -701,17 +702,8 @@ public function postTwoFactorReset(Request $request) : JsonResponse
$this->authorize('update', $user);
$user->two_factor_secret = null;
$user->two_factor_enrolled = 0;
- $user->saveQuietly();
-
- // 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');
+ $user->setLogAction(ActionType::TwoFactorReset);
+ $user->save();
return response()->json(['message' => trans('admin/settings/general.two_factor_reset_success')], 200);
} catch (\Exception $e) {
@@ -756,13 +748,6 @@ public function restore($userId) : JsonResponse
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);
}
diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php
index 079558877677..ecd2588a7f47 100755
--- a/app/Http/Controllers/AssetModelsController.php
+++ b/app/Http/Controllers/AssetModelsController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
+use App\Enums\ActionType;
use App\Helpers\Helper;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\StoreAssetModelRequest;
@@ -213,13 +214,6 @@ public function getRestore($id) : RedirectResponse
}
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
$deleted_models = AssetModel::onlyTrashed()->count();
diff --git a/app/Http/Controllers/AssetModelsFilesController.php b/app/Http/Controllers/AssetModelsFilesController.php
index 14b2c1fc0b39..221b29d3a3e0 100644
--- a/app/Http/Controllers/AssetModelsFilesController.php
+++ b/app/Http/Controllers/AssetModelsFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Requests\UploadFileRequest;
use App\Models\Actionlog;
@@ -41,7 +42,10 @@ public function store(UploadFileRequest $request, $modelId = null) : RedirectRes
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$model->id,$file);
- $model->logUpload($file_name, $request->get('notes'));
+ $model->setLogFilename($file_name);
+ $model->setLogNote($request->input('notes'));
+ $model->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$model->logUpload($file_name, $request->get('notes'));
}
return redirect()->back()->withFragment('files')->with('success', trans('general.file_upload_success'));
diff --git a/app/Http/Controllers/Assets/AssetCheckinController.php b/app/Http/Controllers/Assets/AssetCheckinController.php
index 4452bfa51d27..c1389e66132e 100644
--- a/app/Http/Controllers/Assets/AssetCheckinController.php
+++ b/app/Http/Controllers/Assets/AssetCheckinController.php
@@ -10,6 +10,7 @@
use App\Models\Asset;
use App\Models\CheckoutAcceptance;
use App\Models\LicenseSeat;
+use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Log;
use \Illuminate\Contracts\View\View;
@@ -90,11 +91,11 @@ public function store(AssetCheckinRequest $request, $assetId = null, $backto = n
}
// Add any custom fields that should be included in the checkout
- $asset->customFieldsForCheckinCheckout('display_checkin');
+ $asset->customFieldsForCheckinCheckout('display_checkin'); //FIXME ?
- $this->migrateLegacyLocations($asset);
+ $this->migrateLegacyLocations($asset); //FIXME ?
- $asset->location_id = $asset->rtd_location_id;
+ $asset->location_id = $asset->rtd_location_id; //FIXME more asset logic
if ($request->filled('location_id')) {
Log::debug('NEW Location ID: '.$request->get('location_id'));
@@ -105,36 +106,21 @@ public function store(AssetCheckinRequest $request, $assetId = null, $backto = n
}
}
- $originalValues = $asset->getRawOriginal();
-
- $checkin_at = date('Y-m-d H:i:s');
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
- $originalValues['action_date'] = $checkin_at;
- $checkin_at = $request->get('checkin_at');
+ $asset->setLogDate(new Carbon($request->get('checkin_at')));
}
- $asset->licenseseats->each(function (LicenseSeat $seat) {
- $seat->update(['assigned_to' => null]);
- });
+ if ($request->filled('note')) {
+ $asset->setLogNote($request->get('note'));
+ }
- // Get all pending Acceptances for this asset and delete them
- $acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
- [Asset::class],
- function (Builder $query) use ($asset) {
- $query->where('id', $asset->id);
- })->get();
- $acceptances->map(function($acceptance) {
- $acceptance->delete();
- });
session()->put('redirect_option', $request->get('redirect_option'));
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkin');
- if ($asset->save()) {
-
- event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
+ if ($asset->checkInAndSave()) {
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))->with('success', trans('admin/hardware/message.checkin.success'));
}
// Redirect to the asset management page with error
diff --git a/app/Http/Controllers/Assets/AssetCheckoutController.php b/app/Http/Controllers/Assets/AssetCheckoutController.php
index 4d8c9ffda267..40acf4c56e5f 100644
--- a/app/Http/Controllers/Assets/AssetCheckoutController.php
+++ b/app/Http/Controllers/Assets/AssetCheckoutController.php
@@ -8,6 +8,7 @@
use App\Http\Controllers\Controller;
use App\Http\Requests\AssetCheckoutRequest;
use App\Models\Asset;
+use Carbon\Carbon;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Session;
use \Illuminate\Contracts\View\View;
@@ -68,21 +69,19 @@ public function store(AssetCheckoutRequest $request, $assetId) : RedirectRespons
if (!$asset->model) {
return redirect()->route('hardware.show', $asset)->with('error', trans('admin/hardware/general.model_invalid_fix'));
}
+
+ $asset->setLogTarget($this->determineCheckoutTarget());
- $admin = auth()->user();
+ // $asset = $this->updateAssetLocation($asset, $target); not needed? handled by checkout?
- $target = $this->determineCheckoutTarget();
-
- $asset = $this->updateAssetLocation($asset, $target);
-
- $checkout_at = date('Y-m-d H:i:s');
+ // $checkout_at = date('Y-m-d H:i:s'); //TODO - make sure this gets set to a sensible default?
if (($request->filled('checkout_at')) && ($request->get('checkout_at') != date('Y-m-d'))) {
- $checkout_at = $request->get('checkout_at');
+ $asset->setLogDate(new Carbon($request->get('checkout_at')));
}
- $expected_checkin = '';
+ //$expected_checkin = '';
if ($request->filled('expected_checkin')) {
- $expected_checkin = $request->get('expected_checkin');
+ $asset->expected_checkin = $request->get('expected_checkin');
}
if ($request->filled('status_id')) {
@@ -90,30 +89,43 @@ public function store(AssetCheckoutRequest $request, $assetId) : RedirectRespons
}
+ // This is a kinda weird feature. If we have a bunch of licenses checked out to an _asset_,
+ // and then we check out the _asset_ to a user, those licenses transfer over to the user?
+ // I don't understand why we would even do that, tbh.
+ // FIXME or document or something?
+ // and if we *were* going to do this, it should be in Asset, not here.
if(!empty($asset->licenseseats->all())){
if(request('checkout_to_type') == 'user') {
foreach ($asset->licenseseats as $seat){
- $seat->assigned_to = $target->id;
- $seat->save();
+ $seat->assigned_to = $asset->getLogTarget()->id; //this could get really weird, really quick? FIXME
+ $seat->save(); //FIXME - not transactionalized.
}
}
}
+ if ($request->has('name')) {
+ $asset->name = $request->get('name');
+ }
+
+ if ($request->has('note')) {
+ $asset->setLogNote($request->get('note'));
+ }
+
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkout');
$settings = \App\Models\Setting::getSettings();
// We have to check whether $target->company_id is null here since locations don't have a company yet
- if (($settings->full_multiple_companies_support) && ((!is_null($target->company_id)) && (!is_null($asset->company_id)))) {
- if ($target->company_id != $asset->company_id){
+ if (($settings->full_multiple_companies_support) && ((!is_null($asset->getLogTarget()->company_id)) && (!is_null($asset->company_id)))) {
+ if ($asset->getLogTarget()->company_id != $asset->company_id) {
return redirect()->route('hardware.checkout.create', $asset)->with('error', trans('general.error_user_company'));
}
}
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => $request->get('checkout_to_type')]);
- if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name'))) {
+ if ($asset->checkOutAndSave()) { // $target, $admin, $checkout_at, $expected_checkin, $request->get('note'), $request->get('name')
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
->with('success', trans('admin/hardware/message.checkout.success'));
}
diff --git a/app/Http/Controllers/Assets/AssetFilesController.php b/app/Http/Controllers/Assets/AssetFilesController.php
index cf119edddc8c..f50f79c9d60b 100644
--- a/app/Http/Controllers/Assets/AssetFilesController.php
+++ b/app/Http/Controllers/Assets/AssetFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Assets;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
@@ -38,8 +39,11 @@ public function store(UploadFileRequest $request, Asset $asset) : RedirectRespon
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
-
- $asset->logUpload($file_name, $request->get('notes'));
+
+ $asset->setLogFilename($file_name);
+ $asset->setLogNote(e($request->input('notes')));
+ $asset->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$asset->logUpload($file_name, $request->get('notes'));
}
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.upload.success'));
diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php
index 9578acea6378..c43f179fe125 100755
--- a/app/Http/Controllers/Assets/AssetsController.php
+++ b/app/Http/Controllers/Assets/AssetsController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Assets;
+use App\Enums\ActionType;
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
@@ -199,7 +200,7 @@ public function store(ImageUploadRequest $request) : RedirectResponse
}
if (isset($target)) {
- $asset->checkOut($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
+ $asset->checkOutAndSave($target, auth()->user(), date('Y-m-d H:i:s'), $request->input('expected_checkin', null), 'Checked out on asset creation', $request->get('name'), $location);
}
$successes[] = "" . e($asset->asset_tag) . "";
@@ -918,7 +919,7 @@ public function auditStore(UploadFileRequest $request, Asset $asset)
*
* @see \App\Observers\AssetObserver::updating()
*/
- $asset->unsetEventDispatcher();
+ //$asset->unsetEventDispatcher(); //FIXME - make sure this owrks!
$asset->next_audit_date = $request->input('next_audit_date');
$asset->last_audit_date = date('Y-m-d H:i:s');
@@ -934,15 +935,14 @@ public function auditStore(UploadFileRequest $request, Asset $asset)
* Invoke Watson Validating to check the asset itself and check to make sure it saved correctly.
* We have to invoke this manually because of the unsetEventDispatcher() above.)
*/
- if ($asset->isValid() && $asset->save()) {
-
- $file_name = null;
- // Create the image (if one was chosen.)
- if ($request->hasFile('image')) {
- $file_name = $request->handleFile('private_uploads/audits/', 'audit-'.$asset->id, $request->file('image'));
- }
+ $asset->setLogNote($request->input('note'));
+ // Create the image (if one was chosen.)
+ if ($request->hasFile('image')) {
+ $asset->setLogFilename($request->handleFile('private_uploads/audits/', 'audit-'.$asset->id, $request->file('image')));
+ }
+ if ($asset->AuditAndSave()) {
- $asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
+ //$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
}
diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php
index e433475d3955..8582256afa2b 100644
--- a/app/Http/Controllers/Assets/BulkAssetsController.php
+++ b/app/Http/Controllers/Assets/BulkAssetsController.php
@@ -607,17 +607,11 @@ public function storeCheckout(AssetCheckoutRequest $request) : RedirectResponse
DB::transaction(function () use ($target, $admin, $checkout_at, $expected_checkin, &$errors, $assets, $request) { //NOTE: $errors is passsed by reference!
foreach ($assets as $asset) {
$this->authorize('checkout', $asset);
-
- $checkout_success = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
-
- //TODO - I think this logic is duplicated in the checkOut method?
- if ($target->location_id != '') {
- $asset->location_id = $target->location_id;
- // TODO - I don't know why this is being saved without events
- $asset::withoutEvents(function () use ($asset) {
- $asset->save();
- });
- }
+ $asset->setLogTarget($target);
+ $asset->setLogDate(new Carbon($checkout_at));
+ $asset->expected_checkin = $expected_checkin;
+ $asset->setLogNote(e($request->get('note')));
+ $checkout_success = $asset->checkOutAndSave();
if (!$checkout_success) {
$errors = array_merge_recursive($errors, $asset->getErrors()->toArray());
diff --git a/app/Http/Controllers/CheckInOutRequest.php b/app/Http/Controllers/CheckInOutRequest.php
index 6ab327fff878..3df8ab0049ad 100644
--- a/app/Http/Controllers/CheckInOutRequest.php
+++ b/app/Http/Controllers/CheckInOutRequest.php
@@ -12,7 +12,7 @@ trait CheckInOutRequest
/**
* Find target for checkout
*/
- protected function determineCheckoutTarget() : ?SnipeModel
+ protected function determineCheckoutTarget(): ?SnipeModel // FIXME - I don't know that I want this here anymore. But maybe I do? It *does* have to do with the request?
{
// This item is checked out to a location
switch (request('checkout_to_type')) {
@@ -23,7 +23,7 @@ protected function determineCheckoutTarget() : ?SnipeModel
default:
return User::findOrFail(request('assigned_user'));
}
-
+ \Log::error("NO SUCH TARGET!!!!!");
return null;
}
@@ -33,7 +33,7 @@ protected function determineCheckoutTarget() : ?SnipeModel
* @param SnipeModel $target Target with location
* @return Asset Asset being updated
*/
- protected function updateAssetLocation($asset, $target) : Asset
+ protected function updateAssetLocation($asset, $target): Asset //FIXME -this does some logic we *DON'T* DO!
{
switch (request('checkout_to_type')) {
case 'location':
diff --git a/app/Http/Controllers/Components/ComponentCheckinController.php b/app/Http/Controllers/Components/ComponentCheckinController.php
index 379882c3c5e5..b75625805c90 100644
--- a/app/Http/Controllers/Components/ComponentCheckinController.php
+++ b/app/Http/Controllers/Components/ComponentCheckinController.php
@@ -78,25 +78,10 @@ public function store(Request $request, $component_asset_id, $backto = null)
->withErrors($validator)
->withInput();
}
-
- // Validation passed, so let's figure out what we have to do here.
- $qty_remaining_in_checkout = ($component_assets->assigned_qty - (int) $request->input('checkin_qty'));
-
- // We have to modify the record to reflect the new qty that's
- // actually checked out.
- $component_assets->assigned_qty = $qty_remaining_in_checkout;
- DB::table('components_assets')->where('id',
- $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
-
- // If the checked-in qty is exactly the same as the assigned_qty,
- // we can simply delete the associated components_assets record
- if ($qty_remaining_in_checkout == 0) {
- DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
- }
-
- $asset = Asset::find($component_assets->asset_id);
-
- event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
+ $component->setLogQuantity($request->input('checkin_qty', 1));
+ $component->setLogNote($request->input('note'));
+ $component->setLogTarget(Asset::find($component_assets->asset_id));
+ $component->checkInAndSave();
session()->put(['redirect_option' => $request->get('redirect_option')]);
diff --git a/app/Http/Controllers/Components/ComponentCheckoutController.php b/app/Http/Controllers/Components/ComponentCheckoutController.php
index b40d592369f7..9f8fb13cb390 100644
--- a/app/Http/Controllers/Components/ComponentCheckoutController.php
+++ b/app/Http/Controllers/Components/ComponentCheckoutController.php
@@ -102,18 +102,10 @@ public function store(Request $request, $componentId)
return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company'));
}
- // Update the component data
- $component->asset_id = $request->input('asset_id');
- $component->assets()->attach($component->id, [
- 'component_id' => $component->id,
- 'created_by' => auth()->user()->id,
- 'created_at' => date('Y-m-d H:i:s'),
- 'assigned_qty' => $request->input('assigned_qty'),
- 'asset_id' => $request->input('asset_id'),
- 'note' => $request->input('note'),
- ]);
-
- event(new CheckoutableCheckedOut($component, $asset, auth()->user(), $request->input('note')));
+ $component->setLogQuantity($request->input('assigned_qty', 1));
+ $component->setLogTarget($asset);
+ $component->setLogNote($request->input('note'));
+ $component->checkInAndSave();
$request->request->add(['checkout_to_type' => 'asset']);
$request->request->add(['assigned_asset' => $asset->id]);
diff --git a/app/Http/Controllers/Components/ComponentsFilesController.php b/app/Http/Controllers/Components/ComponentsFilesController.php
index b5e30aa694fd..d57d577feab9 100644
--- a/app/Http/Controllers/Components/ComponentsFilesController.php
+++ b/app/Http/Controllers/Components/ComponentsFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Components;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
@@ -45,8 +46,11 @@ public function store(UploadFileRequest $request, $componentId = null)
foreach ($request->file('file') as $file) {
$file_name = $request->handleFile('private_uploads/components/','component-'.$component->id, $file);
+ $component->setLogFilename($file_name);
+ $component->setLogNote(e($request->input('notes')));
+ $component->logAndSaveIfNeeded(ActionType::Uploaded);
//Log the upload to the log
- $component->logUpload($file_name, e($request->input('notes')));
+ //$component->logUpload($file_name, e($request->input('notes')));
}
diff --git a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php
index e08da4122972..e35bdba7221e 100644
--- a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php
+++ b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php
@@ -74,13 +74,13 @@ public function store(Request $request, $consumableId)
if (!isset($quantity) || !ctype_digit((string)$quantity) || $quantity <= 0) {
$quantity = 1;
}
+ $consumable->setLogQuantity($quantity);
// Make sure there is at least one available to checkout
if ($consumable->numRemaining() <= 0 || $quantity > $consumable->numRemaining()) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable', ['requested' => $quantity, 'remaining' => $consumable->numRemaining() ]));
}
- $admin_user = auth()->user();
$assigned_to = e($request->input('assigned_to'));
// Check if the user exists
@@ -90,20 +90,10 @@ public function store(Request $request, $consumableId)
}
// Update the consumable data
- $consumable->assigned_to = e($request->input('assigned_to'));
-
- for ($i = 0; $i < $quantity; $i++){
- $consumable->users()->attach($consumable->id, [
- 'consumable_id' => $consumable->id,
- 'created_by' => $admin_user->id,
- 'assigned_to' => e($request->input('assigned_to')),
- 'note' => $request->input('note'),
- ]);
- }
-
- $consumable->checkout_qty = $quantity;
- event(new CheckoutableCheckedOut($consumable, $user, auth()->user(), $request->input('note')));
-
+ $consumable->setLogTarget($user);
+ $consumable->setLogNote($request->input('note'));
+ //$consumable->assigned_to = e($request->input('assigned_to'));
+ $consumable->checkoutAndSave();
$request->request->add(['checkout_to_type' => 'user']);
$request->request->add(['assigned_user' => $user->id]);
diff --git a/app/Http/Controllers/Consumables/ConsumablesFilesController.php b/app/Http/Controllers/Consumables/ConsumablesFilesController.php
index 545b008dc0b1..6ce171b0e14e 100644
--- a/app/Http/Controllers/Consumables/ConsumablesFilesController.php
+++ b/app/Http/Controllers/Consumables/ConsumablesFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Consumables;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
@@ -44,7 +45,10 @@ public function store(UploadFileRequest $request, $consumableId = null)
$file_name = $request->handleFile('private_uploads/consumables/','consumable-'.$consumable->id, $file);
//Log the upload to the log
- $consumable->logUpload($file_name, e($request->input('notes')));
+ $consumable->setLogFilename($file_name);
+ $consumable->setLogNote(e($request->input('notes')));
+ $consumable->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$consumable->logUpload($file_name, e($request->input('notes')));
}
diff --git a/app/Http/Controllers/Licenses/LicenseCheckinController.php b/app/Http/Controllers/Licenses/LicenseCheckinController.php
index 4197cf771ee8..de1cb070e59e 100644
--- a/app/Http/Controllers/Licenses/LicenseCheckinController.php
+++ b/app/Http/Controllers/Licenses/LicenseCheckinController.php
@@ -64,46 +64,27 @@ public function store(Request $request, $seatId = null, $backTo = null)
$this->authorize('checkout', $license);
- if (! $license->reassignable) {
+ if (!$license->reassignable) { // FIXME/TODO - should _this_ go into the checkin method? YES! No?
// Not allowed to checkin
Session::flash('error', trans('admin/licenses/message.checkin.not_reassignable') . '.');
return redirect()->back()->withInput();
}
- // Declare the rules for the form validation
- $rules = [
- 'notes' => 'string|nullable',
- ];
-
- // Create a new validator instance from our validation rules
- $validator = Validator::make($request->all(), $rules);
-
- // If validation fails, we'll exit the operation now.
- if ($validator->fails()) {
- // Ooops.. something went wrong
- return redirect()->back()->withInput()->withErrors($validator);
- }
-
if($licenseSeat->assigned_to != null){
- $return_to = User::find($licenseSeat->assigned_to);
+ $licenseSeat->setLogTarget(User::find($licenseSeat->assigned_to));
} else {
- $return_to = Asset::find($licenseSeat->asset_id);
+ $licenseSeat->setLogTarget(Asset::find($licenseSeat->asset_id));
}
- // Update the asset data
- $licenseSeat->assigned_to = null;
- $licenseSeat->asset_id = null;
- $licenseSeat->notes = $request->input('notes');
+ $licenseSeat->notes = $request->input('notes'); //huh. Weird.
+ $licenseSeat->setLogNote($request->input('notes')); //yeah, weird.
session()->put(['redirect_option' => $request->get('redirect_option')]);
// Was the asset updated?
- if ($licenseSeat->save()) {
- event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
-
-
+ if ($licenseSeat->checkInAndSave()) { //here is the thing - this becomes ->logAndSaveIfNeeded()
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkin.success'));
}
@@ -139,11 +120,11 @@ public function bulkCheckin(Request $request, $licenseId) {
->get();
foreach ($licenseSeatsByUser as $user_seat) {
- $user_seat->assigned_to = null;
+ $user_seat->assigned_to = null; //FIXME/TODO - is this already handled in the checkin method?
- if ($user_seat->save()) {
+ $user_seat->setLogNote(trans('admin/licenses/general.bulk.checkin_all.log_msg'));
+ if ($user_seat->checkInAndSave()) {
Log::debug('Checking in '.$license->name.' from user '.$user_seat->username);
- $user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
}
}
@@ -154,11 +135,11 @@ public function bulkCheckin(Request $request, $licenseId) {
$count = 0;
foreach ($licenseSeatsByAsset as $asset_seat) {
- $asset_seat->asset_id = null;
+ $asset_seat->asset_id = null; //FIXME/TODO - don't we have this already?
- if ($asset_seat->save()) {
+ $asset_seat->setLogNote(trans('admin/licenses/general.bulk.checkin_all.log_msg'));
+ if ($asset_seat->checkInAndSave()) {
Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag);
- $asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg'));
$count++;
}
}
diff --git a/app/Http/Controllers/Licenses/LicenseCheckoutController.php b/app/Http/Controllers/Licenses/LicenseCheckoutController.php
index 564ce97a8914..c5b998a92a9a 100644
--- a/app/Http/Controllers/Licenses/LicenseCheckoutController.php
+++ b/app/Http/Controllers/Licenses/LicenseCheckoutController.php
@@ -11,6 +11,7 @@
use App\Models\License;
use App\Models\LicenseSeat;
use App\Models\User;
+use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
@@ -69,32 +70,42 @@ public function store(LicenseCheckoutRequest $request, $licenseId, $seatId = nul
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
$licenseSeat->created_by = auth()->id();
- $licenseSeat->notes = $request->input('notes');
-
-
- $checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
+ $licenseSeat->notes = $request->input('notes'); //weird how this dupes. TODO - should this be part of the checkout method?
+ $licenseSeat->setLogNote($request->input('notes'));
if ($request->filled('asset_id')) {
+ if (is_null($target = Asset::find(request('asset_id')))) {
+ return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist'));
+ }
+ $licenseSeat->asset_id = request('asset_id');
+
+ // Override asset's assigned user if available
+ if ($target->checkedOutToUser()) {
+ $licenseSeat->assigned_to = $target->assigned_to;
+ }
- $checkoutTarget = $this->checkoutToAsset($licenseSeat);
- $request->request->add(['assigned_asset' => $checkoutTarget->id]);
+ $request->request->add(['assigned_asset' => $target->id]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
} elseif ($request->filled('assigned_to')) {
- $checkoutTarget = $this->checkoutToUser($licenseSeat);
- $request->request->add(['assigned_user' => $checkoutTarget->id]);
+ // Fetch the target and set the license user
+ if (is_null($target = User::find(request('assigned_to')))) {
+ return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist'));
+ }
+ $licenseSeat->assigned_to = request('assigned_to');
+
+ $request->request->add(['assigned_user' => $target->id]);
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
+ } else {
+ throw new \Exception("No valid checkout target for license");
}
-
-
- if ($checkoutTarget) {
+ $licenseSeat->setLogTarget($target);
+ if ($licenseSeat->checkOutAndSave()) {
return redirect()->to(Helper::getRedirectOption($request, $license->id, 'Licenses'))->with('success', trans('admin/licenses/message.checkout.success'));
}
-
-
- return redirect()->route('licenses.index')->with('error', trans('Something went wrong handling this checkout.'));
+ return redirect()->route('licenses.index')->with('error', trans('Something went wrong handling this checkout.')); //TODO - translate?
}
protected function findLicenseSeatToCheckout($license, $seatId)
@@ -103,54 +114,18 @@ protected function findLicenseSeatToCheckout($license, $seatId)
if (! $licenseSeat) {
if ($seatId) {
- throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.unavailable')));
+ throw new HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.unavailable')));
}
-
- throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
+
+ throw new HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')));
}
if (! $licenseSeat->license->is($license)) {
- throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
+ throw new HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch')));
}
return $licenseSeat;
}
-
- protected function checkoutToAsset($licenseSeat)
- {
- if (is_null($target = Asset::find(request('asset_id')))) {
- return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist'));
- }
- $licenseSeat->asset_id = request('asset_id');
-
- // Override asset's assigned user if available
- if ($target->checkedOutToUser()) {
- $licenseSeat->assigned_to = $target->assigned_to;
- }
- if ($licenseSeat->save()) {
- event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
- return $target;
- }
-
- return false;
- }
-
- protected function checkoutToUser($licenseSeat)
- {
- // Fetch the target and set the license user
- if (is_null($target = User::find(request('assigned_to')))) {
- return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist'));
- }
- $licenseSeat->assigned_to = request('assigned_to');
-
- if ($licenseSeat->save()) {
- event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes')));
- return $target;
- }
-
- return false;
- }
-
/**
* Bulk checkin all license seats
*
diff --git a/app/Http/Controllers/Licenses/LicenseFilesController.php b/app/Http/Controllers/Licenses/LicenseFilesController.php
index 6ab3cb7703aa..0588bd3c3470 100644
--- a/app/Http/Controllers/Licenses/LicenseFilesController.php
+++ b/app/Http/Controllers/Licenses/LicenseFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Licenses;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
@@ -39,7 +40,10 @@ public function store(UploadFileRequest $request, $licenseId = null)
$file_name = $request->handleFile('private_uploads/licenses/','license-'.$license->id, $file);
//Log the upload to the log
- $license->logUpload($file_name, e($request->input('notes')));
+ $license->setLogFilename($file_name);
+ $license->setLogNote(e($request->input('notes')));
+ $license->logAndSaveIfNeeded(ActionType::Uploaded);
+ //$license->logUpload($file_name, e($request->input('notes')));
}
diff --git a/app/Http/Controllers/LocationsController.php b/app/Http/Controllers/LocationsController.php
index a018b8a68ab9..14c2e9939920 100755
--- a/app/Http/Controllers/LocationsController.php
+++ b/app/Http/Controllers/LocationsController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
+use App\Enums\ActionType;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Asset;
@@ -266,12 +267,6 @@ public function postRestore($id) : RedirectResponse
}
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'));
}
diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php
index 985ec769fc5b..cdd8c779879d 100755
--- a/app/Http/Controllers/ManufacturersController.php
+++ b/app/Http/Controllers/ManufacturersController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
+use App\Enums\ActionType;
use App\Http\Requests\ImageUploadRequest;
use App\Models\Actionlog;
use App\Models\Manufacturer;
@@ -195,12 +196,6 @@ public function restore($id) : RedirectResponse
}
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
$deleted_manufacturers = Manufacturer::onlyTrashed()->count();
diff --git a/app/Http/Controllers/NotesController.php b/app/Http/Controllers/NotesController.php
index c5de66526e15..14d24e2a9b74 100644
--- a/app/Http/Controllers/NotesController.php
+++ b/app/Http/Controllers/NotesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
+use App\Enums\ActionType;
use App\Models\Actionlog;
use App\Models\Asset;
use Illuminate\Http\Request;
@@ -27,12 +28,8 @@ public function store(Request $request)
$this->authorize('update', $item);
- $logaction = new Actionlog;
- $logaction->item_id = $item->id;
- $logaction->item_type = get_class($item);
- $logaction->note = $validated['note'];
- $logaction->created_by = Auth::id();
- $logaction->logaction('note added');
+ $item->setLogNote($validated['note']);
+ $item->logAndSaveIfNeeded(ActionType::NoteAdded);
return redirect()
->route('hardware.show', $validated['id'])
diff --git a/app/Http/Controllers/Users/BulkUsersController.php b/app/Http/Controllers/Users/BulkUsersController.php
index 1909dd8214ad..d0fa1b5d0172 100644
--- a/app/Http/Controllers/Users/BulkUsersController.php
+++ b/app/Http/Controllers/Users/BulkUsersController.php
@@ -2,7 +2,7 @@
namespace App\Http\Controllers\Users;
-use App\Events\UserMerged;
+use App\Enums\ActionType;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Models\Accessory;
@@ -334,49 +334,50 @@ public function destroy(Request $request)
protected function logItemCheckinAndDelete($items, $itemType)
{
foreach ($items as $item) {
- $item_id = $item->id;
- $logAction = new Actionlog();
-
- if ($itemType == License::class){
- $item_id = $item->license_id;
+ if (gettype($item) == 'object' && get_class($item) != 'stdClass') {
+ $real_item = $item;
+ } else {
+ $item_id = $item->id;
+
+ if ($itemType == License::class) {
+ $item_id = $item->license_id; //FIXME - funkery happening here
+ $real_item = License::find($item->license_id);
+ } else {
+ $real_item = (new $itemType())::find($item_id);
+ }
+ }
+ if (property_exists($item, 'assigned_type')) {
+ $assigned_to = (new ($item->assigned_type))::find($item->assigned_to);
+ } else {
+ $assigned_to = User::find($item->assigned_to);
}
- $logAction->item_id = $item_id;
- // We can't rely on get_class here because the licenses/accessories fetched above are not eloquent models, but simply arrays.
- $logAction->item_type = $itemType;
- $logAction->target_id = $item->assigned_to;
- $logAction->target_type = User::class;
- $logAction->created_by = auth()->id();
- $logAction->note = 'Bulk checkin items';
- $logAction->logaction('checkin from');
+ $real_item->setLogTarget($assigned_to); // will this work?!!?!?!?
+ //$logAction->target_id = $item->assigned_to;
+ //$logAction->target_type = User::class;
+ $real_item->setLogNote('Bulk checkin items');
+ $real_item->setLogAction(ActionType::CheckinFrom);
+ $real_item->logAndSaveIfNeeded(ActionType::CheckinFrom);
}
}
private function logAccessoriesCheckin(Collection $accessoryUserRows): void
{
foreach ($accessoryUserRows as $accessoryUserRow) {
- $logAction = new Actionlog();
- $logAction->item_id = $accessoryUserRow->accessory_id;
- $logAction->item_type = Accessory::class;
- $logAction->target_id = $accessoryUserRow->assigned_to;
- $logAction->target_type = User::class;
- $logAction->created_by = auth()->id();
- $logAction->note = 'Bulk checkin items';
- $logAction->logaction('checkin from');
+ $accessory = Accessory::find($accessoryUserRow->accessory_id);
+ $accessory->setLogTarget(User::find($accessoryUserRow->assigned_to)); //FIXME - what if accessory was checked out to location?
+ $accessory->setLogNote('Bulk checkin items');
+ $accessory->logAndSaveIfNeeded(ActionType::CheckinFrom);
}
}
private function logConsumablesCheckin(Collection $consumableUserRows): void
{
foreach ($consumableUserRows as $consumableUserRow) {
- $logAction = new Actionlog();
- $logAction->item_id = $consumableUserRow->consumable_id;
- $logAction->item_type = Consumable::class;
- $logAction->target_id = $consumableUserRow->assigned_to;
- $logAction->target_type = User::class;
- $logAction->created_by = auth()->id();
- $logAction->note = 'Bulk checkin items';
- $logAction->logaction('checkin from');
+ $consumable = Consumable::find($consumableUserRow->consumable_id);
+ $consumable->setLogTarget(User::find($consumableUserRow->assigned_to));
+ $consumable->setLogNote('Bulk checkin items');
+ $consumable->logAndSaveIfNeeded(ActionType::CheckinFrom);
}
}
@@ -407,56 +408,11 @@ public function merge(Request $request)
// Get the users
$merge_into_user = User::find($request->input('merge_into_id'));
$users_to_merge = User::whereIn('id', $user_ids_to_merge)->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations','uploads', 'acceptances')->get();
- $admin = User::find(auth()->id());
// Walk users
foreach ($users_to_merge as $user_to_merge) {
-
- foreach ($user_to_merge->assets as $asset) {
- Log::debug('Updating asset: '.$asset->asset_tag . ' to '.$merge_into_user->id);
- $asset->assigned_to = $request->input('merge_into_id');
- $asset->save();
- }
-
- foreach ($user_to_merge->licenses as $license) {
- Log::debug('Updating license pivot: '.$license->id . ' to '.$merge_into_user->id);
- $user_to_merge->licenses()->updateExistingPivot($license->id, ['assigned_to' => $merge_into_user->id]);
- }
-
- foreach ($user_to_merge->consumables as $consumable) {
- Log::debug('Updating consumable pivot: '.$consumable->id . ' to '.$merge_into_user->id);
- $user_to_merge->consumables()->updateExistingPivot($consumable->id, ['assigned_to' => $merge_into_user->id]);
- }
-
- foreach ($user_to_merge->accessories as $accessory) {
- $user_to_merge->accessories()->updateExistingPivot($accessory->id, ['assigned_to' => $merge_into_user->id]);
- }
-
- foreach ($user_to_merge->userlog as $log) {
- $log->target_id = $merge_into_user->id;
- $log->save();
- }
-
- foreach ($user_to_merge->uploads as $upload) {
- $upload->item_id = $merge_into_user->id;
- $upload->save();
- }
-
- foreach ($user_to_merge->acceptances as $acceptance) {
- $acceptance->item_id = $merge_into_user->id;
- $acceptance->save();
- }
-
- User::where('manager_id', '=', $user_to_merge->id)->update(['manager_id' => $merge_into_user->id]);
-
- foreach ($user_to_merge->managedLocations as $managedLocation) {
- $managedLocation->manager_id = $merge_into_user->id;
- $managedLocation->save();
- }
-
- $user_to_merge->delete();
-
- event(new UserMerged($user_to_merge, $merge_into_user, $admin));
+ \Log::error("MERGING USER: ".$user_to_merge->username." into: ".$merge_into_user->username);
+ $merge_into_user->merge($user_to_merge);
}
diff --git a/app/Http/Controllers/Users/UserFilesController.php b/app/Http/Controllers/Users/UserFilesController.php
index 45bd0c6329d8..8cf216a13f77 100644
--- a/app/Http/Controllers/Users/UserFilesController.php
+++ b/app/Http/Controllers/Users/UserFilesController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Users;
+use App\Enums\ActionType;
use App\Helpers\StorageHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\UploadFileRequest;
@@ -34,17 +35,10 @@ public function store(UploadFileRequest $request, User $user)
$file_name = $request->handleFile('private_uploads/users/', 'user-'.$user->id, $file);
//Log the uploaded file to the log
- $logAction = new Actionlog();
- $logAction->item_id = $user->id;
- $logAction->item_type = User::class;
- $logAction->created_by = auth()->id();
- $logAction->note = $request->input('notes');
- $logAction->target_id = null;
- $logAction->created_at = date("Y-m-d H:i:s");
- $logAction->filename = $file_name;
- $logAction->action_type = 'uploaded';
-
- if (! $logAction->save()) {
+ $user->setLogFilename($file_name);
+ $user->setLogNote($request->input('notes'));
+
+ if (!$user->logAndSaveIfNeeded(ActionType::Uploaded)) {
return JsonResponse::create(['error' => 'Failed validation: '.print_r($logAction->getErrors(), true)], 500);
}
diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php
index 7610939114d9..8eb8a609c29f 100755
--- a/app/Http/Controllers/Users/UsersController.php
+++ b/app/Http/Controllers/Users/UsersController.php
@@ -2,6 +2,7 @@
namespace App\Http\Controllers\Users;
+use App\Enums\ActionType;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\DeleteUserRequest;
@@ -357,14 +358,8 @@ public function getRestore($id = null)
return redirect()->back()->with('error', trans('general.not_deleted', ['item_type' => trans('general.user')]));
}
+ $user->setLogAction(ActionType::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
$deleted_users = User::onlyTrashed()->count();
if ($deleted_users > 0) {
diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php
index bbff6ba4f77e..bf152fa5afbf 100755
--- a/app/Http/Controllers/ViewAssetsController.php
+++ b/app/Http/Controllers/ViewAssetsController.php
@@ -5,6 +5,7 @@
use App\Actions\CheckoutRequests\CancelCheckoutRequestAction;
use App\Actions\CheckoutRequests\CreateCheckoutRequestAction;
use App\Exceptions\AssetNotRequestable;
+use App\Enums\ActionType;
use App\Models\Actionlog;
use App\Models\Asset;
use App\Models\AssetModel;
@@ -96,17 +97,18 @@ public function getRequestItem(Request $request, $itemType, $itemId = null, $can
$user = auth()->user();
- $logaction = new Actionlog();
- $logaction->item_id = $data['asset_id'] = $item->id;
- $logaction->item_type = $fullItemType;
- $logaction->created_at = $data['requested_date'] = date('Y-m-d H:i:s');
-
+ //$logaction = new Actionlog();
+ //$logaction->item_id = $data['asset_id'] = $item->id;
+ //$logaction->item_type = $fullItemType;
+ //$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) {
- $logaction->location_id = $user->location_id;
+ $item->setLocation($user->location);
}
- $logaction->target_id = $data['user_id'] = auth()->id();
- $logaction->target_type = User::class;
+ $item->setLogTarget($user);
+ //$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['requested_by'] = $user->present()->fullName();
@@ -125,7 +127,7 @@ public function getRequestItem(Request $request, $itemType, $itemId = null, $can
if (($item_request = $item->isRequestedBy($user)) || $cancel_by_admin) {
$item->cancelRequest($requestingUser);
$data['item_quantity'] = ($item_request) ? $item_request->qty : 1;
- $logaction->logaction('request_canceled');
+ $item->logAndSaveIfNeeded(ActionType::RequestCanceled);
if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) {
$settings->notify(new RequestAssetCancelation($data));
@@ -133,9 +135,9 @@ public function getRequestItem(Request $request, $itemType, $itemId = null, $can
return redirect()->back()->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
} else {
- $item->request();
+ $item->request(); //!!!!!!!!!!!!!
if (($settings->alert_email != '') && ($settings->alerts_enabled == '1') && (! config('app.lock_passwords'))) {
- $logaction->logaction('requested');
+ $item->logAndSaveIfNeeded(ActionType::Requested);
$settings->notify(new RequestAssetNotification($data));
}
@@ -149,16 +151,68 @@ public function getRequestItem(Request $request, $itemType, $itemId = null, $can
*/
public function store(Asset $asset): RedirectResponse
{
+ /*
+ //"new way" - maybe this is better?
+ try {
+ CreateCheckoutRequestAction::run($asset, auth()->user());
+ return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
+ } catch (AssetNotRequestable $e) {
+ return redirect()->back()->with('error', 'Asset is not requestable');
+ } catch (AuthorizationException $e) {
+ return redirect()->back()->with('error', trans('admin/hardware/message.requests.error'));
+ } catch (Exception $e) {
+ report($e);
+ return redirect()->back()->with('error', trans('general.something_went_wrong'));
+ }
+ */
+ $user = auth()->user();
+
+ // Check if the asset exists and is requestable
+ if ($asset->requestable) { // FIXME - too simplistic, might need to fold in some kind of scopeRequestableAssets bit here?
+ return redirect()->route('requestable-assets')
+ ->with('error', trans('admin/hardware/message.does_not_exist_or_not_requestable'));
+ }
+ if (!Company::isCurrentUserHasAccess($asset)) {
+ return redirect()->route('requestable-assets')
+ ->with('error', trans('general.insufficient_permissions'));
+ }
+
+ $data['item'] = $asset;
+ $data['target'] = auth()->user();
+ $data['item_quantity'] = 1;
+ $settings = Setting::getSettings();
+
+ //$logaction = new Actionlog();
+ $data['asset_id'] = $asset->id;
+ $data['item_type'] = Asset::class;
+ $data['requested_date'] = date('Y-m-d H:i:s');
+
+ $asset->setLocation = $user->location;
+ $asset->setLogTarget($user);
+ $data['user_id'] = auth()->id();
+
+ // If it's already requested, cancel the request.
+ if ($asset->isRequestedBy(auth()->user())) {
+ $asset->cancelRequest(); //wait, what?
+ $asset->decrement('requests_counter', 1); //this too
+
+ $asset->logAndSaveIfNeeded(ActionType::RequestCanceled);
+ try {
+ $settings->notify(new RequestAssetCancelation($data)); //and probably this
+ } catch (\Exception $e) {
+ Log::warning($e);
+ }
+ return redirect()->route('requestable-assets')
+ ->with('success')->with('success', trans('admin/hardware/message.requests.canceled'));
+ }
+
+ $asset->logAndSaveIfNeeded(ActionType::Requested); //ARGH
+ $asset->request(); //HERE <-
+ $asset->increment('requests_counter', 1); //ARGH
try {
- CreateCheckoutRequestAction::run($asset, auth()->user());
- return redirect()->route('requestable-assets')->with('success')->with('success', trans('admin/hardware/message.requests.success'));
- } catch (AssetNotRequestable $e) {
- return redirect()->back()->with('error', 'Asset is not requestable');
- } catch (AuthorizationException $e) {
- return redirect()->back()->with('error', trans('admin/hardware/message.requests.error'));
- } catch (Exception $e) {
- report($e);
- return redirect()->back()->with('error', trans('general.something_went_wrong'));
+ $settings->notify(new RequestAssetNotification($data)); // ANd this.
+ } catch (\Exception $e) {
+ Log::warning($e);
}
}
diff --git a/app/Importer/AssetImporter.php b/app/Importer/AssetImporter.php
index 1112a04e3508..23214f709430 100644
--- a/app/Importer/AssetImporter.php
+++ b/app/Importer/AssetImporter.php
@@ -3,9 +3,11 @@
namespace App\Importer;
use App\Models\Asset;
+use App\Models\Location;
use App\Models\Statuslabel;
use App\Models\User;
use App\Events\CheckoutableCheckedIn;
+use Carbon\Carbon;
use Illuminate\Support\Facades\Crypt;
class AssetImporter extends ItemImporter
@@ -155,11 +157,11 @@ public function createAssetIfNotExists(array $row)
$item['asset_eol_date'] = $this->parseOrNullDate('asset_eol_date');
}
-
+ //dump($item);
if ($editingAsset) {
- $asset->update($item);
+ $asset->update($item); // FIXME - I don't know why this is happening like that?
} else {
- $asset->fill($item);
+ $asset->fill($item); // FIXME - this is wrong, and always has been wrong. ->except(['assigned_to','assigned_type' /* or something? */])
}
// If we're updating, we don't want to overwrite old fields.
@@ -181,12 +183,24 @@ public function createAssetIfNotExists(array $row)
//-- the class that needs to use it (command importer or GUI importer inside the project).
if (isset($target) && ($target !== false)) {
if (!is_null($asset->assigned_to)){
- if ($asset->assigned_to != $target->id) {
- event(new CheckoutableCheckedIn($asset, User::find($asset->assigned_to), auth()->user(), 'Checkin from CSV Importer', $checkin_date));
+ //asset was already checked out to a different target (or different target _class_ )
+ //TODO - can we add a test around this? Checking out from location_id 7 to user_id 7 would've not caused a checkin before.
+ if ($asset->assigned_to != $target->id || $asset->assigned_Type != $target::class) {
+ //$asset->setLogTarget($target); //FIXME: não preciso - é mau
+ $asset->setLogNote('Checkin from CSV Importer');
+ $asset->setLogDate(new Carbon($checkin_date));
+ $asset->saveAndCheckin();
}
}
-
- $asset->fresh()->checkOut($target, $this->created_by, $checkout_date, null, 'Checkout from CSV Importer', $asset->name);
+ $asset->refresh();
+ $asset->setLogTarget($target);
+ $asset->setLogNote('Checkout from CSV Importer');
+ $asset->setLogDate(new Carbon($checkout_date));
+ if ($this->item['location_id']) {
+ //$asset->setLogLocationOverride(Location::find($this->item['location_id']));
+ }
+ $asset->checkOutAndSave();
+ //$asset->fresh()->checkOut($target, $this->created_by, $checkout_date, null, 'Checkout from CSV Importer', $asset->name);
}
return;
diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php
index 0d4b8d493290..a051771c767b 100644
--- a/app/Importer/Importer.php
+++ b/app/Importer/Importer.php
@@ -374,7 +374,7 @@ protected function createOrFetchUser($row, $type = 'user')
$user->activated = 1;
$user->password = $this->tempPassword;
- Log::debug('Creating a user with the following attributes: '.print_r($user_array, true));
+ Log::error('Creating a user with the following attributes: '.print_r($user_array, true)); //FIXME - put back to debug
if ($user->save()) {
$this->log('User '.$user_array['username'].' created');
diff --git a/app/Importer/ItemImporter.php b/app/Importer/ItemImporter.php
index 435f081aba2a..90dc985f6d09 100644
--- a/app/Importer/ItemImporter.php
+++ b/app/Importer/ItemImporter.php
@@ -101,7 +101,7 @@ protected function handle($row)
$this->item['checkout_class'] = $this->findCsvMatch($row, 'checkout_class');
if (get_class($this) !== UserImporter::class) {
// $this->item["user"] = $this->createOrFetchUser($row);
- $this->item['checkout_target'] = $this->determineCheckout($row);
+ $this->item['checkout_target'] = $this->determineCheckout($row); //BERZINGOES?!
}
}
diff --git a/app/Listeners/LogListener.php b/app/Listeners/LogListener.php
deleted file mode 100644
index 27a9168484b1..000000000000
--- a/app/Listeners/LogListener.php
+++ /dev/null
@@ -1,156 +0,0 @@
-checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date, $event->originalValues);
- }
-
- /**
- * These onBlah methods are used by the subscribe() method further down in this file.
- * This one creates an action_logs entry for the checkout
- *
- * @param CheckoutableCheckedOut $event
- * @return void
- *
- */
- public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event)
- {
- $event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout, $event->originalValues);
- }
-
- /**
- * These onBlah methods are used by the subscribe() method further down in this file.
- * This creates the entry in the action_logs table for the accept/decline action
- */
- public function onCheckoutAccepted(CheckoutAccepted $event)
- {
-
- Log::debug('event passed to the onCheckoutAccepted listener:');
- $logaction = new Actionlog();
- $logaction->item()->associate($event->acceptance->checkoutable);
- $logaction->target()->associate($event->acceptance->assignedTo);
- $logaction->accept_signature = $event->acceptance->signature_filename;
- $logaction->filename = $event->acceptance->stored_eula_file;
- $logaction->note = $event->acceptance->note;
- $logaction->action_type = 'accepted';
-
- // TODO: log the actual license seat that was checked out
- if ($event->acceptance->checkoutable instanceof LicenseSeat) {
- $logaction->item()->associate($event->acceptance->checkoutable->license);
- }
-
- $logaction->save();
- }
-
- public function onCheckoutDeclined(CheckoutDeclined $event)
- {
- $logaction = new Actionlog();
- $logaction->item()->associate($event->acceptance->checkoutable);
- $logaction->target()->associate($event->acceptance->assignedTo);
- $logaction->accept_signature = $event->acceptance->signature_filename;
- $logaction->note = $event->acceptance->note;
- $logaction->action_type = 'declined';
-
- // TODO: log the actual license seat that was checked out
- if ($event->acceptance->checkoutable instanceof LicenseSeat) {
- $logaction->item()->associate($event->acceptance->checkoutable->license);
- }
-
- $logaction->save();
- }
-
-
- public function onUserMerged(UserMerged $event)
- {
-
- $to_from_array = [
- 'to_id' => $event->merged_to->id,
- 'to_username' => $event->merged_to->username,
- 'from_id' => $event->merged_from->id,
- 'from_username' => $event->merged_from->username,
- ];
-
- // Add a record to the users being merged FROM
- Log::debug('Users merged: '.$event->merged_from->id .' ('.$event->merged_from->username.') merged into '. $event->merged_to->id. ' ('.$event->merged_to->username.')');
- $logaction = new Actionlog();
- $logaction->item_id = $event->merged_from->id;
- $logaction->item_type = User::class;
- $logaction->target_id = $event->merged_to->id;
- $logaction->target_type = User::class;
- $logaction->action_type = 'merged';
- $logaction->note = trans('general.merged_log_this_user_from', $to_from_array);
- $logaction->created_by = $event->admin->id ?? null;
- $logaction->save();
-
- // Add a record to the users being merged TO
- $logaction = new Actionlog();
- $logaction->target_id = $event->merged_from->id;
- $logaction->target_type = User::class;
- $logaction->item_id = $event->merged_to->id;
- $logaction->item_type = User::class;
- $logaction->action_type = 'merged';
- $logaction->note = trans('general.merged_log_this_user_into', $to_from_array);
- $logaction->created_by = $event->admin->id ?? null;
- $logaction->save();
-
-
- }
-
- /**
- * Register the listeners for the subscriber.
- *
- * @param Illuminate\Events\Dispatcher $events
- */
- public function subscribe($events)
- {
- $list = [
- 'CheckoutableCheckedIn',
- 'CheckoutableCheckedOut',
- 'CheckoutAccepted',
- 'CheckoutDeclined',
- 'UserMerged',
- 'NoteAdded',
- ];
-
- foreach ($list as $event) {
- $events->listen(
- 'App\Events\\'.$event,
- 'App\Listeners\LogListener@on'.$event
- );
- }
- }
-
-
-}
diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php
index fc1bb36ab40d..1516eccc1e70 100755
--- a/app/Models/Accessory.php
+++ b/app/Models/Accessory.php
@@ -2,10 +2,15 @@
namespace App\Models;
+use App\Enums\ActionType;
+use App\Events\CheckoutableCheckedIn;
+use App\Events\CheckoutableCheckedOut;
use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
+use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Storage;
@@ -297,6 +302,47 @@ public function manufacturer()
return $this->belongsTo(\App\Models\Manufacturer::class, 'manufacturer_id');
}
+ public function checkInAndSave(): bool
+ {
+ //FIXME - emit checkoutablecheckedin?
+ //TODO - begin?
+ \Log::error("in accessory checkin method");
+ $accessory_checkout = AccessoryCheckout::find($this->getLogTarget()->id);
+ //dump($accessory_checkout);
+ //now, we twiddle logTarget to be the user (or location) of the AccessoryCheckout
+ $this->setLogTarget($accessory_checkout->assignedTo);
+ //dump($accessory_checkout->assignedTo); //this is what you expect
+ $accessory_checkout->delete();
+ event(new CheckoutableCheckedIn($this, $accessory_checkout->assignedTo, auth()->user(), $this->getLogNote(), $this->getLogDate()));
+ return $this->logAndSaveIfNeeded(ActionType::CheckinFrom);
+ //TODO - COMMIT?
+ }
+
+ public function checkOutAndSave(): bool
+ {
+ //FIXME - what if there are _more_ checkotus than there are availabliieties?
+ for ($i = 0; $i < $this->getLogQuantity() ?? 1; $i++) {
+ \Log::error("DOING A CHECKOUTS!!! - $i");
+ $accessory_checkout = new AccessoryCheckout([
+ 'accessory_id' => $this->id,
+ 'created_at' => Carbon::now(),
+ 'assigned_to' => $this->getLogTarget()->id,
+ 'assigned_type' => $this->getLogTarget()::class,
+ 'note' => $this->getLogNote(),
+ ]);
+
+ $accessory_checkout->created_by = auth()->id();
+ $accessory_checkout->save();
+ }
+ \Log::error("Done doing checkouts now");
+ if ($this->logAndSaveIfNeeded(ActionType::Checkout)) {
+ event(new CheckoutableCheckedOut($this, $this->getLogTarget(), auth()->user(), $this->getLogNote()));
+ return true;
+ }
+ return false;
+
+ }
+
/**
* Determins whether or not an email should be sent for checkin/checkout of this
* accessory based on the category it belongs to.
diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php
index 3a8fcf1cb9f6..7889973a2085 100755
--- a/app/Models/Actionlog.php
+++ b/app/Models/Actionlog.php
@@ -262,27 +262,6 @@ public function get_src($type = 'assets', $fieldname = 'filename')
return false;
}
- /**
- * Saves the log record with the action type
- *
- * @author [A. Gianotto] []
- * @since [v3.0]
- * @return bool
- */
- public function logaction($actiontype)
- {
- $this->action_type = $actiontype;
- $this->remote_ip = request()->ip();
- $this->user_agent = request()->header('User-Agent');
- $this->action_source = $this->determineActionSource();
-
- if ($this->save()) {
- return true;
- } else {
- return false;
- }
- }
-
/**
* Calculate the number of days until the next audit
*
@@ -346,42 +325,6 @@ public function getListingOfActionLogsChronologicalOrder()
->get();
}
- /**
- * Determines what the type of request is so we can log it to the action_log
- *
- * @author A. Gianotto
- * @since v6.3.0
- * @return string
- */
- public function determineActionSource(): string
- {
- // This is a manually set source
- if($this->source) {
- return $this->source;
- }
-
- // This is an API call
- if (((request()->header('content-type') && (request()->header('accept'))=='application/json'))
- && (starts_with(request()->header('authorization'), 'Bearer '))) {
- return 'api';
- }
-
- // This is probably NOT an API call
- if (request()->filled('_token')) {
- return 'gui';
- }
-
- // We're not sure, probably cli
- return 'cli/unknown';
-
- }
-
- // Manually sets $this->source for determineActionSource()
- public function setActionSource($source = null): void
- {
- $this->source = $source;
- }
-
public function scopeOrderByCreatedBy($query, $order)
{
return $query->leftJoin('users as admin_sort', 'action_logs.created_by', '=', 'admin_sort.id')->select('action_logs.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
diff --git a/app/Models/Asset.php b/app/Models/Asset.php
index 673012cf68e6..7876c919ca19 100644
--- a/app/Models/Asset.php
+++ b/app/Models/Asset.php
@@ -2,24 +2,25 @@
namespace App\Models;
+use App\Enums\ActionType;
+use App\Events\CheckoutableCheckedIn;
use App\Events\CheckoutableCheckedOut;
use App\Exceptions\CheckoutNotAllowed;
use App\Helpers\Helper;
use App\Http\Traits\UniqueUndeletedTrait;
use App\Models\Traits\Acceptable;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
-use App\Presenters\Presentable;
use App\Presenters\AssetPresenter;
-use Illuminate\Support\Facades\Auth;
+use App\Presenters\Presentable;
use Carbon\Carbon;
-use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
-use Illuminate\Database\Eloquent\Casts\Attribute;
-use Illuminate\Database\Eloquent\Model;
/**
* Model for Assets.
@@ -41,6 +42,66 @@ class Asset extends Depreciable
use Acceptable;
+ public static function boot()
+ {
+ // handle incrementing of asset tags
+ self::created(function ($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) {
+ // determine if calculated eol and then calculate it - this should only happen on a new asset
+ //\Log::error("Asset RAW array: ".print_r($asset->toArray(), true));
+ if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && ($asset->model?->eol > 0)) { //FIXME - I shouldn't have to do this.
+ $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
*
@@ -312,77 +373,117 @@ public function availableForCheckout()
return false;
}
-
/**
- * Checks the asset out to the target
- *
- * @todo The admin parameter is never used. Can probably be removed.
- *
- * @author [A. Gianotto] []
- * @param User $user
- * @param User $admin
- * @param Carbon $checkout_at
- * @param Carbon $expected_checkin
- * @param string $note
- * @param null $name
- * @return bool
- * @since [v3.0]
+ * Checks out asset to previously-set target
* @return bool
+ * @throws CheckoutNotAllowed
+ * @throws \Illuminate\Database\Eloquent\ModelNotFoundException
*/
- public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null)
+ public function checkOutAndSave(): bool
{
- if (! $target) {
+ \Log::error("checkout and save has fired!!!!!!");
+ if (!$this->getLogTarget()) {
+ \Log::error("NO TARGET SET FOR CHECKOUT!");
+ throw new \Exception("NO TARGET SET FOR CHECKOUT!"); //TODO - use a first-class Exception?
return false;
}
- if ($this->is($target)) {
+ if ($this->is($this->getLogTarget())) {
throw new CheckoutNotAllowed('You cannot check an asset out to itself.');
}
- if ($expected_checkin) {
- $this->expected_checkin = $expected_checkin;
- }
+ $this->last_checkout = $this->getLogDate();
- $this->last_checkout = $checkout_at;
- $this->name = $name;
+ $this->assignedTo()->associate($this->getLogTarget());
- $this->assignedTo()->associate($target);
- if ($location != null) {
- $this->location_id = $location;
+ \Log::error("managed to at least associate the target (maybe?)");
+ //if ($location != null) { //STET - this is Asset logic.
+ // $this->location_id = $location;
+ //} else {
+ //if (isset($this->getLogTarget()->location)) { // FIXME okay, I think this is failing when the logTarget() has a location, but it's null?
+ // $this->location_id = $this->getLogTarget()->location->id;
+ //}
+ if ($this->getLogTarget() instanceof Location) {
+ $this->location_id = $this->getLogTarget()->id;
} else {
- if (isset($target->location)) {
- $this->location_id = $target->location->id;
- }
- if ($target instanceof Location) {
- $this->location_id = $target->id;
+ //FIXME or validate this - this is *WEIRD*
+ $this->location_id = $this->getLogTarget()->location?->id;
+ if (!$this->location_id && $this->assigned_type == Asset::class) {
+ //TODO - this is SUPER weird. We only do this for _assets_ assigned to _assets_ without a location set?
+ // But not for other cases? I don't know that I get it.
+ //handle assets checked out to assets that have no location, but an rtd_location_id
+ //FIXME - jankinated
+ // I _think_ this is failing on 'checkout to assets without a location set'
+ //I'm going to guess it's an asset checkout to an asset?
+ $this->location_id = $this->getLogTarget()->rtd_location_id; //FIXME - this is *WEIRD*
+ //FIXME - I'm commenting that line out for a minute, I'm not sure it's right?
+ } elseif (!$this->location_id) {
+ //uh, okay, so now this is for - there is still no location_id, but we're not dealing with being checked out to an asset?
+ $this->location_id = $this->rtd_location_id; //I guess?! I mean, that's how it works now...FIXME or TODO or at least DOCUMENT
}
}
+ //}
- $originalValues = $this->getRawOriginal();
-
+ //checkout_at is action_date.
// attempt to detect change in value if different from today's date
- if ($checkout_at && strpos($checkout_at, date('Y-m-d')) === false) {
- $originalValues['action_date'] = date('Y-m-d H:i:s');
+ //if ($checkout_at && strpos($checkout_at, date('Y-m-d')) === false) {
+ // $originalValues['action_date'] = date('Y-m-d H:i:s'); //FIXME - not being respected
+ //}
+
+ //FIXME - this isn't going to be transactionally safe I don't think. Even if we do a 'fresh()' or 'refresh()' or whatever
+ //TODO - idea - we save the things we want to increment in a table, and _Then_ execute those within the transaction?
+ //That oughtta work - esp. if we can say `SET checkout_counter = checkout_counter + 1`
+ // which would, totally, do the trick
+ $this->checkout_counter = $this->checkout_counter ? $this->checkout_counter + 1 : 1;
+
+ if ($this->logAndSaveIfNeeded(ActionType::Checkout)) { //in all likelihood, this is going to translate to a 'save()', but just in case...
+ //TODO - what to do with this 'admin' thing?
+ //if (is_int($admin)) {
+ // $checkedOutBy = User::findOrFail($admin);
+ //} elseif ($admin && get_class($admin) === \App\Models\User::class) {
+ // $checkedOutBy = $admin;
+ //} else {
+ // $checkedOutBy = auth()->user();
+ //}
+ // FIXME - I'm not sure of the 'general solution' for if there's no autheenticated user (CLI?)
+ event(new CheckoutableCheckedOut($this, $this->getLogTarget(), $this->getLogAdmin(), $this->getLogNote()));
+ return true;
}
- if ($this->save()) {
- if (is_int($admin)) {
- $checkedOutBy = User::findOrFail($admin);
- } elseif ($admin && get_class($admin) === \App\Models\User::class) {
- $checkedOutBy = $admin;
- } else {
- $checkedOutBy = auth()->user();
- }
- event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note, $originalValues));
+ return false;
+ }
+
+ public function checkInAndSave(): bool
+ {
+ //FIXME - how does this fit into a transaction?
+ $this->licenseseats->each(function (LicenseSeat $seat) {
+ $seat->update(['assigned_to' => null]);
+ });
- $this->increment('checkout_counter', 1);
+ $asset_id = $this->id;
+ // Get all pending Acceptances for this asset and delete them
+ $acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
+ [Asset::class],
+ function (Builder $query) use ($asset_id) {
+ $query->where('id', $asset_id);
+ })->get();
+ $acceptances->map(function ($acceptance) {
+ $acceptance->delete();
+ });
+ if ($this->logAndSaveIfNeeded(ActionType::CheckinFrom)) {
+ \Log::error("EMITTING EVENT NOW!!!!!!!!!");
+ $results = event(new CheckoutableCheckedIn($this, $this->getLogTarget(), Auth::user(), $this->getLogNote(), $this->getLogDate()));
+ //dump($results);
+ //if (!$results) {
+ // \Log::error("BIG WARN TIME - no results");
+ //}
return true;
+ } else {
+ \Log::error("FAILED TO EMIT EVENT!!!!");
+ return false;
}
-
- return false;
}
-
/**
* Sets the detailedNameAttribute
*
diff --git a/app/Models/AssetModel.php b/app/Models/AssetModel.php
index 8d60474b9622..e6375ff00ee7 100755
--- a/app/Models/AssetModel.php
+++ b/app/Models/AssetModel.php
@@ -2,15 +2,16 @@
namespace App\Models;
+use App\Http\Traits\TwoColumnUniqueUndeletedTrait;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
+use App\Presenters\AssetModelPresenter;
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;
-use \App\Presenters\AssetModelPresenter;
-use App\Http\Traits\TwoColumnUniqueUndeletedTrait;
/**
* Model for Asset Models. Asset Models contain higher level
diff --git a/app/Models/Component.php b/app/Models/Component.php
index d9277d7da7d1..bfc37266ea27 100644
--- a/app/Models/Component.php
+++ b/app/Models/Component.php
@@ -2,11 +2,18 @@
namespace App\Models;
+use App\Enums\ActionType;
+use App\Events\CheckoutableCheckedIn;
+use App\Events\CheckoutableCheckedOut;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
+use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Log;
use Watson\Validating\ValidatingTrait;
/**
@@ -104,6 +111,98 @@ class Component extends SnipeModel
'manufacturer' => ['name'],
];
+ public function checkOutAndSave()
+ {
+ //FIXME - can we emit some kind of error *here* if you don't have enough? A validation error, maybe?
+ // I think it wants to be *here* and not in the controller; the controller shouldn't need to know
+ // the explicit business logic behind which checkouts will, and will not, fail. No?
+ //$this->assigned_to = $this->getLogTarget()->id; //huh? FIXME or TODO or SOMETHING? Why are we assigning a single component's assigned_to, when we have the 'attach' method?
+ $this->assets()->attach($this->id,
+ [ // TODO - this feels a little duplicative... we say this->id multiple times
+ 'component_id' => $this->id,
+ 'created_at' => Carbon::now(),
+ 'assigned_qty' => $this->getLogQuantity(),
+ 'created_by' => auth()->id(),
+ 'asset_id' => $this->getLogTarget()->id,
+ 'note' => $this->getLogNote(),
+ ]
+ );
+ //huh. something about location_id here? I don't think we're doing that.
+
+ if ($this->logAndSaveIfNeeded(ActionType::Checkout)) {
+ // TODO/FIXME - emit checkoutableCheckedOut here?
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public function checkinAndSave()
+ {
+ //TODO - throw validation error if quantity is wrong?
+ //TODO/FIXME - transaction?
+ // Update the component data
+ // Validation passed, so let's figure out what we have to do here.
+ /* dupe - same logic ?
+ // Validation passed, so let's figure out what we have to do here.
+ $qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty', 1));
+
+ // We have to modify the record to reflect the new qty that's
+ // actually checked out.
+ $component_assets->assigned_qty = $qty_remaining_in_checkout; //whoa, whoa, whoa - we definitely don't want to do this here. And I'm not sure we do the opposite in 'checkout'
+
+ Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id);
+
+ DB::table('components_assets')->where('id', $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
+
+ // If the checked-in qty is exactly the same as the assigned_qty,
+ // we can simply delete the associated components_assets record
+ if ($qty_remaining_in_checkout === 0) {
+ DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
+ }
+
+ $asset = Asset::find($component_assets->asset_id);
+
+ event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
+ */
+ $component_asset_id = $this->getLogTarget()->id; //EWWWWWW GROSSSSSS!!!! FIXME
+ \Log::error("ASSIGNED QUANTITY IS: ".$this->getLogTarget()->assigned_qty." and log quantity is: ".$this->getLogQuantity());
+
+ $qty_remaining_in_checkout = ($this->getLogTarget()->assigned_qty - (int) $this->getLogQuantity());
+
+ // We have to modify the record to reflect the new qty that's
+ // actually checked out.
+ //$component_asset->assigned_qty = $qty_remaining_in_checkout; //why is this needed? Is it? FIXME TODO
+
+ // If the checked-in qty is exactly the same as the assigned_qty,
+ // we can simply delete the associated components_assets record
+ if ($qty_remaining_in_checkout == 0) {
+ \Log::error("ZERO QUANTITY REMAINING _ DELETING RECORD! (for id: $component_asset_id)");
+ DB::table('components_assets')->where('id', '=', $component_asset_id)->delete();
+ } else {
+ \Log::error("Non-Zero quantity remaining ($qty_remaining_in_checkout) - updating record in-place");
+ DB::table('components_assets')->where('id',
+ $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]);
+ }
+ $this->setLogTarget(Asset::find($this->getLogTarget()->asset_id)); //TODO - this 'thunk' from one class to another is weird, but we do do it elsewhere too.
+ //$this->asset_id = $this->getLogTarget()->asset_id; //WEIRD . yeah. and fails.
+ //$this->assets()->attach($this->id, [
+ // 'component_id' => $this->id,
+ // 'created_by' => auth()->user()->id,
+ // 'created_at' => $this->getLogDate(), //TODO - this is a cahnge, is it OK?
+ // 'assigned_qty' => $this->getLogQuantity(),
+ // 'asset_id' => $this->getLogTarget()->id,
+ // 'note' => $this->getLogNote(),
+ //]); WTAF was this doing here?! DELETE ME.
+ if ($this->logAndSaveIfNeeded(ActionType::CheckinFrom)) {
+ event(new CheckoutableCheckedIn($this, $this->getLogTarget(), auth()->user(), $this->getLogNote()));
+ return true;
+ } else {
+ return false;
+ }
+
+ }
+
public function isDeletable()
{
diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php
index 30161e84296a..e636ceb78805 100644
--- a/app/Models/Consumable.php
+++ b/app/Models/Consumable.php
@@ -2,23 +2,20 @@
namespace App\Models;
+use App\Enums\ActionType;
+use App\Events\CheckoutableCheckedOut;
use App\Helpers\Helper;
use App\Models\Traits\Acceptable;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
+use App\Presenters\ConsumablePresenter;
use App\Presenters\Presentable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\SoftDeletes;
+use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Watson\Validating\ValidatingTrait;
-use Illuminate\Database\Eloquent\Relations\Relation;
-use App\Presenters\ConsumablePresenter;
-use App\Models\Actionlog;
-use App\Models\ConsumableAssignment;
-use App\Models\User;
-use App\Models\Location;
-use App\Models\Manufacturer;
-use App\Models\Supplier;
-use App\Models\Category;
class Consumable extends SnipeModel
{
@@ -54,6 +51,34 @@ class Consumable extends SnipeModel
'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
* validation rules before attempting validation. If this property
@@ -271,6 +296,32 @@ public function supplier()
return $this->belongsTo(Supplier::class, 'supplier_id');
}
+ public function checkoutAndSave()
+ {
+ \Log::error("CHECKOUT AND SAVE - hey i wonder what the log quantity is? :".$this->getLogQuantity());
+ // FIXME - no quantity checking; you can ask for whatever you want and possibly get it.
+ for ($i = 0; $i < $this->getLogQuantity(); $i++) {
+ \Log::error("ATTACHING consumable #$i");
+ $this->users()->attach($this->id, [
+ 'consumable_id' => $this->id,
+ 'created_by' => auth()->user()->id,
+ 'assigned_to' => $this->getLogTarget()->id,
+ 'note' => $this->getLogNote(),
+ ]);
+ }
+ //dump($this->users);
+
+ //$consumable->checkout_qty = $quantity; //this is stupid, but, well, it used to be there. DELETE ME FIXME
+ if ($this->logAndSaveIfNeeded(ActionType::Checkout)) {
+ event(new CheckoutableCheckedOut($this, $this->getLogTarget(), auth()->user(), $this->getLogNote()));
+ return true;
+ } else {
+ \Log::error("FAILED to checkout consumable!");
+ return false;
+ }
+
+ }
+
/**
* Determine whether to send a checkin/checkout email based on
diff --git a/app/Models/License.php b/app/Models/License.php
index 0997c1e57b99..7cfaa2fb1be3 100755
--- a/app/Models/License.php
+++ b/app/Models/License.php
@@ -3,15 +3,16 @@
namespace App\Models;
use App\Helpers\Helper;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
use Carbon\Carbon;
-use Illuminate\Support\Facades\DB;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
-use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Session;
use Watson\Validating\ValidatingTrait;
+use App\Enums\ActionType;
class License extends Depreciable
{
@@ -180,13 +181,8 @@ public static function adjustSeatCount($license, $oldSeats, $newSeats)
$seatsAvailableForDelete->pop()->delete();
}
// Log Deletion of seats.
- $logAction = new Actionlog;
- $logAction->item_type = self::class;
- $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');
+ $license->setLogNote("deleted {$change} seats");
+ $license->logAndSaveIfNeeded(ActionType::DeleteSeats);
return true;
}
@@ -212,13 +208,8 @@ public static function adjustSeatCount($license, $oldSeats, $newSeats)
// On initial create, we shouldn't log the addition of seats.
if ($license->id) {
//Log the addition of license to the log.
- $logAction = new Actionlog();
- $logAction->item_type = self::class;
- $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');
+ $license->setLogNote("added {$change} seats");
+ $license->logAndSaveIfNeeded(ActionType::AddSeats);
}
return true;
diff --git a/app/Models/LicenseSeat.php b/app/Models/LicenseSeat.php
index 397a14146870..840dcac7bc66 100755
--- a/app/Models/LicenseSeat.php
+++ b/app/Models/LicenseSeat.php
@@ -2,7 +2,11 @@
namespace App\Models;
+use App\Enums\ActionType;
+use App\Events\CheckoutableCheckedIn;
+use App\Events\CheckoutableCheckedOut;
use App\Models\Traits\Acceptable;
+use App\Models\Traits\Loggable;
use App\Notifications\CheckinLicenseNotification;
use App\Notifications\CheckoutLicenseNotification;
use App\Presenters\Presentable;
@@ -95,6 +99,27 @@ public function asset()
return $this->belongsTo(\App\Models\Asset::class, 'asset_id')->withTrashed();
}
+ public function checkInAndSave(): bool
+ {
+ // Update the asset data
+ $this->assigned_to = null;
+ $this->asset_id = null;
+ if ($this->logAndSaveIfNeeded(ActionType::CheckinFrom)) {
+ event(new CheckoutableCheckedIn($this, $this->getLogTarget(), auth()->user(), $this->getLogNote()));
+ return true;
+ }
+ return false;
+ }
+
+ public function checkOutAndSave()
+ {
+ if ($this->logAndSaveIfNeeded(ActionType::Checkout)) {
+ event(new CheckoutableCheckedOut($this, $this->getLogTarget(), auth()->user(), $this->getLogNote()));
+ return true;
+ }
+ return false;
+ }
+
/**
* Determines the assigned seat's location based on user
* or asset its assigned to
diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php
deleted file mode 100644
index 1e4a9120274c..000000000000
--- a/app/Models/Loggable.php
+++ /dev/null
@@ -1,311 +0,0 @@
-
- * @since [v3.4]
- * @return \App\Models\Actionlog
- */
- public function log()
- {
- return $this->morphMany(Actionlog::class, 'item');
- }
-
- public function setImported(bool $bool): void
- {
- $this->imported = $bool;
- }
-
- /**
- * @author Daniel Meltzer
- * @since [v3.4]
- * @return \App\Models\Actionlog
- */
- public function logCheckout($note, $target, $action_date = null, $originalValues = [])
- {
-
- $log = new Actionlog;
-
- $fields_array = [];
-
- $log = $this->determineLogItemType($log);
- if (auth()->user()) {
- $log->created_by = auth()->id();
- }
-
- if (! isset($target)) {
- throw new \Exception('All checkout logs require a target.');
-
- return;
- }
-
- if (! isset($target->id)) {
- throw new \Exception('That target seems invalid (no target ID available).');
-
- return;
- }
-
- $log->target_type = get_class($target);
- $log->target_id = $target->id;
-
-
- // Figure out what the target is
- if ($log->target_type == Location::class) {
- $log->location_id = $target->id;
- } elseif ($log->target_type == Asset::class) {
- $log->location_id = $target->location_id;
- } else {
- $log->location_id = $target->location_id;
- }
-
- if (static::class == Asset::class) {
- if ($asset = Asset::find($log->item_id)) {
-
- // add the custom fields that were changed
- if ($asset->model->fieldset) {
- $fields_array = [];
- foreach ($asset->model->fieldset->fields as $field) {
- if ($field->display_checkout == 1) {
- $fields_array[$field->db_column] = $asset->{$field->db_column};
- }
- }
- }
- }
- }
-
- $log->note = $note;
- $log->action_date = $action_date;
-
- if (! $log->action_date) {
- $log->action_date = date('Y-m-d H:i:s');
- }
-
- $changed = [];
- $array_to_flip = array_keys($fields_array);
- $array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
- $originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
-
-
- foreach ($originalValues as $key => $value) {
- if ($key == 'action_date' && $value != $action_date) {
- $changed[$key]['old'] = $value;
- $changed[$key]['new'] = is_string($action_date) ? $action_date : $action_date->format('Y-m-d H:i:s');
- } elseif ($value != $this->getAttributes()[$key]) {
- $changed[$key]['old'] = $value;
- $changed[$key]['new'] = $this->getAttributes()[$key];
- }
- }
-
- if (!empty($changed)){
- $log->log_meta = json_encode($changed);
- }
-
- $log->logaction('checkout');
-
- return $log;
- }
-
- /**
- * Helper method to determine the log item type
- */
- private function determineLogItemType($log)
- {
- // We need to special case licenses because of license_seat vs license. So much for clean polymorphism :
- if (static::class == LicenseSeat::class) {
- $log->item_type = License::class;
- $log->item_id = $this->license_id;
- } else {
- $log->item_type = static::class;
- $log->item_id = $this->id;
- }
-
- return $log;
- }
-
- /**
- * @author Daniel Meltzer
- * @since [v3.4]
- * @return \App\Models\Actionlog
- */
- public function logCheckin($target, $note, $action_date = null, $originalValues = [])
- {
- $log = new Actionlog;
-
- $fields_array = [];
-
- if($target != null){
- $log->target_type = get_class($target);
- $log->target_id = $target->id;
-
- }
-
- if (static::class == LicenseSeat::class) {
- $log->item_type = License::class;
- $log->item_id = $this->license_id;
- } else {
- $log->item_type = static::class;
- $log->item_id = $this->id;
-
- if (static::class == Asset::class) {
- if ($asset = Asset::find($log->item_id)) {
- $asset->increment('checkin_counter', 1);
-
- // add the custom fields that were changed
- if ($asset->model->fieldset) {
- $fields_array = [];
- foreach ($asset->model->fieldset->fields as $field) {
- if ($field->display_checkin == 1) {
- $fields_array[$field->db_column] = $asset->{$field->db_column};
- }
- }
- }
- }
- }
- }
-
- $log->location_id = null;
- $log->note = $note;
- $log->action_date = $action_date;
-
- if (! $log->action_date) {
- $log->action_date = date('Y-m-d H:i:s');
- }
-
- if (auth()->user()) {
- $log->created_by = auth()->id();
- }
-
- $changed = [];
-
- $array_to_flip = array_keys($fields_array);
- $array_to_flip = array_merge($array_to_flip, ['action_date','name','status_id','location_id','expected_checkin']);
-
- $originalValues = array_intersect_key($originalValues, array_flip($array_to_flip));
-
- foreach ($originalValues as $key => $value) {
-
- if ($key == 'action_date' && $value != $action_date) {
- $changed[$key]['old'] = $value;
- $changed[$key]['new'] = is_string($action_date) ? $action_date : $action_date->format('Y-m-d H:i:s');
- } elseif ($value != $this->getAttributes()[$key]) {
- $changed[$key]['old'] = $value;
- $changed[$key]['new'] = $this->getAttributes()[$key];
- }
- }
-
- if (!empty($changed)){
- $log->log_meta = json_encode($changed);
- }
-
- $log->logaction('checkin from');
-
- return $log;
- }
-
- /**
- * @author A. Gianotto
- * @since [v4.0]
- * @return \App\Models\Actionlog
- */
- public function logAudit($note, $location_id, $filename = null)
- {
- $log = new Actionlog;
- $location = Location::find($location_id);
- if (static::class == LicenseSeat::class) {
- $log->item_type = License::class;
- $log->item_id = $this->license_id;
- } else {
- $log->item_type = static::class;
- $log->item_id = $this->id;
- }
- $log->location_id = ($location_id) ? $location_id : null;
- $log->note = $note;
- $log->created_by = auth()->id();
- $log->filename = $filename;
- $log->logaction('audit');
-
- $params = [
- 'item' => $log->item,
- 'filename' => $log->filename,
- 'admin' => $log->adminuser,
- 'location' => ($location) ? $location->name : '',
- 'note' => $note,
- ];
- if(Setting::getSettings()->webhook_selected === 'microsoft' && Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows')){
- $message = AuditNotification::toMicrosoftTeams($params);
- $notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
- $notification->success()->sendMessage($message[0], $message[1]);
- }
- else {
- Setting::getSettings()->notify(new AuditNotification($params));
- }
-
- return $log;
- }
-
- /**
- * @author Daniel Meltzer
- * @since [v3.5]
- * @return \App\Models\Actionlog
- */
- public function logCreate($note = null)
- {
- $created_by = -1;
- if (auth()->user()) {
- $created_by = auth()->id();
- }
- $log = new Actionlog;
- if (static::class == LicenseSeat::class) {
- $log->item_type = License::class;
- $log->item_id = $this->license_id;
- } else {
- $log->item_type = static::class;
- $log->item_id = $this->id;
- }
- $log->location_id = null;
- $log->note = $note;
- $log->created_by = $created_by;
- $log->logaction('create');
- $log->save();
-
- return $log;
- }
-
- /**
- * @author Daniel Meltzer
- * @since [v3.4]
- * @return \App\Models\Actionlog
- */
- public function logUpload($filename, $note)
- {
- $log = new Actionlog;
- if (static::class == LicenseSeat::class) {
- $log->item_type = License::class;
- $log->item_id = $this->license_id;
- } else {
- $log->item_type = static::class;
- $log->item_id = $this->id;
- }
- $log->created_by = auth()->id();
- $log->note = $note;
- $log->target_id = null;
- $log->created_at = date('Y-m-d H:i:s');
- $log->filename = $filename;
- $log->logaction('uploaded');
-
- return $log;
- }
-}
diff --git a/app/Models/Requestable.php b/app/Models/Requestable.php
index 4dead82bb3e0..ef3e9a84ffcb 100644
--- a/app/Models/Requestable.php
+++ b/app/Models/Requestable.php
@@ -28,6 +28,7 @@ public function scopeRequestedBy($query, User $user)
public function request($qty = 1)
{
+ // THIS is where the requested log action thing should go, yeah? FIXME
$this->requests()->save(
new CheckoutRequest(['user_id' => auth()->id(), 'qty' => $qty])
);
diff --git a/app/Models/Setting.php b/app/Models/Setting.php
index 199aee33dcc3..42c3cb4fed54 100755
--- a/app/Models/Setting.php
+++ b/app/Models/Setting.php
@@ -74,6 +74,14 @@ class Setting extends Model
'require_checkinout_notes' => 'boolean',
];
+ public static function boot()
+ {
+ self::saved(function ($model) {
+ Cache::forget(Setting::SETUP_CHECK_KEY);
+ });
+ parent::boot();
+ }
+
/**
* Get the app settings.
* Cache is expired on Setting model saved in EventServiceProvider.
diff --git a/app/Models/Traits/Loggable.php b/app/Models/Traits/Loggable.php
new file mode 100644
index 000000000000..d69e185873a2
--- /dev/null
+++ b/app/Models/Traits/Loggable.php
@@ -0,0 +1,386 @@
+setLogAction(ActionType::Restore);
+ });
+
+ static::updating(function ($model) {
+ //\Log::error("Updating is fired, current log message is: ".$model->log_action);
+ // if we're doing a restore, this 'updating' hook fires *after* the restoring hook
+ // so we make sure not to overwrite the log_action
+ if (!$model->log_action) {
+ $model->setLogAction(ActionType::Update);
+ }
+ });
+
+ static::creating(function ($model) {
+ $model->setLogAction(ActionType::Create);
+ });
+
+ static::deleting(function ($model) { //TODO - is this only for 'hard' delete? Or soft?
+ \Log::error("DELETING TRIGGER HAS FIRED!!!!!!!!!!!!!!! for id: ".$model->id." old log_action was: ".$model->log_action);
+ if (self::class == \App\Models\User::class) { //FIXME - Janky AF!
+ $model->setLogTarget($model); //FIXME - this makes *NO* sense!!!!
+ }
+ $model->setLogAction(ActionType::Delete);
+ });
+
+ //static::trashing(function ($model) { //TODO - is *this* the right one?
+ // $model->setLogAction(ActionType::Delete); // No, no it is very much not. there is 'trashed' but not 'trashING'
+ //});
+
+ // 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.
+ // note that this may run *BEFORE* the more specific events, above? I don't know why that is though.
+ // OPEN QUESTION - does this run on soft-delete? I don't know.
+ static::saving(function ($model) {
+ //possibly consider a "$this->saveWithoutTransaction" thing you can invoke?
+ // use "BEGIN" here?! TODO FIXME
+ $changed = [];
+
+ // something here with custom fields is needed? or will getRawOriginal et al just do that for us?
+ 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 (property_exists(self::class, 'hide_changes') && in_array($key, self::$hide_changes)) {
+ $changed[$key]['old'] = '*************';
+ $changed[$key]['new'] = '*************';
+ }
+ }
+ }
+
+ $model->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) {
+ if (!$model->log_action && !$model->log_meta) {
+ //nothing was changed, nothing was saved, nothing happened. So there should be no log message.
+ //FIXME if we do the transaction thing!!!!
+ \Log::error("LOG MESSAGE IS BLANK, ****AND**** log_meta is blank! Not sure what that means though...");
+ return;
+ }
+ if (!$model->log_action) {
+ throw new \Exception("Log Message was unset, but log_meta *does* exist - it's: ".print_r($model->log_meta, true));
+ }
+ $model->logWithoutSave();
+ // DO COMMIT HERE? TODO FIXME
+ });
+ static::deleted(function ($model) {
+ \Log::error("Deleted callback has fired!!!!!!!!!!! I guess that means do stuff here? For id: ".$model->id);
+ $results = $model->logWithoutSave(); //TODO - if we do commits up there, we should do them here too?
+ \Log::error("result of logging without save? ".($results ? 'true' : 'false'));
+ });
+ static::restored(function ($model) {
+ \Log::error("RestorED callback firing.");
+ $model->logWithoutSave(); //TODO - this is getting duplicative.
+ });
+
+ // CRAP.
+ //static::trashed(function ($model) {
+ // $model->logWithoutSave(ActionType::Delete);
+ //});
+
+ }
+
+ // 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'
+ // I think direct usage of it is probably, generally wrong - you should be using logAndSaveIfNeeded
+ // 99% of the time, unless a save got triggered somehow else. And if it was, you should probably
+ // rejigger it so it isn't.
+ private function logWithoutSave(?ActionType $log_action = null): bool //FIXME - this is named dumb. It should be "createLog()" I think?
+ {
+ if ($log_action) {
+ $this->setLogAction($log_action);
+ }
+ $logAction = new Actionlog(); // THIS should be the only place you _instantiate_ one of these, for the most part
+ //$logAction->item_type = self::class;
+ //$logAction->item_id = $this->id;
+
+ // LicenseSeat->License transformation - blech
+ if (static::class == LicenseSeat::class) {
+ $logAction->item_type = License::class;
+ $logAction->item_id = $this->license_id;
+ } else {
+ $logAction->item_type = static::class;
+ $logAction->item_id = $this->id;
+ }
+ $logAction->created_at = date('Y-m-d H:i:s');
+ $logAction->created_by = auth()->id(); //TODO - should we use the log_admin attribute here, and build in a default of auth()->user() or whatever?
+ $logAction->log_meta = $this->log_meta ? json_encode($this->log_meta) : null;
+ if ($this->log_target) {
+ $logAction->target_type = $this->log_target::class;
+ $logAction->target_id = $this->log_target->id;
+
+ //logic to set the location_id of the ActionLog based on the Target
+ if ($logAction->target_type == Location::class) {
+ $logAction->location_id = $this->log_target->id;
+ } elseif ($logAction->target_type == Asset::class) { //TODO - these branches might be able to be folded together?
+ $logAction->location_id = $this->log_target->location_id;
+ } else {
+ $logAction->location_id = $this->log_target->location_id;
+ }
+ }
+ // TODO - this allows for 'weird' behavior, but is how the system currently works
+ // we don't want to break things for people who are already used to our ways of doing things
+ if ($this->log_location_override) {
+ \Log::error("Log Location Override!!!!!!!!!!!!!!!!");
+ //so - FIXME - open question - do we _log_ the location the same way we _set_ the location on the FCO?
+ $this->location_id = $this->log_location_override->id;
+ $logAction->location_id = $this->log_location_override->id;
+ }
+
+
+ if ($this->log_note) {
+ \Log::error("Got a note, so we're using it for the logaction - ".$this->log_note);
+ $logAction->note = $this->log_note;
+ } else {
+ \Log::error("NO LOG NOTE!");
+ }
+
+
+ if ($this->log_date) { //FIXME - there's _something_ wrong with this; I'm just not sure _what_ - see the various Asset checkin tests that are failing
+ \Log::error("Setting EXPLICIT log_date of: ".$this->log_date);
+ $logAction->action_date = $this->log_date;
+ } else {
+ \Log::error("using Carbon::now for action_date");
+ $logAction->action_date = Carbon::now(); //date('Y-m-d H:i:s'); //TODO - this is right?
+ }
+
+ if ($this->log_filename) {
+ $logAction->filename = $this->log_filename;
+ }
+
+ if ($this->log_accept_signature) {
+ $logAction->accept_signature = $this->log_accept_signature;
+ }
+
+ //\Log::error("Here is the logaction BEFORE we save it ($this->log_action)...".print_r($logAction->toArray(), true));
+ //return $logAction->logaction();
+ $logAction->action_type = $this->log_action;
+ $logAction->remote_ip = request()->ip();
+ $logAction->user_agent = request()->header('User-Agent');
+ //$logAction->action_source = $this->determineActionSource();
+ if ($this->imported) {
+ $logAction->action_source = 'importer';
+ //}
+ //if ($this->source) { //FIXME I think I got this wrong.
+ // // This is a manually set source
+ // $logAction->source = $this->source;
+ } else {
+ if (((request()->header('content-type') && (request()->header('accept')) == 'application/json'))
+ && (starts_with(request()->header('authorization'), 'Bearer '))) {
+ // This is an API call
+ $logAction->action_source = 'api';
+ } else {
+ if (request()->filled('_token')) {
+ $logAction->action_source = 'gui';
+ } else {
+ // We're not sure, probably cli
+ $logAction->action_source = 'cli/unknown';
+ }
+ }
+ }
+
+ \Log::error("About to really 'logaction' - date is: ".$this->action_date);
+ if ($logAction->save()) {
+ \Log::error("SAVE SUCCESSFUL!!!!! Action date *really* is: ".$this->fresh()->action_date);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // This is the main interface we should be using, most of the time
+ // if the object is dirty, save it and let the save hooks fire. If it's not, then just
+ // add the log.
+ public function logAndSaveIfNeeded(?ActionType $log_action = null)
+ {
+ if ($this->isDirty()) {
+ //\Log::error("Doing REAL save because this is dirty");
+ if ($log_action) {
+ $this->setLogAction($log_action);
+ }
+ return $this->save(); //save will do what you need
+ } else {
+ //transact this? We won't have the 'saving'/'saved' entries - but it generally is just one insert anyway, so it either works or doesn't.
+ //\Log::error("just doing log without save because this is not dirty");
+ return $this->logWithoutSave($log_action);
+ }
+ }
+
+ // setter functions for private variables
+ public function setLogAction(ActionType $message)
+ {
+ $this->log_action = $message->value;
+ }
+
+ public function setLogMeta(array $changed)
+ {
+ $this->log_meta = $changed;
+ }
+
+ public function setLogTarget(Model|stdClass|null $target) //FIXME I HATE THIS!!!!!
+ {
+ //might want to do our weird logic about LicenseSeats->Licenses _here_ ? Then we don't have to worry about it anymore?
+ // or maybe somewhere else, since we'll lose 'resolution' - the license seat will 'go away'
+ $this->log_target = $target;
+ }
+
+ public function setLogNote(?string $note)
+ {
+ $this->log_note = $note;
+ }
+
+ public function setLogDate(?Carbon $date)
+ {
+ $this->log_date = $date;
+ }
+
+ public function setLogQuantity(?int $quantity)
+ {
+ $this->log_quantity = $quantity;
+ }
+
+ public function setLogFilename(?string $filename)
+ {
+ $this->log_filename = $filename;
+ }
+
+ public function setLogAdmin(?User $admin)
+ {
+ $this->log_admin = $admin;
+ }
+
+ public function setLogAcceptSignature(?string $signature)
+ {
+ $this->log_accept_signature = $signature;
+ }
+
+ public function setLogLocationOverride(?Location $location)
+ {
+ $this->log_location_override = $location;
+ }
+
+ // getter functions for private variables
+ public function getLogTarget(): mixed //?Model FIXME!!!!!!!
+ {
+ return $this->log_target;
+ }
+
+ public function getLogDate(): ?Carbon
+ {
+ \Log::error("Getting log date. From \$this it's: ".$this->log_date." but from Carbon::now it's: ".Carbon::now());
+ if (!$this->log_date) {
+ $this->log_date = Carbon::now();
+ }
+ return $this->log_date;
+ }
+
+ public function getLogNote(): ?string
+ {
+ return $this->log_note;
+ }
+
+ public function getLogQuantity(): ?int
+ {
+ return $this->log_quantity;
+ }
+
+ public function getLogAdmin(): ?User
+ {
+ return $this->log_admin ?? auth()->user();
+ }
+
+ // relationships
+ /**
+ * @author Daniel Meltzer
+ * @since [v3.4]
+ * @return \App\Models\Actionlog
+ */
+ public function log()
+ {
+ return $this->morphMany(Actionlog::class, 'item');
+ }
+
+ public function setImported(bool $bool): void
+ {
+ $this->imported = $bool;
+ }
+
+ // This is weird, as most of the checkinAndSave logic isn't here, it's in the various classes
+ // which all have their own weird behavior
+ // but audits are all the same, regardless, and there's nothing asset-specific in here, so
+ // might as well make it available to everyone?
+
+ public function AuditAndSave(): bool
+ {
+ if ($this->logAndSaveIfNeeded(ActionType::Audit)) {
+ $params = [
+ 'item' => $this,
+ 'filename' => $this->log_filename,
+ 'admin' => Auth::user(), //I mean, I _guess_?
+ 'location' => ($this->wasChanged('location_id')) ? $this->location?->name : '', //?? this is the overridden location, right? And it's blank otherwise?
+ 'note' => $this->getLogNote(),
+ ];
+ if (Setting::getSettings()->webhook_selected === 'microsoft' && Str::contains(Setting::getSettings()->webhook_endpoint, 'workflows')) {
+ $message = AuditNotification::toMicrosoftTeams($params);
+ $notification = new TeamsNotification(Setting::getSettings()->webhook_endpoint);
+ $notification->success()->sendMessage($message[0], $message[1]);
+ } else {
+ Setting::getSettings()->notify(new AuditNotification($params));
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+}
diff --git a/app/Models/User.php b/app/Models/User.php
index fac4e69e473e..fd18cd1b93fe 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -2,9 +2,12 @@
namespace App\Models;
+use App\Enums\ActionType;
use App\Http\Traits\UniqueUndeletedTrait;
+use App\Models\Traits\Loggable;
use App\Models\Traits\Searchable;
use App\Presenters\Presentable;
+use Carbon\Carbon;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
@@ -18,6 +21,7 @@
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Gate;
+use Illuminate\Support\Facades\Log;
use Laravel\Passport\HasApiTokens;
use Watson\Validating\ValidatingTrait;
@@ -33,11 +37,16 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
use Notifiable;
use Presentable;
use Searchable;
+ use Loggable;
+
+ // that 'use Loggable' thing is NEW!
protected $hidden = ['password', 'remember_token', 'permissions', 'reset_password_code', 'persist_code'];
protected $table = 'users';
protected $injectUniqueIdentifier = true;
+ public static array $hide_changes = ['password', 'remember_token', 'two_factor_secret', 'reset_password_code', 'persist_code'];
+
protected $fillable = [
'activated',
'address',
@@ -886,5 +895,94 @@ public function scopeUserLocation($query, $location, $search){
+ }
+
+ public function merge(self $bad_user)
+ {
+ //okay, we have _some_ logic in "MergeUsersByUsername" - the console command.
+ // and _some_ logic is in the LogListener thing.
+ // from the console command, we have this:
+
+ // Walk the list of assets
+ foreach ($bad_user->assets as $asset) {
+ Log::info('Updating asset '.$asset->asset_tag.' '.$asset->id.' to user '.$this->id);
+ $asset->assigned_to = $this->id;
+ if (!$asset->save()) {
+ $this->error('Could not update assigned_to field on asset '.$asset->asset_tag.' '.$asset->id.' to user '.$this->id);
+ $this->error('Error saving: '.$asset->getErrors());
+ }
+ }
+
+ // Walk the list of licenses
+ foreach ($bad_user->licenses as $license) {
+ Log::info('Updating license '.$license->name.' '.$license->id.' to user '.$this->id);
+ $bad_user->licenses()->updateExistingPivot($license->id, ['assigned_to' => $this->id]);
+ }
+
+ // Walk the list of consumables
+ foreach ($bad_user->consumables as $consumable) {
+ Log::info('Updating consumable '.$consumable->id.' to user '.$this->id);
+ $bad_user->consumables()->updateExistingPivot($consumable->id, ['assigned_to' => $this->id]);
+ }
+
+ // Walk the list of accessories
+ foreach ($bad_user->accessories as $accessory) {
+ Log::info('Updating accessory '.$accessory->id.' to user '.$this->id);
+ $bad_user->accessories()->updateExistingPivot($accessory->id, ['assigned_to' => $this->id]);
+ }
+
+ // Walk the list of logs
+ foreach ($bad_user->userlog as $log) {
+ Log::info('Updating action log record '.$log->id.' to user '.$this->id);
+ $log->target_id = $this->id;
+ $log->save();
+ }
+
+ // Update any manager IDs
+ Log::info('Updating managed user records to user '.$this->id);
+ User::where('manager_id', '=', $bad_user->id)->update(['manager_id' => $this->id]);
+
+ // Update location manager IDs
+ foreach ($bad_user->managedLocations as $managedLocation) {
+ Log::info('Updating managed location record '.$managedLocation->name.' to manager '.$this->id);
+ $managedLocation->manager_id = $this->id;
+ $managedLocation->save();
+ }
+
+ foreach ($bad_user->uploads as $upload) {
+ Log::info('Updating upload log record '.$upload->id.' to user '.$this->id);
+ $upload->item_id = $this->id;
+ $upload->save();
+ }
+
+ foreach ($bad_user->acceptances as $acceptance) {
+ Log::info('Updating acceptance log record '.$acceptance->id.' to user '.$this->id);
+ $acceptance->item_id = $this->id;
+ $acceptance->save();
+ }
+
+ // Mark the user as deleted
+ Log::info('Marking the user as deleted');
+ //$bad_user->deleted_at = Carbon::now()->timestamp;
+ $bad_user->delete();
+
+ //This used to be in LogListener -
+ $to_from_array = [
+ 'to_id' => $this->id,
+ 'to_username' => $this->username,
+ 'from_id' => $bad_user->id,
+ 'from_username' => $bad_user->username,
+ ];
+
+ // Add a record to the users being merged FROM
+ Log::debug('Users merged: '.$bad_user->id.' ('.$bad_user->username.') merged into '.$this->id.' ('.$this->username.')');
+ $bad_user->setLogNote(trans('general.merged_log_this_user_from', $to_from_array));
+ $bad_user->setLogTarget($this);
+ $bad_user->logAndSaveIfNeeded(ActionType::Merged);
+
+ $this->setLogTarget($bad_user);
+ $this->setLogNote(trans('general.merged_log_this_user_into', $to_from_array));
+ $this->logAndSaveIfNeeded(ActionType::Merged);
+
}
}
diff --git a/app/Observers/AccessoryObserver.php b/app/Observers/AccessoryObserver.php
deleted file mode 100644
index 0f8b2492cd50..000000000000
--- a/app/Observers/AccessoryObserver.php
+++ /dev/null
@@ -1,62 +0,0 @@
-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');
- }
-}
diff --git a/app/Observers/AssetObserver.php b/app/Observers/AssetObserver.php
deleted file mode 100644
index c807ac4d1d11..000000000000
--- a/app/Observers/AssetObserver.php
+++ /dev/null
@@ -1,187 +0,0 @@
-getAttributes();
- $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']));
- }
-
- 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 ($asset->getRawOriginal() as $key => $value) {
- if ((array_key_exists($key, $asset->getAttributes())) && ($asset->getRawOriginal()[$key] != $asset->getAttributes()[$key])) {
- $changed[$key]['old'] = $asset->getRawOriginal()[$key];
- $changed[$key]['new'] = $asset->getAttributes()[$key];
- }
- }
-
- if (empty($changed)){
- return;
- }
-
- $logAction = new Actionlog();
- $logAction->item_type = Asset::class;
- $logAction->item_id = $asset->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 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');
- }
-
- /**
- * Listen to the Asset deleting event.
- *
- * @param Asset $asset
- * @return void
- */
- public function deleting(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->created_by = auth()->id();
- $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->created_by = auth()->id();
- $logAction->logaction('restore');
- }
-
- /**
- * 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 = (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true);
- 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;
- }
-
- }
-}
diff --git a/app/Observers/ComponentObserver.php b/app/Observers/ComponentObserver.php
deleted file mode 100644
index cd2c58c3674e..000000000000
--- a/app/Observers/ComponentObserver.php
+++ /dev/null
@@ -1,62 +0,0 @@
-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');
- }
-}
diff --git a/app/Observers/ConsumableObserver.php b/app/Observers/ConsumableObserver.php
deleted file mode 100644
index 57471cee9c7b..000000000000
--- a/app/Observers/ConsumableObserver.php
+++ /dev/null
@@ -1,104 +0,0 @@
-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');
- }
-}
diff --git a/app/Observers/LicenseObserver.php b/app/Observers/LicenseObserver.php
deleted file mode 100644
index 4e355bf639d8..000000000000
--- a/app/Observers/LicenseObserver.php
+++ /dev/null
@@ -1,62 +0,0 @@
-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');
- }
-}
diff --git a/app/Observers/SettingObserver.php b/app/Observers/SettingObserver.php
deleted file mode 100644
index ec9dec3f2304..000000000000
--- a/app/Observers/SettingObserver.php
+++ /dev/null
@@ -1,21 +0,0 @@
-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');
- }
-
-
-}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index aa2604bce585..55fa7da07885 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -2,21 +2,7 @@
namespace App\Providers;
-use App\Models\Accessory;
-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;
-use App\Observers\SettingObserver;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
@@ -66,13 +52,6 @@ public function boot(UrlGenerator $url)
\Illuminate\Pagination\Paginator::useBootstrap();
Schema::defaultStringLength(191);
- Asset::observe(AssetObserver::class);
- User::observe(UserObserver::class);
- Accessory::observe(AccessoryObserver::class);
- Component::observe(ComponentObserver::class);
- Consumable::observe(ConsumableObserver::class);
- License::observe(LicenseObserver::class);
- Setting::observe(SettingObserver::class);
}
/**
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index 1f08b445c9ec..651911c70354 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -3,7 +3,6 @@
namespace App\Providers;
use App\Listeners\CheckoutableListener;
-use App\Listeners\LogListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
@@ -29,7 +28,6 @@ class EventServiceProvider extends ServiceProvider
* @var array
*/
protected $subscribe = [
- LogListener::class,
CheckoutableListener::class,
];
}
diff --git a/app/Services/PredefinedKitCheckoutService.php b/app/Services/PredefinedKitCheckoutService.php
index 2cf4593687f1..7409bc73179b 100644
--- a/app/Services/PredefinedKitCheckoutService.php
+++ b/app/Services/PredefinedKitCheckoutService.php
@@ -5,6 +5,7 @@
use App\Events\CheckoutableCheckedOut;
use App\Models\PredefinedKit;
use App\Models\User;
+use Carbon\Carbon;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@@ -149,8 +150,11 @@ protected function saveToDb($user, $admin, $checkout_at, $expected_checkin, $err
function () use ($user, $admin, $checkout_at, $expected_checkin, $errors, $assets_to_add, $license_seats_to_add, $consumables_to_add, $accessories_to_add, $note) {
// assets
foreach ($assets_to_add as $asset) {
- $asset->location_id = $user->location_id;
- $error = $asset->checkOut($user, $admin, $checkout_at, $expected_checkin, $note, null);
+ $asset->setLogTarget($user);
+ $asset->setLogNote($note);
+ $asset->expected_checkin = $expected_checkin;
+ $asset->setLogDate(new Carbon($checkout_at));
+ $error = $asset->checkoutAndSave();
if ($error) {
array_merge_recursive($errors, $asset->getErrors()->toArray());
}
diff --git a/tests/Feature/Assets/Api/StoreAssetTest.php b/tests/Feature/Assets/Api/StoreAssetTest.php
index ea5cfb617820..ed8b961400b6 100644
--- a/tests/Feature/Assets/Api/StoreAssetTest.php
+++ b/tests/Feature/Assets/Api/StoreAssetTest.php
@@ -68,7 +68,7 @@ public function testAllAssetAttributesAreStored()
$this->assertEquals($userAssigned->id, $asset->assigned_to);
$this->assertTrue($asset->company->is($company));
$this->assertEquals('2023-09-03 00:00:00', $asset->last_audit_date);
- $this->assertTrue($asset->location->is($location));
+ $this->assertTrue($asset->location->is($location)); // FIXME - the _test_ or the behavior are somehow incorrect or weird? What is the correct behavior here?!
$this->assertTrue($asset->model->is($model));
$this->assertEquals('A New Asset', $asset->name);
$this->assertEquals('Some notes', $asset->notes);
diff --git a/tests/Feature/Checkins/Api/AssetCheckinTest.php b/tests/Feature/Checkins/Api/AssetCheckinTest.php
index 7ce3d05619ff..7c0493a0feef 100644
--- a/tests/Feature/Checkins/Api/AssetCheckinTest.php
+++ b/tests/Feature/Checkins/Api/AssetCheckinTest.php
@@ -155,6 +155,7 @@ public function testCheckinTimeAndActionLogNoteCanBeSet()
]);
Event::assertDispatched(function (CheckoutableCheckedIn $event) {
+ dump($event);
return Carbon::parse('2023-01-02')->isSameDay(Carbon::parse($event->action_date))
&& $event->note === 'hi there';
}, 1);
diff --git a/tests/Feature/Checkins/Api/ComponentCheckinTest.php b/tests/Feature/Checkins/Api/ComponentCheckinTest.php
index 0497a8135ccc..535dd8adad48 100644
--- a/tests/Feature/Checkins/Api/ComponentCheckinTest.php
+++ b/tests/Feature/Checkins/Api/ComponentCheckinTest.php
@@ -109,6 +109,7 @@ public function testCheckingInEntireAssignedQuantityClearsThePivotRecordFromTheD
->assertOk()
->assertStatusMessageIs('success');
+ dump($component->fresh()->assets);
$this->assertEmpty($component->fresh()->assets);
Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($user, $component) {
diff --git a/tests/Feature/Checkins/Ui/AssetCheckinTest.php b/tests/Feature/Checkins/Ui/AssetCheckinTest.php
index 4f1c62cf2ce3..eb209679f9bf 100644
--- a/tests/Feature/Checkins/Ui/AssetCheckinTest.php
+++ b/tests/Feature/Checkins/Ui/AssetCheckinTest.php
@@ -170,7 +170,7 @@ public function testCheckinTimeAndActionLogNoteCanBeSet()
]);
Event::assertDispatched(function (CheckoutableCheckedIn $event) {
- return $event->action_date === '2023-01-02' && $event->note === 'hello';
+ return $event->action_date->isSameDay(new Carbon('2023-01-02')) && $event->note === 'hello';
}, 1);
}
diff --git a/tests/Feature/Checkouts/Api/ConsumableCheckoutTest.php b/tests/Feature/Checkouts/Api/ConsumableCheckoutTest.php
index fba2c50df377..712e41b1408f 100644
--- a/tests/Feature/Checkouts/Api/ConsumableCheckoutTest.php
+++ b/tests/Feature/Checkouts/Api/ConsumableCheckoutTest.php
@@ -47,7 +47,7 @@ public function testConsumableCanBeCheckedOut()
->postJson(route('api.consumables.checkout', $consumable), [
'assigned_to' => $user->id,
]);
-
+ dump($user->consumables);
$this->assertTrue($user->consumables->contains($consumable));
}
diff --git a/tests/Feature/Checkouts/Ui/AssetCheckoutTest.php b/tests/Feature/Checkouts/Ui/AssetCheckoutTest.php
index 00197917522e..3a4e3ff804fe 100644
--- a/tests/Feature/Checkouts/Ui/AssetCheckoutTest.php
+++ b/tests/Feature/Checkouts/Ui/AssetCheckoutTest.php
@@ -141,7 +141,8 @@ public static function checkoutTargets(): array
'expected_location' => $userLocation,
];
}],
- 'Asset without location set' => [function () {
+ 'Asset without location set' => [
+ function () { //HERE!
$rtdLocation = Location::factory()->create();
$asset = Asset::factory()->for($rtdLocation, 'defaultLoc')->create(['location_id' => null]);
@@ -203,7 +204,11 @@ public function testAssetCanBeCheckedOut($data)
$asset->refresh();
$this->assertTrue($asset->assignedTo()->is($target));
- $this->assertTrue($asset->location->is($expectedLocation));
+ if ($expectedLocation) {
+ $this->assertTrue($asset->location?->is($expectedLocation));
+ } else {
+ $this->assertNull($asset->location);
+ }
$this->assertEquals('Changed Name', $asset->name);
$this->assertTrue($asset->assetstatus->is($newStatus));
$this->assertEquals('2024-03-18 00:00:00', $asset->last_checkout);
diff --git a/tests/Feature/Console/FixupAssignedToAssignedTypeTest.php b/tests/Feature/Console/FixupAssignedToAssignedTypeTest.php
index 2b5f9b415d0e..f8def6f9da59 100644
--- a/tests/Feature/Console/FixupAssignedToAssignedTypeTest.php
+++ b/tests/Feature/Console/FixupAssignedToAssignedTypeTest.php
@@ -14,9 +14,11 @@ public function testEmptyAssignedType()
$user = User::factory()->create();
$admin = User::factory()->admin()->create();
- $asset->checkOut($user, $admin);
- $asset->assigned_type=null; //blank out the assigned type
- $asset->save();
+ $asset->setLogTarget($user);
+ $asset->checkOutAndSave(); //this _should_ work but we don't have an auth::user() to work with and the null notification breaks things?
+
+ $asset->assigned_type = null; //blank out the assigned type
+ $asset->forceSave();
$this->artisan('snipeit:assigned-to-fixup --debug')->assertExitCode(0);
@@ -30,7 +32,7 @@ public function testInvalidAssignedTo()
$user = User::factory()->create();
$admin = User::factory()->admin()->create();
- $asset->checkOut($user, $admin);
+ $asset->checkOutAndSave($user, $admin);
$asset->assigned_type=null;
$asset->assigned_to=null;
$asset->saveOrFail(); //*should* generate a 'checkin'?
diff --git a/tests/Feature/Console/MergeUsersTest.php b/tests/Feature/Console/MergeUsersTest.php
index 4c43e6293d3e..922d2394889e 100644
--- a/tests/Feature/Console/MergeUsersTest.php
+++ b/tests/Feature/Console/MergeUsersTest.php
@@ -127,7 +127,9 @@ public function testUserUpdateHistoryIsTransferredOnUserMerge(): void
// This needs to be more than the otherwise expected because the merge action itself is logged for the two merging users
$this->assertEquals(7, $user_to_merge_into->refresh()->userlog->count());
- $this->assertEquals(1, $user1->refresh()->userlog->count());
+ //okay, in the *GUI* merge, this makes *TWO* records - one for the merge, one for the delete. but apparently it used to _not_ in the CLI merge
+ //I decided to make them the same, so this expected amount is now changed
+ $this->assertEquals(2, $user1->refresh()->userlog->count());
}
diff --git a/tests/Feature/Importing/Api/ImportAssetsTest.php b/tests/Feature/Importing/Api/ImportAssetsTest.php
index 0f54b22e92d7..0ff1bf24c3c5 100644
--- a/tests/Feature/Importing/Api/ImportAssetsTest.php
+++ b/tests/Feature/Importing/Api/ImportAssetsTest.php
@@ -59,6 +59,7 @@ public function importAsset(): void
$importFileBuilder = ImportFileBuilder::new();
$row = $importFileBuilder->firstRow();
+ dump($row);
$import = Import::factory()->asset()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
$this->actingAsForApi(User::factory()->superuser()->create());
@@ -74,8 +75,10 @@ public function importAsset(): void
->with(['location', 'supplier', 'company', 'assignedAssets', 'defaultLoc', 'assetStatus', 'model.category', 'model.manufacturer'])
->where('serial', $row['serialNumber'])
->sole();
+ dump($newAsset);
$assignee = User::query()->find($newAsset->assigned_to, ['id', 'first_name', 'last_name', 'email', 'username']);
+ dump($assignee);
$activityLogs = ActionLog::query()
->where('item_type', Asset::class)
@@ -109,6 +112,14 @@ public function importAsset(): void
$this->assertEquals($row['purchaseDate'], $newAsset->purchase_date->toDateString());
$this->assertNull($newAsset->asset_eol_date);
$this->assertEquals(0, $newAsset->eol_explicit);
+ /*
+ * FIXME FIXME FIXME please - I don't know what the right thing to do here is.
+ //Hrm. I'm not sure about this. So it's saying that the asset's location should be the same as the asset's rtd_location_id - but that doesn't make sense to me.
+ If an asset is assigned to a *user* who has no location, the *asset* should get no location. The user definitely has no location - I've dumped them, I've looked
+ at the factories. So the asset's location should be changed from its rtd_location_id to the User's location_id - which is definitively null. So I think this test
+ might be wrong? But, at the same time, if that's something we've been doing for years, we might have to keep doing that for years. Which is weird. Very, very weird.
+ Not sure what to do on this one.
+ */
$this->assertEquals($newAsset->location_id, $newAsset->rtd_location_id);
$this->assertEquals($row['purchaseCost'], $newAsset->purchase_cost);
$this->assertNull($newAsset->order_number);
@@ -135,7 +146,7 @@ public function importAsset(): void
$this->assertEquals(1, $newAsset->checkout_counter);
$this->assertEquals(0, $newAsset->requests_counter);
$this->assertEquals(0, $newAsset->byod);
-
+// die("By NOW");
//Notes is never read.
// $this->assertEquals($row['notes'], $newAsset->notes);
@@ -415,7 +426,7 @@ public function updateAssetFromImport(): void
$this->assertEquals($row['status'], $updatedAsset->assetStatus->name);
$this->assertEquals($row['warrantyInMonths'], $updatedAsset->warranty_months);
$this->assertEquals($row['supplierName'], $updatedAsset->supplier->name);
- $this->assertEquals($row['location'], $updatedAsset->defaultLoc->name);
+ $this->assertEquals($row['location'], $updatedAsset->defaultLoc->name); //FIXME here, this is failing. For the same reason as above? Very weird.
$this->assertEquals($row['companyName'], $updatedAsset->company->name);
$this->assertEquals($row['location'], $updatedAsset->location->name);
$this->assertEquals(1, $updatedAsset->checkout_counter);
@@ -464,15 +475,15 @@ public function customColumnMapping(): void
'import' => $import->id,
'column-mappings' => [
'Asset Tag' => 'email',
- 'Category' => 'location',
+ 'Category' => 'location', //okay, this is where the confusion is.
'Company' => 'purchase_cost',
'Email' => 'manufacturer',
'Full Name' => 'supplier',
'Item Name' => 'model_number',
- 'Location' => 'username',
+ 'Location' => 'username', //wait, wat?
'Manufacturer' => 'status',
'Model name' => 'item_name',
- 'Model Number' => 'category',
+ 'Model Number' => 'category', //another wat. wat?
'Notes' => 'asset_notes',
'Purchase Cost' => 'asset_model',
'Purchase Date' => 'company',
@@ -508,7 +519,7 @@ public function customColumnMapping(): void
$this->assertEquals($row['assigneeFullName'], $asset->supplier->name);
$this->assertEquals($row['category'], $asset->defaultLoc->name);
$this->assertEquals($row['purchaseDate'], $asset->company->name);
- $this->assertEquals($row['category'], $asset->location->name);
+ $this->assertEquals($row['category'], $asset->location->name); // fIXME: this one is weird too. UGH. But weird for the same reason - importer treats location different than checkout.
$this->assertEquals($row['notes'], $asset->notes);
$this->assertNull($asset->asset_eol_date);
$this->assertEquals(0, $asset->eol_explicit);
diff --git a/tests/Feature/Importing/Api/ImportLicenseTest.php b/tests/Feature/Importing/Api/ImportLicenseTest.php
index 0cd5fe447c18..284dfcb4b5a4 100644
--- a/tests/Feature/Importing/Api/ImportLicenseTest.php
+++ b/tests/Feature/Importing/Api/ImportLicenseTest.php
@@ -251,7 +251,7 @@ public function updateLicenseFromImport(): void
$this->importFileResponse(['import' => $import->id, 'import-update' => true])->assertOk();
$updatedLicense = License::query()
- ->with(['manufacturer', 'category', 'supplier'])
+ // ->with(['manufacturer', 'category', 'supplier'])
->where('serial', $row['serialNumber'])
->sole();
diff --git a/tests/Feature/Users/Api/UpdateUserTest.php b/tests/Feature/Users/Api/UpdateUserTest.php
index e70471770fa0..b6077d13c4d7 100644
--- a/tests/Feature/Users/Api/UpdateUserTest.php
+++ b/tests/Feature/Users/Api/UpdateUserTest.php
@@ -451,7 +451,8 @@ public function testMultiCompanyUserCannotBeMovedIfHasAssetInDifferentCompany()
'company_id' => $companyB->id,
])->assertStatusMessageIs('success');
- $asset->checkOut($user, $superUser);
+ $asset->setLogTarget($user);
+ $asset->checkOutAndSave();
// asset assigned, therefore error
$this->actingAsForApi($superUser)->patchJson(route('api.users.update', $user), [
@@ -496,7 +497,8 @@ public function testMultiCompanyUserCanBeUpdatedIfHasAssetInSameCompany()
'company_id' => $companyB->id,
])->assertStatusMessageIs('success');
- $asset->checkOut($user, $superUser);
+ $asset->setLogTarget($user);
+ $asset->checkOutAndSave();
// asset assigned from other company, therefore error
$this->actingAsForApi($superUser)->patchJson(route('api.users.update', $user), [
diff --git a/tests/Feature/Users/Ui/MergeUsersTest.php b/tests/Feature/Users/Ui/MergeUsersTest.php
index a9ae11171bf7..9a54af703a06 100644
--- a/tests/Feature/Users/Ui/MergeUsersTest.php
+++ b/tests/Feature/Users/Ui/MergeUsersTest.php
@@ -204,9 +204,12 @@ public function testUserUpdateHistoryIsTransferredOnUserMerge()
// This needs to be 2 more than the otherwise expected because the merge action itself is logged for the two merging users
$this->assertEquals(11, $user_to_merge_into->refresh()->userlog->count());
- $this->assertEquals(2, $user1->refresh()->userlog->count());
+ $this->assertTrue($user1->refresh()->trashed(), "User 1 should be trashed and isn't!");
+ $this->assertTrue($user2->refresh()->trashed(), "User 2 should be trashed and isn't!");
+ dump($user1->refresh()->userlog);
+ $this->assertEquals(2, $user1->refresh()->userlog->count()); //wait, so what _are_ the two messages we should see? A merge, sure, but then a delete?
$this->assertEquals(2, $user2->refresh()->userlog->count());
-
+ dump($user2->refresh()->userlog);
}
diff --git a/tests/Feature/Users/Ui/UpdateUserTest.php b/tests/Feature/Users/Ui/UpdateUserTest.php
index abaec1b70e93..aad4c01ade32 100644
--- a/tests/Feature/Users/Ui/UpdateUserTest.php
+++ b/tests/Feature/Users/Ui/UpdateUserTest.php
@@ -113,7 +113,8 @@ public function testMultiCompanyUserCannotBeMovedIfHasAssetInDifferentCompany()
'redirect_option' => 'index'
])->assertRedirect(route('users.index'));
- $asset->checkOut($user, $superUser);
+ $asset->setLogTarget($user);
+ $asset->checkOutAndSave();
// asset assigned, therefore error
$response = $this->actingAs($superUser)->patchJson(route('users.update', $user), [
@@ -149,7 +150,8 @@ public function testMultiCompanyUserCanBeUpdatedIfHasAssetInSameCompany()
'redirect_option' => 'index'
])->assertRedirect(route('users.index'));
- $asset->checkOut($user, $superUser);
+ $asset->setLogTarget($user);
+ $asset->checkOutAndSave();
// asset assigned, therefore error
$response = $this->actingAs($superUser)->patchJson(route('users.update', $user), [
diff --git a/tests/Unit/Listeners/LogListenerTest.php b/tests/Unit/Listeners/LogListenerTest.php
deleted file mode 100644
index 64dd2a3d673b..000000000000
--- a/tests/Unit/Listeners/LogListenerTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-create();
- $checkedOutTo = User::factory()->create();
- $checkedOutBy = User::factory()->create();
-
- // Simply to ensure `created_by` is set in the action log
- $this->actingAs($checkedOutBy);
-
- (new LogListener())->onCheckoutableCheckedOut(new CheckoutableCheckedOut(
- $asset,
- $checkedOutTo,
- $checkedOutBy,
- 'A simple note...',
- ));
-
- $this->assertDatabaseHas('action_logs', [
- 'action_type' => 'checkout',
- 'created_by' => $checkedOutBy->id,
- 'target_id' => $checkedOutTo->id,
- 'target_type' => User::class,
- 'item_id' => $asset->id,
- 'item_type' => Asset::class,
- 'note' => 'A simple note...',
- ]);
- }
-
-}
diff --git a/tests/Unit/NotificationTest.php b/tests/Unit/NotificationTest.php
index 5b420a675385..80d41ae3e3b1 100644
--- a/tests/Unit/NotificationTest.php
+++ b/tests/Unit/NotificationTest.php
@@ -30,7 +30,9 @@ public function testAUserIsEmailedIfTheyCheckoutAnAssetWithEULA()
]);
Mail::fake();
- $asset->checkOut($user, $admin->id);
+ $asset->setLogTarget($user);
+ $asset->setLogAdmin($admin);
+ $asset->checkOutAndSave();
Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) use ($user) {
return $mail->hasTo($user->email) && $mail->hasSubject(trans('mail.Asset_Checkout_Notification'));
});
@@ -51,7 +53,9 @@ public function testDefaultEulaIsSentWhenSetInCategory()
$model = AssetModel::factory()->for($category)->create();
$asset = Asset::factory()->for($model, 'model')->create();
- $asset->checkOut($user, User::factory()->superuser()->create()->id);
+ $asset->setLogTarget($user);
+ $asset->setLogAdmin(User::factory()->superuser()->create());
+ $asset->checkOutAndSave();
Mail::assertSent(CheckoutAssetMail::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) &&