Compare commits
120 Commits
renamed-us
...
use-tcpdf-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
685bbf4375 | ||
|
|
5d03038734 | ||
|
|
75b11de0f4 | ||
|
|
c5bede8594 | ||
|
|
cd9ea6ae3b | ||
|
|
113b762ec7 | ||
|
|
78704d8b85 | ||
|
|
1109db76fe | ||
|
|
b1b390febf | ||
|
|
be451fa0c0 | ||
|
|
1fa553c785 | ||
|
|
905f61371d | ||
|
|
7da5210a01 | ||
|
|
18172d3896 | ||
|
|
c28e78b9e2 | ||
|
|
e7827a3847 | ||
|
|
db9f85e9da | ||
|
|
27022954b1 | ||
|
|
30362c924f | ||
|
|
bf63b15b46 | ||
|
|
19aea4bd6c | ||
|
|
090890e9c6 | ||
|
|
605022a9e3 | ||
|
|
b06c58fe7b | ||
|
|
f5c8b3eb04 | ||
|
|
739980aa09 | ||
|
|
afde5943e3 | ||
|
|
32300cb42c | ||
|
|
de3b1697c8 | ||
|
|
a18fb10b5a | ||
|
|
52140dbe06 | ||
|
|
db5bb1928e | ||
|
|
65b66beb07 | ||
|
|
c83504b4e7 | ||
|
|
cd2e7ee31d | ||
|
|
c3a0a0415a | ||
|
|
709f4672b7 | ||
|
|
e6c030b050 | ||
|
|
7bd3a791a1 | ||
|
|
b9cfc03b4f | ||
|
|
131327a64d | ||
|
|
77d002a158 | ||
|
|
94699893ac | ||
|
|
9f81989bdd | ||
|
|
15abe36c53 | ||
|
|
3094e007ee | ||
|
|
eb259aee22 | ||
|
|
c05c8defb9 | ||
|
|
bf5668a42e | ||
|
|
ec310bc8fb | ||
|
|
db477421b2 | ||
|
|
30a9496cf5 | ||
|
|
6cefa0d0b3 | ||
|
|
9284984265 | ||
|
|
53b96168a9 | ||
|
|
eadce51f10 | ||
|
|
b3c583b6dc | ||
|
|
28abeab31d | ||
|
|
12a649ec4b | ||
|
|
35b79e4d14 | ||
|
|
751dad7f2e | ||
|
|
b08d86220a | ||
|
|
3a27ecc475 | ||
|
|
da6fab5d43 | ||
|
|
ca95b29cd6 | ||
|
|
c5c68e9dd5 | ||
|
|
44fbde26fa | ||
|
|
6e2bcd6aa9 | ||
|
|
9c0202e5ce | ||
|
|
39ef353073 | ||
|
|
7b5d90dd81 | ||
|
|
d1129081df | ||
|
|
315a812df5 | ||
|
|
cfc979acf0 | ||
|
|
d7407d70a3 | ||
|
|
8ccd2e97a8 | ||
|
|
988204619f | ||
|
|
35b358d336 | ||
|
|
ae109be631 | ||
|
|
3f7ed73395 | ||
|
|
553ab8851a | ||
|
|
2b8ea9a233 | ||
|
|
b0067fee51 | ||
|
|
732c3dae89 | ||
|
|
d45bd67cae | ||
|
|
9200de5032 | ||
|
|
3fbbff5a47 | ||
|
|
c22efc2c3d | ||
|
|
8c0281bf70 | ||
|
|
720a4bc4a2 | ||
|
|
7fd93645b3 | ||
|
|
fcbfbca6d0 | ||
|
|
f2bca9491c | ||
|
|
b48f309ab6 | ||
|
|
0b1be3e63b | ||
|
|
8c129c10af | ||
|
|
63ce2a14fe | ||
|
|
f435ebb110 | ||
|
|
843f001bf6 | ||
|
|
0d28165c04 | ||
|
|
ee31bfbcd4 | ||
|
|
1c67d6802d | ||
|
|
5da8c86ec7 | ||
|
|
10a2d59ec1 | ||
|
|
34e8360b10 | ||
|
|
ca259ee4c3 | ||
|
|
2143952a1e | ||
|
|
6bab6e7151 | ||
|
|
d217c2e295 | ||
|
|
52bf0faaa5 | ||
|
|
3f3f2bfc61 | ||
|
|
f050864fb4 | ||
|
|
db11fc35f4 | ||
|
|
f47a2b10c0 | ||
|
|
344b4e7d60 | ||
|
|
7a23372489 | ||
|
|
9da15a8e58 | ||
|
|
50e0e4a07b | ||
|
|
5e1562ae4c | ||
|
|
8a0ed49623 |
12
.github/workflows/tests-mysql.yml
vendored
12
.github/workflows/tests-mysql.yml
vendored
@@ -76,4 +76,16 @@ jobs:
|
||||
DB_DATABASE: snipeit
|
||||
DB_PORT: ${{ job.services.mysql.ports[3306] }}
|
||||
DB_USERNAME: root
|
||||
LOG_CHANNEL: single
|
||||
LOG_LEVEL: debug
|
||||
run: php artisan test
|
||||
|
||||
- name: Upload Laravel logs as artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
|
||||
path: |
|
||||
storage/logs/*.log
|
||||
if-no-files-found: ignore
|
||||
retention-days: 7
|
||||
|
||||
12
.github/workflows/tests-postgres.yml
vendored
12
.github/workflows/tests-postgres.yml
vendored
@@ -75,4 +75,16 @@ jobs:
|
||||
DB_PORT: ${{ job.services.postgresql.ports[5432] }}
|
||||
DB_USERNAME: snipeit
|
||||
DB_PASSWORD: password
|
||||
LOG_CHANNEL: single
|
||||
LOG_LEVEL: debug
|
||||
run: php artisan test
|
||||
|
||||
- name: Upload Laravel logs as artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
|
||||
path: |
|
||||
storage/logs/*.log
|
||||
if-no-files-found: ignore
|
||||
retention-days: 7
|
||||
|
||||
12
.github/workflows/tests-sqlite.yml
vendored
12
.github/workflows/tests-sqlite.yml
vendored
@@ -61,4 +61,16 @@ jobs:
|
||||
- name: Execute tests (Unit and Feature tests) via PHPUnit
|
||||
env:
|
||||
DB_CONNECTION: sqlite
|
||||
LOG_CHANNEL: single
|
||||
LOG_LEVEL: debug
|
||||
run: php artisan test
|
||||
|
||||
- name: Upload Laravel logs as artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }}
|
||||
path: |
|
||||
storage/logs/*.log
|
||||
if-no-files-found: ignore
|
||||
retention-days: 7
|
||||
|
||||
@@ -59,6 +59,9 @@ class PaveIt extends Command
|
||||
'migrations',
|
||||
'settings',
|
||||
'users',
|
||||
'telescope_entries',
|
||||
'telescope_entries_tags',
|
||||
'telescope_monitoring',
|
||||
];
|
||||
|
||||
// We only need to find out what these are so we can nuke these columns on the assets table.
|
||||
|
||||
@@ -65,7 +65,7 @@ class Purge extends Command
|
||||
$maintenances = 0;
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
$this->info('- Asset "'.$asset->present()->name().'" deleted.');
|
||||
$this->info('- Asset "'.$asset->display_name.'" deleted.');
|
||||
$asset_assoc += $asset->assetlog()->count();
|
||||
$asset->assetlog()->forceDelete();
|
||||
$maintenances += $asset->maintenances()->count();
|
||||
|
||||
@@ -82,6 +82,13 @@ class Helper
|
||||
'zu' => 'zu-ZA', // Zulu
|
||||
];
|
||||
|
||||
public static function hasRtl($value) {
|
||||
$rtlChar = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u';
|
||||
return preg_match($rtlChar, $value) != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple helper to invoke the markdown parser
|
||||
*
|
||||
@@ -1706,5 +1713,5 @@ class Helper
|
||||
}
|
||||
}
|
||||
return $mismatched;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ class IconHelper
|
||||
case 'clone':
|
||||
return 'far fa-clone';
|
||||
case 'delete':
|
||||
case 'upload deleted':
|
||||
return 'fas fa-trash';
|
||||
case 'create':
|
||||
return 'fa-solid fa-plus';
|
||||
|
||||
@@ -71,6 +71,7 @@ class AccessoryCheckoutController extends Controller
|
||||
$this->authorize('checkout', $accessory);
|
||||
|
||||
$target = $this->determineCheckoutTarget();
|
||||
session()->put(['checkout_to_type' => $target]);
|
||||
|
||||
$accessory->checkout_qty = $request->input('checkout_qty', 1);
|
||||
|
||||
|
||||
@@ -30,11 +30,12 @@ use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Http\Controllers\SettingsController;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Carbon\Carbon;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
use \Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use TCPDF;
|
||||
use App\Helpers\Helper;
|
||||
|
||||
class AcceptanceController extends Controller
|
||||
{
|
||||
@@ -178,7 +179,7 @@ class AcceptanceController extends Controller
|
||||
break;
|
||||
|
||||
case 'App\Models\Component':
|
||||
$pdf_view_route ='account.accept.accept-component-eula';
|
||||
$pdf_view_route = 'account.accept.accept-component-eula';
|
||||
$component = Component::find($item->id);
|
||||
$display_model = $component->name;
|
||||
break;
|
||||
@@ -217,7 +218,7 @@ class AcceptanceController extends Controller
|
||||
} elseif (!is_null($branding_settings->logo)) {
|
||||
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
|
||||
}
|
||||
|
||||
|
||||
$data = [
|
||||
'item_tag' => $item->asset_tag,
|
||||
'item_model' => $display_model,
|
||||
@@ -225,9 +226,9 @@ class AcceptanceController extends Controller
|
||||
'item_status' => $item->assetstatus?->name,
|
||||
'eula' => $item->getEula(),
|
||||
'note' => $request->input('note'),
|
||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'),
|
||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'),
|
||||
'assigned_to' => $assigned_user->present()->fullName,
|
||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d H:i:s'),
|
||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d H:i:s'),
|
||||
'assigned_to' => $assigned_user->display_name,
|
||||
'company_name' => $branding_settings->site_name,
|
||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||
'logo' => $path_logo,
|
||||
@@ -235,13 +236,88 @@ class AcceptanceController extends Controller
|
||||
'admin' => auth()->user()->present()?->fullName,
|
||||
];
|
||||
|
||||
|
||||
if ($pdf_view_route!='') {
|
||||
Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||
//$pdf = new PDF;
|
||||
|
||||
// set some language dependent data:
|
||||
$lg = Array();
|
||||
$lg['a_meta_charset'] = 'UTF-8';
|
||||
$lg['w_page'] = 'page';
|
||||
|
||||
$pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false);
|
||||
// $pdf->SetHeaderData(PDF_HEADER_LOGO, 5, PDF_HEADER_TITLE.' 006', PDF_HEADER_STRING);
|
||||
// $pdf->SetHeaderData('https://snipe-it.test/uploads/snipe-logo.png', '5', $data['company_name'], $item->company?->name);
|
||||
//$pdf->headerText = ('Anything you want ' . date('c'));
|
||||
$pdf->setRTL(false);
|
||||
//$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, $data['company_name'], '');
|
||||
$pdf->setLanguageArray($lg);
|
||||
$pdf->SetCreator('Snipe-IT');
|
||||
$pdf->SetAuthor($data['assigned_to']);
|
||||
$pdf->SetTitle('Asset Acceptance: '.$data['item_tag']);
|
||||
// $pdf->SetSubject('Document Subject');
|
||||
//$pdf->SetKeywords('keywords, here');
|
||||
$pdf->SetFont('dejavusans', '', 8, '', true);
|
||||
|
||||
|
||||
$pdf->SetPrintHeader(false);
|
||||
$pdf->SetPrintFooter(false);
|
||||
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
|
||||
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
|
||||
|
||||
$pdf->AddPage();
|
||||
$pdf->writeHTML('<img src="'.$path_logo.'" height="30">', true, 0, true, 0, '');
|
||||
|
||||
// $pdf->writeHTML(trans('general.date').': '.date($data['date_settings']), true, 0, true, 0, '');
|
||||
$pdf->writeHTML("<strong>".trans('general.asset_tag').'</strong>: '.$data['item_tag'], true, 0, true, 0, '');
|
||||
$pdf->writeHTML("<strong>".trans('general.asset_model').'</strong>: '.$data['item_model'], true, 0, true, 0, '');
|
||||
$pdf->writeHTML("<strong>".trans('admin/hardware/form.serial').'</strong>: '.$data['item_serial'], true, 0, true, 0, '');
|
||||
$pdf->writeHTML("<strong>".trans('general.assigned_date').'</strong>: '.$data['check_out_date'], true, 0, true, 0, '');
|
||||
$pdf->writeHTML("<strong>".trans('general.assignee').'</strong>: '.$data['assigned_to'], true, 0, true, 0, '');
|
||||
$pdf->Ln();
|
||||
// $html = view($pdf_view_route, $data)->render();
|
||||
// $pdf->writeHTML($html, true, 0, true, 0, '');
|
||||
|
||||
// $eula_lines = explode("\n\n", $item->getEula());
|
||||
$eula_lines = preg_split("/\r\n|\n|\r/", $item->getEula());
|
||||
|
||||
foreach ($eula_lines as $eula_line) {
|
||||
if (Helper::hasRtl($eula_line)) {
|
||||
$pdf->setRTL(true);
|
||||
} else {
|
||||
$pdf->setRTL(false);
|
||||
}
|
||||
$pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, '');
|
||||
}
|
||||
$pdf->Ln();
|
||||
$pdf->Ln();
|
||||
$pdf->setRTL(false);
|
||||
$pdf->writeHTML('<br><br>', true, 0, true, 0, '');
|
||||
|
||||
if ($data['note'] != null) {
|
||||
$pdf->writeHTML("<strong>".trans('general.notes') . '</strong>: ' . $data['note'], true, 0, true, 0, '');
|
||||
$pdf->Ln();
|
||||
}
|
||||
|
||||
if ($data['signature'] != null) {
|
||||
|
||||
$pdf->writeHTML('<img src="'.$data['signature'].'" style="max-width: 600px;">', true, 0, true, 0, '');
|
||||
$pdf->writeHTML('<hr>', true, 0, true, 0, '');
|
||||
}
|
||||
|
||||
$pdf->writeHTML("<strong>".trans('general.accepted_date').'</strong>: '.$data['accepted_date'], true, 0, true, 0, '');
|
||||
|
||||
|
||||
$pdf_content = $pdf->Output($pdf_filename, 'S');
|
||||
|
||||
|
||||
//$html = view($pdf_view_route, $data)->render();
|
||||
//$pdf = PDF::writeHTML($html, true, false, true, false, '');
|
||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf_content);
|
||||
}
|
||||
|
||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||
// $acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note'));
|
||||
|
||||
// Send the PDF to the signing user
|
||||
if (($request->input('send_copy') == '1') && ($assigned_user->email !='')) {
|
||||
|
||||
@@ -288,32 +288,42 @@ class AccessoriesController extends Controller
|
||||
'note' => $request->input('note'),
|
||||
]);
|
||||
|
||||
|
||||
$accessory_checkout->created_by = auth()->id();
|
||||
$accessory_checkout->save();
|
||||
|
||||
$payload = [
|
||||
'accessory_id' => $accessory->id,
|
||||
'assigned_to' => $target->id,
|
||||
'assigned_type' => $target::class,
|
||||
'note' => $request->input('note'),
|
||||
'created_by' => auth()->id(),
|
||||
'pivot' => $accessory_checkout->id,
|
||||
];
|
||||
}
|
||||
|
||||
// Set this value to be able to pass the qty through to the event
|
||||
event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note')));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkout.success')));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check in the item so that it can be checked out again to someone else
|
||||
*
|
||||
* @uses Accessory::checkin_email() to determine if an email can and should be sent
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param Request $request
|
||||
* @param int $accessoryUserId
|
||||
* @param string $backto
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @return JsonResponse
|
||||
* @uses Accessory::checkin_email() to determine if an email can and should be sent
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @internal param int $accessoryId
|
||||
*/
|
||||
public function checkin(Request $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')));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist', ['id' => $accessoryUserId])));
|
||||
}
|
||||
|
||||
$accessory = Accessory::find($accessory_checkout->accessory_id);
|
||||
@@ -327,7 +337,14 @@ class AccessoriesController extends Controller
|
||||
$user = User::find($accessory_checkout->assigned_to);
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success')));
|
||||
$payload = [
|
||||
'accessory_id' => $accessory->id,
|
||||
'note' => $request->input('note'),
|
||||
'created_by' => auth()->id(),
|
||||
'pivot' => $accessory_checkout->id,
|
||||
];
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkin.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error')));
|
||||
|
||||
@@ -50,6 +50,7 @@ class AssetModelsController extends Controller
|
||||
'fieldset',
|
||||
'deleted_at',
|
||||
'updated_at',
|
||||
'require_serial',
|
||||
];
|
||||
|
||||
$assetmodels = AssetModel::select([
|
||||
@@ -69,6 +70,7 @@ class AssetModelsController extends Controller
|
||||
'models.fieldset_id',
|
||||
'models.deleted_at',
|
||||
'models.updated_at',
|
||||
'models.require_serial'
|
||||
])
|
||||
->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser')
|
||||
->withCount('assets as assets_count');
|
||||
|
||||
@@ -69,7 +69,7 @@ class ImportController extends Controller
|
||||
if (function_exists('iconv')) {
|
||||
$file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it?
|
||||
$encoding = $detector->getEncoding($file_contents);
|
||||
\Log::warning("Discovered encoding: $encoding in uploaded CSV");
|
||||
\Log::debug("Discovered encoding: $encoding in uploaded CSV");
|
||||
$reader = null;
|
||||
if (strcasecmp($encoding, 'UTF-8') != 0) {
|
||||
$transliterated = false;
|
||||
@@ -103,7 +103,7 @@ class ImportController extends Controller
|
||||
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
|
||||
|
||||
try {
|
||||
$import->header_row = $reader->fetchOne(0);
|
||||
$import->header_row = $reader->nth(0);
|
||||
} catch (JsonEncodingException $e) {
|
||||
return response()->json(
|
||||
Helper::formatStandardApiResponse(
|
||||
@@ -136,7 +136,7 @@ class ImportController extends Controller
|
||||
|
||||
try {
|
||||
// Grab the first row to display via ajax as the user picks fields
|
||||
$import->first_row = $reader->fetchOne(1);
|
||||
$import->first_row = $reader->nth(1);
|
||||
} catch (JsonEncodingException $e) {
|
||||
return response()->json(
|
||||
Helper::formatStandardApiResponse(
|
||||
|
||||
@@ -128,7 +128,9 @@ class LicenseSeatsController extends Controller
|
||||
// nothing to update
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
||||
}
|
||||
|
||||
if( $touched && $licenseSeat->unreassignable_seat) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.checkout.unavailable')));
|
||||
}
|
||||
// the logging functions expect only one "target". if both asset and user are present in the request,
|
||||
// we simply let assets take precedence over users...
|
||||
if ($licenseSeat->isDirty('assigned_to')) {
|
||||
@@ -145,7 +147,11 @@ class LicenseSeatsController extends Controller
|
||||
if ($licenseSeat->save()) {
|
||||
|
||||
if ($is_checkin) {
|
||||
$licenseSeat->logCheckin($target, $request->input('notes'));
|
||||
if(!$licenseSeat->license->reassignable){
|
||||
$licenseSeat->unreassignable_seat = true;
|
||||
$licenseSeat->save();
|
||||
}
|
||||
$licenseSeat->logCheckin($target, $licenseSeat->notes);
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ class ProfileController extends Controller
|
||||
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
|
||||
$assets = [
|
||||
'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()),
|
||||
'name' => e($checkoutRequest->itemRequested()->present()->name()),
|
||||
'name' => e($checkoutRequest->itemRequested()->display_name),
|
||||
'type' => e($checkoutRequest->itemType()),
|
||||
'qty' => (int) $checkoutRequest->quantity,
|
||||
'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null,
|
||||
|
||||
@@ -32,7 +32,7 @@ class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('view', $object);
|
||||
|
||||
if (!$object) {
|
||||
@@ -51,11 +51,7 @@ class UploadedFilesController extends Controller
|
||||
];
|
||||
|
||||
|
||||
$uploads = Actionlog::select('action_logs.*')
|
||||
->whereNotNull('filename')
|
||||
->where('item_type', self::$map_object_type[$object_type])
|
||||
->where('item_id', $object->id)
|
||||
->where('action_type', '=', 'uploaded')
|
||||
$uploads = self::$map_object_type[$object_type]::withTrashed()->find($id)->uploads()
|
||||
->with('adminuser');
|
||||
|
||||
$offset = ($request->input('offset') > $uploads->count()) ? $uploads->count() : abs($request->input('offset'));
|
||||
@@ -96,7 +92,7 @@ class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('view', $object);
|
||||
|
||||
if (!$object) {
|
||||
@@ -144,7 +140,7 @@ class UploadedFilesController extends Controller
|
||||
public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
||||
{
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('view', $object);
|
||||
|
||||
if (!$object) {
|
||||
@@ -188,7 +184,7 @@ class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('update', self::$map_object_type[$object_type]);
|
||||
|
||||
if (!$object) {
|
||||
@@ -206,7 +202,7 @@ class UploadedFilesController extends Controller
|
||||
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||
}
|
||||
// Delete the record of the file
|
||||
if ($log->delete()) {
|
||||
if ($log->logUploadDelete($object, $log->filename)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200);
|
||||
}
|
||||
|
||||
|
||||
@@ -435,7 +435,7 @@ class UsersController extends Controller
|
||||
$user->password = $user->noPassword();
|
||||
}
|
||||
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
if ($user->save()) {
|
||||
|
||||
@@ -560,7 +560,7 @@ class UsersController extends Controller
|
||||
Asset::where('assigned_type', User::class)
|
||||
->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]);
|
||||
}
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar');
|
||||
app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
if ($user->save()) {
|
||||
// Check if the request has groups passed and has a value, AND that the user us a superuser
|
||||
|
||||
@@ -82,6 +82,7 @@ class AssetModelsController extends Controller
|
||||
$model->notes = $request->input('notes');
|
||||
$model->created_by = auth()->id();
|
||||
$model->requestable = $request->has('requestable');
|
||||
$model->require_serial = $request->input('require_serial', 0);
|
||||
|
||||
if ($request->input('fieldset_id') != '') {
|
||||
$model->fieldset_id = $request->input('fieldset_id');
|
||||
@@ -155,7 +156,7 @@ class AssetModelsController extends Controller
|
||||
$model->category_id = $request->input('category_id');
|
||||
$model->notes = $request->input('notes');
|
||||
$model->requestable = $request->input('requestable', '0');
|
||||
|
||||
$model->require_serial = $request->input('require_serial', 0);
|
||||
$model->fieldset_id = $request->input('fieldset_id');
|
||||
|
||||
if ($model->save()) {
|
||||
|
||||
@@ -65,6 +65,8 @@ class AssetCheckoutController extends Controller
|
||||
*/
|
||||
public function store(AssetCheckoutRequest $request, $assetId) : RedirectResponse
|
||||
{
|
||||
|
||||
|
||||
try {
|
||||
// Check if the asset exists
|
||||
if (! $asset = Asset::find($assetId)) {
|
||||
@@ -81,6 +83,7 @@ class AssetCheckoutController extends Controller
|
||||
$admin = auth()->user();
|
||||
|
||||
$target = $this->determineCheckoutTarget();
|
||||
session()->put(['checkout_to_type' => $target]);
|
||||
|
||||
$asset = $this->updateAssetLocation($asset, $target);
|
||||
|
||||
|
||||
@@ -110,17 +110,35 @@ class AssetsController extends Controller
|
||||
// This is only necessary on create, not update, since bulk editing is handled
|
||||
// differently
|
||||
$asset_tags = $request->input('asset_tags');
|
||||
$model = AssetModel::find($request->input('model_id'));
|
||||
$serial_errors = [];
|
||||
$serials = $request->input('serials');
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
//Validate required serial based on model setting
|
||||
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
|
||||
if ($model && $model->require_serial === 1 && empty($serials[$a])) {
|
||||
$serial_errors["serials.$a"] = trans('admin/hardware/form.serial_required', ['number' => $a]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!empty($serial_errors)) {
|
||||
return redirect()->back()
|
||||
->withInput()
|
||||
->withErrors($serial_errors);
|
||||
}
|
||||
|
||||
$asset = null;
|
||||
$companyId = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$successes = [];
|
||||
$failures = [];
|
||||
$serials = $request->input('serials');
|
||||
$asset = null;
|
||||
|
||||
for ($a = 1; $a <= count($asset_tags); $a++) {
|
||||
for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) {
|
||||
$asset = new Asset();
|
||||
$asset->model()->associate(AssetModel::find($request->input('model_id')));
|
||||
|
||||
$asset->model()->associate($model);
|
||||
$asset->name = $request->input('name');
|
||||
|
||||
// Check for a corresponding serial
|
||||
@@ -132,7 +150,7 @@ class AssetsController extends Controller
|
||||
$asset->asset_tag = $asset_tags[$a];
|
||||
}
|
||||
|
||||
$asset->company_id = Company::getIdForCurrentUser($request->input('company_id'));
|
||||
$asset->company_id = $companyId;
|
||||
$asset->model_id = $request->input('model_id');
|
||||
$asset->order_number = $request->input('order_number');
|
||||
$asset->notes = $request->input('notes');
|
||||
@@ -172,7 +190,6 @@ class AssetsController extends Controller
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
@@ -453,6 +470,13 @@ class AssetsController extends Controller
|
||||
]);
|
||||
|
||||
|
||||
//Validate required serial based on model setting
|
||||
if ($model && $model->require_serial === 1 && empty($serial[1])) {
|
||||
return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets'))
|
||||
->with('warning', trans('admin/hardware/form.serial_required_post_model_update', [
|
||||
'asset_model' => $model->name
|
||||
]));
|
||||
}
|
||||
if ($asset->save()) {
|
||||
return Helper::getRedirectOption($request, $asset->id, 'Assets')
|
||||
->with('success', trans('admin/hardware/message.update.success'));
|
||||
|
||||
@@ -637,6 +637,7 @@ class BulkAssetsController extends Controller
|
||||
$admin = auth()->user();
|
||||
|
||||
$target = $this->determineCheckoutTarget();
|
||||
session()->put(['checkout_to_type' => $target]);
|
||||
|
||||
if (! is_array($request->get('selected_assets'))) {
|
||||
return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
|
||||
|
||||
@@ -92,7 +92,9 @@ class BulkAssetModelsController extends Controller
|
||||
$update_array['min_amt'] = $request->input('min_amt');
|
||||
}
|
||||
|
||||
|
||||
if ($request->filled('require_serial')) {
|
||||
$update_array['require_serial'] = $request->input('require_serial');
|
||||
}
|
||||
|
||||
if (count($update_array) > 0) {
|
||||
AssetModel::whereIn('id', $models_raw_array)->update($update_array);
|
||||
|
||||
@@ -64,12 +64,7 @@ class LicenseCheckinController extends Controller
|
||||
|
||||
$this->authorize('checkout', $license);
|
||||
|
||||
if (! $license->reassignable) {
|
||||
// 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 = [
|
||||
@@ -98,6 +93,9 @@ class LicenseCheckinController extends Controller
|
||||
$licenseSeat->assigned_to = null;
|
||||
$licenseSeat->asset_id = null;
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
if (! $licenseSeat->license->reassignable) {
|
||||
$licenseSeat->unreassignable_seat = true;
|
||||
}
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
if ($request->get('redirect_option') === 'target'){
|
||||
@@ -106,7 +104,7 @@ class LicenseCheckinController extends Controller
|
||||
|
||||
// Was the asset updated?
|
||||
if ($licenseSeat->save()) {
|
||||
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes')));
|
||||
event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $licenseSeat->notes));
|
||||
|
||||
|
||||
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||
@@ -132,21 +130,17 @@ class LicenseCheckinController extends Controller
|
||||
$license = License::findOrFail($licenseId);
|
||||
$this->authorize('checkin', $license);
|
||||
|
||||
if (! $license->reassignable) {
|
||||
// Not allowed to checkin
|
||||
Session::flash('error', 'License not reassignable.');
|
||||
|
||||
return redirect()->back()->withInput();
|
||||
}
|
||||
|
||||
$licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId)
|
||||
->whereNotNull('assigned_to')
|
||||
->with('user')
|
||||
->with('user', 'license')
|
||||
->get();
|
||||
|
||||
$license = $licenseSeatsByUser->first()?->license;
|
||||
foreach ($licenseSeatsByUser as $user_seat) {
|
||||
$user_seat->assigned_to = null;
|
||||
|
||||
if ($license && ! $license->reassignable) {
|
||||
$user_seat->unreassignable_seat = true;
|
||||
}
|
||||
if ($user_seat->save()) {
|
||||
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'));
|
||||
@@ -159,9 +153,12 @@ class LicenseCheckinController extends Controller
|
||||
->get();
|
||||
|
||||
$count = 0;
|
||||
$license = $licenseSeatsByAsset->first()?->license;
|
||||
foreach ($licenseSeatsByAsset as $asset_seat) {
|
||||
$asset_seat->asset_id = null;
|
||||
|
||||
if ($license && ! $license->reassignable) {
|
||||
$asset_seat->unreassignable_seat = true;
|
||||
}
|
||||
if ($asset_seat->save()) {
|
||||
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'));
|
||||
|
||||
@@ -39,6 +39,11 @@ class LicenseCheckoutController extends Controller
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'));
|
||||
}
|
||||
|
||||
// We don't currently allow checking out licenses to locations, so we'll reset that to user if needed
|
||||
if (session()->get('checkout_to_type') == 'location') {
|
||||
session()->put(['checkout_to_type' => 'user']);
|
||||
}
|
||||
|
||||
// Return the checkout view
|
||||
return view('licenses/checkout', compact('license'));
|
||||
}
|
||||
@@ -70,17 +75,15 @@ class LicenseCheckoutController extends Controller
|
||||
$licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId);
|
||||
$licenseSeat->created_by = auth()->id();
|
||||
$licenseSeat->notes = $request->input('notes');
|
||||
|
||||
|
||||
$checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type'));
|
||||
|
||||
if ($request->filled('asset_id')) {
|
||||
|
||||
session()->put(['checkout_to_type' => 'asset']);
|
||||
$checkoutTarget = $this->checkoutToAsset($licenseSeat);
|
||||
$request->request->add(['assigned_asset' => $checkoutTarget->id]);
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']);
|
||||
|
||||
} elseif ($request->filled('assigned_to')) {
|
||||
session()->put(['checkout_to_type' => 'user']);
|
||||
$checkoutTarget = $this->checkoutToUser($licenseSeat);
|
||||
$request->request->add(['assigned_user' => $checkoutTarget->id]);
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']);
|
||||
@@ -89,6 +92,7 @@ class LicenseCheckoutController extends Controller
|
||||
|
||||
|
||||
if ($checkoutTarget) {
|
||||
|
||||
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||
->with('success', trans('admin/licenses/message.checkout.success'));
|
||||
}
|
||||
|
||||
@@ -245,16 +245,25 @@ class LicensesController extends Controller
|
||||
$license = License::with('assignedusers')->find($license->id);
|
||||
|
||||
$users_count = User::where('autoassign_licenses', '1')->count();
|
||||
$total_seats_count = $license->totalSeatsByLicenseID();
|
||||
|
||||
$total_seats_count = (int) $license->totalSeatsByLicenseID();
|
||||
$available_seats_count = $license->availCount()->count();
|
||||
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
|
||||
$unreassignable_seats_count = License::unReassignableCount($license);
|
||||
|
||||
if(!$license->reassignable){
|
||||
$checkedout_seats_count = ($total_seats_count - $available_seats_count - $unreassignable_seats_count );
|
||||
}
|
||||
else {
|
||||
$checkedout_seats_count = ($total_seats_count - $available_seats_count);
|
||||
}
|
||||
|
||||
$this->authorize('view', $license);
|
||||
return view('licenses.view', compact('license'))
|
||||
->with('users_count', $users_count)
|
||||
->with('total_seats_count', $total_seats_count)
|
||||
->with('available_seats_count', $available_seats_count)
|
||||
->with('checkedout_seats_count', $checkedout_seats_count);
|
||||
->with('checkedout_seats_count', $checkedout_seats_count)
|
||||
->with('unreassignable_seats_count', $unreassignable_seats_count);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -159,7 +159,7 @@ class ReportsController extends Controller
|
||||
$row[] = e($asset->serial);
|
||||
|
||||
if ($target = $asset->assignedTo) {
|
||||
$row[] = e($target->present()->name());
|
||||
$row[] = e($target->display_name);
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
@@ -830,7 +830,7 @@ class ReportsController extends Controller
|
||||
}
|
||||
|
||||
if ($request->filled('location')) {
|
||||
$row[] = ($asset->location) ? $asset->location->present()->name() : '';
|
||||
$row[] = ($asset->location) ? $asset->location->display_name : '';
|
||||
}
|
||||
|
||||
if ($request->filled('location_address')) {
|
||||
@@ -843,7 +843,7 @@ class ReportsController extends Controller
|
||||
}
|
||||
|
||||
if ($request->filled('rtd_location')) {
|
||||
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->present()->name() : '';
|
||||
$row[] = ($asset->defaultLoc) ? $asset->defaultLoc->display_name : '';
|
||||
}
|
||||
|
||||
if ($request->filled('rtd_location_address')) {
|
||||
@@ -856,8 +856,8 @@ class ReportsController extends Controller
|
||||
}
|
||||
|
||||
if ($request->filled('assigned_to')) {
|
||||
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ?? $asset->assigned->display_name;
|
||||
$row[] = ($asset->checkedOutToUser() && $asset->assigned) ? 'user' : $asset->assignedType();
|
||||
$row[] = ($asset->assigned) ? $asset->assigned->display_name : '';
|
||||
$row[] = ($asset->assigned) ? $asset->assignedType() : '';
|
||||
}
|
||||
|
||||
if ($request->filled('username')) {
|
||||
@@ -1260,7 +1260,7 @@ class ReportsController extends Controller
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
|
||||
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
|
||||
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->display_name : trans('admin/reports/general.deleted_user')));
|
||||
$rows[] = implode(',', $row);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('update', $object);
|
||||
|
||||
if (!$object) {
|
||||
@@ -85,7 +85,7 @@ class UploadedFilesController extends Controller
|
||||
public function show($object_type, $id, $file_id) : RedirectResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse
|
||||
{
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('view', $object);
|
||||
|
||||
if (!$object) {
|
||||
@@ -130,7 +130,7 @@ class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$object = self::$map_object_type[$object_type]::withTrashed()->find($id);
|
||||
$this->authorize('update', self::$map_object_type[$object_type]);
|
||||
|
||||
if (!$object) {
|
||||
@@ -139,7 +139,7 @@ class UploadedFilesController extends Controller
|
||||
|
||||
|
||||
// Check for the file
|
||||
$log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
|
||||
$log = Actionlog::where('id',$file_id)->where('item_type', self::$map_object_type[$object_type])
|
||||
->where('item_id', $object->id)->first();
|
||||
|
||||
if ($log) {
|
||||
@@ -148,7 +148,7 @@ class UploadedFilesController extends Controller
|
||||
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||
}
|
||||
// Delete the record of the file
|
||||
if ($log->delete()) {
|
||||
if ($log->logUploadDelete($object, $log->filename)) {
|
||||
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.success', 1));
|
||||
}
|
||||
|
||||
|
||||
@@ -50,17 +50,20 @@ class ActionlogsTransformer
|
||||
|
||||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||
{
|
||||
|
||||
$icon = $actionlog->present()->icon();
|
||||
|
||||
if (($actionlog->filename!='') && ($actionlog->action_type!='upload deleted')) {
|
||||
$icon = Helper::filetype_icon($actionlog->filename);
|
||||
}
|
||||
|
||||
static $custom_fields = false;
|
||||
|
||||
if ($custom_fields === false) {
|
||||
$custom_fields = CustomField::all();
|
||||
}
|
||||
|
||||
if ($actionlog->filename!='') {
|
||||
$icon = Helper::filetype_icon($actionlog->filename);
|
||||
}
|
||||
|
||||
|
||||
// This is necessary since we can't escape special characters within a JSON object
|
||||
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
|
||||
|
||||
@@ -65,6 +65,7 @@ class AssetModelsTransformer
|
||||
'default_fieldset_values' => $default_field_values,
|
||||
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
|
||||
'requestable' => ($assetmodel->requestable == '1') ? true : false,
|
||||
'require_serial' => $assetmodel->require_serial,
|
||||
'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes),
|
||||
'created_by' => ($assetmodel->adminuser) ? [
|
||||
'id' => (int) $assetmodel->adminuser->id,
|
||||
|
||||
@@ -76,7 +76,7 @@ class ComponentsTransformer
|
||||
$array[] = [
|
||||
'assigned_pivot_id' => $asset->pivot->id,
|
||||
'id' => (int) $asset->id,
|
||||
'name' => e($asset->model->present()->name).' '.e($asset->present()->name),
|
||||
'name' => e($asset->model->display_name).' '.e($asset->display_name),
|
||||
'qty' => $asset->pivot->assigned_qty,
|
||||
'note' => $asset->pivot->note,
|
||||
'type' => 'asset',
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class LicenseSeatsTransformer
|
||||
{
|
||||
public function transformLicenseSeats(Collection $seats, $total)
|
||||
@@ -52,6 +51,7 @@ class LicenseSeatsTransformer
|
||||
'reassignable' => (bool) $seat->license->reassignable,
|
||||
'notes' => e($seat->notes),
|
||||
'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')),
|
||||
'disabled' => $seat->unreassignable_seat,
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
|
||||
@@ -37,7 +37,7 @@ class LicensesTransformer
|
||||
'notes' => Helper::parseEscapedMarkedownInline($license->notes),
|
||||
'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'),
|
||||
'seats' => (int) $license->seats,
|
||||
'free_seats_count' => (int) $license->free_seats_count,
|
||||
'free_seats_count' => (int) $license->free_seats_count - License::unReassignableCount($license),
|
||||
'remaining' => (int) $license->free_seats_count,
|
||||
'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null,
|
||||
'license_name' => ($license->license_name) ? e($license->license_name) : null,
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class ProfileTransformer
|
||||
@@ -26,7 +25,7 @@ class ProfileTransformer
|
||||
'id' => (int) $file->id,
|
||||
'icon' => Helper::filetype_icon($file->filename),
|
||||
'item' => ($file->item) ? [
|
||||
'name' => ($file->itemType()=='user') ? e($file->item->display_name) : e($file->item->getDisplayNameAttribute()),
|
||||
'name' => $file->item->display_name ? e($file->item->display_name) : null,
|
||||
'type' => e($file->itemType()),
|
||||
] : null,
|
||||
'filename' => e($file->filename),
|
||||
|
||||
@@ -22,7 +22,7 @@ class UsersTransformer
|
||||
public function transformUser(User $user)
|
||||
{
|
||||
|
||||
$role = '';
|
||||
$role = null;
|
||||
if ($user->isSuperUser()) {
|
||||
$role = 'superadmin';
|
||||
} elseif ($user->isAdmin()) {
|
||||
@@ -34,7 +34,7 @@ class UsersTransformer
|
||||
'name' => e($user->getFullNameAttribute()) ?? null,
|
||||
'first_name' => e($user->first_name) ?? null,
|
||||
'last_name' => e($user->last_name) ?? null,
|
||||
'display_name' => e($user->getRawOriginal('display_name')) ?? null,
|
||||
'display_name' => ($user->getRawOriginal('display_name')) ? e($user->getRawOriginal('display_name')) : null,
|
||||
'username' => e($user->username) ?? null,
|
||||
'remote' => ($user->remote == '1') ? true : false,
|
||||
'locale' => ($user->locale) ? e($user->locale) : null,
|
||||
|
||||
@@ -40,11 +40,32 @@ class AssetModelImporter extends ItemImporter
|
||||
{
|
||||
|
||||
$editingAssetModel = false;
|
||||
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
|
||||
/**
|
||||
* This part gets a little confusing, since folks might be importing multiple models with the same name and different model numbers for the first time
|
||||
* or they might be wanting to update existing models with new model numbers.
|
||||
*/
|
||||
|
||||
// They are not trying to update existing models, so we'll check for duplicates with model name *and* number
|
||||
if (! $this->updating) {
|
||||
$this->log('Finding model by name and model number: '.$this->findCsvMatch($row, 'name').' / '.$this->findCsvMatch($row, 'model_number'));
|
||||
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->where('model_number', '=', $this->findCsvMatch($row, 'model_number'))->first();
|
||||
} else {
|
||||
|
||||
if ($this->findCsvMatch($row, 'id')!='') {
|
||||
// Override model if an ID was given
|
||||
$this->log('Finding model by ID: '.$this->findCsvMatch($row, 'id'));
|
||||
$assetModel = AssetModel::find($this->findCsvMatch($row, 'id'));
|
||||
} else {
|
||||
$this->log('Finding model by name: '.$this->findCsvMatch($row, 'name'));
|
||||
$assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($assetModel) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Model '.$this->item['name'].' already exists');
|
||||
$this->log('A matching Model '.$this->item['name'].' already exists and we are not updating. Skipping.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -66,6 +87,7 @@ class AssetModelImporter extends ItemImporter
|
||||
$this->item['fieldset'] = trim($this->findCsvMatch($row, 'fieldset'));
|
||||
$this->item['depreciation'] = trim($this->findCsvMatch($row, 'depreciation'));
|
||||
$this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? 1 : 0;
|
||||
$this->item['require_serial'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'require_serial'))) == 1) ? 1 : 0;
|
||||
|
||||
if (!empty($this->item['category'])) {
|
||||
if ($category = $this->createOrFetchCategory($this->item['category'])) {
|
||||
|
||||
@@ -27,7 +27,7 @@ class ManufacturerImporter extends ItemImporter
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a supplier if a duplicate does not exist.
|
||||
* Create a manufacturer if a duplicate does not exist.
|
||||
* @todo Investigate how this should interact with Importer::createManufacturerIfNotExists
|
||||
*
|
||||
* @author A. Gianotto
|
||||
@@ -39,16 +39,16 @@ class ManufacturerImporter extends ItemImporter
|
||||
|
||||
$editingManufacturer = false;
|
||||
|
||||
$supplier = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
$manufacturer = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first();
|
||||
|
||||
if ($this->findCsvMatch($row, 'id')!='') {
|
||||
// Override supplier if an ID was given
|
||||
\Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id'));
|
||||
$supplier = Manufacturer::find($this->findCsvMatch($row, 'id'));
|
||||
// Override manufacturer if an ID was given
|
||||
\Log::debug('Finding manufacturer by ID: '.$this->findCsvMatch($row, 'id'));
|
||||
$manufacturer = Manufacturer::find($this->findCsvMatch($row, 'id'));
|
||||
}
|
||||
|
||||
|
||||
if ($supplier) {
|
||||
if ($manufacturer) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching Manufacturer '.$this->item['name'].' already exists');
|
||||
return;
|
||||
@@ -58,8 +58,8 @@ class ManufacturerImporter extends ItemImporter
|
||||
$editingManufacturer = true;
|
||||
} else {
|
||||
$this->log('No Matching Manufacturer, Create a new one');
|
||||
$supplier = new Manufacturer;
|
||||
$supplier->created_by = auth()->id();
|
||||
$manufacturer = new Manufacturer;
|
||||
$manufacturer->created_by = auth()->id();
|
||||
}
|
||||
|
||||
// Pull the records from the CSV to determine their values
|
||||
@@ -79,21 +79,21 @@ class ManufacturerImporter extends ItemImporter
|
||||
|
||||
|
||||
if ($editingManufacturer) {
|
||||
Log::debug('Updating existing supplier');
|
||||
$supplier->update($this->sanitizeItemForUpdating($supplier));
|
||||
Log::debug('Updating existing manufacturer');
|
||||
$manufacturer->update($this->sanitizeItemForUpdating($manufacturer));
|
||||
} else {
|
||||
Log::debug('Creating supplier');
|
||||
$supplier->fill($this->sanitizeItemForStoring($supplier));
|
||||
Log::debug('Creating manufacturer');
|
||||
$manufacturer->fill($this->sanitizeItemForStoring($manufacturer));
|
||||
}
|
||||
|
||||
if ($supplier->save()) {
|
||||
$this->log('Manufacturer '.$supplier->name.' created or updated from CSV import');
|
||||
return $supplier;
|
||||
if ($manufacturer->save()) {
|
||||
$this->log('Manufacturer '.$manufacturer->name.' created or updated from CSV import');
|
||||
return $manufacturer;
|
||||
|
||||
} else {
|
||||
Log::debug($supplier->getErrors());
|
||||
$this->logError($supplier, 'Manufacturer "'.$this->item['name'].'"');
|
||||
return $supplier->errors;
|
||||
Log::debug($manufacturer->getErrors());
|
||||
$this->logError($manufacturer, 'Manufacturer "'.$this->item['name'].'"');
|
||||
return $manufacturer->errors;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -403,6 +403,7 @@ class Importer extends Component
|
||||
|
||||
|
||||
$this->assetmodels_fields = [
|
||||
'id' => trans('general.id'),
|
||||
'category' => trans('general.category'),
|
||||
'eol' => trans('general.eol'),
|
||||
'fieldset' => trans('admin/models/general.fieldset'),
|
||||
@@ -412,6 +413,7 @@ class Importer extends Component
|
||||
'model_number' => trans('general.model_no'),
|
||||
'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]),
|
||||
'requestable' => trans('admin/models/general.requestable'),
|
||||
'require_serial' => trans('admin/hardware/general.require_serial'),
|
||||
|
||||
];
|
||||
|
||||
@@ -535,6 +537,10 @@ class Importer extends Component
|
||||
'product key',
|
||||
'key',
|
||||
],
|
||||
'require_serial' =>
|
||||
[
|
||||
'serial required',
|
||||
],
|
||||
'model_number' =>
|
||||
[
|
||||
'model',
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
@@ -65,7 +66,7 @@ class Accessory extends SnipeModel
|
||||
'company_id' => 'integer|nullable',
|
||||
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
||||
'min_amt' => 'integer|min:0|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||
];
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Carbon\Carbon;
|
||||
@@ -245,19 +246,6 @@ class Actionlog extends SnipeModel
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the actionlog -> uploads relationship
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function uploads()
|
||||
{
|
||||
return $this->morphTo('item')
|
||||
->where('action_type', '=', 'uploaded')
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the actionlog -> userlog relationship
|
||||
@@ -455,6 +443,26 @@ class Actionlog extends SnipeModel
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author Godfrey Martinez
|
||||
* @since [v8.0.4]
|
||||
* @return \App\Models\Actionlog
|
||||
*/
|
||||
public function logUploadDelete($object, $filename)
|
||||
{
|
||||
$log = new Actionlog;
|
||||
$log->item_type = $object instanceof SnipeModel ? get_class($object) : $object;
|
||||
$log->item_id = $object->id;
|
||||
$log->created_by = auth()->id();
|
||||
$log->target_id = null;
|
||||
$log->filename = $filename;
|
||||
$log->created_at = date('Y-m-d H:i:s');
|
||||
$log->logaction('upload deleted');
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
public function uploads_file_url()
|
||||
{
|
||||
|
||||
|
||||
@@ -7,19 +7,20 @@ use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use App\Presenters\AssetPresenter;
|
||||
use App\Presenters\Presentable;
|
||||
use Carbon\Carbon;
|
||||
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\Crypt;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
|
||||
/**
|
||||
* Model for Assets.
|
||||
@@ -113,7 +114,7 @@ class Asset extends Depreciable
|
||||
'rtd_location_id' => ['nullable', 'exists:locations,id', 'fmcs_location'],
|
||||
'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'],
|
||||
'serial' => ['nullable', 'string', 'unique_undeleted:assets,serial'],
|
||||
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:9999999999999'],
|
||||
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:99999999999999999.99'],
|
||||
'supplier_id' => ['nullable', 'exists:suppliers,id'],
|
||||
'asset_eol_date' => ['nullable', 'date'],
|
||||
'eol_explicit' => ['nullable', 'boolean'],
|
||||
@@ -1031,10 +1032,10 @@ class Asset extends Depreciable
|
||||
{
|
||||
|
||||
if (($this->model) && ($this->model->category)) {
|
||||
if (($this->model->category->eula_text) && ($this->model->category->use_default_eula === 0)) {
|
||||
return Helper::parseEscapedMarkedown($this->model->category->eula_text);
|
||||
} elseif ($this->model->category->use_default_eula === 1) {
|
||||
return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text);
|
||||
if (($this->model->category->eula_text) && ($this->model->category->use_default_eula == 0)) {
|
||||
return $this->model->category->eula_text;
|
||||
} elseif ($this->model->category->use_default_eula == 1) {
|
||||
return Setting::getSettings()->default_eula_text;
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
@@ -71,6 +71,7 @@ class AssetModel extends SnipeModel
|
||||
'name',
|
||||
'notes',
|
||||
'requestable',
|
||||
'require_serial'
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
|
||||
@@ -46,7 +46,7 @@ class CheckoutRequest extends Model
|
||||
public function name()
|
||||
{
|
||||
if ($this->itemType() == 'asset') {
|
||||
return $this->itemRequested()->present()->name();
|
||||
return $this->itemRequested()->display_name;
|
||||
}
|
||||
|
||||
return $this->itemRequested()->name;
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
/**
|
||||
* Model for Companies.
|
||||
*
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
/**
|
||||
@@ -43,7 +43,7 @@ class Component extends SnipeModel
|
||||
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
||||
'min_amt' => 'integer|min:0|nullable',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||
'manufacturer_id' => 'integer|exists:manufacturers,id|nullable',
|
||||
];
|
||||
|
||||
|
||||
@@ -4,22 +4,16 @@ namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
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\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
|
||||
{
|
||||
@@ -53,7 +47,7 @@ class Consumable extends SnipeModel
|
||||
'company_id' => 'integer|nullable',
|
||||
'location_id' => 'exists:locations,id|nullable|fmcs_location',
|
||||
'min_amt' => 'integer|min:0|max:99999|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable',
|
||||
];
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\Searchable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
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;
|
||||
|
||||
@@ -51,7 +51,7 @@ class License extends Depreciable
|
||||
'notes' => 'string|nullable',
|
||||
'category_id' => 'required|exists:categories,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'purchase_cost'=> 'numeric|nullable|gte:0',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||
'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id',
|
||||
'expiration_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
'termination_date' => 'date_format:Y-m-d|nullable|max:10',
|
||||
@@ -534,6 +534,7 @@ class License extends Depreciable
|
||||
return $this->licenseSeatsRelation()
|
||||
->whereNull('asset_id')
|
||||
->whereNull('assigned_to')
|
||||
->where('unreassignable_seat', '=', false)
|
||||
->whereNull('deleted_at');
|
||||
}
|
||||
|
||||
@@ -585,7 +586,22 @@ class License extends Depreciable
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of unreassignable seats
|
||||
*
|
||||
* @author G. Martinez
|
||||
* @since [v7.1.15]
|
||||
*/
|
||||
public static function unReassignableCount($license) : int
|
||||
{
|
||||
$count = 0;
|
||||
if (!$license->reassignable) {
|
||||
$count = licenseSeat::query()->where('unreassignable_seat', '=', true)
|
||||
->where('license_id', '=', $license->id)
|
||||
->count();
|
||||
}
|
||||
return $count;
|
||||
}
|
||||
/**
|
||||
* Calculates the number of remaining seats
|
||||
*
|
||||
@@ -593,11 +609,12 @@ class License extends Depreciable
|
||||
* @since [v1.0]
|
||||
* @return int
|
||||
*/
|
||||
public function remaincount()
|
||||
public function remaincount() : int
|
||||
{
|
||||
$total = $this->licenseSeatsCount;
|
||||
$taken = $this->assigned_seats_count;
|
||||
$diff = ($total - $taken);
|
||||
$unreassignable = self::unReassignableCount($this);
|
||||
$diff = ($total - $taken - $unreassignable);
|
||||
|
||||
return (int) $diff;
|
||||
}
|
||||
@@ -655,12 +672,11 @@ class License extends Depreciable
|
||||
{
|
||||
return $this->licenseseats()
|
||||
->whereNull('deleted_at')
|
||||
->where(
|
||||
function ($query) {
|
||||
$query->whereNull('assigned_to')
|
||||
->whereNull('asset_id');
|
||||
}
|
||||
)
|
||||
->where('unreassignable_seat', '=', false)
|
||||
->where(function ($query) {
|
||||
$query->whereNull('assigned_to')
|
||||
->whereNull('asset_id');
|
||||
})
|
||||
->orderBy('id', 'asc')
|
||||
->first();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Traits\Acceptable;
|
||||
use App\Models\Traits\CompanyableChildTrait;
|
||||
use App\Notifications\CheckinLicenseNotification;
|
||||
use App\Notifications\CheckoutLicenseNotification;
|
||||
use App\Presenters\Presentable;
|
||||
@@ -21,6 +22,9 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild
|
||||
|
||||
protected $guarded = 'id';
|
||||
protected $table = 'license_seats';
|
||||
protected $casts = [
|
||||
'unreassignable_seat' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
||||
@@ -3,16 +3,11 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Models\User;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Traits\CompanyableChildTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
|
||||
/**
|
||||
* Model for Asset Maintenances.
|
||||
@@ -31,12 +32,12 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
'asset_id' => 'required|integer',
|
||||
'supplier_id' => 'nullable|integer',
|
||||
'asset_maintenance_type' => 'required',
|
||||
'name' => 'required|max:100',
|
||||
'name' => 'required|max:100',
|
||||
'is_warranty' => 'boolean',
|
||||
'start_date' => 'required|date_format:Y-m-d',
|
||||
'completion_date' => 'date_format:Y-m-d|nullable|after_or_equal:start_date',
|
||||
'notes' => 'string|nullable',
|
||||
'cost' => 'numeric|nullable',
|
||||
'cost' => 'numeric|nullable|gte:0|max:99999999999999999.99',
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
namespace App\Models\Traits;
|
||||
|
||||
use App\Models\CompanyableChildScope;
|
||||
|
||||
trait CompanyableChildTrait
|
||||
{
|
||||
@@ -1,6 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
namespace App\Models\Traits;
|
||||
|
||||
use App\Models\CompanyableScope;
|
||||
use App\Models\Setting;
|
||||
|
||||
trait CompanyableTrait
|
||||
{
|
||||
@@ -12,7 +12,14 @@ trait HasUploads
|
||||
return $this->hasMany(Actionlog::class, 'item_id')
|
||||
->where('item_type', self::class)
|
||||
->where('action_type', '=', 'uploaded')
|
||||
->whereNotNull('filename');
|
||||
->whereNotNull('filename')
|
||||
->whereNotIn('filename', function ($query) {
|
||||
$query->select('filename')
|
||||
->from('action_logs')
|
||||
->where('item_type', '=', self::class)
|
||||
->where('action_type', '=', 'upload deleted')
|
||||
->where('item_id', $this->id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,9 +3,11 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Models\Traits\CompanyableTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use App\Presenters\UserPresenter;
|
||||
use Illuminate\Auth\Authenticatable;
|
||||
use Illuminate\Auth\Passwords\CanResetPassword;
|
||||
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
|
||||
@@ -13,6 +15,7 @@ use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
|
||||
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
|
||||
use Illuminate\Contracts\Translation\HasLocalePreference;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
@@ -22,8 +25,6 @@ use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Passport\HasApiTokens;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use App\Presenters\UserPresenter;
|
||||
|
||||
class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||
}
|
||||
$message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->display_name;
|
||||
$details = [
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.notes') => $note ?: '',
|
||||
trans('general.location') => $location ?: '',
|
||||
];
|
||||
|
||||
@@ -90,7 +90,7 @@ class CheckinAccessoryNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -107,7 +107,7 @@ class CheckinAccessoryNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('Accessory_Checkin_Notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||
->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '')
|
||||
->fact(trans('mail.Accessory_Checkin_Notification')." by ", $admin->display_name)
|
||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||
@@ -116,7 +116,7 @@ class CheckinAccessoryNotification extends Notification
|
||||
|
||||
$message = trans('mail.Accessory_Checkin_Notification');
|
||||
$details = [
|
||||
trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.checked_into') => $item->location->name ? $item->location->name : '',
|
||||
trans('mail.Accessory_Checkin_Notification'). ' by' => $admin->display_name,
|
||||
trans('admin/consumables/general.remaining')=> $item->numRemaining(),
|
||||
@@ -135,7 +135,7 @@ class CheckinAccessoryNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Accessory_Checkin_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -93,11 +93,11 @@ class CheckinAssetNotification extends Notification
|
||||
|
||||
|
||||
return (new SlackMessage)
|
||||
->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification'))
|
||||
->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification', ['tag' => '']))
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -112,21 +112,21 @@ class CheckinAssetNotification extends Notification
|
||||
return MicrosoftTeamsMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->type('success')
|
||||
->title(trans('mail.Asset_Checkin_Notification'))
|
||||
->title(trans('mail.Asset_Checkin_Notification', ['tag' => '']))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityText')
|
||||
->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '')
|
||||
->fact(trans('mail.Asset_Checkin_Notification') . " by ", $admin->display_name)
|
||||
->fact(trans('general.administrator'), $admin->display_name)
|
||||
->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name)
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
|
||||
|
||||
$message = trans('mail.Asset_Checkin_Notification');
|
||||
$message = trans('mail.Asset_Checkin_Notification', ['tag' => '']);
|
||||
$details = [
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.checked_into') => ($item->location) ? $item->location->name : '',
|
||||
trans('mail.Asset_Checkin_Notification')." by " => $admin->display_name,
|
||||
trans('general.administrator') => $admin->display_name,
|
||||
trans('admin/hardware/form.status') => $item->assetstatus?->name,
|
||||
trans('mail.notes') => $note ?: '',
|
||||
];
|
||||
@@ -144,8 +144,8 @@ class CheckinAssetNotification extends Notification
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Asset_Checkin_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
'<strong>'.trans('mail.Asset_Checkin_Notification', ['tag' =>'']).'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -100,7 +100,7 @@ class CheckinComponentNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -118,7 +118,7 @@ class CheckinComponentNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('mail.Component_checkin_notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'header')
|
||||
->fact(trans('mail.Component_checkin_notification')." by ", $admin->display_name ?: 'CLI tool')
|
||||
->fact(trans('mail.checkedin_from'), $target->display_name)
|
||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||
@@ -147,7 +147,7 @@ class CheckinComponentNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Component_checkin_notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -101,7 +101,7 @@ class CheckinLicenseSeatNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -119,7 +119,7 @@ class CheckinLicenseSeatNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('mail.License_Checkin_Notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'header')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'header')
|
||||
->fact(trans('mail.License_Checkin_Notification')." by ", $admin->display_name ?: 'CLI tool')
|
||||
->fact(trans('mail.checkedin_from'), $target->display_name)
|
||||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||
@@ -129,7 +129,7 @@ class CheckinLicenseSeatNotification extends Notification
|
||||
$message = trans('mail.License_Checkin_Notification');
|
||||
$details = [
|
||||
trans('mail.checkedin_from')=> $target->display_name,
|
||||
trans('mail.license_for') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.license_for') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.License_Checkin_Notification')." by " => $admin->display_name ?: 'CLI tool',
|
||||
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
|
||||
trans('mail.notes') => $note ?: '',
|
||||
@@ -149,7 +149,7 @@ class CheckinLicenseSeatNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.License_Checkin_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -117,7 +117,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -136,8 +136,8 @@ class CheckoutAccessoryNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('mail.Accessory_Checkout_Notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
||||
->fact(trans('mail.assigned_to'), $target->present()->name)
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||
->fact(trans('general.qty'), $this->checkout_qty)
|
||||
->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '')
|
||||
->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->display_name)
|
||||
@@ -148,7 +148,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||
$message = trans('mail.Accessory_Checkout_Notification');
|
||||
$details = [
|
||||
trans('mail.assigned_to') => $target->present()->name,
|
||||
trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name),
|
||||
trans('general.qty') => $this->checkout_qty,
|
||||
trans('mail.checkedout_from') => $item->location->name ? $item->location->name : '',
|
||||
trans('mail.Accessory_Checkout_Notification'). ' by' => $admin->display_name,
|
||||
@@ -169,7 +169,7 @@ class CheckoutAccessoryNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Accessory_Checkout_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -110,11 +110,11 @@ class CheckoutAssetNotification extends Notification
|
||||
}
|
||||
|
||||
return (new SlackMessage)
|
||||
->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification'))
|
||||
->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification', ['tag' => '']))
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -131,19 +131,19 @@ class CheckoutAssetNotification extends Notification
|
||||
return MicrosoftTeamsMessage::create()
|
||||
->to($this->settings->webhook_endpoint)
|
||||
->type('success')
|
||||
->title(trans('mail.Asset_Checkout_Notification'))
|
||||
->title(trans('mail.Asset_Checkout_Notification', ['tag' => '']))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(trans('mail.assigned_to'), $target->present()->name)
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText')
|
||||
->fact(trans('mail.Asset_Checkout_Notification') . " by ", $admin->display_name)
|
||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityText')
|
||||
->fact(trans('general.administrator'), $admin->display_name)
|
||||
->fact(trans('mail.notes'), $note ?: '');
|
||||
}
|
||||
|
||||
$message = trans('mail.Asset_Checkout_Notification');
|
||||
$message = trans('mail.Asset_Checkout_Notification', ['tag' => '']);
|
||||
$details = [
|
||||
trans('mail.assigned_to') => $target->present()->name,
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.Asset_Checkout_Notification'). ' by' => $admin->display_name,
|
||||
trans('mail.asset') => htmlspecialchars_decode($item->display_name),
|
||||
trans('general.administrator') => $admin->display_name,
|
||||
trans('mail.notes') => $note ?: '',
|
||||
];
|
||||
return array($message, $details);
|
||||
@@ -159,8 +159,8 @@ public function toGoogleChat()
|
||||
->card(
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Asset_Checkout_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
'<strong>'.trans('mail.Asset_Checkout_Notification', ['tag' => '']).'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -97,7 +97,7 @@ class CheckoutComponentNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -116,7 +116,7 @@ class CheckoutComponentNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('mail.Component_checkout_notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||
->fact(trans('mail.Component_checkout_notification')." by ", $admin->display_name)
|
||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||
@@ -126,7 +126,7 @@ class CheckoutComponentNotification extends Notification
|
||||
$message = trans('mail.Component_checkout_notification');
|
||||
$details = [
|
||||
trans('mail.assigned_to') => $target->display_name,
|
||||
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.item') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.Component_checkout_notification').' by' => $admin->display_name,
|
||||
trans('admin/consumables/general.remaining') => $item->numRemaining(),
|
||||
trans('mail.notes') => $note ?: '',
|
||||
@@ -146,7 +146,7 @@ class CheckoutComponentNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Component_checkout_notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -97,7 +97,7 @@ class CheckoutConsumableNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -116,7 +116,7 @@ class CheckoutConsumableNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('mail.Consumable_checkout_notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||
->fact(trans('mail.Consumable_checkout_notification')." by ", $admin->display_name)
|
||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||
@@ -126,7 +126,7 @@ class CheckoutConsumableNotification extends Notification
|
||||
$message = trans('mail.Consumable_checkout_notification');
|
||||
$details = [
|
||||
trans('mail.assigned_to') => $target->display_name,
|
||||
trans('mail.item') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.item') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.Consumable_checkout_notification').' by' => $admin->display_name,
|
||||
trans('admin/consumables/general.remaining') => $item->numRemaining(),
|
||||
trans('mail.notes') => $note ?: '',
|
||||
@@ -146,7 +146,7 @@ class CheckoutConsumableNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.Consumable_checkout_notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -95,7 +95,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $admin, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
@@ -114,7 +114,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
||||
->addStartGroupToSection('activityTitle')
|
||||
->title(trans('mail.License_Checkout_Notification'))
|
||||
->addStartGroupToSection('activityText')
|
||||
->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle')
|
||||
->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle')
|
||||
->fact(trans('mail.License_Checkout_Notification')." by ", $admin->display_name)
|
||||
->fact(trans('mail.assigned_to'), $target->display_name)
|
||||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||
@@ -124,7 +124,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
||||
$message = trans('mail.License_Checkout_Notification');
|
||||
$details = [
|
||||
trans('mail.assigned_to') => $target->display_name,
|
||||
trans('mail.license_for') => htmlspecialchars_decode($item->present()->name),
|
||||
trans('mail.license_for') => htmlspecialchars_decode($item->display_name),
|
||||
trans('mail.License_Checkout_Notification').' by' => $admin->display_name,
|
||||
trans('admin/consumables/general.remaining') => $item->availCount()->count(),
|
||||
trans('mail.notes') => $note ?: '',
|
||||
@@ -143,7 +143,7 @@ class CheckoutLicenseSeatNotification extends Notification
|
||||
Card::create()
|
||||
->header(
|
||||
'<strong>'.trans('mail.License_Checkout_Notification').'</strong>' ?: '',
|
||||
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||
htmlspecialchars_decode($item->display_name) ?: '',
|
||||
)
|
||||
->section(
|
||||
Section::create(
|
||||
|
||||
@@ -50,11 +50,11 @@ class ExpectedCheckinNotification extends Notification
|
||||
$message = (new MailMessage)->markdown('notifications.markdown.expected-checkin',
|
||||
[
|
||||
'date' => Helper::getFormattedDateObject($this->params->expected_checkin, 'date', false),
|
||||
'asset' => $this->params->present()->name(),
|
||||
'asset' => $this->params->display_name,
|
||||
'serial' => $this->params->serial,
|
||||
'asset_tag' => $this->params->asset_tag,
|
||||
])
|
||||
->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->present()->name()]));
|
||||
->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->display_name]));
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ class RequestAssetCancelation extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@ class RequestAssetNotification extends Notification
|
||||
->from($botname)
|
||||
->to($channel)
|
||||
->attachment(function ($attachment) use ($item, $note, $fields) {
|
||||
$attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl())
|
||||
$attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl())
|
||||
->fields($fields)
|
||||
->content($note);
|
||||
});
|
||||
|
||||
@@ -62,6 +62,10 @@ class ActionlogPresenter extends Presenter
|
||||
return 'fa-solid fa-user-minus';
|
||||
}
|
||||
|
||||
if ($this->action_type == 'upload deleted') {
|
||||
return 'fa-solid fa-trash';
|
||||
}
|
||||
|
||||
if ($this->action_type == 'update') {
|
||||
return 'fa-solid fa-user-pen';
|
||||
}
|
||||
@@ -74,7 +78,7 @@ class ActionlogPresenter extends Presenter
|
||||
return 'fa-solid fa-plus';
|
||||
}
|
||||
|
||||
if ($this->action_type == 'delete') {
|
||||
if (($this->action_type == 'delete') || ($this->action_type == 'upload deleted')) {
|
||||
return 'fa-solid fa-trash';
|
||||
}
|
||||
|
||||
@@ -141,7 +145,7 @@ class ActionlogPresenter extends Presenter
|
||||
return $target->present()->nameUrl();
|
||||
}
|
||||
|
||||
return '<del>'.$target->present()->name().'</del>';
|
||||
return '<del>'.$target->display_name.'</del>';
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
@@ -143,6 +143,14 @@ class AssetModelPresenter extends Presenter
|
||||
'title' => trans('admin/hardware/general.requestable'),
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'require_serial',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('admin/hardware/general.require_serial'),
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'notes',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -85,6 +85,12 @@ class AppServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
|
||||
if ($this->app->environment('local')) {
|
||||
$this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class);
|
||||
$this->app->register(TelescopeServiceProvider::class);
|
||||
}
|
||||
|
||||
// Only load rollbar if there is a rollbar key and the app is in production
|
||||
if (($this->app->environment('production')) && (config('logging.channels.rollbar.access_token'))) {
|
||||
$this->app->register(\Rollbar\Laravel\RollbarServiceProvider::class);
|
||||
|
||||
66
app/Providers/TelescopeServiceProvider.php
Normal file
66
app/Providers/TelescopeServiceProvider.php
Normal file
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Laravel\Telescope\IncomingEntry;
|
||||
use Laravel\Telescope\Telescope;
|
||||
use Laravel\Telescope\TelescopeApplicationServiceProvider;
|
||||
|
||||
class TelescopeServiceProvider extends TelescopeApplicationServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
// Telescope::night();
|
||||
|
||||
$this->hideSensitiveRequestDetails();
|
||||
|
||||
$isLocal = $this->app->environment('local');
|
||||
|
||||
Telescope::filter(function (IncomingEntry $entry) use ($isLocal) {
|
||||
return $isLocal ||
|
||||
$entry->isReportableException() ||
|
||||
$entry->isFailedRequest() ||
|
||||
$entry->isFailedJob() ||
|
||||
$entry->isScheduledTask() ||
|
||||
$entry->hasMonitoredTag();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent sensitive request details from being logged by Telescope.
|
||||
*/
|
||||
protected function hideSensitiveRequestDetails(): void
|
||||
{
|
||||
if ($this->app->environment('local')) {
|
||||
return;
|
||||
}
|
||||
|
||||
Telescope::hideRequestParameters(['_token']);
|
||||
|
||||
Telescope::hideRequestHeaders([
|
||||
'cookie',
|
||||
'x-csrf-token',
|
||||
'x-xsrf-token',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the Telescope gate.
|
||||
*
|
||||
* This gate determines who can access Telescope in NON-LOCAL environments.
|
||||
*/
|
||||
protected function gate(): void
|
||||
{
|
||||
Gate::define('viewTelescope', function ($user) {
|
||||
if ($user->isSuperUser()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -32,11 +32,11 @@
|
||||
"arietimmerman/laravel-scim-server": "dev-laravel_11_compatibility",
|
||||
"bacon/bacon-qr-code": "^2.0",
|
||||
"barryvdh/laravel-debugbar": "^3.13",
|
||||
"barryvdh/laravel-dompdf": "^2.0",
|
||||
"doctrine/cache": "^1.10",
|
||||
"doctrine/dbal": "^3.1",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"eduardokum/laravel-mail-auto-embed": "^2.0",
|
||||
"elibyy/tcpdf-laravel": "^11.5",
|
||||
"enshrined/svg-sanitize": "^0.22.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"fakerphp/faker": "^1.24",
|
||||
@@ -84,6 +84,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"larastan/larastan": "^2.9",
|
||||
"laravel/telescope": "^5.11",
|
||||
"mockery/mockery": "^1.4",
|
||||
"nunomaduro/phpinsights": "^2.11",
|
||||
"php-mock/php-mock-phpunit": "^2.10",
|
||||
@@ -95,7 +96,8 @@
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": [
|
||||
"rollbar/rollbar-laravel"
|
||||
"rollbar/rollbar-laravel",
|
||||
"laravel/telescope"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
1330
composer.lock
generated
1330
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -300,7 +300,6 @@ return [
|
||||
App\Providers\SnipeTranslationServiceProvider::class, //we REPLACE the default Laravel translator with our own
|
||||
Illuminate\Validation\ValidationServiceProvider::class,
|
||||
Illuminate\View\ViewServiceProvider::class,
|
||||
Barryvdh\DomPDF\ServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Package Service Providers...
|
||||
@@ -315,6 +314,7 @@ return [
|
||||
Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class,
|
||||
Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class,
|
||||
Laravel\Socialite\SocialiteServiceProvider::class,
|
||||
Elibyy\TCPDF\ServiceProvider::class,
|
||||
|
||||
/*
|
||||
* Application Service Providers...
|
||||
@@ -371,7 +371,7 @@ return [
|
||||
'Mail' => Illuminate\Support\Facades\Mail::class,
|
||||
'Notification' => Illuminate\Support\Facades\Notification::class,
|
||||
'Password' => Illuminate\Support\Facades\Password::class,
|
||||
'PDF' => Barryvdh\DomPDF\Facade::class,
|
||||
'PDF' => Elibyy\TCPDF\Facades\TCPDF::class,
|
||||
'Queue' => Illuminate\Support\Facades\Queue::class,
|
||||
'Redirect' => Illuminate\Support\Facades\Redirect::class,
|
||||
'Redis' => Illuminate\Support\Facades\Redis::class,
|
||||
|
||||
17
config/pdf.php
Normal file
17
config/pdf.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'mode' => 'utf-8',
|
||||
'format' => 'A4',
|
||||
'author' => '',
|
||||
'subject' => '',
|
||||
'keywords' => '',
|
||||
'creator' => 'Laravel Pdf',
|
||||
'display_mode' => 'fullpage',
|
||||
'tempDir' => base_path('../temp/'),
|
||||
'pdf_a' => false,
|
||||
'pdf_a_auto' => false,
|
||||
'icc_profile_path' => '',
|
||||
'defaultCssFile' => false,
|
||||
'pdfWrapper' => 'misterspelik\LaravelPdf\Wrapper\PdfWrapper',
|
||||
];
|
||||
205
config/telescope.php
Normal file
205
config/telescope.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Telescope\Http\Middleware\Authorize;
|
||||
use Laravel\Telescope\Watchers;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Master Switch
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option may be used to disable all Telescope watchers regardless
|
||||
| of their individual configuration, which simply provides a single
|
||||
| and convenient way to enable or disable Telescope data storage.
|
||||
|
|
||||
*/
|
||||
|
||||
'enabled' => env('TELESCOPE_ENABLED', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Domain
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the subdomain where Telescope will be accessible from. If the
|
||||
| setting is null, Telescope will reside under the same domain as the
|
||||
| application. Otherwise, this value will be used as the subdomain.
|
||||
|
|
||||
*/
|
||||
|
||||
'domain' => env('TELESCOPE_DOMAIN'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Path
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This is the URI path where Telescope will be accessible from. Feel free
|
||||
| to change this path to anything you like. Note that the URI will not
|
||||
| affect the paths of its internal API that aren't exposed to users.
|
||||
|
|
||||
*/
|
||||
|
||||
'path' => env('TELESCOPE_PATH', 'telescope'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Storage Driver
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration options determines the storage driver that will
|
||||
| be used to store Telescope's data. In addition, you may set any
|
||||
| custom options as needed by the particular driver you choose.
|
||||
|
|
||||
*/
|
||||
|
||||
'driver' => env('TELESCOPE_DRIVER', 'database'),
|
||||
|
||||
'storage' => [
|
||||
'database' => [
|
||||
'connection' => env('DB_CONNECTION', 'mysql'),
|
||||
'chunk' => 1000,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Queue
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This configuration options determines the queue connection and queue
|
||||
| which will be used to process ProcessPendingUpdate jobs. This can
|
||||
| be changed if you would prefer to use a non-default connection.
|
||||
|
|
||||
*/
|
||||
|
||||
'queue' => [
|
||||
'connection' => env('TELESCOPE_QUEUE_CONNECTION'),
|
||||
'queue' => env('TELESCOPE_QUEUE'),
|
||||
'delay' => env('TELESCOPE_QUEUE_DELAY', 10),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Route Middleware
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| These middleware will be assigned to every Telescope route, giving you
|
||||
| the chance to add your own middleware to this list or change any of
|
||||
| the existing middleware. Or, you can simply stick with this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'middleware' => [
|
||||
'web',
|
||||
Authorize::class,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Allowed / Ignored Paths & Commands
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the URI paths and Artisan commands that will
|
||||
| not be watched by Telescope. In addition to this list, some Laravel
|
||||
| commands, like migrations and queue commands, are always ignored.
|
||||
|
|
||||
*/
|
||||
|
||||
'only_paths' => [
|
||||
// 'api/*'
|
||||
],
|
||||
|
||||
'ignore_paths' => [
|
||||
'livewire*',
|
||||
],
|
||||
|
||||
'ignore_commands' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telescope Watchers
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following array lists the "watchers" that will be registered with
|
||||
| Telescope. The watchers gather the application's profile data when
|
||||
| a request or task is executed. Feel free to customize this list.
|
||||
|
|
||||
*/
|
||||
|
||||
'watchers' => [
|
||||
Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true),
|
||||
|
||||
Watchers\CacheWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_CACHE_WATCHER', true),
|
||||
'hidden' => [],
|
||||
'ignore' => [],
|
||||
],
|
||||
|
||||
Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true),
|
||||
|
||||
Watchers\CommandWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_COMMAND_WATCHER', true),
|
||||
'ignore' => [],
|
||||
],
|
||||
|
||||
Watchers\DumpWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_DUMP_WATCHER', true),
|
||||
'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false),
|
||||
],
|
||||
|
||||
Watchers\EventWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_EVENT_WATCHER', true),
|
||||
'ignore' => [],
|
||||
],
|
||||
|
||||
Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true),
|
||||
|
||||
Watchers\GateWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_GATE_WATCHER', true),
|
||||
'ignore_abilities' => [],
|
||||
'ignore_packages' => true,
|
||||
'ignore_paths' => [],
|
||||
],
|
||||
|
||||
Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true),
|
||||
|
||||
Watchers\LogWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_LOG_WATCHER', true),
|
||||
'level' => 'error',
|
||||
],
|
||||
|
||||
Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true),
|
||||
|
||||
Watchers\ModelWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_MODEL_WATCHER', true),
|
||||
'events' => ['eloquent.*'],
|
||||
'hydrations' => true,
|
||||
],
|
||||
|
||||
Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true),
|
||||
|
||||
Watchers\QueryWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_QUERY_WATCHER', true),
|
||||
'ignore_packages' => true,
|
||||
'ignore_paths' => [],
|
||||
'slow' => 100,
|
||||
],
|
||||
|
||||
Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true),
|
||||
|
||||
Watchers\RequestWatcher::class => [
|
||||
'enabled' => env('TELESCOPE_REQUEST_WATCHER', true),
|
||||
'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64),
|
||||
'ignore_http_methods' => [],
|
||||
'ignore_status_codes' => [],
|
||||
],
|
||||
|
||||
Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true),
|
||||
Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true),
|
||||
],
|
||||
];
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v8.2.2-pre',
|
||||
'full_app_version' => 'v8.2.2-pre - build 19319-ga36afbcb2',
|
||||
'build_version' => '19319',
|
||||
'app_version' => 'v8.3.1',
|
||||
'full_app_version' => 'v8.3.1 - build 19577-g7dd493da3',
|
||||
'build_version' => '19577',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'ga36afbcb2',
|
||||
'full_hash' => 'v8.2.2-pre-249-ga36afbcb2',
|
||||
'hash_version' => 'g7dd493da3',
|
||||
'full_hash' => 'v8.3.1-15-g7dd493da3',
|
||||
'branch' => 'develop',
|
||||
);
|
||||
@@ -33,6 +33,7 @@ class AssetModelFactory extends Factory
|
||||
'category_id' => Category::factory(),
|
||||
'model_number' => $this->faker->creditCardNumber(),
|
||||
'notes' => 'Created by demo seeder',
|
||||
'require_serial' => 0,
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ class LicenseSeatFactory extends Factory
|
||||
{
|
||||
return [
|
||||
'license_id' => License::factory(),
|
||||
'unreassignable_seat' => false,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Get the migration connection name.
|
||||
*/
|
||||
public function getConnection(): ?string
|
||||
{
|
||||
return config('telescope.storage.database.connection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$schema = Schema::connection($this->getConnection());
|
||||
|
||||
$schema->create('telescope_entries', function (Blueprint $table) {
|
||||
$table->bigIncrements('sequence');
|
||||
$table->uuid('uuid');
|
||||
$table->uuid('batch_id');
|
||||
$table->string('family_hash')->nullable();
|
||||
$table->boolean('should_display_on_index')->default(true);
|
||||
$table->string('type', 20);
|
||||
$table->longText('content');
|
||||
$table->dateTime('created_at')->nullable();
|
||||
|
||||
$table->unique('uuid');
|
||||
$table->index('batch_id');
|
||||
$table->index('family_hash');
|
||||
$table->index('created_at');
|
||||
$table->index(['type', 'should_display_on_index']);
|
||||
});
|
||||
|
||||
$schema->create('telescope_entries_tags', function (Blueprint $table) {
|
||||
$table->uuid('entry_uuid');
|
||||
$table->string('tag');
|
||||
|
||||
$table->primary(['entry_uuid', 'tag']);
|
||||
$table->index('tag');
|
||||
|
||||
$table->foreign('entry_uuid')
|
||||
->references('uuid')
|
||||
->on('telescope_entries')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
|
||||
$schema->create('telescope_monitoring', function (Blueprint $table) {
|
||||
$table->string('tag')->primary();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$schema = Schema::connection($this->getConnection());
|
||||
|
||||
$schema->dropIfExists('telescope_entries_tags');
|
||||
$schema->dropIfExists('telescope_entries');
|
||||
$schema->dropIfExists('telescope_monitoring');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('license_seats', function (Blueprint $table) {
|
||||
$table->addColumn('boolean', 'unreassignable_seat')->default(false)->after('assigned_to');
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('license_seats', function (Blueprint $table) {
|
||||
$table->dropColumn('unreassignable_seat');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('models', function (Blueprint $table) {
|
||||
$table->boolean( 'require_serial')->after('category_id')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('models', function (Blueprint $table) {
|
||||
$table->dropColumn('require_serial');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -306,9 +306,6 @@ a.accordion-header {
|
||||
padding: 0px;
|
||||
/* adjust based on your layout */
|
||||
}
|
||||
.skin-blue .main-header .navbar .dropdown-menu li a {
|
||||
color: #333;
|
||||
}
|
||||
a.logo.no-hover a:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
3
public/css/dist/all.css
vendored
3
public/css/dist/all.css
vendored
@@ -21642,9 +21642,6 @@ a.accordion-header {
|
||||
padding: 0px;
|
||||
/* adjust based on your layout */
|
||||
}
|
||||
.skin-blue .main-header .navbar .dropdown-menu li a {
|
||||
color: #333;
|
||||
}
|
||||
a.logo.no-hover a:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=42f97cd5b9ee7521b04a448e7fc16ac9",
|
||||
"/css/dist/skins/_all-skins.css": "/css/dist/skins/_all-skins.css?id=d81a7ed323f68a7c5e3e9115f7fb5404",
|
||||
"/css/build/overrides.css": "/css/build/overrides.css?id=257e65d85ce9cf5a413065df1b131c03",
|
||||
"/css/build/app.css": "/css/build/app.css?id=a1136819126f6c7c3cd37861d69abb84",
|
||||
"/css/build/app.css": "/css/build/app.css?id=3dcb1500ec5991cc4058fd5e4d9b8b49",
|
||||
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=ee0ed88465dd878588ed044eefb67723",
|
||||
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=3d8a3d2035ea28aaad4a703c2646f515",
|
||||
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=3979929a3423ff35b96b1fc84299fdf3",
|
||||
@@ -19,7 +19,7 @@
|
||||
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=b2cd9f59d7e8587939ce27b2d3363d82",
|
||||
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=7277edd636cf46aa7786a4449ce0ead7",
|
||||
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=cbd06cc1d58197ccc81d4376bbaf0d28",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=4130f13eb82937aa7147bd89f93aaca5",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=a6b8969f0f70c07cf740f30bb7139b45",
|
||||
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||
"/js/select2/i18n/af.js": "/js/select2/i18n/af.js?id=4f6fcd73488ce79fae1b7a90aceaecde",
|
||||
|
||||
@@ -376,10 +376,6 @@ a.accordion-header {
|
||||
/* adjust based on your layout */
|
||||
}
|
||||
|
||||
.skin-blue .main-header .navbar .dropdown-menu li a {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
a.logo.no-hover a:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -44,6 +44,8 @@ return [
|
||||
'redirect_to_checked_out_to' => 'Go to Checked Out to',
|
||||
'select_statustype' => 'Select Status Type',
|
||||
'serial' => 'Serial',
|
||||
'serial_required' => 'Asset :number requires a serial number',
|
||||
'serial_required_post_model_update' => ':asset_model have been updated to require a serial number. Please add a serial number for this asset.',
|
||||
'status' => 'Status',
|
||||
'tag' => 'Asset Tag',
|
||||
'update' => 'Asset Update',
|
||||
|
||||
@@ -22,6 +22,8 @@ return [
|
||||
'requested' => 'Requested',
|
||||
'not_requestable' => 'Not Requestable',
|
||||
'requestable_status_warning' => 'Do not change requestable status',
|
||||
'require_serial' => 'Require Serial Number',
|
||||
'require_serial_help' => 'A serial number will be required when creating a new asset of this model.',
|
||||
'restore' => 'Restore Asset',
|
||||
'pending' => 'Pending',
|
||||
'undeployable' => 'Undeployable',
|
||||
|
||||
@@ -50,7 +50,7 @@ return array(
|
||||
|
||||
'checkin' => array(
|
||||
'error' => 'There was an issue checking in the license. Please try again.',
|
||||
'not_reassignable' => 'License not reassignable',
|
||||
'not_reassignable' => 'Seat has been used',
|
||||
'success' => 'The license was checked in successfully'
|
||||
),
|
||||
|
||||
|
||||
@@ -611,6 +611,7 @@ return [
|
||||
'use_cloned_no_image_help' => 'This item does not have an associated image and instead inherits from the model or category it belongs to. If you would like to use a specific image for this item, you can upload a new one below.',
|
||||
'footer_credit' => '<a target="_blank" href="https://snipeitapp.com" rel="noopener">Snipe-IT</a> is open source software, made with <i class="fa fa-heart" aria-hidden="true" style="color: #a94442; font-size: 10px" /></i><span class="sr-only">love</span> by <a href="https://bsky.app/profile/snipeitapp.com" rel="noopener">@snipeitapp.com</a>.',
|
||||
'set_password' => 'Set a Password',
|
||||
'upload_deleted' => 'Upload Deleted',
|
||||
|
||||
// Add form placeholders here
|
||||
'placeholders' => [
|
||||
@@ -627,11 +628,11 @@ return [
|
||||
'site_default' => 'Site Default',
|
||||
'default_blue' => 'Default Blue',
|
||||
'blue_dark' => 'Blue (Dark Mode)',
|
||||
'green' => 'Green Dark',
|
||||
'green' => 'Green',
|
||||
'green_dark' => 'Green (Dark Mode)',
|
||||
'red' => 'Red Dark',
|
||||
'red' => 'Red',
|
||||
'red_dark' => 'Red (Dark Mode)',
|
||||
'orange' => 'Orange Dark',
|
||||
'orange' => 'Orange',
|
||||
'orange_dark' => 'Orange (Dark Mode)',
|
||||
'black' => 'Black',
|
||||
'black_dark' => 'Black (Dark Mode)',
|
||||
|
||||
@@ -4,8 +4,8 @@ return [
|
||||
|
||||
'Accessory_Checkin_Notification' => 'Accessory checked in',
|
||||
'Accessory_Checkout_Notification' => 'Accessory checked out',
|
||||
'Asset_Checkin_Notification' => 'Asset checked in: [:tag]',
|
||||
'Asset_Checkout_Notification' => 'Asset checked out: [:tag]',
|
||||
'Asset_Checkin_Notification' => 'Asset checked in: :tag',
|
||||
'Asset_Checkout_Notification' => 'Asset checked out: :tag',
|
||||
'Confirm_Accessory_Checkin' => 'Accessory checkin confirmation',
|
||||
'Confirm_Asset_Checkin' => 'Asset checkin confirmation',
|
||||
'Confirm_component_checkin' => 'Component checkin confirmation',
|
||||
|
||||
@@ -80,12 +80,10 @@
|
||||
<!-- checkout selector -->
|
||||
|
||||
@include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'true'])
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.select_user'), 'fieldname' => 'assigned_user'])
|
||||
<!-- We have to pass unselect here so that we don't default to the asset that's being checked out. We want that asset to be pre-selected everywhere else. -->
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'company_id' => $accessory->company_id, 'fieldname' => 'assigned_user', 'style' => session('checkout_to_type') == 'user' ? '' : 'display: none;'])
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.asset'), 'asset_selector_div_id' => 'assigned_asset', 'company_id' => $accessory->company_id, 'fieldname' => 'assigned_asset', 'unselect' => 'true', 'style' => session('checkout_to_type') == 'asset' ? '' : 'display: none;'])
|
||||
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'company_id' => $accessory->company_id, 'style' => session('checkout_to_type') == 'location' ? '' : 'display: none;'])
|
||||
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.select_asset'), 'fieldname' => 'assigned_asset', 'company_id' => $accessory->company_id, 'unselect' => 'true', 'style' => 'display:none;'])
|
||||
|
||||
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => 'display:none;'])
|
||||
|
||||
|
||||
<!-- Checkout QTY -->
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}"
|
||||
dir="{{ Helper::determineLanguageDirection() }}">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<style>
|
||||
body {
|
||||
font-family:'Dejavu Sans', Arial, Helvetica, sans-serif;
|
||||
@@ -31,7 +33,12 @@
|
||||
|
||||
@if ($eula)
|
||||
<hr>
|
||||
{!! $eula !!}
|
||||
|
||||
{!! $eula !!}
|
||||
|
||||
{!! str_replace('<p>', '<p dir="auto">', $eula) !!}
|
||||
|
||||
{{ str_replace('<p>', '<p dir="auto">', $eula) }}
|
||||
<hr>
|
||||
@endif
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
{{-- Page title --}}
|
||||
@section('title')
|
||||
{{trans('general.accept', ['asset' => $acceptance->checkoutable->present()->name()])}}
|
||||
{{trans('general.accept', ['asset' => $acceptance->checkoutable->display_name])}}
|
||||
@parent
|
||||
@stop
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="panel box box-default">
|
||||
<div class="box-header with-border">
|
||||
<h2 class="box-title">
|
||||
{{$acceptance->checkoutable->present()->name()}}
|
||||
{{ $acceptance->checkoutable->display_name }}
|
||||
{{ (($acceptance->checkoutable) && ($acceptance->checkoutable->serial)) ? ' - '.trans('general.serial_number').': '.$acceptance->checkoutable->serial : '' }}
|
||||
</h2>
|
||||
</div>
|
||||
@@ -46,7 +46,7 @@
|
||||
@if ($acceptance->checkoutable->getEula())
|
||||
<div class="col-md-12" style="padding-top: 15px; padding-bottom: 15px;">
|
||||
<div style="background-color: rgba(211,211,211,0.25); padding: 10px; border: lightgrey 1px solid;">
|
||||
{!! $acceptance->checkoutable->getEula() !!}
|
||||
{!! str_replace('<p>', '<p dir="auto">', Helper::parseEscapedMarkedown($acceptance->checkoutable->getEula())) !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<div class="box-body">
|
||||
<!-- Asset -->
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.select_asset'), 'fieldname' => 'asset_id', 'company_id' => $component->company_id])
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.select_asset'), 'fieldname' => 'asset_id', 'company_id' => $component->company_id, 'required' => 'true', 'value' => old('asset_id')])
|
||||
|
||||
<div class="form-group {{ $errors->has('assigned_qty') ? ' has-error' : '' }}">
|
||||
<label for="assigned_qty" class="col-md-3 control-label">
|
||||
|
||||
@@ -58,11 +58,13 @@
|
||||
|
||||
|
||||
<!-- Checkout selector -->
|
||||
@include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'true'])
|
||||
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_user'])
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.asset'), 'asset_selector_div_id' => 'assigned_asset', 'fieldname' => 'assigned_asset', 'unselect' => 'true', 'style' => 'display:none;'])
|
||||
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => 'display:none;'])
|
||||
|
||||
@include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'true'])
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_user', 'style' => session('checkout_to_type') == 'user' ? '' : 'display: none;'])
|
||||
<!-- We have to pass unselect here so that we don't default to the asset that's being checked out. We want that asset to be pre-selected everywhere else. -->
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.asset'), 'asset_selector_div_id' => 'assigned_asset', 'fieldname' => 'assigned_asset', 'unselect' => 'true', 'style' => session('checkout_to_type') == 'asset' ? '' : 'display: none;'])
|
||||
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => session('checkout_to_type') == 'location' ? '' : 'display: none;'])
|
||||
|
||||
<!-- Checkout/Checkin Date -->
|
||||
<div class="form-group {{ $errors->has('checkout_at') ? 'error' : '' }}">
|
||||
|
||||
@@ -40,17 +40,17 @@
|
||||
<tr>
|
||||
<td><input type="checkbox" name="ids[]" value="{{ $asset->id }}" checked="checked"></td>
|
||||
<td>{{ $asset->id }}</td>
|
||||
<td>{{ $asset->present()->name() }}</td>
|
||||
<td>{{ $asset->display_name }}</td>
|
||||
<td>
|
||||
@if ($asset->location)
|
||||
{{ $asset->location->present()->name() }}
|
||||
{{ $asset->location->display_name }}
|
||||
@elseif($asset->rtd_location)
|
||||
{{ $asset->defaultLoc->present()->name() }}
|
||||
{{ $asset->defaultLoc->display_name }}
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@if ($asset->assigned)
|
||||
{{ $asset->assigned->present()->name() }}
|
||||
{{ $asset->assigned->display_name }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
<tr>
|
||||
<td><input type="checkbox" name="ids[]" value="{{ $asset->id }}" checked="checked"></td>
|
||||
<td>{{ $asset->id }}</td>
|
||||
<td>{{ $asset->present()->name() }}</td>
|
||||
<td>{{ $asset->display_name }}</td>
|
||||
<td>
|
||||
@if ($asset->location)
|
||||
{{ $asset->location->name }}
|
||||
|
||||
@@ -94,13 +94,10 @@
|
||||
</div>
|
||||
|
||||
@include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'true'])
|
||||
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_user'])
|
||||
|
||||
@include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_user', 'style' => session('checkout_to_type') == 'user' ? '' : 'display: none;'])
|
||||
<!-- We have to pass unselect here so that we don't default to the asset that's being checked out. We want that asset to be pre-selected everywhere else. -->
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.asset'), 'fieldname' => 'assigned_asset', 'unselect' => 'true', 'style' => 'display:none;'])
|
||||
|
||||
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => 'display:none;'])
|
||||
@include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.select_asset'), 'fieldname' => 'assigned_asset', 'company_id' => $asset->company_id, 'unselect' => 'true', 'style' => session('checkout_to_type') == 'asset' ? '' : 'display: none;'])
|
||||
@include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => session('checkout_to_type') == 'location' ? '' : 'display: none;'])
|
||||
|
||||
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user