diff --git a/app/Events/CheckoutableCheckedIn.php b/app/Events/CheckoutableCheckedIn.php
index f6a20fd3d265..4a1d46d2f479 100644
--- a/app/Events/CheckoutableCheckedIn.php
+++ b/app/Events/CheckoutableCheckedIn.php
@@ -22,12 +22,14 @@ class CheckoutableCheckedIn
public $originalValues;
+ public ?string $filename;
+
/**
* Create a new event instance.
*
* @return void
*/
- public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $note, $action_date = null, $originalValues = [])
+ public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $note, $action_date = null, $originalValues = [], ?string $filename = null)
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
@@ -35,5 +37,6 @@ public function __construct($checkoutable, $checkedOutTo, User $checkedInBy, $no
$this->note = $note;
$this->action_date = $action_date ?? date('Y-m-d H:i:s');
$this->originalValues = $originalValues;
+ $this->filename = $filename;
}
}
diff --git a/app/Events/CheckoutableCheckedOut.php b/app/Events/CheckoutableCheckedOut.php
index 0d47f64552d6..958a519aa63f 100644
--- a/app/Events/CheckoutableCheckedOut.php
+++ b/app/Events/CheckoutableCheckedOut.php
@@ -24,12 +24,14 @@ class CheckoutableCheckedOut
public bool $signInPlace;
+ public ?string $filename;
+
/**
* Create a new event instance.
*
* @return void
*/
- public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [], $quantity = 1, bool $signInPlace = false)
+ public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $note, $originalValues = [], $quantity = 1, bool $signInPlace = false, ?string $filename = null)
{
$this->checkoutable = $checkoutable;
$this->checkedOutTo = $checkedOutTo;
@@ -38,5 +40,6 @@ public function __construct($checkoutable, $checkedOutTo, User $checkedOutBy, $n
$this->originalValues = $originalValues;
$this->quantity = $quantity;
$this->signInPlace = $signInPlace;
+ $this->filename = $filename;
}
}
diff --git a/app/Http/Controllers/Accessories/AccessoryCheckinController.php b/app/Http/Controllers/Accessories/AccessoryCheckinController.php
index 5a7dc55bcf9a..3856c659c031 100644
--- a/app/Http/Controllers/Accessories/AccessoryCheckinController.php
+++ b/app/Http/Controllers/Accessories/AccessoryCheckinController.php
@@ -5,11 +5,11 @@
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
+use App\Http\Requests\UploadFileRequest;
use App\Models\Accessory;
use App\Models\AccessoryCheckout;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
-use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AccessoryCheckinController extends Controller
@@ -53,7 +53,7 @@ public function create($accessoryUserId = null, $backto = null): View|RedirectRe
* @param null $accessoryCheckoutId
* @param string $backto
*/
- public function store(Request $request, $accessoryCheckoutId = null, $backto = null): RedirectResponse
+ public function store(UploadFileRequest $request, $accessoryCheckoutId = null, $backto = null): RedirectResponse
{
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryCheckoutId))) {
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
@@ -75,9 +75,14 @@ public function store(Request $request, $accessoryCheckoutId = null, $backto = n
$checkin_at = $request->input('checkin_at').' '.$checkin_hours;
}
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/accessories/', 'checkin-'.$accessory->id, $request->file('file'));
+ }
+
// Was the accessory updated?
if ($accessory_checkout->delete()) {
- event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at));
+ event(new CheckoutableCheckedIn($accessory, $accessory_checkout->assignedTo, auth()->user(), $request->input('note'), $checkin_at, [], $file_name));
session()->put(['redirect_option' => $request->input('redirect_option')]);
diff --git a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php
index f1e3502f1185..2c220020f0af 100644
--- a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php
+++ b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php
@@ -96,6 +96,11 @@ public function store(AccessoryCheckoutRequest $request, Accessory $accessory):
$accessory_checkout->save();
}
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/accessories/', 'checkout-'.$accessory->id, $request->file('file'));
+ }
+
event(new CheckoutableCheckedOut(
$accessory,
$target,
@@ -104,6 +109,7 @@ public function store(AccessoryCheckoutRequest $request, Accessory $accessory):
[],
$accessory->checkout_qty,
$request->boolean('sign_in_place'),
+ $file_name,
));
$request->request->add(['checkout_to_type' => request('checkout_to_type')]);
diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php
index 5f9998f596bd..f36b868e6a32 100644
--- a/app/Http/Controllers/Api/AccessoriesController.php
+++ b/app/Http/Controllers/Api/AccessoriesController.php
@@ -8,6 +8,7 @@
use App\Http\Requests\AccessoryCheckoutRequest;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\StoreAccessoryRequest;
+use App\Http\Requests\UploadFileRequest;
use App\Http\Traits\CheckInOutTrait;
use App\Http\Transformers\AccessoriesTransformer;
use App\Http\Transformers\ActionlogsTransformer;
@@ -22,6 +23,7 @@
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Gate;
class AccessoriesController extends Controller
{
@@ -314,8 +316,13 @@ public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory
$accessory->checkout_qty = $request->input('checkout_qty', 1);
$payload = null;
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/accessories/', 'checkout-'.$accessory->id, $request->file('file'));
+ }
+
// Keep checkout rows and checkout log/event atomic to avoid ghost assignments.
- DB::transaction(function () use ($accessory, $request, $target, &$payload): void {
+ DB::transaction(function () use ($accessory, $request, $target, $file_name, &$payload): void {
for ($i = 0; $i < $accessory->checkout_qty; $i++) {
$accessory_checkout = new AccessoryCheckout([
@@ -347,6 +354,8 @@ public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory
$request->input('note'),
[],
$accessory->checkout_qty,
+ false,
+ $file_name,
));
});
@@ -367,7 +376,7 @@ public function checkout(AccessoryCheckoutRequest $request, Accessory $accessory
*
* @internal param int $accessoryId
*/
- public function checkin(Request $request, $accessoryUserId = null)
+ public function checkin(UploadFileRequest $request, $accessoryUserId = null)
{
if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) {
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist', ['id' => $accessoryUserId])));
@@ -376,7 +385,16 @@ 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'));
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/accessories/', 'checkin-'.$accessory->id, $request->file('file'));
+ }
+
+ $accessory->logCheckin(User::find($accessory_checkout->assigned_to), $request->input('note'), null, []);
+
+ if ($file_name && Gate::allows('files', $accessory)) {
+ $accessory->logUpload($file_name, null);
+ }
// Was the accessory updated?
if ($accessory_checkout->delete()) {
diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php
index b2b1a4042cfb..49fc96fcf39c 100644
--- a/app/Http/Controllers/Api/AssetsController.php
+++ b/app/Http/Controllers/Api/AssetsController.php
@@ -10,6 +10,7 @@
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\StoreAssetRequest;
use App\Http\Requests\UpdateAssetRequest;
+use App\Http\Requests\UploadFileRequest;
use App\Http\Traits\MigratesLegacyAssetLocations;
use App\Http\Transformers\ActionlogsTransformer;
use App\Http\Transformers\AssetsTransformer;
@@ -1085,9 +1086,14 @@ public function checkout(AssetCheckoutRequest $request, $asset_id): JsonResponse
// $asset->location_id = $target->rtd_location_id;
// }
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/assets/', 'checkout-'.$asset->id, $request->file('file'));
+ }
+
// Keep checkout mutation + checkout logging/event side effects atomic.
- $wasCheckedOut = DB::transaction(function () use ($asset, $target, $checkout_at, $expected_checkin, $note, $asset_name): bool {
- return $asset->checkOut($target, auth()->user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id);
+ $wasCheckedOut = DB::transaction(function () use ($asset, $target, $checkout_at, $expected_checkin, $note, $asset_name, $file_name): bool {
+ return $asset->checkOut($target, auth()->user(), $checkout_at, $expected_checkin, $note, $asset_name, $asset->location_id, false, $file_name);
});
if ($wasCheckedOut) {
@@ -1106,7 +1112,7 @@ public function checkout(AssetCheckoutRequest $request, $asset_id): JsonResponse
*
* @since [v4.0]
*/
- public function checkin(Request $request, $asset_id): JsonResponse
+ public function checkin(UploadFileRequest $request, $asset_id): JsonResponse
{
$asset = Asset::with('model')->findOrFail($asset_id);
$this->authorize('checkin', $asset);
@@ -1173,6 +1179,11 @@ function (Builder $query) use ($asset) {
$acceptance->delete();
});
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/assets/', 'checkin-'.$asset->id, $request->file('file'));
+ }
+
if ($asset->save()) {
// Update the location of any child assets
@@ -1180,7 +1191,7 @@ function (Builder $query) use ($asset) {
->where('assigned_to', $asset->id)
->update(['location_id' => $asset->location_id]);
- event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
+ event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues, $file_name));
return response()->json(Helper::formatStandardApiResponse('success', [
'asset_tag' => e($asset->asset_tag),
@@ -1199,7 +1210,7 @@ function (Builder $query) use ($asset) {
*
* @since [v6.0]
*/
- public function checkinByTag(Request $request, $tag = null): JsonResponse
+ public function checkinByTag(UploadFileRequest $request, $tag = null): JsonResponse
{
$this->authorize('checkin', Asset::class);
if ($tag == null && null !== ($request->input('asset_tag'))) {
diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php
index bf754ba1a55d..ac527b3b5645 100644
--- a/app/Http/Controllers/Api/ComponentsController.php
+++ b/app/Http/Controllers/Api/ComponentsController.php
@@ -6,6 +6,7 @@
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\ImageUploadRequest;
+use App\Http\Requests\UploadFileRequest;
use App\Http\Transformers\ActionlogsTransformer;
use App\Http\Transformers\ComponentsTransformer;
use App\Models\Asset;
@@ -17,6 +18,7 @@
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
+use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
@@ -290,7 +292,7 @@ public function getAssets(Component $component, Request $request): array
*
* @param int $componentId
*/
- public function checkout(Request $request, $componentId): JsonResponse
+ public function checkout(UploadFileRequest $request, $componentId): JsonResponse
{
// Check if the component exists
if (! $component = Component::find($componentId)) {
@@ -327,6 +329,11 @@ public function checkout(Request $request, $componentId): JsonResponse
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.error_user_company')));
}
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/components/', 'checkout-'.$component->id, $request->file('file'));
+ }
+
// Keep pivot + action log in one transaction so checkout is all-or-nothing.
DB::transaction(function () use ($component, $request, $asset): void {
$component->assigned_to = $request->input('assigned_to');
@@ -343,6 +350,10 @@ public function checkout(Request $request, $componentId): JsonResponse
$component->logCheckout($request->input('note'), $asset, null, [], $request->get('assigned_qty', 1));
});
+ if ($file_name && Gate::allows('files', $component)) {
+ $component->logUpload($file_name, null);
+ }
+
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkout.success')));
}
@@ -356,7 +367,7 @@ public function checkout(Request $request, $componentId): JsonResponse
*
* @since [v5.1.8]
*/
- public function checkin(Request $request, $component_asset_id): JsonResponse
+ public function checkin(UploadFileRequest $request, $component_asset_id): JsonResponse
{
if ($component_assets = DB::table('components_assets')->find($component_asset_id)) {
if (is_null($component = Component::find($component_assets->component_id))) {
@@ -394,7 +405,12 @@ public function checkin(Request $request, $component_asset_id): JsonResponse
$asset = Asset::find($component_assets->asset_id);
- event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/components/', 'checkin-'.$component->id, $request->file('file'));
+ }
+
+ event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now(), [], $file_name));
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 83758d47b930..44d33d8a41d2 100644
--- a/app/Http/Controllers/Api/ConsumablesController.php
+++ b/app/Http/Controllers/Api/ConsumablesController.php
@@ -8,6 +8,7 @@
use App\Http\Requests\FilterRequest;
use App\Http\Requests\ImageUploadRequest;
use App\Http\Requests\StoreConsumableRequest;
+use App\Http\Requests\UploadFileRequest;
use App\Http\Transformers\ActionlogsTransformer;
use App\Http\Transformers\ConsumablesTransformer;
use App\Http\Transformers\SelectlistTransformer;
@@ -282,7 +283,7 @@ public function getDataView($consumableId): array
*
* @since [v4.9.5]
*/
- public function checkout(Request $request, $id): JsonResponse
+ public function checkout(UploadFileRequest $request, $id): JsonResponse
{
// Check if the consumable exists
if (! $consumable = Consumable::with('users')->find($id)) {
@@ -322,8 +323,13 @@ public function checkout(Request $request, $id): JsonResponse
// Update the consumable data
$consumable->assigned_to = $request->input('assigned_to');
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/consumables/', 'checkout-'.$consumable->id, $request->file('file'));
+ }
+
// Keep pivot writes and checkout log/event atomic to avoid partial checkout state.
- DB::transaction(function () use ($consumable, $request, $user): void {
+ DB::transaction(function () use ($consumable, $request, $user, $file_name): void {
for ($i = 0; $i < $consumable->checkout_qty; $i++) {
$consumable->users()->attach($consumable->id,
[
@@ -342,6 +348,8 @@ public function checkout(Request $request, $id): JsonResponse
$request->input('note'),
[],
$consumable->checkout_qty,
+ false,
+ $file_name,
));
});
diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php
index 458f900dd159..a551faa97307 100644
--- a/app/Http/Controllers/Api/LicensesController.php
+++ b/app/Http/Controllers/Api/LicensesController.php
@@ -7,6 +7,7 @@
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
use App\Http\Requests\FilterRequest;
+use App\Http\Requests\UploadFileRequest;
use App\Http\Transformers\ActionlogsTransformer;
use App\Http\Transformers\LicenseSeatsTransformer;
use App\Http\Transformers\LicensesTransformer;
@@ -278,7 +279,7 @@ public function destroy($id): JsonResponse
*
* @param int $licenseId
*/
- public function checkout(Request $request, $licenseId): JsonResponse
+ public function checkout(UploadFileRequest $request, $licenseId): JsonResponse
{
$license = License::findOrFail($licenseId);
$this->authorize('checkout', $license);
@@ -295,11 +296,16 @@ public function checkout(Request $request, $licenseId): JsonResponse
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.checkout.license_is_inactive')));
}
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/licenses/', 'checkout-'.$license->id, $request->file('file'));
+ }
+
$errorResponse = null;
$updatedSeat = null;
$target = null;
- DB::transaction(function () use ($license, $validated, &$errorResponse, &$updatedSeat, &$target): void {
+ DB::transaction(function () use ($license, $validated, $file_name, &$errorResponse, &$updatedSeat, &$target): void {
$seatId = $validated['seat_id'] ?? null;
$licenseSeat = $seatId
@@ -365,7 +371,7 @@ public function checkout(Request $request, $licenseId): JsonResponse
return;
}
- event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), $validated['notes'] ?? null));
+ event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), $validated['notes'] ?? null, [], 1, false, $file_name));
$updatedSeat = $licenseSeat->load('license', 'user', 'asset');
});
@@ -387,7 +393,7 @@ public function checkout(Request $request, $licenseId): JsonResponse
*
* @param int $licenseId
*/
- public function checkin(Request $request, $licenseId): JsonResponse
+ public function checkin(UploadFileRequest $request, $licenseId): JsonResponse
{
$license = License::findOrFail($licenseId);
$this->authorize('checkin', $license);
@@ -423,7 +429,12 @@ public function checkin(Request $request, $licenseId): JsonResponse
return response()->json(Helper::formatStandardApiResponse('error', null, $licenseSeat->getErrors()));
}
- event(new CheckoutableCheckedIn($licenseSeat, $target, auth()->user(), $licenseSeat->notes));
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/licenses/', 'checkin-'.$license->id, $request->file('file'));
+ }
+
+ event(new CheckoutableCheckedIn($licenseSeat, $target, auth()->user(), $licenseSeat->notes, null, [], $file_name));
return response()->json(Helper::formatStandardApiResponse('success', (new LicenseSeatsTransformer)->transformLicenseSeat($licenseSeat->load('license', 'user', 'asset')), trans('admin/licenses/message.checkin.success')));
}
diff --git a/app/Http/Controllers/Assets/AssetCheckinController.php b/app/Http/Controllers/Assets/AssetCheckinController.php
index fb3b81eacb16..a197b7e8bb29 100644
--- a/app/Http/Controllers/Assets/AssetCheckinController.php
+++ b/app/Http/Controllers/Assets/AssetCheckinController.php
@@ -178,13 +178,18 @@ function (Builder $query) use ($asset) {
// Add any custom fields that should be included in the checkout
$asset->customFieldsForCheckinCheckout('display_checkin');
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/assets/', 'checkin-'.$asset->id, $request->file('file'));
+ }
+
if ($asset->save()) {
// Update the location of any child assets
Asset::where('assigned_type', Asset::class)
->where('assigned_to', $asset->id)
->update(['location_id' => $asset->location_id]);
- event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues));
+ event(new CheckoutableCheckedIn($asset, $target, auth()->user(), $request->input('note'), $checkin_at, $originalValues, $file_name));
return Helper::getRedirectOption($request, $asset->id, 'Assets')
->with('success', trans('admin/hardware/message.checkin.success'));
diff --git a/app/Http/Controllers/Assets/AssetCheckoutController.php b/app/Http/Controllers/Assets/AssetCheckoutController.php
index 0c8e0d7f2ee3..e0ae289ea91b 100644
--- a/app/Http/Controllers/Assets/AssetCheckoutController.php
+++ b/app/Http/Controllers/Assets/AssetCheckoutController.php
@@ -138,7 +138,12 @@ public function store(AssetCheckoutRequest $request, $assetId): RedirectResponse
'sign_in_place' => $request->boolean('sign_in_place'),
]);
- if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->input('note'), $request->input('name'), null, $request->boolean('sign_in_place'))) {
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/assets/', 'checkout-'.$asset->id, $request->file('file'));
+ }
+
+ if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, $request->input('note'), $request->input('name'), null, $request->boolean('sign_in_place'), $file_name)) {
// When sign_in_place is requested and the target is a user, redirect to the
// acceptance/signature page so the user can sign in person. The signature is
diff --git a/app/Http/Controllers/Components/ComponentCheckinController.php b/app/Http/Controllers/Components/ComponentCheckinController.php
index 4980b4e997ec..a506e2b9b4de 100644
--- a/app/Http/Controllers/Components/ComponentCheckinController.php
+++ b/app/Http/Controllers/Components/ComponentCheckinController.php
@@ -5,12 +5,12 @@
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
+use App\Http\Requests\UploadFileRequest;
use App\Models\Asset;
use App\Models\Component;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
-use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
@@ -62,7 +62,7 @@ public function create($component_asset_id)
*
* @throws AuthorizationException
*/
- public function store(Request $request, $component_asset_id, $backto = null)
+ public function store(UploadFileRequest $request, $component_asset_id, $backto = null)
{
if ($component_assets = DB::table('components_assets')->find($component_asset_id)) {
if (is_null($component = Component::find($component_assets->component_id))) {
@@ -101,7 +101,12 @@ public function store(Request $request, $component_asset_id, $backto = null)
$asset = Asset::find($component_assets->asset_id);
- event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now()));
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/components/', 'checkin-'.$component->id, $request->file('file'));
+ }
+
+ event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now(), [], $file_name));
session()->put(['redirect_option' => $request->input('redirect_option')]);
diff --git a/app/Http/Controllers/Components/ComponentCheckoutController.php b/app/Http/Controllers/Components/ComponentCheckoutController.php
index 90c0bc309be8..945f91037c60 100644
--- a/app/Http/Controllers/Components/ComponentCheckoutController.php
+++ b/app/Http/Controllers/Components/ComponentCheckoutController.php
@@ -5,12 +5,12 @@
use App\Events\CheckoutableCheckedOut;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
+use App\Http\Requests\UploadFileRequest;
use App\Models\Asset;
use App\Models\Component;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
-use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
class ComponentCheckoutController extends Controller
@@ -72,7 +72,7 @@ public function create($id)
*
* @throws AuthorizationException
*/
- public function store(Request $request, $componentId)
+ public function store(UploadFileRequest $request, $componentId)
{
// Check if the component exists
if (! $component = Component::find($componentId)) {
@@ -124,6 +124,11 @@ public function store(Request $request, $componentId)
'note' => $request->input('note'),
]);
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/components/', 'checkout-'.$component->id, $request->file('file'));
+ }
+
event(new CheckoutableCheckedOut(
$component,
$asset,
@@ -131,6 +136,8 @@ public function store(Request $request, $componentId)
$request->input('note'),
[],
$component->checkout_qty,
+ false,
+ $file_name,
));
$request->request->add(['checkout_to_type' => 'asset']);
diff --git a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php
index 018655fe7c20..2550c068a0c4 100644
--- a/app/Http/Controllers/Consumables/ConsumableCheckoutController.php
+++ b/app/Http/Controllers/Consumables/ConsumableCheckoutController.php
@@ -5,13 +5,13 @@
use App\Events\CheckoutableCheckedOut;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
+use App\Http\Requests\UploadFileRequest;
use App\Models\CheckoutAcceptance;
use App\Models\Consumable;
use App\Models\User;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
-use Illuminate\Http\Request;
class ConsumableCheckoutController extends Controller
{
@@ -68,7 +68,7 @@ public function create($id): View|RedirectResponse
*
* @throws AuthorizationException
*/
- public function store(Request $request, $consumableId)
+ public function store(UploadFileRequest $request, $consumableId)
{
if (is_null($consumable = Consumable::with('users')->find($consumableId))) {
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.not_found'));
@@ -118,6 +118,11 @@ public function store(Request $request, $consumableId)
$consumable->checkout_qty = $quantity;
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/consumables/', 'checkout-'.$consumable->id, $request->file('file'));
+ }
+
event(new CheckoutableCheckedOut(
$consumable,
$user,
@@ -126,6 +131,7 @@ public function store(Request $request, $consumableId)
[],
$consumable->checkout_qty,
$request->boolean('sign_in_place'),
+ $file_name,
));
$request->request->add(['checkout_to_type' => 'user']);
diff --git a/app/Http/Controllers/Licenses/LicenseCheckinController.php b/app/Http/Controllers/Licenses/LicenseCheckinController.php
index 6960caadbf61..87bb6e7ea20e 100644
--- a/app/Http/Controllers/Licenses/LicenseCheckinController.php
+++ b/app/Http/Controllers/Licenses/LicenseCheckinController.php
@@ -5,6 +5,7 @@
use App\Events\CheckoutableCheckedIn;
use App\Helpers\Helper;
use App\Http\Controllers\Controller;
+use App\Http\Requests\UploadFileRequest;
use App\Models\Asset;
use App\Models\License;
use App\Models\LicenseSeat;
@@ -55,7 +56,7 @@ public function create(LicenseSeat $licenseSeat, $backTo = null)
*
* @throws AuthorizationException
*/
- public function store(Request $request, $seatId = null, $backTo = null)
+ public function store(UploadFileRequest $request, $seatId = null, $backTo = null)
{
// Check if the asset exists
if (is_null($licenseSeat = LicenseSeat::find($seatId))) {
@@ -108,9 +109,14 @@ public function store(Request $request, $seatId = null, $backTo = null)
session()->put(['checkout_to_type' => 'user']);
}
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/licenses/', 'checkin-'.$licenseSeat->license_id, $request->file('file'));
+ }
+
// Was the asset updated?
if ($licenseSeat->save()) {
- event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $licenseSeat->notes));
+ event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $licenseSeat->notes, null, [], $file_name));
return Helper::getRedirectOption($request, $license->id, 'Licenses')
->with('success', trans('admin/licenses/message.checkin.success'));
diff --git a/app/Http/Controllers/Licenses/LicenseCheckoutController.php b/app/Http/Controllers/Licenses/LicenseCheckoutController.php
index 54bcef42f8d1..53c6a5bdb3c0 100644
--- a/app/Http/Controllers/Licenses/LicenseCheckoutController.php
+++ b/app/Http/Controllers/Licenses/LicenseCheckoutController.php
@@ -118,18 +118,23 @@ public function store(LicenseCheckoutRequest $request, $licenseId, $seatId = nul
}
}
+ $file_name = null;
+ if ($request->hasFile('file')) {
+ $file_name = $request->handleFile('private_uploads/licenses/', 'checkout-'.$license->id, $request->file('file'));
+ }
+
$licenseSeat = null;
$checkoutTarget = null;
- DB::transaction(function () use ($request, $license, $seatId, &$licenseSeat, &$checkoutTarget): void {
+ DB::transaction(function () use ($request, $license, $seatId, $file_name, &$licenseSeat, &$checkoutTarget): void {
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId, lock: true);
$licenseSeat->created_by = auth()->id();
$licenseSeat->notes = $request->input('notes');
if ($request->filled('asset_id')) {
- $checkoutTarget = $this->checkoutToAsset($licenseSeat);
+ $checkoutTarget = $this->checkoutToAsset($licenseSeat, $file_name);
} elseif ($request->filled('assigned_to')) {
- $checkoutTarget = $this->checkoutToUser($licenseSeat);
+ $checkoutTarget = $this->checkoutToUser($licenseSeat, $file_name);
}
});
@@ -209,7 +214,7 @@ protected function findLicenseSeatToCheckout($license, $seatId, bool $lock = fal
return $licenseSeat;
}
- protected function checkoutToAsset($licenseSeat)
+ protected function checkoutToAsset($licenseSeat, ?string $file_name = null)
{
if (is_null($target = Asset::find(request('asset_id')))) {
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist'));
@@ -221,7 +226,7 @@ protected function checkoutToAsset($licenseSeat)
$licenseSeat->assigned_to = $target->assigned_to;
}
if ($licenseSeat->save()) {
- event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'), [], 1, request()->boolean('sign_in_place')));
+ event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'), [], 1, request()->boolean('sign_in_place'), $file_name));
return $target;
}
@@ -229,7 +234,7 @@ protected function checkoutToAsset($licenseSeat)
return false;
}
- protected function checkoutToUser($licenseSeat)
+ protected function checkoutToUser($licenseSeat, ?string $file_name = null)
{
// Fetch the target and set the license user
if (is_null($target = User::find(request('assigned_to')))) {
@@ -238,7 +243,7 @@ protected function checkoutToUser($licenseSeat)
$licenseSeat->assigned_to = request('assigned_to');
if ($licenseSeat->save()) {
- event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'), [], 1, request()->boolean('sign_in_place')));
+ event(new CheckoutableCheckedOut($licenseSeat, $target, auth()->user(), request('notes'), [], 1, request()->boolean('sign_in_place'), $file_name));
return $target;
}
diff --git a/app/Http/Requests/AssetCheckinRequest.php b/app/Http/Requests/AssetCheckinRequest.php
index dc5179f49c5b..0cbe96eacfc6 100644
--- a/app/Http/Requests/AssetCheckinRequest.php
+++ b/app/Http/Requests/AssetCheckinRequest.php
@@ -4,7 +4,7 @@
use App\Models\Setting;
-class AssetCheckinRequest extends Request
+class AssetCheckinRequest extends UploadFileRequest
{
/**
* Determine if the user is authorized to make this request.
diff --git a/app/Http/Requests/AssetCheckoutRequest.php b/app/Http/Requests/AssetCheckoutRequest.php
index 35e972d1c6f4..7f9e8e2d3ce6 100644
--- a/app/Http/Requests/AssetCheckoutRequest.php
+++ b/app/Http/Requests/AssetCheckoutRequest.php
@@ -4,7 +4,7 @@
use App\Models\Setting;
-class AssetCheckoutRequest extends Request
+class AssetCheckoutRequest extends UploadFileRequest
{
/**
* Determine if the user is authorized to make this request.
diff --git a/app/Http/Requests/ImageUploadRequest.php b/app/Http/Requests/ImageUploadRequest.php
index 8c30c486f134..9e5289d84dc7 100644
--- a/app/Http/Requests/ImageUploadRequest.php
+++ b/app/Http/Requests/ImageUploadRequest.php
@@ -13,7 +13,7 @@
use Intervention\Image\Exception\NotReadableException;
use Intervention\Image\Facades\Image;
-class ImageUploadRequest extends Request
+class ImageUploadRequest extends UploadFileRequest
{
use ConvertsBase64ToFiles;
diff --git a/app/Http/Requests/LicenseCheckoutRequest.php b/app/Http/Requests/LicenseCheckoutRequest.php
index ad14e00e1c93..daafefbbe2b7 100644
--- a/app/Http/Requests/LicenseCheckoutRequest.php
+++ b/app/Http/Requests/LicenseCheckoutRequest.php
@@ -2,9 +2,7 @@
namespace App\Http\Requests;
-use Illuminate\Foundation\Http\FormRequest;
-
-class LicenseCheckoutRequest extends FormRequest
+class LicenseCheckoutRequest extends UploadFileRequest
{
/**
* Determine if the user is authorized to make this request.
diff --git a/app/Listeners/LogListener.php b/app/Listeners/LogListener.php
index c2de69d88827..b90b45c2ec93 100644
--- a/app/Listeners/LogListener.php
+++ b/app/Listeners/LogListener.php
@@ -10,6 +10,7 @@
use App\Models\Actionlog;
use App\Models\LicenseSeat;
use App\Models\User;
+use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
class LogListener
@@ -23,6 +24,13 @@ class LogListener
public function onCheckoutableCheckedIn(CheckoutableCheckedIn $event)
{
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date, $event->originalValues);
+
+ if ($event->filename) {
+ $item = $event->checkoutable instanceof LicenseSeat ? $event->checkoutable->license : $event->checkoutable;
+ if (Gate::allows('files', $item)) {
+ $event->checkoutable->logUpload($event->filename, null);
+ }
+ }
}
/**
@@ -40,6 +48,13 @@ public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event)
$event->originalValues,
$event->quantity
);
+
+ if ($event->filename) {
+ $item = $event->checkoutable instanceof LicenseSeat ? $event->checkoutable->license : $event->checkoutable;
+ if (Gate::allows('files', $item)) {
+ $event->checkoutable->logUpload($event->filename, null);
+ }
+ }
}
/**
diff --git a/app/Models/Asset.php b/app/Models/Asset.php
index d3b1991a5a3a..1cb9eafb44dc 100644
--- a/app/Models/Asset.php
+++ b/app/Models/Asset.php
@@ -520,7 +520,7 @@ public function availableForCheckIn()
*
* @return bool
*/
- public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null, bool $signInPlace = false)
+ public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null, bool $signInPlace = false, ?string $filename = null)
{
if (! $target) {
return false;
@@ -564,7 +564,7 @@ public function checkOut($target, $admin = null, $checkout_at = null, $expected_
} else {
$checkedOutBy = auth()->user();
}
- event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note, $originalValues, 1, $signInPlace));
+ event(new CheckoutableCheckedOut($this, $target, $checkedOutBy, $note, $originalValues, 1, $signInPlace, $filename));
$this->increment('checkout_counter', 1);
diff --git a/app/Models/Traits/HasUploads.php b/app/Models/Traits/HasUploads.php
index 3af2a94c9c3c..e81e765fd13c 100644
--- a/app/Models/Traits/HasUploads.php
+++ b/app/Models/Traits/HasUploads.php
@@ -15,7 +15,7 @@ public function uploads()
return $this->hasMany(Actionlog::class, 'item_id')
->withoutGlobalScope(CompanyableScope::class)
->where('item_type', self::class)
- ->where('action_type', '=', 'uploaded')
+ ->whereIn('action_type', ['uploaded', 'checkout', 'checkin', 'audit'])
->whereNotNull('filename')
->whereNotIn('filename', function ($query) {
$query->select('filename')
diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php
index 6adaa776ff78..2cac4cae8044 100644
--- a/database/factories/UserFactory.php
+++ b/database/factories/UserFactory.php
@@ -475,6 +475,31 @@ public function manageSupplierFiles()
return $this->appendPermission(['suppliers.files' => '1']);
}
+ public function assetsFiles()
+ {
+ return $this->appendPermission(['assets.files' => '1']);
+ }
+
+ public function accessoriesFiles()
+ {
+ return $this->appendPermission(['accessories.files' => '1']);
+ }
+
+ public function licensesFiles()
+ {
+ return $this->appendPermission(['licenses.files' => '1']);
+ }
+
+ public function componentsFiles()
+ {
+ return $this->appendPermission(['components.files' => '1']);
+ }
+
+ public function consumablesFiles()
+ {
+ return $this->appendPermission(['consumables.files' => '1']);
+ }
+
private function appendPermission(array $permission)
{
return $this->state(function ($currentState) use ($permission) {
diff --git a/resources/views/accessories/checkin.blade.php b/resources/views/accessories/checkin.blade.php
index e467aa5f7281..2665d6032e17 100755
--- a/resources/views/accessories/checkin.blade.php
+++ b/resources/views/accessories/checkin.blade.php
@@ -30,6 +30,8 @@
type="textarea"
/>
+
+ {{ $help_text ?? trans('general.upload_filetypes_help', ['allowed_filetypes' => config('filesystems.allowed_upload_extensions'), 'size' => Helper::file_upload_max_size_readable()]) }} +
+ + {!! $errors->first($name, '') !!} +{{ trans('general.upload_filetypes_help', ['allowed_filetypes' => config('filesystems.allowed_upload_extensions'), 'size' => Helper::file_upload_max_size_readable()]) }}
-{{ trans('general.image_filetypes_help', ['size' => Helper::file_upload_max_size_readable()]) }} {{ $help_text ?? '' }}
+{{ $help_text ?? trans('general.image_filetypes_help', ['size' => Helper::file_upload_max_size_readable()]) }}
{!! $errors->first('image', '') !!}