3
0
mirror of https://github.com/snipe/snipe-it.git synced 2026-08-22 21:29:23 +00:00
Files
snipe-it/app/Http/Controllers/Licenses/BulkLicensesController.php
2026-07-31 00:41:21 +01:00

142 lines
4.9 KiB
PHP

<?php
namespace App\Http\Controllers\Licenses;
use App\Http\Controllers\Controller;
use App\Models\License;
use App\Models\LicenseSeat;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;
use Illuminate\Support\Facades\Log;
class BulkLicensesController extends Controller
{
public function destroy(Request $request)
{
$this->authorize('delete', License::class);
$action = $request->input('bulk_actions', 'delete');
$errors = [];
$success_count = 0;
$checked_in_count = 0;
foreach ($request->input('ids', []) as $id) {
$license = License::find($id);
if (is_null($license)) {
$errors[] = trans('admin/licenses/message.does_not_exist');
continue;
}
if (! Gate::allows('delete', $license)) {
$errors[] = trans('general.insufficient_permissions');
continue;
}
if ($action === 'delete_with_checkin') {
if (! Gate::allows('checkin', $license)) {
$errors[] = trans('general.insufficient_permissions');
continue;
}
$checked_in_count += $this->checkinAssignedSeats($license);
$this->hardResetAndDelete($license);
$success_count++;
continue;
}
if ($license->assigned_seats_count > 0) {
$errors[] = trans('admin/licenses/message.delete.bulk_checkout_warning', ['license_name' => $license->name]);
continue;
}
$this->hardResetAndDelete($license);
$success_count++;
}
if (count($errors) > 0) {
if ($success_count > 0) {
return redirect()->route('licenses.index')
->with('success', $this->partialSuccessMessage($action, $success_count, $checked_in_count))
->with('multi_error_messages', $errors);
}
return redirect()->route('licenses.index')->with('multi_error_messages', $errors);
}
return redirect()->route('licenses.index')
->with('success', $this->fullSuccessMessage($action, $success_count, $checked_in_count));
}
private function checkinAssignedSeats(License $license): int
{
$count = 0;
$note = trans('admin/licenses/general.bulk.delete_with_checkin.log_msg');
LicenseSeat::where('license_id', $license->id)
->where(function ($query) {
$query->whereNotNull('assigned_to')->orWhereNotNull('asset_id');
})
->chunkById(100, function ($seats) use ($license, $note, &$count) {
foreach ($seats as $seat) {
$target = $seat->user ?? $seat->asset;
$seat->assigned_to = null;
$seat->asset_id = null;
if (! $license->reassignable) {
$seat->unreassignable_seat = true;
}
if ($seat->save()) {
Log::debug('Checking in '.$license->name.' seat '.$seat->id.' via bulk delete_with_checkin');
$seat->logCheckin($target, $note);
$count++;
}
}
});
return $count;
}
private function hardResetAndDelete(License $license): void
{
// Any residual seat rows are wiped in one statement (assigned_to/asset_id already null
// for anything we care about). Bypassing Eloquent here is intentional and safe; check-in
// history for seats is preserved in action_log keyed by LicenseSeat item_type/item_id.
DB::table('license_seats')
->where('license_id', $license->id)
->update(['assigned_to' => null, 'asset_id' => null]);
$license->licenseseats()->delete();
$license->delete();
}
private function fullSuccessMessage(string $action, int $success_count, int $checked_in_count): string
{
if ($action === 'delete_with_checkin') {
return trans('admin/licenses/message.delete_with_checkin.bulk_success', [
'count' => $success_count,
'seats' => $checked_in_count,
]);
}
return trans('admin/licenses/message.delete.bulk_success');
}
private function partialSuccessMessage(string $action, int $success_count, int $checked_in_count): string
{
if ($action === 'delete_with_checkin') {
return trans('admin/licenses/message.delete_with_checkin.partial_success', [
'count' => $success_count,
'seats' => $checked_in_count,
]);
}
return trans_choice('admin/licenses/message.delete.partial_success', $success_count, ['count' => $success_count]);
}
}