Compare commits
15 Commits
added-tele
...
shift-1551
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07e252d58f | ||
|
|
5143b87b3a | ||
|
|
b1ef176dbc | ||
|
|
4226642b1b | ||
|
|
e40ba0f79c | ||
|
|
b8c0279105 | ||
|
|
aae215a968 | ||
|
|
bb847b9d99 | ||
|
|
a1c85fef14 | ||
|
|
c65335a61e | ||
|
|
f95b014d2b | ||
|
|
91e4fddd83 | ||
|
|
2af991023d | ||
|
|
a993ab97c6 | ||
|
|
f002c65608 |
@@ -4189,24 +4189,6 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "mckaygerhard",
|
||||
"name": "Герхард PICCORO Lenz McKAY ",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1571724?v=4",
|
||||
"profile": "https://github-readme-stats.vercel.app/api?username=mckaygerhard",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "FlorestanII",
|
||||
"name": "Johannes Pollitt",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/15015119?v=4",
|
||||
"profile": "https://github.com/FlorestanII",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<img src="https://avatars.githubusercontent.com/u/181059?v=4" width="110px;"/><br /><sub>Juan Font</sub>](https://github.com/juanfont)<br />[💻](https://github.com/snipe/snipe-it/commits?author=juanfont "Code") | [<img src="https://avatars.githubusercontent.com/u/13137708?v=4" width="110px;"/><br /><sub>Juho Taipale</sub>](https://github.com/juhotaipale)<br />[💻](https://github.com/snipe/snipe-it/commits?author=juhotaipale "Code") | [<img src="https://avatars.githubusercontent.com/u/1007419?v=4" width="110px;"/><br /><sub>Korvin Szanto</sub>](https://github.com/KorvinSzanto)<br />[💻](https://github.com/snipe/snipe-it/commits?author=KorvinSzanto "Code") | [<img src="https://avatars.githubusercontent.com/u/8513053?v=4" width="110px;"/><br /><sub>Lewis Foster</sub>](https://lewisfoster.foo/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sniff122 "Code") | [<img src="https://avatars.githubusercontent.com/u/33877541?v=4" width="110px;"/><br /><sub>Logan Swartzendruber</sub>](https://github.com/loganswartz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=loganswartz "Code") | [<img src="https://avatars.githubusercontent.com/u/1156208?v=4" width="110px;"/><br /><sub>Lorenzo P.</sub>](https://github.com/lopezio)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lopezio "Code") | [<img src="https://avatars.githubusercontent.com/u/33946590?v=4" width="110px;"/><br /><sub>Lukas Jung</sub>](https://github.com/m4us1ne)<br />[💻](https://github.com/snipe/snipe-it/commits?author=m4us1ne "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/10965027?v=4" width="110px;"/><br /><sub>Ellie</sub>](https://leafedfox.xyz/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=LeafedFox "Code") | [<img src="https://avatars.githubusercontent.com/u/20960555?v=4" width="110px;"/><br /><sub>GA Stamper</sub>](https://github.com/gastamper)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gastamper "Code") | [<img src="https://avatars.githubusercontent.com/u/206553556?v=4" width="110px;"/><br /><sub>Guillaume Lefranc</sub>](https://github.com/gl-pup)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gl-pup "Code") | [<img src="https://avatars.githubusercontent.com/u/733892?v=4" width="110px;"/><br /><sub>Hajo Möller</sub>](https://github.com/dasjoe)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dasjoe "Code") | [<img src="https://avatars.githubusercontent.com/u/3420063?v=4" width="110px;"/><br /><sub>Istvan Basa</sub>](https://github.com/pottom)<br />[💻](https://github.com/snipe/snipe-it/commits?author=pottom "Code") | [<img src="https://avatars.githubusercontent.com/u/810824?v=4" width="110px;"/><br /><sub>JJ Asghar</sub>](https://jjasghar.github.io/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jjasghar "Code") | [<img src="https://avatars.githubusercontent.com/u/40404495?v=4" width="110px;"/><br /><sub>James E. Msenga</sub>](https://github.com/JemCdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JemCdo "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/6865786?v=4" width="110px;"/><br /><sub>Jan Felix Wiebe</sub>](https://github.com/jfwiebe)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jfwiebe "Code") | [<img src="https://avatars.githubusercontent.com/u/43412008?v=4" width="110px;"/><br /><sub>Jo Drexl</sub>](https://www.nfon.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=drexljo "Code") | [<img src="https://avatars.githubusercontent.com/u/4807843?v=4" width="110px;"/><br /><sub>Austin Sasko</sub>](https://github.com/austinsasko)<br />[💻](https://github.com/snipe/snipe-it/commits?author=austinsasko "Code") | [<img src="https://avatars.githubusercontent.com/u/4875039?v=4" width="110px;"/><br /><sub>Jasson</sub>](http://jassoncordones.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JassonCordones "Code") | [<img src="https://avatars.githubusercontent.com/u/76069640?v=4" width="110px;"/><br /><sub>Okean</sub>](https://github.com/Tinyblargon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tinyblargon "Code") | [<img src="https://avatars.githubusercontent.com/u/6515064?v=4" width="110px;"/><br /><sub>Alejandro Medrano</sub>](https://www.lst.tfo.upm.es/alejandro-medrano/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=amedranogil "Code") | [<img src="https://avatars.githubusercontent.com/u/58696401?v=4" width="110px;"/><br /><sub>Lukas Kraic</sub>](https://github.com/lukaskraic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukaskraic "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/1571724?v=4" width="110px;"/><br /><sub>Герхард PICCORO Lenz McKAY </sub>](https://github-readme-stats.vercel.app/api?username=mckaygerhard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mckaygerhard "Code") | [<img src="https://avatars.githubusercontent.com/u/15015119?v=4" width="110px;"/><br /><sub>Johannes Pollitt</sub>](https://github.com/FlorestanII)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FlorestanII "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\CheckoutRequest;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CleanOldCheckoutRequests extends Command
|
||||
{
|
||||
private int $deletions = 0;
|
||||
private int $skips = 0;
|
||||
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:clean-old-checkout-requests';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Removes checkout requests that reference deleted assets or users.';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$requests = CheckoutRequest::with([
|
||||
'user' => function ($query) {
|
||||
$query->withTrashed();
|
||||
},
|
||||
'requestedItem' => function ($query) {
|
||||
$query->withTrashed();
|
||||
},
|
||||
])->get();
|
||||
|
||||
$this->info("Processing {$requests->count()} checkout requests");
|
||||
|
||||
$this->withProgressBar($requests, function ($request) {
|
||||
if ($this->shouldForceDelete($request)) {
|
||||
$request->forceDelete();
|
||||
$this->deletions++;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->shouldSoftDelete($request)) {
|
||||
$request->delete();
|
||||
$this->deletions++;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->skips++;
|
||||
});
|
||||
|
||||
$this->info("Final deletion count: $this->deletions, and skip count: $this->skips");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function shouldForceDelete(CheckoutRequest $request)
|
||||
{
|
||||
// check if the requestable or user relationship is null
|
||||
return !$request->requestable || !$request->user;
|
||||
}
|
||||
|
||||
private function shouldSoftDelete(CheckoutRequest $request)
|
||||
{
|
||||
return $request->requestable->trashed() || $request->user->trashed();
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class MoveUploadsToNewDisk extends Command
|
||||
$private_uploads['assets'] = glob('storage/private_uploads/assets'."/*.*");
|
||||
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'."/*.*");
|
||||
$private_uploads['audits'] = glob('storage/private_uploads/audits'."/*.*");
|
||||
$private_uploads['assetmodels'] = glob('storage/private_uploads/models'."/*.*");
|
||||
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'."/*.*");
|
||||
$private_uploads['imports'] = glob('storage/private_uploads/imports'."/*.*");
|
||||
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'."/*.*");
|
||||
$private_uploads['users'] = glob('storage/private_uploads/users'."/*.*");
|
||||
|
||||
@@ -62,19 +62,19 @@ class Purge extends Command
|
||||
$assetcount = $assets->count();
|
||||
$this->info($assets->count().' assets purged.');
|
||||
$asset_assoc = 0;
|
||||
$maintenances = 0;
|
||||
$asset_maintenances = 0;
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
$this->info('- Asset "'.$asset->present()->name().'" deleted.');
|
||||
$asset_assoc += $asset->assetlog()->count();
|
||||
$asset->assetlog()->forceDelete();
|
||||
$maintenances += $asset->maintenances()->count();
|
||||
$asset->maintenances()->forceDelete();
|
||||
$asset_maintenances += $asset->assetmaintenances()->count();
|
||||
$asset->assetmaintenances()->forceDelete();
|
||||
$asset->forceDelete();
|
||||
}
|
||||
|
||||
$this->info($asset_assoc.' corresponding log records purged.');
|
||||
$this->info($maintenances.' corresponding maintenance records purged.');
|
||||
$this->info($asset_maintenances.' corresponding maintenance records purged.');
|
||||
|
||||
$locations = Location::whereNotNull('deleted_at')->withTrashed()->get();
|
||||
$this->info($locations->count().' locations purged.');
|
||||
|
||||
@@ -243,8 +243,6 @@ class RestoreFromBackup extends Command
|
||||
$private_dirs = [
|
||||
'storage/private_uploads/accessories',
|
||||
'storage/private_uploads/assetmodels',
|
||||
'storage/private_uploads/maintenances',
|
||||
'storage/private_uploads/models',
|
||||
'storage/private_uploads/assets', // these are asset _files_, not the pictures.
|
||||
'storage/private_uploads/audits',
|
||||
'storage/private_uploads/components',
|
||||
@@ -262,10 +260,9 @@ class RestoreFromBackup extends Command
|
||||
];
|
||||
$public_dirs = [
|
||||
'public/uploads/accessories',
|
||||
'public/uploads/assetmodels',
|
||||
'public/uploads/maintenances',
|
||||
'public/uploads/assets', // these are asset _pictures_, not asset files
|
||||
'public/uploads/avatars',
|
||||
//'public/uploads/barcodes', // we don't want this, let the barcodes be regenerated
|
||||
'public/uploads/categories',
|
||||
'public/uploads/companies',
|
||||
'public/uploads/components',
|
||||
|
||||
@@ -138,13 +138,13 @@ class Handler extends ExceptionHandler
|
||||
if (in_array('bulkedit', $ids, true)) {
|
||||
$error_array = session()->get('bulk_asset_errors');
|
||||
return redirect()
|
||||
->route('hardware.index')
|
||||
->route('hardware.bulkedit')
|
||||
->withErrors($error_array, 'bulk_asset_errors')
|
||||
->withInput();
|
||||
}
|
||||
|
||||
// This gets the MVC model name from the exception and formats in a way that's less fugly
|
||||
$model_name = trim(strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel()))))));
|
||||
// This gets the MVC model name from the exception and formats in a way that's less fugly
|
||||
$model_name = strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel())))));
|
||||
$route = str_plural(strtolower(last(explode('\\', $e->getModel())))).'.index';
|
||||
|
||||
// Sigh.
|
||||
@@ -160,7 +160,9 @@ class Handler extends ExceptionHandler
|
||||
$route = 'maintenances.index';
|
||||
} elseif ($route === 'licenseseats.index') {
|
||||
$route = 'licenses.index';
|
||||
} elseif (($route === 'customfieldsets.index') || ($route === 'customfields.index')) {
|
||||
} elseif ($route === 'customfields.index') {
|
||||
$route = 'fields.index';
|
||||
} elseif ($route === 'customfieldsets.index') {
|
||||
$route = 'fields.index';
|
||||
}
|
||||
|
||||
|
||||
@@ -1197,30 +1197,19 @@ class Helper
|
||||
'webp' => 'far fa-image',
|
||||
'avif' => 'far fa-image',
|
||||
'svg' => 'fas fa-vector-square',
|
||||
|
||||
// word
|
||||
'doc' => 'far fa-file-word',
|
||||
'docx' => 'far fa-file-word',
|
||||
|
||||
// Excel
|
||||
'xls' => 'far fa-file-excel',
|
||||
'xlsx' => 'far fa-file-excel',
|
||||
'ods' => 'far fa-file-excel',
|
||||
|
||||
// Presentation
|
||||
'ppt' => 'far fa-file-powerpoint',
|
||||
'odp' => 'far fa-file-powerpoint',
|
||||
|
||||
// archive
|
||||
'zip' => 'fas fa-file-archive',
|
||||
'rar' => 'fas fa-file-archive',
|
||||
|
||||
//Text
|
||||
'odt' => 'far fa-file-alt',
|
||||
'txt' => 'far fa-file-alt',
|
||||
'rtf' => 'far fa-file-alt',
|
||||
'xml' => 'fas fa-code',
|
||||
|
||||
// Misc
|
||||
'pdf' => 'far fa-file-pdf',
|
||||
'lic' => 'far fa-save',
|
||||
@@ -1554,6 +1543,11 @@ class Helper
|
||||
|
||||
// return to previous page
|
||||
if ($redirect_option === 'back') {
|
||||
if ($backUrl === route('home')) {
|
||||
return redirect()->to($backUrl)
|
||||
->with('warning', trans('general.page_error'));
|
||||
}
|
||||
|
||||
return redirect()->to($backUrl);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ class IconHelper
|
||||
return 'fa-regular fa-envelope';
|
||||
case 'phone':
|
||||
return 'fa-solid fa-phone';
|
||||
case 'mobile':
|
||||
return 'fas fa-mobile-screen-button';
|
||||
case 'long-arrow-right':
|
||||
return 'fas fa-long-arrow-alt-right';
|
||||
case 'download':
|
||||
@@ -153,7 +151,6 @@ class IconHelper
|
||||
case 'location':
|
||||
return 'fas fa-map-marker-alt';
|
||||
case 'superadmin':
|
||||
case 'admin':
|
||||
return 'fas fa-crown';
|
||||
case 'print':
|
||||
return 'fa-solid fa-print';
|
||||
|
||||
@@ -27,45 +27,6 @@ class StorageHelper
|
||||
}
|
||||
}
|
||||
|
||||
public static function getMediaType($file_with_path) {
|
||||
|
||||
// Get the file extension and determine the media type
|
||||
if (Storage::exists($file_with_path)) {
|
||||
$fileinfo = pathinfo($file_with_path);
|
||||
$extension = strtolower($fileinfo['extension']);
|
||||
switch ($extension) {
|
||||
case 'avif':
|
||||
case 'jpg':
|
||||
case 'png':
|
||||
case 'gif':
|
||||
case 'svg':
|
||||
case 'webp':
|
||||
return 'image';
|
||||
case 'pdf':
|
||||
return 'pdf';
|
||||
case 'mp3':
|
||||
case 'wav':
|
||||
case 'ogg':
|
||||
return 'audio';
|
||||
case 'mp4':
|
||||
case 'webm':
|
||||
case 'mov':
|
||||
return 'video';
|
||||
case 'doc':
|
||||
case 'docx':
|
||||
return 'document';
|
||||
case 'txt':
|
||||
return 'text';
|
||||
case 'xls':
|
||||
case 'xlsx':
|
||||
case 'ods':
|
||||
return 'spreadsheet';
|
||||
default:
|
||||
return $extension; // Default for unknown types
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This determines the file types that should be allowed inline and checks their fileinfo extension
|
||||
@@ -91,6 +52,7 @@ class StorageHelper
|
||||
'pdf',
|
||||
'png',
|
||||
'svg',
|
||||
'svg',
|
||||
'wav',
|
||||
'webm',
|
||||
'webp',
|
||||
|
||||
@@ -77,25 +77,9 @@ class AccessoriesController extends Controller
|
||||
$accessory->supplier_id = request('supplier_id');
|
||||
$accessory->notes = request('notes');
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = Accessory::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
|
||||
$new_image = 'accessories/'.$new_image_name;
|
||||
Storage::disk('public')->copy('accessories/'.$cloned_model_img->image, $new_image);
|
||||
$accessory->image = $new_image_name;
|
||||
}
|
||||
|
||||
} else {
|
||||
$accessory = $request->handleImages($accessory);
|
||||
}
|
||||
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
}
|
||||
$accessory = $request->handleImages($accessory);
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
// Was the accessory created?
|
||||
if ($accessory->save()) {
|
||||
// Redirect to the new accessory page
|
||||
@@ -130,12 +114,11 @@ class AccessoriesController extends Controller
|
||||
|
||||
$this->authorize('create', Accessory::class);
|
||||
$cloned = clone $accessory;
|
||||
$accessory_to_clone = $accessory;
|
||||
$cloned->id = null;
|
||||
$cloned->deleted_at = '';
|
||||
$cloned->location_id = null;
|
||||
|
||||
return view('accessories/edit')
|
||||
->with('cloned_model', $accessory_to_clone)
|
||||
->with('item', $cloned);
|
||||
|
||||
}
|
||||
|
||||
132
app/Http/Controllers/Accessories/AccessoriesFilesController.php
Normal file
132
app/Http/Controllers/Accessories/AccessoriesFilesController.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Accessories;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Accessory;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
use \Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
class AccessoriesFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a accessory.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $accessoryId
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
*/
|
||||
public function store(UploadFileRequest $request, $accessoryId = null) : RedirectResponse
|
||||
{
|
||||
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('accessories.show', ['accessory'=>$accessoryId])->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
$accessory = Accessory::find($accessoryId);
|
||||
|
||||
if (isset($accessory->id)) {
|
||||
$this->authorize('accessories.files', $accessory);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/accessories')) {
|
||||
Storage::makeDirectory('private_uploads/accessories', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
|
||||
$file_name = $request->handleFile('private_uploads/accessories/', 'accessory-'.$accessory->id, $file);
|
||||
//Log the upload to the log
|
||||
$accessory->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('accessories.show', $accessory->id)->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.show', $accessory->id)->withFragment('files')->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected accessory file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $accessoryId
|
||||
* @param int $fileId
|
||||
*/
|
||||
public function destroy($accessoryId = null, $fileId = null) : RedirectResponse
|
||||
{
|
||||
if ($accessory = Accessory::find($accessoryId)) {
|
||||
$this->authorize('update', $accessory);
|
||||
|
||||
if ($log = Actionlog::find($fileId)) {
|
||||
|
||||
if (Storage::exists('private_uploads/accessories/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('private_uploads/accessories/' . $log->filename);
|
||||
$log->delete();
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return redirect()->route('accessories.show', ['accessory' => $accessory])->withFragment('files')->with('error', trans('general.log_record_not_found'));
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $accessoryId
|
||||
* @param int $fileId
|
||||
*/
|
||||
public function show($accessoryId = null, $fileId = null) : View | RedirectResponse | Response | BinaryFileResponse | StreamedResponse
|
||||
{
|
||||
|
||||
|
||||
// the accessory is valid
|
||||
if ($accessory = Accessory::find($accessoryId)) {
|
||||
$this->authorize('view', $accessory);
|
||||
$this->authorize('accessories.files', $accessory);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $accessory->id)->find($fileId)) {
|
||||
$file = 'private_uploads/accessories/'.$log->filename;
|
||||
|
||||
try {
|
||||
return StorageHelper::showOrDownloadFile($file, $log->filename);
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('accessories.show', ['accessory' => $accessory])->with('error', trans('general.file_not_found'));
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.show', ['accessory' => $accessory])->withFragment('files')->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,6 @@ class AcceptanceController extends Controller
|
||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||
'logo' => $path_logo,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
'admin' => auth()->user()->present()?->fullName,
|
||||
];
|
||||
|
||||
if ($pdf_view_route!='') {
|
||||
@@ -348,7 +347,6 @@ class AcceptanceController extends Controller
|
||||
|
||||
$acceptance->decline($sig_filename, $request->input('note'));
|
||||
$acceptance->notify(new AcceptanceAssetDeclinedNotification($data));
|
||||
Log::debug('New event acceptance.');
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
}
|
||||
@@ -358,16 +356,13 @@ class AcceptanceController extends Controller
|
||||
$recipient = User::find($acceptance->alert_on_response_id);
|
||||
|
||||
if ($recipient) {
|
||||
Log::debug('Attempting to send email acceptance.');
|
||||
Mail::to($recipient)->send(new CheckoutAcceptanceResponseMail(
|
||||
$acceptance,
|
||||
$recipient,
|
||||
$request->input('asset_acceptance') === 'accepted',
|
||||
));
|
||||
Log::debug('Send email notification sucess on checkout acceptance response.');
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
Log::error($e->getMessage());
|
||||
Log::warning($e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Transformers\MaintenancesTransformer;
|
||||
use App\Http\Transformers\AssetMaintenancesTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
@@ -18,13 +18,13 @@ use Illuminate\Http\JsonResponse;
|
||||
*
|
||||
* @version v2.0
|
||||
*/
|
||||
class MaintenancesController extends Controller
|
||||
class AssetMaintenancesController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Generates the JSON response for asset maintenances listing view.
|
||||
*
|
||||
* @see MaintenancesController::getIndex() method that generates view
|
||||
* @see AssetMaintenancesController::getIndex() method that generates view
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
@@ -33,7 +33,7 @@ class MaintenancesController extends Controller
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
|
||||
$maintenances = Maintenance::select('maintenances.*')
|
||||
$maintenances = AssetMaintenance::select('asset_maintenances.*')
|
||||
->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'asset.assetstatus', 'adminuser');
|
||||
|
||||
if ($request->filled('search')) {
|
||||
@@ -45,11 +45,11 @@ class MaintenancesController extends Controller
|
||||
}
|
||||
|
||||
if ($request->filled('supplier_id')) {
|
||||
$maintenances->where('maintenances.supplier_id', '=', $request->input('supplier_id'));
|
||||
$maintenances->where('asset_maintenances.supplier_id', '=', $request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('created_by')) {
|
||||
$maintenances->where('maintenances.created_by', '=', $request->input('created_by'));
|
||||
$maintenances->where('asset_maintenances.created_by', '=', $request->input('created_by'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_maintenance_type')) {
|
||||
@@ -63,7 +63,7 @@ class MaintenancesController extends Controller
|
||||
|
||||
$allowed_columns = [
|
||||
'id',
|
||||
'name',
|
||||
'title',
|
||||
'asset_maintenance_time',
|
||||
'asset_maintenance_type',
|
||||
'cost',
|
||||
@@ -112,7 +112,7 @@ class MaintenancesController extends Controller
|
||||
|
||||
$total = $maintenances->count();
|
||||
$maintenances = $maintenances->skip($offset)->take($limit)->get();
|
||||
return (new MaintenancesTransformer())->transformMaintenances($maintenances, $total);
|
||||
return (new AssetMaintenancesTransformer())->transformAssetMaintenances($maintenances, $total);
|
||||
|
||||
|
||||
}
|
||||
@@ -121,23 +121,22 @@ class MaintenancesController extends Controller
|
||||
/**
|
||||
* Validates and stores the new asset maintenance
|
||||
*
|
||||
* @see MaintenancesController::getCreate() method for the form
|
||||
* @see AssetMaintenancesController::getCreate() method for the form
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function store(ImageUploadRequest $request) : JsonResponse | array
|
||||
public function store(Request $request) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
// create a new model instance
|
||||
$maintenance = new Maintenance();
|
||||
$maintenance = new AssetMaintenance();
|
||||
$maintenance->fill($request->all());
|
||||
$maintenance->created_by = auth()->id();
|
||||
$maintenance = $request->handleImages($maintenance);
|
||||
|
||||
// Was the asset maintenance created?
|
||||
if ($maintenance->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/maintenances/message.create.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/asset_maintenances/message.create.success')));
|
||||
|
||||
}
|
||||
|
||||
@@ -158,11 +157,11 @@ class MaintenancesController extends Controller
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
if ($maintenance = Maintenance::with('asset')->find($id)) {
|
||||
if ($maintenance = AssetMaintenance::with('asset')->find($id)) {
|
||||
|
||||
// Can this user manage this asset?
|
||||
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')])));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.action_permission_denied', ['item_type' => trans('admin/asset_maintenances/general.maintenance'), 'id' => $id, 'action' => trans('general.edit')])));
|
||||
}
|
||||
|
||||
// The asset this miantenance is attached to is not valid or has been deleted
|
||||
@@ -173,13 +172,13 @@ class MaintenancesController extends Controller
|
||||
$maintenance->fill($request->all());
|
||||
|
||||
if ($maintenance->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/maintenances/message.edit.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/asset_maintenances/message.edit.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $maintenance->getErrors()));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('admin/maintenances/general.maintenance'), 'id' => $id])));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.item_not_found', ['item_type' => trans('admin/asset_maintenances/general.maintenance'), 'id' => $id])));
|
||||
|
||||
}
|
||||
|
||||
@@ -187,20 +186,20 @@ class MaintenancesController extends Controller
|
||||
* Delete an asset maintenance
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @param int $maintenanceId
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
*/
|
||||
public function destroy($maintenanceId) : JsonResponse | array
|
||||
public function destroy($assetMaintenanceId) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
|
||||
$maintenance = Maintenance::findOrFail($maintenanceId);
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
|
||||
$maintenance->delete();
|
||||
$assetMaintenance->delete();
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $maintenance, trans('admin/maintenances/message.delete.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.delete.success')));
|
||||
|
||||
|
||||
}
|
||||
@@ -209,19 +208,19 @@ class MaintenancesController extends Controller
|
||||
* View an asset maintenance
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @param int $maintenanceId
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
*/
|
||||
public function show($maintenanceId) : JsonResponse | array
|
||||
public function show($assetMaintenanceId) : JsonResponse | array
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
$maintenance = Maintenance::findOrFail($maintenanceId);
|
||||
if (! Company::isCurrentUserHasAccess($maintenance->asset)) {
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
if (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot view a maintenance for that asset'));
|
||||
}
|
||||
|
||||
return (new MaintenancesTransformer())->transformMaintenance($maintenance);
|
||||
return (new AssetMaintenancesTransformer())->transformAssetMaintenance($assetMaintenance);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -117,20 +117,15 @@ class AssetsController extends Controller
|
||||
'jobtitle',
|
||||
];
|
||||
|
||||
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
|
||||
|
||||
foreach ($all_custom_fields as $field) {
|
||||
$allowed_columns[] = $field->db_column_name();
|
||||
}
|
||||
|
||||
$filter = [];
|
||||
|
||||
if ($request->filled('filter')) {
|
||||
$filter = json_decode($request->input('filter'), true);
|
||||
}
|
||||
|
||||
$filter = array_filter($filter, function ($key) use ($allowed_columns) {
|
||||
return in_array($key, $allowed_columns);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
$all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load
|
||||
foreach ($all_custom_fields as $field) {
|
||||
$allowed_columns[] = $field->db_column_name();
|
||||
}
|
||||
|
||||
$assets = Asset::select('assets.*')
|
||||
@@ -146,7 +141,6 @@ class AssetsController extends Controller
|
||||
'model.category',
|
||||
'model.manufacturer',
|
||||
'model.fieldset',
|
||||
'model.depreciation',
|
||||
'supplier'
|
||||
); // it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users.
|
||||
|
||||
|
||||
@@ -228,16 +228,11 @@ class ConsumablesController extends Controller
|
||||
foreach ($consumable->consumableAssignments as $consumable_assignment) {
|
||||
$rows[] = [
|
||||
'avatar' => ($consumable_assignment->user) ? e($consumable_assignment->user->present()->gravatar) : '',
|
||||
'user' => ($consumable_assignment->user) ? [
|
||||
'id' => (int) $consumable_assignment->user->id,
|
||||
'name'=> e($consumable_assignment->user->present()->fullName()),
|
||||
] : null,
|
||||
'name' => ($consumable_assignment->user) ? $consumable_assignment->user->present()->nameUrl() : 'Deleted User',
|
||||
'created_at' => Helper::getFormattedDateObject($consumable_assignment->created_at, 'datetime'),
|
||||
'note' => ($consumable_assignment->note) ? e($consumable_assignment->note) : null,
|
||||
'created_by' => ($consumable_assignment->adminuser) ? [
|
||||
'id' => (int) $consumable_assignment->adminuser->id,
|
||||
'name'=> e($consumable_assignment->adminuser->present()->fullName()),
|
||||
] : null,
|
||||
'admin' => ($consumable_assignment->adminuser) ? $consumable_assignment->adminuser->present()->nameUrl() : null, // legacy, so we don't change the shape of the response
|
||||
'created_by' => ($consumable_assignment->adminuser) ? $consumable_assignment->adminuser->present()->nameUrl() : null,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -150,11 +150,8 @@ class SettingsController extends Controller
|
||||
if (!config('app.lock_passwords')) {
|
||||
try {
|
||||
Notification::send(Setting::first(), new MailTest());
|
||||
Log::debug('Attempting to sending to '.config('mail.reply_to.address'));
|
||||
return response()->json(['message' => 'Mail sent to '.config('mail.reply_to.address')], 200);
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Mail sent error using '.config('mail.reply_to.address') .': '. $e->getMessage());
|
||||
Log::debug($e);
|
||||
return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
@@ -318,4 +315,4 @@ class SettingsController extends Controller
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -194,7 +194,7 @@ class SuppliersController extends Controller
|
||||
public function destroy($id) : JsonResponse
|
||||
{
|
||||
$this->authorize('delete', Supplier::class);
|
||||
$supplier = Supplier::with('maintenances', 'assets', 'licenses')->withCount('maintenances as maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
|
||||
$supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->findOrFail($id);
|
||||
$this->authorize('delete', $supplier);
|
||||
|
||||
|
||||
@@ -202,8 +202,8 @@ class SuppliersController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count])));
|
||||
}
|
||||
|
||||
if ($supplier->maintenances_count > 0) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_maintenances', ['maintenances_count' => $supplier->maintenances_count])));
|
||||
if ($supplier->asset_maintenances_count > 0) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/suppliers/message.delete.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count])));
|
||||
}
|
||||
|
||||
if ($supplier->licenses_count > 0) {
|
||||
|
||||
@@ -7,9 +7,18 @@ use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Http\Transformers\UploadedFilesTransformer;
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
@@ -19,6 +28,45 @@ class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
|
||||
static $map_object_type = [
|
||||
'accessories' => Accessory::class,
|
||||
'assets' => Asset::class,
|
||||
'components' => Component::class,
|
||||
'consumables' => Consumable::class,
|
||||
'hardware' => Asset::class,
|
||||
'licenses' => License::class,
|
||||
'locations' => Location::class,
|
||||
'models' => AssetModel::class,
|
||||
'users' => User::class,
|
||||
];
|
||||
|
||||
static $map_storage_path = [
|
||||
'accessories' => 'private_uploads/accessories/',
|
||||
'assets' => 'private_uploads/assets/',
|
||||
'components' => 'private_uploads/components/',
|
||||
'consumables' => 'private_uploads/consumables/',
|
||||
'hardware' => 'private_uploads/assets/',
|
||||
'licenses' => 'private_uploads/licenses/',
|
||||
'locations' => 'private_uploads/locations/',
|
||||
'models' => 'private_uploads/assetmodels/',
|
||||
'users' => 'private_uploads/users/',
|
||||
];
|
||||
|
||||
static $map_file_prefix= [
|
||||
'accessories' => 'accessory',
|
||||
'assets' => 'asset',
|
||||
'components' => 'component',
|
||||
'consumables' => 'consumable',
|
||||
'hardware' => 'asset',
|
||||
'licenses' => 'license',
|
||||
'locations' => 'location',
|
||||
'models' => 'model',
|
||||
'users' => 'user',
|
||||
];
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* List files for an object
|
||||
*
|
||||
@@ -50,22 +98,15 @@ class UploadedFilesController extends Controller
|
||||
'created_at',
|
||||
];
|
||||
|
||||
|
||||
$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')
|
||||
->with('adminuser');
|
||||
|
||||
$offset = ($request->input('offset') > $uploads->count()) ? $uploads->count() : abs($request->input('offset'));
|
||||
$uploads = $object->uploads();
|
||||
$offset = ($request->input('offset') > $object->count()) ? $object->count() : abs($request->input('offset'));
|
||||
$limit = app('api_limit_value');
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'action_logs.created_at';
|
||||
|
||||
// Text search on action_logs fields
|
||||
// We could use the normal Actionlogs text scope, but it's a very heavy query since it's searching across all relations
|
||||
// and we generally won't need that here
|
||||
// We could use the normal Actionlogs text scope, but it's a very heavy query since it's searcghing across all relations
|
||||
// And we generally won't need that here
|
||||
if ($request->filled('search')) {
|
||||
|
||||
$uploads->where(
|
||||
@@ -76,10 +117,8 @@ class UploadedFilesController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
$total = $uploads->count();
|
||||
$uploads = $uploads->skip($offset)->take($limit)->orderBy($sort, $order)->get();
|
||||
|
||||
return (new UploadedFilesTransformer())->transformFiles($uploads, $total);
|
||||
return (new UploadedFilesTransformer())->transformFiles($uploads, $uploads->count());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CurrentInventory;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -70,7 +69,6 @@ class UsersController extends Controller
|
||||
'users.notes',
|
||||
'users.permissions',
|
||||
'users.phone',
|
||||
'users.mobile',
|
||||
'users.state',
|
||||
'users.two_factor_enrolled',
|
||||
'users.two_factor_optin',
|
||||
@@ -110,26 +108,10 @@ class UsersController extends Controller
|
||||
$users = $users->where('users.activated', '=', $request->input('activated'));
|
||||
}
|
||||
|
||||
if ($request->input('admins') == 'true') {
|
||||
$users = $users->OnlyAdminsAndSuperAdmins();
|
||||
}
|
||||
|
||||
if ($request->input('superadmins') == 'true') {
|
||||
$users = $users->OnlySuperAdmins();
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$users = $users->where('users.company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('phone')) {
|
||||
$users = $users->where('users.phone', '=', $request->input('phone'));
|
||||
}
|
||||
|
||||
if ($request->filled('mobile')) {
|
||||
$users = $users->where('users.mobile', '=', $request->input('mobile'));
|
||||
}
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
$users = $users->where('users.location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
@@ -302,7 +284,6 @@ class UsersController extends Controller
|
||||
'manages_users_count',
|
||||
'manages_locations_count',
|
||||
'phone',
|
||||
'mobile',
|
||||
'address',
|
||||
'city',
|
||||
'state',
|
||||
@@ -833,37 +814,4 @@ class UsersController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found')), 200);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the LDAP sync command to import users from LDAP via API.
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since 8.2.2
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function syncLdapUsers(Request $request)
|
||||
{
|
||||
$this->authorize('update', User::class);
|
||||
// Call Artisan LDAP import command.
|
||||
|
||||
Artisan::call('snipeit:ldap-sync', ['--location_id' => $request->input('location_id'), '--json_summary' => true]);
|
||||
|
||||
// Collect and parse JSON summary.
|
||||
$ldap_results_json = Artisan::output();
|
||||
$ldap_results = json_decode($ldap_results_json, true);
|
||||
|
||||
if (!$ldap_results) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null,trans('general.no_results')), 200);
|
||||
}
|
||||
|
||||
// Direct user to appropriate status page.
|
||||
if ($ldap_results['error']) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $ldap_results['error_message']), 200);
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, $ldap_results['summary']), 200);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Carbon\Carbon;
|
||||
@@ -18,23 +17,29 @@ use \Illuminate\Http\RedirectResponse;
|
||||
*
|
||||
* @version v2.0
|
||||
*/
|
||||
class MaintenancesController extends Controller
|
||||
class AssetMaintenancesController extends Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns a view that invokes the ajax tables which actually contains
|
||||
* the content for the asset maintenances listing.
|
||||
* the content for the asset maintenances listing, which is generated in getDatatable.
|
||||
*
|
||||
* @todo This should be replaced with middleware and/or policies
|
||||
* @see AssetMaintenancesController::getDatatable() method that generates the JSON response
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function index() : View
|
||||
{
|
||||
$this->authorize('view', Asset::class);
|
||||
return view('maintenances.index');
|
||||
return view('asset_maintenances/index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a form view to create a new asset maintenance.
|
||||
*
|
||||
* @see MaintenancesController::postCreate() method that stores the data
|
||||
* @see AssetMaintenancesController::postCreate() method that stores the data
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
@@ -50,21 +55,21 @@ class MaintenancesController extends Controller
|
||||
$asset->asset_id = $asset->id;
|
||||
}
|
||||
|
||||
return view('maintenances/edit')
|
||||
->with('maintenanceType', Maintenance::getImprovementOptions())
|
||||
return view('asset_maintenances/edit')
|
||||
->with('assetMaintenanceType', AssetMaintenance::getImprovementOptions())
|
||||
->with('asset', $asset)
|
||||
->with('item', new Maintenance);
|
||||
->with('item', new AssetMaintenance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and stores the new asset maintenance
|
||||
*
|
||||
* @see MaintenancesController::getCreate() method for the form
|
||||
* @see AssetMaintenancesController::getCreate() method for the form
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function store(ImageUploadRequest $request) : RedirectResponse
|
||||
public function store(Request $request) : RedirectResponse
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
@@ -73,73 +78,72 @@ class MaintenancesController extends Controller
|
||||
// Loop through the selected assets
|
||||
foreach ($assets as $asset) {
|
||||
|
||||
$maintenance = new Maintenance();
|
||||
$maintenance->supplier_id = $request->input('supplier_id');
|
||||
$maintenance->is_warranty = $request->input('is_warranty');
|
||||
$maintenance->cost = $request->input('cost');
|
||||
$maintenance->notes = $request->input('notes');
|
||||
$assetMaintenance = new AssetMaintenance();
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
||||
$assetMaintenance->cost = $request->input('cost');
|
||||
$assetMaintenance->notes = $request->input('notes');
|
||||
|
||||
// Save the asset maintenance data
|
||||
$maintenance->asset_id = $asset->id;
|
||||
$maintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||
$maintenance->name = $request->input('name');
|
||||
$maintenance->start_date = $request->input('start_date');
|
||||
$maintenance->completion_date = $request->input('completion_date');
|
||||
$maintenance->created_by = auth()->id();
|
||||
$assetMaintenance->asset_id = $asset->id;
|
||||
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||
$assetMaintenance->title = $request->input('title');
|
||||
$assetMaintenance->start_date = $request->input('start_date');
|
||||
$assetMaintenance->completion_date = $request->input('completion_date');
|
||||
$assetMaintenance->created_by = auth()->id();
|
||||
|
||||
if (($maintenance->completion_date !== null)
|
||||
&& ($maintenance->start_date !== '')
|
||||
&& ($maintenance->start_date !== '0000-00-00')
|
||||
if (($assetMaintenance->completion_date !== null)
|
||||
&& ($assetMaintenance->start_date !== '')
|
||||
&& ($assetMaintenance->start_date !== '0000-00-00')
|
||||
) {
|
||||
$startDate = Carbon::parse($maintenance->start_date);
|
||||
$completionDate = Carbon::parse($maintenance->completion_date);
|
||||
$maintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
||||
$startDate = Carbon::parse($assetMaintenance->start_date);
|
||||
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
||||
$assetMaintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
||||
}
|
||||
|
||||
$maintenance = $request->handleImages($maintenance);
|
||||
|
||||
// Was the asset maintenance created?
|
||||
if (!$maintenance->save()) {
|
||||
return redirect()->back()->withInput()->withErrors($maintenance->getErrors());
|
||||
if (!$assetMaintenance->save()) {
|
||||
return redirect()->back()->withInput()->withErrors($assetMaintenance->getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('maintenances.index')
|
||||
->with('success', trans('admin/maintenances/message.create.success'));
|
||||
->with('success', trans('admin/asset_maintenances/message.create.success'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a form view to edit a selected asset maintenance.
|
||||
*
|
||||
* @see MaintenancesController::postEdit() method that stores the data
|
||||
* @see AssetMaintenancesController::postEdit() method that stores the data
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function edit(Maintenance $maintenance) : View | RedirectResponse
|
||||
public function edit(AssetMaintenance $maintenance) : View | RedirectResponse
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('update', $maintenance->asset);
|
||||
|
||||
return view('maintenances/edit')
|
||||
return view('asset_maintenances/edit')
|
||||
->with('selected_assets', $maintenance->asset->pluck('id')->toArray())
|
||||
->with('asset_ids', request()->input('asset_ids', []))
|
||||
->with('maintenanceType', Maintenance::getImprovementOptions())
|
||||
->with('assetMaintenanceType', AssetMaintenance::getImprovementOptions())
|
||||
->with('item', $maintenance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and stores an update to an asset maintenance
|
||||
*
|
||||
* @see MaintenancesController::postEdit() method that stores the data
|
||||
* @see AssetMaintenancesController::postEdit() method that stores the data
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @param Request $request
|
||||
* @param int $maintenanceId
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function update(ImageUploadRequest $request, Maintenance $maintenance) : View | RedirectResponse
|
||||
public function update(Request $request, AssetMaintenance $maintenance) : View | RedirectResponse
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('update', $maintenance->asset);
|
||||
@@ -149,7 +153,7 @@ class MaintenancesController extends Controller
|
||||
$maintenance->cost = $request->input('cost');
|
||||
$maintenance->notes = $request->input('notes');
|
||||
$maintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||
$maintenance->name = $request->input('name');
|
||||
$maintenance->title = $request->input('title');
|
||||
$maintenance->start_date = $request->input('start_date');
|
||||
$maintenance->completion_date = $request->input('completion_date');
|
||||
|
||||
@@ -172,11 +176,10 @@ class MaintenancesController extends Controller
|
||||
$completionDate = Carbon::parse($maintenance->completion_date);
|
||||
$maintenance->asset_maintenance_time = (int) $completionDate->diffInDays($startDate, true);
|
||||
}
|
||||
$maintenance = $request->handleImages($maintenance);
|
||||
|
||||
if ($maintenance->save()) {
|
||||
return redirect()->route('maintenances.index')
|
||||
->with('success', trans('admin/maintenances/message.edit.success'));
|
||||
->with('success', trans('admin/asset_maintenances/message.edit.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($maintenance->getErrors());
|
||||
@@ -186,11 +189,11 @@ class MaintenancesController extends Controller
|
||||
* Delete an asset maintenance
|
||||
*
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @param int $maintenanceId
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function destroy(Maintenance $maintenance) : RedirectResponse
|
||||
public function destroy(AssetMaintenance $maintenance) : RedirectResponse
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('update', $maintenance->asset);
|
||||
@@ -198,19 +201,19 @@ class MaintenancesController extends Controller
|
||||
$maintenance->delete();
|
||||
// Redirect to the asset_maintenance management page
|
||||
return redirect()->route('maintenances.index')
|
||||
->with('success', trans('admin/maintenances/message.delete.success'));
|
||||
->with('success', trans('admin/asset_maintenances/message.delete.success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* View an asset maintenance
|
||||
*
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @param int $maintenanceId
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function show(Maintenance $maintenance) : View | RedirectResponse
|
||||
public function show(AssetMaintenance $maintenance) : View | RedirectResponse
|
||||
{
|
||||
return view('maintenances.view')->with('maintenance', $maintenance);
|
||||
return view('asset_maintenances/view')->with('assetMaintenance', $maintenance);
|
||||
}
|
||||
}
|
||||
@@ -87,20 +87,7 @@ class AssetModelsController extends Controller
|
||||
$model->fieldset_id = $request->input('fieldset_id');
|
||||
}
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = AssetModel::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
|
||||
$new_image = 'models/'.$new_image_name;
|
||||
Storage::disk('public')->copy('models/'.$cloned_model_img->image, $new_image);
|
||||
$model->image = $new_image_name;
|
||||
}
|
||||
|
||||
} else {
|
||||
$model = $request->handleImages($model);
|
||||
}
|
||||
|
||||
|
||||
$model = $request->handleImages($model);
|
||||
|
||||
if ($model->save()) {
|
||||
if ($this->shouldAddDefaultValues($request->input())) {
|
||||
@@ -284,7 +271,7 @@ class AssetModelsController extends Controller
|
||||
->with('depreciation_list', Helper::depreciationList())
|
||||
->with('item', $model)
|
||||
->with('model_id', $model->id)
|
||||
->with('cloned_model', $cloned_model);
|
||||
->with('clone_model', $cloned_model);
|
||||
}
|
||||
|
||||
|
||||
|
||||
115
app/Http/Controllers/AssetModelsFilesController.php
Normal file
115
app/Http/Controllers/AssetModelsFilesController.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\AssetModel;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use \Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class AssetModelsFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Upload a file to the server.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $modelId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*@since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function store(UploadFileRequest $request, $modelId = null) : RedirectResponse
|
||||
{
|
||||
if (! $model = AssetModel::find($modelId)) {
|
||||
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$this->authorize('update', $model);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/assetmodels')) {
|
||||
Storage::makeDirectory('private_uploads/assetmodels', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
|
||||
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$model->id,$file);
|
||||
|
||||
$model->logUpload($file_name, $request->get('notes'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for permissions and display the file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $modelId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function show(AssetModel $model, $fileId = null) : StreamedResponse | Response | RedirectResponse | BinaryFileResponse
|
||||
{
|
||||
|
||||
$this->authorize('view', $model);
|
||||
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that model/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/assetmodels/'.$log->filename;
|
||||
|
||||
if (! Storage::exists($file)) {
|
||||
return response('File '.$file.' not found on server', 404)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
if (request('inline') == 'true') {
|
||||
|
||||
$headers = [
|
||||
'Content-Disposition' => 'inline',
|
||||
];
|
||||
|
||||
return Storage::download($file, $log->filename, $headers);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associated file
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $modelId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function destroy(AssetModel $model, $fileId = null) : RedirectResponse
|
||||
{
|
||||
$rel_path = 'private_uploads/assetmodels';
|
||||
$this->authorize('update', $model);
|
||||
$log = Actionlog::find($fileId);
|
||||
if ($log) {
|
||||
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
||||
Storage::delete($rel_path.'/'.$log->filename);
|
||||
}
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
|
||||
}
|
||||
}
|
||||
108
app/Http/Controllers/Assets/AssetFilesController.php
Normal file
108
app/Http/Controllers/Assets/AssetFilesController.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Assets;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use \Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
use \Illuminate\Http\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class AssetFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Upload a file to the server.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $assetId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*@since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function store(UploadFileRequest $request, Asset $asset) : RedirectResponse
|
||||
{
|
||||
|
||||
$this->authorize('update', $asset);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/assets')) {
|
||||
Storage::makeDirectory('private_uploads/assets', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
||||
|
||||
$asset->logUpload($file_name, $request->get('notes'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.upload.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for permissions and display the file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $assetId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function show(Asset $asset, $fileId = null) : View | RedirectResponse | Response | StreamedResponse | BinaryFileResponse
|
||||
{
|
||||
|
||||
$this->authorize('view', $asset);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $asset->id)->find($fileId)) {
|
||||
$file = 'private_uploads/assets/'.$log->filename;
|
||||
|
||||
if ($log->action_type == 'audit') {
|
||||
$file = 'private_uploads/audits/'.$log->filename;
|
||||
}
|
||||
|
||||
try {
|
||||
return StorageHelper::showOrDownloadFile($file, $log->filename);
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('hardware.show', $asset)->with('error', trans('general.file_not_found'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('hardware.show', $asset)->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associated file
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $assetId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function destroy(Asset $asset, $fileId = null) : RedirectResponse
|
||||
{
|
||||
$this->authorize('update', $asset);
|
||||
$rel_path = 'private_uploads/assets';
|
||||
|
||||
if ($log = Actionlog::find($fileId)) {
|
||||
if (Storage::exists($rel_path.'/'.$log->filename)) {
|
||||
Storage::delete($rel_path.'/'.$log->filename);
|
||||
}
|
||||
$log->delete();
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->route('hardware.show', $asset)->with('error', trans('general.log_record_not_found'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -157,16 +157,8 @@ class AssetsController extends Controller
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = Asset::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
|
||||
$new_image = 'assets/'.$new_image_name;
|
||||
Storage::disk('public')->copy('assets/'.$cloned_model_img->image, $new_image);
|
||||
$asset->image = $new_image_name;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Create the image (if one was chosen.)
|
||||
if ($request->has('image')) {
|
||||
$asset = $request->handleImages($asset);
|
||||
}
|
||||
|
||||
@@ -234,13 +226,9 @@ class AssetsController extends Controller
|
||||
$failures[] = join(",", $asset->getErrors()->all());
|
||||
}
|
||||
}
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
}
|
||||
|
||||
session()->put(['checkout_to_type' => $request->get('checkout_to_type'),
|
||||
session()->put(['redirect_option' => $request->get('redirect_option'),
|
||||
'checkout_to_type' => $request->get('checkout_to_type'),
|
||||
'other_redirect' => 'model' ]);
|
||||
|
||||
|
||||
@@ -424,9 +412,6 @@ class AssetsController extends Controller
|
||||
$model = AssetModel::find($request->get('model_id'));
|
||||
if (($model) && ($model->fieldset)) {
|
||||
foreach ($model->fieldset->fields as $field) {
|
||||
if ($field->element == 'checkbox' && !$request->has($field->db_column)) {
|
||||
$asset->{$field->db_column} = null;
|
||||
}
|
||||
if ($request->has($field->db_column)) {
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('assets.view.encrypted_custom_fields')) {
|
||||
@@ -659,9 +644,8 @@ class AssetsController extends Controller
|
||||
*/
|
||||
public function getClone(Asset $asset)
|
||||
{
|
||||
$this->authorize('create', Asset::class);
|
||||
$this->authorize('create', $asset);
|
||||
$cloned = clone $asset;
|
||||
$cloned_model = $asset;
|
||||
$cloned->id = null;
|
||||
$cloned->asset_tag = '';
|
||||
$cloned->serial = '';
|
||||
@@ -671,7 +655,6 @@ class AssetsController extends Controller
|
||||
return view('hardware/edit')
|
||||
->with('statuslabel_list', Helper::statusLabelList())
|
||||
->with('statuslabel_types', Helper::statusTypeList())
|
||||
->with('cloned_model', $cloned_model)
|
||||
->with('item', $cloned);
|
||||
}
|
||||
|
||||
|
||||
@@ -544,7 +544,7 @@ class BulkAssetsController extends Controller
|
||||
session()->put('bulk_asset_errors',$error_array);
|
||||
|
||||
return redirect()
|
||||
->route('hardware.index')
|
||||
->route('hardware.bulkedit')
|
||||
->with('bulk_asset_errors', $error_array)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
@@ -88,12 +88,7 @@ class ComponentsController extends Controller
|
||||
|
||||
$component = $request->handleImages($component);
|
||||
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
}
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
|
||||
if ($component->save()) {
|
||||
return Helper::getRedirectOption($request, $component->id, 'Components')
|
||||
|
||||
138
app/Http/Controllers/Components/ComponentsFilesController.php
Normal file
138
app/Http/Controllers/Components/ComponentsFilesController.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Components;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Component;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ComponentsFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a component.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $componentId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
*/
|
||||
public function store(UploadFileRequest $request, $componentId = null)
|
||||
{
|
||||
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('components.show', ['component'=>$componentId])->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
$component = Component::find($componentId);
|
||||
|
||||
if (isset($component->id)) {
|
||||
$this->authorize('update', $component);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/components')) {
|
||||
Storage::makeDirectory('private_uploads/components', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
$file_name = $request->handleFile('private_uploads/components/','component-'.$component->id, $file);
|
||||
|
||||
//Log the upload to the log
|
||||
$component->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('components.show', $component->id)->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('components.show', $component->id)->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('components.index')
|
||||
->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected component file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $componentId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($componentId = null, $fileId = null)
|
||||
{
|
||||
$component = Component::find($componentId);
|
||||
|
||||
// the asset is valid
|
||||
if (isset($component->id)) {
|
||||
$this->authorize('update', $component);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('components/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('components/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()->withFragment('files')
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the licence management page
|
||||
return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $componentId
|
||||
* @param int $fileId
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($componentId = null, $fileId = null)
|
||||
{
|
||||
Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||
|
||||
|
||||
// the component is valid
|
||||
if ($component = Component::find($componentId)) {
|
||||
$this->authorize('view', $component);
|
||||
$this->authorize('components.files', $component);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $component->id)->find($fileId)) {
|
||||
|
||||
$file = 'private_uploads/components/'.$log->filename;
|
||||
|
||||
try {
|
||||
return StorageHelper::showOrDownloadFile($file, $log->filename);
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('components.show', ['component' => $component])->with('error', trans('general.file_not_found'));
|
||||
}
|
||||
}
|
||||
return redirect()->route('components.show', ['component' => $component])->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
@@ -81,29 +81,13 @@ class ConsumablesController extends Controller
|
||||
$consumable->purchase_date = $request->input('purchase_date');
|
||||
$consumable->purchase_cost = $request->input('purchase_cost');
|
||||
$consumable->qty = $request->input('qty');
|
||||
$consumable->created_by = auth()->id();
|
||||
$consumable->created_by = auth()->id();
|
||||
$consumable->notes = $request->input('notes');
|
||||
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = Consumable::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
|
||||
$new_image = 'consumables/'.$new_image_name;
|
||||
Storage::disk('public')->copy('consumables/'.$cloned_model_img->image, $new_image);
|
||||
$consumable->image = $new_image_name;
|
||||
}
|
||||
|
||||
} else {
|
||||
$consumable = $request->handleImages($consumable);
|
||||
}
|
||||
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
}
|
||||
$consumable = $request->handleImages($consumable);
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
|
||||
if ($consumable->save()) {
|
||||
return Helper::getRedirectOption($request, $consumable->id, 'Consumables')
|
||||
@@ -229,10 +213,9 @@ class ConsumablesController extends Controller
|
||||
$consumable_to_close = $consumable;
|
||||
$consumable = clone $consumable_to_close;
|
||||
$consumable->id = null;
|
||||
$consumable->image = null;
|
||||
$consumable->created_by = null;
|
||||
|
||||
return view('consumables/edit')
|
||||
->with('cloned_model', $consumable_to_close)
|
||||
->with('item', $consumable);
|
||||
return view('consumables/edit')->with('item', $consumable);
|
||||
}
|
||||
}
|
||||
|
||||
134
app/Http/Controllers/Consumables/ConsumablesFilesController.php
Normal file
134
app/Http/Controllers/Consumables/ConsumablesFilesController.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Consumables;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Consumable;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
class ConsumablesFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a consumable.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $consumableId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
*/
|
||||
public function store(UploadFileRequest $request, $consumableId = null)
|
||||
{
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('consumables.show', ['consumable'=>$consumableId])->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
$consumable = Consumable::find($consumableId);
|
||||
|
||||
if (isset($consumable->id)) {
|
||||
$this->authorize('update', $consumable);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/consumables')) {
|
||||
Storage::makeDirectory('private_uploads/consumables', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
$file_name = $request->handleFile('private_uploads/consumables/','consumable-'.$consumable->id, $file);
|
||||
|
||||
//Log the upload to the log
|
||||
$consumable->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('consumables.show', $consumable->id)->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('consumables.show', $consumable->id)->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('consumables.index')
|
||||
->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected consumable file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $consumableId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($consumableId = null, $fileId = null)
|
||||
{
|
||||
$consumable = Consumable::find($consumableId);
|
||||
|
||||
// the asset is valid
|
||||
if (isset($consumable->id)) {
|
||||
$this->authorize('update', $consumable);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('consumables/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('consumables/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()->withFragment('files')
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the licence management page
|
||||
return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $consumableId
|
||||
* @param int $fileId
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($consumableId = null, $fileId = null)
|
||||
{
|
||||
$consumable = Consumable::find($consumableId);
|
||||
|
||||
// the consumable is valid
|
||||
if (isset($consumable->id)) {
|
||||
$this->authorize('view', $consumable);
|
||||
$this->authorize('consumables.files', $consumable);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $consumable->id)->find($fileId)) {
|
||||
$file = 'private_uploads/consumables/'.$log->filename;
|
||||
|
||||
try {
|
||||
return StorageHelper::showOrDownloadFile($file, $log->filename);
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('consumables.show', ['consumable' => $consumable])->with('error', trans('general.file_not_found'));
|
||||
}
|
||||
}
|
||||
// The log record doesn't exist somehow
|
||||
return redirect()->route('consumables.show', ['consumable' => $consumable])->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
|
||||
}
|
||||
}
|
||||
@@ -22,15 +22,6 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\Location;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
@@ -41,45 +32,6 @@ abstract class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
static $map_object_type = [
|
||||
'accessories' => Accessory::class,
|
||||
'maintenances' => Maintenance::class,
|
||||
'assets' => Asset::class,
|
||||
'components' => Component::class,
|
||||
'consumables' => Consumable::class,
|
||||
'hardware' => Asset::class,
|
||||
'licenses' => License::class,
|
||||
'locations' => Location::class,
|
||||
'models' => AssetModel::class,
|
||||
'users' => User::class,
|
||||
];
|
||||
|
||||
static $map_storage_path = [
|
||||
'accessories' => 'private_uploads/accessories/',
|
||||
'maintenances' => 'private_uploads/maintenances/',
|
||||
'assets' => 'private_uploads/assets/',
|
||||
'components' => 'private_uploads/components/',
|
||||
'consumables' => 'private_uploads/consumables/',
|
||||
'hardware' => 'private_uploads/assets/',
|
||||
'licenses' => 'private_uploads/licenses/',
|
||||
'locations' => 'private_uploads/locations/',
|
||||
'models' => 'private_uploads/models/',
|
||||
'users' => 'private_uploads/users/',
|
||||
];
|
||||
|
||||
static $map_file_prefix= [
|
||||
'accessories' => 'accessory',
|
||||
'maintenances' => 'maintenance',
|
||||
'assets' => 'asset',
|
||||
'components' => 'component',
|
||||
'consumables' => 'consumable',
|
||||
'hardware' => 'asset',
|
||||
'licenses' => 'license',
|
||||
'locations' => 'location',
|
||||
'models' => 'model',
|
||||
'users' => 'user',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
view()->share('signedIn', Auth::check());
|
||||
|
||||
@@ -144,9 +144,10 @@ class CustomFieldsController extends Controller
|
||||
*/
|
||||
public function deleteFieldFromFieldset($field_id, $fieldset_id) : RedirectResponse
|
||||
{
|
||||
$this->authorize('update', CustomField::class);
|
||||
$field = CustomField::find($field_id);
|
||||
|
||||
$this->authorize('update', $field);
|
||||
|
||||
// Check that the field exists - this is mostly related to the demo, where we
|
||||
// rewrite the data every x minutes, so it's possible someone might be disassociating
|
||||
// a field from a fieldset just as we're wiping the database
|
||||
@@ -156,12 +157,11 @@ class CustomFieldsController extends Controller
|
||||
return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id])
|
||||
->with('success', trans('admin/custom_fields/message.field.delete.success'));
|
||||
} else {
|
||||
return redirect()->back()->with('error', trans('admin/custom_fields/message.field.delete.error'))
|
||||
->withInput();
|
||||
return redirect()->back()->withErrors(['message' => "Field is in use and cannot be deleted."]);
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('admin/custom_fields/message.field.delete.error'));
|
||||
return redirect()->back()->withErrors(['message' => "Error deleting field from fieldset"]);
|
||||
|
||||
|
||||
}
|
||||
@@ -172,16 +172,20 @@ class CustomFieldsController extends Controller
|
||||
* @author [Brady Wetherington] [<uberbrady@gmail.com>]
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function destroy(CustomField $field) : RedirectResponse
|
||||
public function destroy($field_id) : RedirectResponse
|
||||
{
|
||||
$this->authorize('delete', CustomField::class);
|
||||
if ($field = CustomField::find($field_id)) {
|
||||
$this->authorize('delete', $field);
|
||||
|
||||
if (($field->fieldset) && ($field->fieldset->count() > 0)) {
|
||||
return redirect()->back()->with('error', trans('admin/custom_fields/message.field.delete.in_use'));
|
||||
if (($field->fieldset) && ($field->fieldset->count() > 0)) {
|
||||
return redirect()->back()->withErrors(['message' => 'Field is in-use']);
|
||||
}
|
||||
$field->delete();
|
||||
return redirect()->route("fields.index")
|
||||
->with("success", trans('admin/custom_fields/message.field.delete.success'));
|
||||
}
|
||||
$field->delete();
|
||||
return redirect()->route("fields.index")
|
||||
->with("success", trans('admin/custom_fields/message.field.delete.success'));
|
||||
|
||||
return redirect()->back()->withErrors(['message' => 'Field does not exist']);
|
||||
}
|
||||
|
||||
|
||||
@@ -194,7 +198,7 @@ class CustomFieldsController extends Controller
|
||||
*/
|
||||
public function edit(Request $request, CustomField $field) : View | RedirectResponse
|
||||
{
|
||||
$this->authorize('update', CustomField::class);
|
||||
$this->authorize('update', $field);
|
||||
$fieldsets = CustomFieldset::get();
|
||||
$customFormat = '';
|
||||
if ((stripos($field->format, 'regex') === 0) && ($field->format !== CustomField::PREDEFINED_FORMATS['MAC'])) {
|
||||
@@ -224,7 +228,7 @@ class CustomFieldsController extends Controller
|
||||
*/
|
||||
public function update(CustomFieldRequest $request, CustomField $field) : RedirectResponse
|
||||
{
|
||||
$this->authorize('update', CustomField::class);
|
||||
$this->authorize('update', $field);
|
||||
$show_in_email = $request->get("show_in_email", 0);
|
||||
$display_in_user_view = $request->get("display_in_user_view", 0);
|
||||
|
||||
@@ -261,6 +265,7 @@ class CustomFieldsController extends Controller
|
||||
|
||||
if ($field->save()) {
|
||||
|
||||
|
||||
// Sync fields with fieldsets
|
||||
$fieldset_array = $request->input('associate_fieldsets');
|
||||
if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) {
|
||||
|
||||
@@ -87,9 +87,7 @@ class LicenseCheckinController extends Controller
|
||||
|
||||
if($licenseSeat->assigned_to != null){
|
||||
$return_to = User::withTrashed()->find($licenseSeat->assigned_to);
|
||||
if ($return_to) {
|
||||
session()->put('checkedInFrom', $return_to->id);
|
||||
}
|
||||
session()->put('checkedInFrom', $return_to->id);
|
||||
} else {
|
||||
$return_to = Asset::find($licenseSeat->asset_id);
|
||||
}
|
||||
|
||||
132
app/Http/Controllers/Licenses/LicenseFilesController.php
Normal file
132
app/Http/Controllers/Licenses/LicenseFilesController.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Licenses;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\License;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class LicenseFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a license.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $licenseId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
*/
|
||||
public function store(UploadFileRequest $request, $licenseId = null)
|
||||
{
|
||||
$license = License::find($licenseId);
|
||||
|
||||
if (isset($license->id)) {
|
||||
$this->authorize('update', $license);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/licenses')) {
|
||||
Storage::makeDirectory('private_uploads/licenses', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
$file_name = $request->handleFile('private_uploads/licenses/','license-'.$license->id, $file);
|
||||
|
||||
//Log the upload to the log
|
||||
$license->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('licenses.show', $license->id)->with('success', trans('admin/licenses/message.upload.success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('licenses.show', $license->id)->with('error', trans('admin/licenses/message.upload.nofiles'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('licenses.index')
|
||||
->with('error', trans('admin/licenses/message.does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected license file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $licenseId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($licenseId = null, $fileId = null)
|
||||
{
|
||||
if ($license = License::find($licenseId)) {
|
||||
|
||||
$this->authorize('update', $license);
|
||||
|
||||
if ($log = Actionlog::find($fileId)) {
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('licenses/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('licenses/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->route('licenses.index')->with('error', trans('general.log_does_not_exist'));
|
||||
}
|
||||
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $licenseId
|
||||
* @param int $fileId
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($licenseId = null, $fileId = null, $download = true)
|
||||
{
|
||||
$license = License::find($licenseId);
|
||||
|
||||
// the license is valid
|
||||
if (isset($license->id)) {
|
||||
$this->authorize('view', $license);
|
||||
$this->authorize('licenses.files', $license);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $license->id)->find($fileId)) {
|
||||
$file = 'private_uploads/licenses/'.$log->filename;
|
||||
|
||||
try {
|
||||
return StorageHelper::showOrDownloadFile($file, $log->filename);
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('licenses.show', ['licenses' => $license])->with('error', trans('general.file_not_found'));
|
||||
}
|
||||
}
|
||||
|
||||
// The log record doesn't exist somehow
|
||||
return redirect()->route('licenses.show', ['licenses' => $license])->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist', ['id' => $fileId]));
|
||||
}
|
||||
}
|
||||
@@ -102,11 +102,7 @@ class LicensesController extends Controller
|
||||
$license->created_by = auth()->id();
|
||||
$license->min_amt = $request->input('min_amt');
|
||||
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
}
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
|
||||
if ($license->save()) {
|
||||
return Helper::getRedirectOption($request, $license->id, 'Licenses')
|
||||
@@ -308,16 +304,13 @@ class LicensesController extends Controller
|
||||
$response = new StreamedResponse(function () {
|
||||
// Open output stream
|
||||
$handle = fopen('php://output', 'w');
|
||||
$licenses = License::with('company',
|
||||
$licenses= License::with('company',
|
||||
'manufacturer',
|
||||
'category',
|
||||
'supplier',
|
||||
'adminuser',
|
||||
'assignedusers');
|
||||
if (request()->filled('category_id')) {
|
||||
$licenses = $licenses->where('category_id', request()->input('category_id'));
|
||||
}
|
||||
$licenses = $licenses->orderBy('created_at', 'DESC');
|
||||
'assignedusers')
|
||||
->orderBy('created_at', 'DESC');
|
||||
Company::scopeCompanyables($licenses)
|
||||
->chunk(500, function ($licenses) use ($handle) {
|
||||
$headers = [
|
||||
|
||||
@@ -96,18 +96,7 @@ class LocationsController extends Controller
|
||||
$location->company_id = $request->input('company_id');
|
||||
}
|
||||
|
||||
if ($request->has('use_cloned_image')) {
|
||||
$cloned_model_img = Location::select('image')->find($request->input('clone_image_from_id'));
|
||||
if ($cloned_model_img) {
|
||||
$new_image_name = 'clone-'.date('U').'-'.$cloned_model_img->image;
|
||||
$new_image = 'locations/'.$new_image_name;
|
||||
Storage::disk('public')->copy('locations/'.$cloned_model_img->image, $new_image);
|
||||
$location->image = $new_image_name;
|
||||
}
|
||||
|
||||
} else {
|
||||
$location = $request->handleImages($location);
|
||||
}
|
||||
$location = $request->handleImages($location);
|
||||
|
||||
if ($location->save()) {
|
||||
return redirect()->route('locations.index')->with('success', trans('admin/locations/message.create.success'));
|
||||
@@ -286,9 +275,9 @@ class LocationsController extends Controller
|
||||
|
||||
// unset these values
|
||||
$location->id = null;
|
||||
$location->image = null;
|
||||
|
||||
return view('locations/edit')
|
||||
->with('cloned_model', $location_to_clone)
|
||||
->with('item', $location);
|
||||
}
|
||||
|
||||
|
||||
111
app/Http/Controllers/LocationsFilesController.php
Normal file
111
app/Http/Controllers/LocationsFilesController.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Location;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use \Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
|
||||
class LocationsFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Upload a file to the server.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $modelId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*@since [v1.0]
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
*/
|
||||
public function store(UploadFileRequest $request, Location $location) : RedirectResponse
|
||||
{
|
||||
$this->authorize('update', $location);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
|
||||
if (! Storage::exists('private_uploads/locations')) {
|
||||
Storage::makeDirectory('private_uploads/locations', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
$file_name = $request->handleFile('private_uploads/locations/','location-'.$location->id, $file);
|
||||
$location->logUpload($file_name, $request->get('notes'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('general.file_upload_success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for permissions and display the file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $modelId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function show(Location $location, $fileId = null) : StreamedResponse | Response | RedirectResponse | BinaryFileResponse
|
||||
{
|
||||
|
||||
$this->authorize('view', $location);
|
||||
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return redirect()->back()->withFragment('files')->with('error', 'No matching file record');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/locations/'.$log->filename;
|
||||
|
||||
if (! Storage::exists($file)) {
|
||||
return redirect()->back()->withFragment('files')->with('error', 'No matching file on server');
|
||||
}
|
||||
|
||||
if (request('inline') == 'true') {
|
||||
|
||||
$headers = [
|
||||
'Content-Disposition' => 'inline',
|
||||
];
|
||||
|
||||
return Storage::download($file, $log->filename, $headers);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associated file
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $modelId
|
||||
* @param int $fileId
|
||||
* @since [v1.0]
|
||||
*/
|
||||
public function destroy(Location $location, $fileId = null) : RedirectResponse
|
||||
{
|
||||
$rel_path = 'private_uploads/locations';
|
||||
$this->authorize('update', $location);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
if ($log) {
|
||||
|
||||
// This should be moved to purge
|
||||
// if (Storage::exists($rel_path.'/'.$log->filename)) {
|
||||
// Storage::delete($rel_path.'/'.$log->filename);
|
||||
// }
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class ManufacturersController extends Controller
|
||||
$manufacturers_count = Manufacturer::withTrashed()->count();
|
||||
|
||||
if ($manufacturers_count == 0) {
|
||||
Artisan::call('db:seed', ['--class' => 'Database\\Seeders\\ManufacturerSeeder', '--force' => true]);
|
||||
Artisan::call('db:seed', ['--class' => 'ManufacturerSeeder']);
|
||||
return redirect()->route('manufacturers.index')->with('success', trans('general.seeding.manufacturers.success'));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
@@ -17,11 +17,13 @@ use App\Models\Depreciation;
|
||||
use App\Models\License;
|
||||
use App\Models\ReportTemplate;
|
||||
use App\Models\Setting;
|
||||
use App\Notifications\CheckoutAssetNotification;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
use League\Csv\Reader;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
@@ -1036,11 +1038,11 @@ class ReportsController extends Controller
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
*/
|
||||
public function getMaintenancesReport() : View
|
||||
public function getAssetMaintenancesReport() : View
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
|
||||
return view('reports.maintenances');
|
||||
return view('reports.asset_maintenances');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1049,11 +1051,11 @@ class ReportsController extends Controller
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
*/
|
||||
public function exportMaintenancesReport() : Response
|
||||
public function exportAssetMaintenancesReport() : Response
|
||||
{
|
||||
$this->authorize('reports.view');
|
||||
// Grab all the improvements
|
||||
$Maintenances = Maintenance::with('asset', 'supplier')
|
||||
$assetMaintenances = AssetMaintenance::with('asset', 'supplier')
|
||||
->orderBy('created_at', 'DESC')
|
||||
->get();
|
||||
|
||||
@@ -1061,36 +1063,36 @@ class ReportsController extends Controller
|
||||
|
||||
$header = [
|
||||
trans('admin/hardware/table.asset_tag'),
|
||||
trans('admin/maintenances/table.asset_name'),
|
||||
trans('admin/asset_maintenances/table.asset_name'),
|
||||
trans('general.supplier'),
|
||||
trans('admin/maintenances/form.asset_maintenance_type'),
|
||||
trans('admin/maintenances/form.title'),
|
||||
trans('admin/maintenances/form.start_date'),
|
||||
trans('admin/maintenances/form.completion_date'),
|
||||
trans('admin/maintenances/form.asset_maintenance_time'),
|
||||
trans('admin/maintenances/form.cost'),
|
||||
trans('admin/asset_maintenances/form.asset_maintenance_type'),
|
||||
trans('admin/asset_maintenances/form.title'),
|
||||
trans('admin/asset_maintenances/form.start_date'),
|
||||
trans('admin/asset_maintenances/form.completion_date'),
|
||||
trans('admin/asset_maintenances/form.asset_maintenance_time'),
|
||||
trans('admin/asset_maintenances/form.cost'),
|
||||
];
|
||||
|
||||
$header = array_map('trim', $header);
|
||||
$rows[] = implode(',', $header);
|
||||
|
||||
foreach ($Maintenances as $maintenance) {
|
||||
foreach ($assetMaintenances as $assetMaintenance) {
|
||||
$row = [];
|
||||
$row[] = str_replace(',', '', e($maintenance->asset->asset_tag));
|
||||
$row[] = str_replace(',', '', e($maintenance->asset->name));
|
||||
$row[] = str_replace(',', '', e($maintenance->supplier->name));
|
||||
$row[] = e($maintenance->improvement_type);
|
||||
$row[] = e($maintenance->name);
|
||||
$row[] = e($maintenance->start_date);
|
||||
$row[] = e($maintenance->completion_date);
|
||||
if (is_null($maintenance->asset_maintenance_time)) {
|
||||
$row[] = str_replace(',', '', e($assetMaintenance->asset->asset_tag));
|
||||
$row[] = str_replace(',', '', e($assetMaintenance->asset->name));
|
||||
$row[] = str_replace(',', '', e($assetMaintenance->supplier->name));
|
||||
$row[] = e($assetMaintenance->improvement_type);
|
||||
$row[] = e($assetMaintenance->title);
|
||||
$row[] = e($assetMaintenance->start_date);
|
||||
$row[] = e($assetMaintenance->completion_date);
|
||||
if (is_null($assetMaintenance->asset_maintenance_time)) {
|
||||
$improvementTime = (int) Carbon::now()
|
||||
->diffInDays(Carbon::parse($maintenance->start_date), true);
|
||||
->diffInDays(Carbon::parse($assetMaintenance->start_date), true);
|
||||
} else {
|
||||
$improvementTime = (int) $maintenance->asset_maintenance_time;
|
||||
$improvementTime = (int) $assetMaintenance->asset_maintenance_time;
|
||||
}
|
||||
$row[] = $improvementTime;
|
||||
$row[] = trans('general.currency') . Helper::formatCurrencyOutput($maintenance->cost);
|
||||
$row[] = trans('general.currency') . Helper::formatCurrencyOutput($assetMaintenance->cost);
|
||||
$rows[] = implode(',', $row);
|
||||
}
|
||||
|
||||
|
||||
@@ -1084,7 +1084,6 @@ class SettingsController extends Controller
|
||||
|
||||
if (! config('app.lock_passwords')) {
|
||||
if (Storage::exists($path.'/'.$filename)) {
|
||||
Log::warning('User '.auth()->user()->username.' is attempting to download backup file: '.$filename);
|
||||
return StorageHelper::downloader($path.'/'.$filename);
|
||||
} else {
|
||||
// Redirect to the backup page
|
||||
@@ -1112,7 +1111,6 @@ class SettingsController extends Controller
|
||||
if (Storage::exists($path . '/' . $filename)) {
|
||||
|
||||
try {
|
||||
Log::warning('User '.auth()->user()->username.' is attempting to delete backup file: '.$filename);
|
||||
Storage::delete($path . '/' . $filename);
|
||||
return redirect()->route('settings.backups.index')->with('success', trans('admin/settings/message.backup.file_deleted'));
|
||||
} catch (\Exception $e) {
|
||||
@@ -1192,7 +1190,7 @@ class SettingsController extends Controller
|
||||
'--force' => true,
|
||||
]);
|
||||
|
||||
Log::warning('User '.auth()->user()->username.' is attempting to restore from: '. storage_path($path).'/'.$filename);
|
||||
Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);
|
||||
|
||||
$restore_params = [
|
||||
'--force' => true,
|
||||
@@ -1341,11 +1339,9 @@ class SettingsController extends Controller
|
||||
'name' => config('mail.from.name'),
|
||||
'email' => config('mail.from.address'),
|
||||
])->notify(new MailTest());
|
||||
Log::debug('Attempting to send mail to '.config('mail.from.address'));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('mail_sent.mail_sent')));
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Mail sent from '.config('mail.from.address') .' with errors '. $e->getMessage());
|
||||
Log::debug($e);
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Models\Supplier;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use \Illuminate\Contracts\View\View;
|
||||
|
||||
@@ -121,7 +122,7 @@ class SuppliersController extends Controller
|
||||
public function destroy($supplierId) : RedirectResponse
|
||||
{
|
||||
$this->authorize('delete', Supplier::class);
|
||||
if (is_null($supplier = Supplier::with('maintenances', 'assets', 'licenses')->withCount('maintenances as maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->find($supplierId))) {
|
||||
if (is_null($supplier = Supplier::with('asset_maintenances', 'assets', 'licenses')->withCount('asset_maintenances as asset_maintenances_count', 'assets as assets_count', 'licenses as licenses_count')->find($supplierId))) {
|
||||
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.not_found'));
|
||||
}
|
||||
|
||||
@@ -129,8 +130,8 @@ class SuppliersController extends Controller
|
||||
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_assets', ['asset_count' => (int) $supplier->assets_count]));
|
||||
}
|
||||
|
||||
if ($supplier->maintenances_count > 0) {
|
||||
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_maintenances', ['maintenances_count' => $supplier->maintenances_count]));
|
||||
if ($supplier->asset_maintenances_count > 0) {
|
||||
return redirect()->route('suppliers.index')->with('error', trans('admin/suppliers/message.delete.assoc_maintenances', ['asset_maintenances_count' => $supplier->asset_maintenances_count]));
|
||||
}
|
||||
|
||||
if ($supplier->licenses_count > 0) {
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
|
||||
/**
|
||||
* This controller provide the health route for
|
||||
* the Snipe-IT Asset Management application.
|
||||
*
|
||||
* @version v1.0
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
|
||||
*/
|
||||
class UploadedFilesController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Accepts a POST to upload a file to the server.
|
||||
*
|
||||
* @param \App\Http\Requests\UploadFileRequest $request
|
||||
* @param string $object_type the type of object to upload the file to
|
||||
* @param int $id the ID of the object to store so we can check permisisons
|
||||
* @since [v8.2.2]
|
||||
* @author [A. Gianotto <snipe@snipe.net>]
|
||||
*/
|
||||
public function store(UploadFileRequest $request, $object_type, $id) : RedirectResponse
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$this->authorize('update', $object);
|
||||
|
||||
if (!$object) {
|
||||
return redirect()->back()->withFragment('files')->with('error',trans('general.file_upload_status.invalid_object'));
|
||||
}
|
||||
|
||||
// If the file storage directory doesn't exist, create it
|
||||
if (! Storage::exists(self::$map_storage_path[$object_type])) {
|
||||
Storage::makeDirectory(self::$map_storage_path[$object_type], 775);
|
||||
}
|
||||
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
// Loop over the attached files and add them to the object
|
||||
foreach ($request->file('file') as $file) {
|
||||
$file_name = $request->handleFile(self::$map_storage_path[$object_type], self::$map_file_prefix[$object_type].'-'.$object->id, $file);
|
||||
$files[] = $file_name;
|
||||
$object->logUpload($file_name, $request->get('notes'));
|
||||
}
|
||||
|
||||
$files = Actionlog::select('action_logs.*')->where('action_type', '=', 'uploaded')
|
||||
->where('item_type', '=', self::$map_object_type[$object_type])
|
||||
->where('item_id', '=', $id)->whereIn('filename', $files)
|
||||
->get();
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.upload.success', count($files)));
|
||||
}
|
||||
|
||||
// No files were submitted
|
||||
return redirect()->back()->withFragment('files')->with('error', trans('general.file_upload_status.nofiles'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check for permissions and display the file.
|
||||
* This isn't currently used, but is here for future use.
|
||||
*
|
||||
* @param \App\Http\Requests\UploadFileRequest $request
|
||||
* @param string $object_type the type of object to upload the file to
|
||||
* @param int $id the ID of the object to delete from so we can check permisisons
|
||||
* @param $file_id the ID of the file to show from the action_logs table
|
||||
* @since [v8.2.2]
|
||||
* @author [A. Gianotto <snipe@snipe.net>]
|
||||
*/
|
||||
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);
|
||||
$this->authorize('view', $object);
|
||||
|
||||
if (!$object) {
|
||||
return redirect()->back()->withFragment('files')->with('error',trans('general.file_upload_status.invalid_object'));
|
||||
}
|
||||
|
||||
|
||||
// Check that the file being requested exists for the object
|
||||
if (! $log = Actionlog::whereNotNull('filename')->where('item_type', self::$map_object_type[$object_type])->where('item_id', $object->id)->find($file_id))
|
||||
{
|
||||
return redirect()->back()->withFragment('files')->with('error', trans('general.file_upload_status.invalid_id'));
|
||||
}
|
||||
|
||||
|
||||
if (! Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename))
|
||||
{
|
||||
return redirect()->back()->withFragment('files')->with('error', trans('general.file_upload_status.file_not_found'));
|
||||
}
|
||||
|
||||
if (request('inline') == 'true') {
|
||||
$headers = [
|
||||
'Content-Disposition' => 'inline',
|
||||
];
|
||||
return Storage::download(self::$map_storage_path[$object_type].'/'.$log->filename, $log->filename, $headers);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the associated file
|
||||
*
|
||||
* @param \App\Http\Requests\UploadFileRequest $request
|
||||
* @param string $object_type the type of object to upload the file to
|
||||
* @param int $id the ID of the object to delete from so we can check permisisons
|
||||
* @param $file_id the ID of the file to delete from the action_logs table
|
||||
* @since [v8.2.2]
|
||||
* @author [A. Gianotto <snipe@snipe.net>]
|
||||
*/
|
||||
public function destroy($object_type, $id, $file_id) : RedirectResponse
|
||||
{
|
||||
|
||||
// Check the permissions to make sure the user can view the object
|
||||
$object = self::$map_object_type[$object_type]::find($id);
|
||||
$this->authorize('update', self::$map_object_type[$object_type]);
|
||||
|
||||
if (!$object) {
|
||||
return redirect()->back()->withFragment('files')->with('error',trans('general.file_upload_status.invalid_object'));
|
||||
}
|
||||
|
||||
|
||||
// Check for the file
|
||||
$log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type])
|
||||
->where('item_id', $object->id)->first();
|
||||
|
||||
if ($log) {
|
||||
// Check the file actually exists, and delete it
|
||||
if (Storage::exists(self::$map_storage_path[$object_type].'/'.$log->filename)) {
|
||||
Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename);
|
||||
}
|
||||
// Delete the record of the file
|
||||
if ($log->delete()) {
|
||||
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.success', 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The file doesn't seem to really exist, so report an error
|
||||
return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.error', 1));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
129
app/Http/Controllers/Users/UserFilesController.php
Normal file
129
app/Http/Controllers/Users/UserFilesController.php
Normal file
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Users;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\UploadFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\User;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class UserFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Return JSON response with a list of user details for the getIndex() view.
|
||||
*
|
||||
* @param UploadFileRequest $request
|
||||
* @param int $userId
|
||||
* @return string JSON
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.6]
|
||||
*/
|
||||
public function store(UploadFileRequest $request, User $user)
|
||||
{
|
||||
$this->authorize('update', $user);
|
||||
$files = $request->file('file');
|
||||
|
||||
if (is_null($files)) {
|
||||
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
$file_name = $request->handleFile('private_uploads/users/', 'user-'.$user->id, $file);
|
||||
|
||||
//Log the uploaded file to the log
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_id = $user->id;
|
||||
$logAction->item_type = User::class;
|
||||
$logAction->created_by = auth()->id();
|
||||
$logAction->note = $request->input('notes');
|
||||
$logAction->target_id = null;
|
||||
$logAction->created_at = date("Y-m-d H:i:s");
|
||||
$logAction->filename = $file_name;
|
||||
$logAction->action_type = 'uploaded';
|
||||
|
||||
if (! $logAction->save()) {
|
||||
return JsonResponse::create(['error' => 'Failed validation: '.print_r($logAction->getErrors(), true)], 500);
|
||||
}
|
||||
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/users/message.upload.success'));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete file
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.6]
|
||||
* @param int $userId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($userId = null, $fileId = null)
|
||||
{
|
||||
if ($user = User::find($userId)) {
|
||||
|
||||
$this->authorize('delete', $user);
|
||||
$rel_path = 'private_uploads/users';
|
||||
|
||||
|
||||
if ($log = Actionlog::find($fileId)) {
|
||||
$filename = $log->filename;
|
||||
$log->delete();
|
||||
|
||||
if (Storage::exists($rel_path.'/'.$filename)) {
|
||||
Storage::delete($rel_path.'/'.$filename);
|
||||
return redirect()->back()->withFragment('files')->with('success', trans('admin/users/message.deletefile.success'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The log record doesn't exist somehow
|
||||
return redirect()->back()->with('success', trans('admin/users/message.deletefile.success'));
|
||||
}
|
||||
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', ['id' => $userId]));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Display/download the uploaded file
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.6]
|
||||
* @param int $userId
|
||||
* @param int $fileId
|
||||
* @return mixed
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show(User $user, $fileId = null)
|
||||
{
|
||||
|
||||
|
||||
if (empty($fileId)) {
|
||||
return redirect()->route('users.show')->with('error', 'Invalid file request');
|
||||
}
|
||||
|
||||
$this->authorize('view', $user);
|
||||
|
||||
if ($log = Actionlog::whereNotNull('filename')->where('item_id', $user->id)->find($fileId)) {
|
||||
$file = 'private_uploads/users/'.$log->filename;
|
||||
|
||||
try {
|
||||
return StorageHelper::showOrDownloadFile($file, $log->filename);
|
||||
} catch (\Exception $e) {
|
||||
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.file_not_found'));
|
||||
}
|
||||
}
|
||||
|
||||
// The log record doesn't exist somehow
|
||||
return redirect()->route('users.show', ['user' => $user])->with('error', trans('general.log_record_not_found'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,7 +98,6 @@ class UsersController extends Controller
|
||||
$user->activated = $request->input('activated', 0);
|
||||
$user->jobtitle = $request->input('jobtitle');
|
||||
$user->phone = $request->input('phone');
|
||||
$user->mobile = $request->input('mobile');
|
||||
$user->location_id = $request->input('location_id', null);
|
||||
$user->department_id = $request->input('department_id', null);
|
||||
$user->company_id = Company::getIdForUser($request->input('company_id', null));
|
||||
@@ -127,12 +126,7 @@ class UsersController extends Controller
|
||||
// we have to invoke the form request here to handle image uploads
|
||||
app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar');
|
||||
|
||||
if($request->get('redirect_option') === 'back'){
|
||||
session()->put(['redirect_option' => 'index']);
|
||||
} else {
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
}
|
||||
|
||||
session()->put(['redirect_option' => $request->get('redirect_option')]);
|
||||
|
||||
if ($user->save()) {
|
||||
if ($request->filled('groups')) {
|
||||
@@ -245,7 +239,6 @@ class UsersController extends Controller
|
||||
$user->employee_num = $request->input('employee_num');
|
||||
$user->jobtitle = $request->input('jobtitle', null);
|
||||
$user->phone = $request->input('phone');
|
||||
$user->mobile = $request->input('mobile');
|
||||
$user->location_id = $request->input('location_id', null);
|
||||
$user->company_id = Company::getIdForUser($request->input('company_id', null));
|
||||
$user->manager_id = $request->input('manager_id', null);
|
||||
@@ -439,7 +432,7 @@ class UsersController extends Controller
|
||||
app('request')->request->set('permissions', $permissions);
|
||||
|
||||
|
||||
$user_to_clone = User::with('userloc')->withTrashed()->find($user->id);
|
||||
$user_to_clone = User::with('assets', 'assets.model', 'consumables', 'accessories', 'licenses', 'userloc')->withTrashed()->find($user->id);
|
||||
// Make sure they can view this particular user
|
||||
$this->authorize('view', $user_to_clone);
|
||||
|
||||
@@ -454,8 +447,6 @@ class UsersController extends Controller
|
||||
$user->last_name = '';
|
||||
$user->email = substr($user->email, ($pos = strpos($user->email, '@')) !== false ? $pos : 0);
|
||||
$user->id = null;
|
||||
$user->username = null;
|
||||
$user->avatar = null;
|
||||
|
||||
// Get this user's groups
|
||||
$userGroups = $user_to_clone->groups()->pluck('name', 'id');
|
||||
@@ -471,7 +462,7 @@ class UsersController extends Controller
|
||||
->with('user', $user)
|
||||
->with('groups', Group::pluck('name', 'id'))
|
||||
->with('userGroups', $userGroups)
|
||||
->with('cloned_model', $user_to_clone)
|
||||
->with('clone_user', $user_to_clone)
|
||||
->with('item', $user);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class SecurityHeaders
|
||||
$response = $next($request);
|
||||
|
||||
$response->headers->set('X-Content-Type-Options', 'nosniff');
|
||||
$response->headers->set('X-XSS-Protection', '1; mode=block');
|
||||
|
||||
// Ugh. Feature-Policy is dumb and clumsy and mostly irrelevant for Snipe-IT,
|
||||
// since we don't provide any way to IFRAME anything in in the first place.
|
||||
|
||||
@@ -11,7 +11,6 @@ use Illuminate\Support\Facades\Storage;
|
||||
use Intervention\Image\Exception\NotReadableException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class ImageUploadRequest extends Request
|
||||
{
|
||||
@@ -71,25 +70,19 @@ class ImageUploadRequest extends Request
|
||||
public function handleImages($item, $w = 600, $form_fieldname = 'image', $path = null, $db_fieldname = 'image')
|
||||
{
|
||||
|
||||
$type = class_basename(get_class($item));
|
||||
$type = strtolower(class_basename(get_class($item)));
|
||||
|
||||
if (is_null($path)) {
|
||||
|
||||
$path = strtolower(str_plural($type));
|
||||
$path = str_plural($type);
|
||||
|
||||
if ($type == 'AssetModel') {
|
||||
if ($type == 'assetmodel') {
|
||||
$path = 'models';
|
||||
}
|
||||
|
||||
if ($type == 'user') {
|
||||
$path = 'avatars';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!Storage::disk('public')->exists($path)) {
|
||||
Storage::disk('public')->makeDirectory($path);
|
||||
}
|
||||
|
||||
if ($this->offsetGet($form_fieldname) instanceof UploadedFile) {
|
||||
@@ -100,9 +93,10 @@ class ImageUploadRequest extends Request
|
||||
|
||||
if (isset($image)) {
|
||||
|
||||
if (!config('app.lock_passwords')) {
|
||||
|
||||
$ext = $image->guessExtension();
|
||||
$file_name = $type.'-'.$form_fieldname.($item->id ?? '-'.$item->id).'-'.str_random(10).'.'.$ext;
|
||||
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
|
||||
|
||||
if (($image->getMimeType() == 'image/vnd.microsoft.icon') || ($image->getMimeType() == 'image/x-icon') || ($image->getMimeType() == 'image/avif') || ($image->getMimeType() == 'image/webp')) {
|
||||
// If the file is an icon, webp or avif, we need to just move it since gd doesn't support resizing
|
||||
@@ -144,7 +138,7 @@ class ImageUploadRequest extends Request
|
||||
// Remove Current image if exists
|
||||
$item = $this->deleteExistingImage($item, $path, $db_fieldname);
|
||||
$item->{$db_fieldname} = $file_name;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// If the user isn't uploading anything new but wants to delete their old image, do so
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CustomField;
|
||||
@@ -17,7 +16,6 @@ use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ActionlogsTransformer
|
||||
{
|
||||
@@ -135,6 +133,24 @@ class ActionlogsTransformer
|
||||
$clean_meta= $this->changedInfo($clean_meta);
|
||||
}
|
||||
|
||||
$file_url = '';
|
||||
if($actionlog->filename!='') {
|
||||
if ($actionlog->action_type == 'accepted') {
|
||||
$file_url = route('log.storedeula.download', ['filename' => $actionlog->filename]);
|
||||
} else {
|
||||
if ($actionlog->item) {
|
||||
if ($actionlog->itemType() == 'asset') {
|
||||
$file_url = route('show/assetfile', ['asset' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'accessory') {
|
||||
$file_url = route('show.accessoryfile', ['accessoryId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'license') {
|
||||
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'user') {
|
||||
$file_url = route('show/userfile', ['user' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$array = [
|
||||
'id' => (int) $actionlog->id,
|
||||
@@ -142,10 +158,8 @@ class ActionlogsTransformer
|
||||
'file' => ($actionlog->filename!='')
|
||||
?
|
||||
[
|
||||
'url' => $actionlog->uploads_file_url(),
|
||||
'url' => $file_url,
|
||||
'filename' => $actionlog->filename,
|
||||
'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_url()),
|
||||
'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false,
|
||||
] : null,
|
||||
|
||||
'item' => ($actionlog->item) ? [
|
||||
|
||||
@@ -4,24 +4,23 @@ namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\AssetMaintenance;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class MaintenancesTransformer
|
||||
class AssetMaintenancesTransformer
|
||||
{
|
||||
public function transformMaintenances(Collection $maintenances, $total)
|
||||
public function transformAssetMaintenances(Collection $assetmaintenances, $total)
|
||||
{
|
||||
$array = [];
|
||||
foreach ($maintenances as $assetmaintenance) {
|
||||
$array[] = self::transformMaintenance($assetmaintenance);
|
||||
foreach ($assetmaintenances as $assetmaintenance) {
|
||||
$array[] = self::transformAssetMaintenance($assetmaintenance);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformMaintenance(Maintenance $assetmaintenance)
|
||||
public function transformAssetMaintenance(AssetMaintenance $assetmaintenance)
|
||||
{
|
||||
$array = [
|
||||
'id' => (int) $assetmaintenance->id,
|
||||
@@ -34,7 +33,6 @@ class MaintenancesTransformer
|
||||
'created_at' => Helper::getFormattedDateObject($assetmaintenance->asset->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($assetmaintenance->asset->updated_at, 'datetime'),
|
||||
] : null,
|
||||
'image' => ($assetmaintenance->image != '') ? Storage::disk('public')->url('maintenances/'.e($assetmaintenance->image)) : null,
|
||||
'model' => (($assetmaintenance->asset) && ($assetmaintenance->asset->model)) ? [
|
||||
'id' => (int) $assetmaintenance->asset->model->id,
|
||||
'name'=> ($assetmaintenance->asset->model->name) ? e($assetmaintenance->asset->model->name).' '.e($assetmaintenance->asset->model->model_number) : null,
|
||||
@@ -50,8 +48,7 @@ class MaintenancesTransformer
|
||||
'name'=> ($assetmaintenance->asset->company->name) ? e($assetmaintenance->asset->company->name) : null,
|
||||
|
||||
] : null,
|
||||
'name' => ($assetmaintenance->name) ? e($assetmaintenance->name) : null,
|
||||
'title' => ($assetmaintenance->name) ? e($assetmaintenance->name) : null, // legacy to not change the shape of the API
|
||||
'title' => ($assetmaintenance->title) ? e($assetmaintenance->title) : null,
|
||||
'location' => (($assetmaintenance->asset) && ($assetmaintenance->asset->location)) ? [
|
||||
'id' => (int) $assetmaintenance->asset->location->id,
|
||||
'name'=> e($assetmaintenance->asset->location->name),
|
||||
@@ -58,13 +58,6 @@ class AssetsTransformer
|
||||
'id' => (int) $asset->model->manufacturer->id,
|
||||
'name'=> e($asset->model->manufacturer->name),
|
||||
] : null,
|
||||
'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? [
|
||||
'id' => (int) $asset->model->depreciation->id,
|
||||
'name'=> e($asset->model->depreciation->name),
|
||||
'months'=> (int) $asset->model->depreciation->months,
|
||||
'type'=> e($asset->model->depreciation->depreciation_type),
|
||||
'minimum'=> ($asset->model->depreciation->depreciation_min) ? (int) $asset->model->depreciation->depreciation_min : null,
|
||||
] : null,
|
||||
'supplier' => ($asset->supplier) ? [
|
||||
'id' => (int) $asset->supplier->id,
|
||||
'name'=> e($asset->supplier->name),
|
||||
|
||||
@@ -25,7 +25,7 @@ class ConsumablesTransformer
|
||||
$array = [
|
||||
'id' => (int) $consumable->id,
|
||||
'name' => e($consumable->name),
|
||||
'image' => ($consumable->getImageUrl()) ? ($consumable->getImageUrl()) : null,
|
||||
'image' => ($consumable->image) ? Storage::disk('public')->url('consumables/'.e($consumable->image)) : null,
|
||||
'category' => ($consumable->category) ? ['id' => $consumable->category->id, 'name' => e($consumable->category->name)] : null,
|
||||
'company' => ($consumable->company) ? ['id' => (int) $consumable->company->id, 'name' => e($consumable->company->name)] : null,
|
||||
'item_no' => e($consumable->item_no),
|
||||
|
||||
@@ -62,7 +62,7 @@ class LicensesTransformer
|
||||
'checkin' => Gate::allows('checkin', License::class),
|
||||
'clone' => Gate::allows('create', License::class),
|
||||
'update' => Gate::allows('update', License::class),
|
||||
'delete' => (Gate::allows('delete', License::class) && ($license->free_seats_count == $license->seats)) ? true : false,
|
||||
'delete' => (Gate::allows('delete', License::class) && ($license->free_seats_count > 0)) ? true : false,
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
|
||||
@@ -32,11 +32,10 @@ class UploadedFilesTransformer
|
||||
'name' => e($file->filename),
|
||||
'item' => ($file->item_type) ? [
|
||||
'id' => (int) $file->item_id,
|
||||
'type' => str_plural(strtolower(class_basename($file->item_type))),
|
||||
'type' => strtolower(class_basename($file->item_type)),
|
||||
] : null,
|
||||
'filename' => e($file->filename),
|
||||
'filetype' => StorageHelper::getFiletype($file->uploads_file_path()),
|
||||
'mediatype' => StorageHelper::getMediaType($file->uploads_file_path()),
|
||||
'url' => $file->uploads_file_url(),
|
||||
'note' => ($file->note) ? e($file->note) : null,
|
||||
'created_by' => ($file->adminuser) ? [
|
||||
@@ -45,7 +44,7 @@ class UploadedFilesTransformer
|
||||
] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'),
|
||||
'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'),
|
||||
'inlineable' => StorageHelper::allowSafeInline($file->uploads_file_path()) ?? false,
|
||||
'inline' => StorageHelper::allowSafeInline($file->uploads_file_path()),
|
||||
'exists_on_disk' => (Storage::exists($file->uploads_file_path()) ? true : false),
|
||||
];
|
||||
|
||||
|
||||
@@ -22,12 +22,6 @@ class UsersTransformer
|
||||
public function transformUser(User $user)
|
||||
{
|
||||
|
||||
$role = '';
|
||||
if ($user->isSuperUser()) {
|
||||
$role = 'superadmin';
|
||||
} elseif ($user->isAdmin()) {
|
||||
$role = 'admin';
|
||||
}
|
||||
$array = [
|
||||
'id' => (int) $user->id,
|
||||
'avatar' => e($user->present()->gravatar) ?? null,
|
||||
@@ -45,7 +39,6 @@ class UsersTransformer
|
||||
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
|
||||
'vip' => ($user->vip == '1') ? true : false,
|
||||
'phone' => ($user->phone) ? e($user->phone) : null,
|
||||
'mobile' => ($user->mobile) ? e($user->mobile) : null,
|
||||
'website' => ($user->website) ? e($user->website) : null,
|
||||
'address' => ($user->address) ? e($user->address) : null,
|
||||
'city' => ($user->city) ? e($user->city) : null,
|
||||
@@ -66,7 +59,6 @@ class UsersTransformer
|
||||
'name'=> e($user->userloc->name),
|
||||
] : null,
|
||||
'notes'=> Helper::parseEscapedMarkedownInline($user->notes),
|
||||
'role' => $role,
|
||||
'permissions' => $user->decodePermissions(),
|
||||
'activated' => ($user->activated == '1') ? true : false,
|
||||
'autoassign_licenses' => ($user->autoassign_licenses == '1') ? true : false,
|
||||
|
||||
@@ -52,7 +52,6 @@ class UserImporter extends ItemImporter
|
||||
$this->item['email'] = trim($this->findCsvMatch($row, 'email'));
|
||||
$this->item['gravatar'] = trim($this->findCsvMatch($row, 'gravatar'));
|
||||
$this->item['phone'] = trim($this->findCsvMatch($row, 'phone_number'));
|
||||
$this->item['mobile'] = trim($this->findCsvMatch($row, 'mobile_number'));
|
||||
$this->item['website'] = trim($this->findCsvMatch($row, 'website'));
|
||||
$this->item['jobtitle'] = trim($this->findCsvMatch($row, 'jobtitle'));
|
||||
$this->item['address'] = trim($this->findCsvMatch($row, 'address'));
|
||||
|
||||
@@ -334,7 +334,6 @@ class Importer extends Component
|
||||
'manager_username' => trans('general.importer.manager_username'),
|
||||
'notes' => trans('general.notes'),
|
||||
'phone_number' => trans('admin/users/table.phone'),
|
||||
'mobile_number' => trans('admin/users/table.mobile'),
|
||||
'remote' => trans('admin/users/general.remote'),
|
||||
'start_date' => trans('general.start_date'),
|
||||
'state' => trans('general.state'),
|
||||
@@ -511,13 +510,6 @@ class Importer extends Component
|
||||
'telephone',
|
||||
'tel.',
|
||||
],
|
||||
'mobile_number' =>
|
||||
[
|
||||
'mobile',
|
||||
'mobile number',
|
||||
'cell',
|
||||
'cellphone',
|
||||
],
|
||||
|
||||
'serial' =>
|
||||
[
|
||||
|
||||
@@ -47,7 +47,7 @@ class CheckinAssetMail extends Mailable
|
||||
|
||||
return new Envelope(
|
||||
from: $from,
|
||||
subject: trans('mail.Asset_Checkin_Notification', ['tag' => $this->item->asset_tag]),
|
||||
subject: trans('mail.Asset_Checkin_Notification'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,25 +24,16 @@ class CheckoutAssetMail extends Mailable
|
||||
|
||||
/**
|
||||
* Create a new message instance.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct(Asset $asset, $checkedOutTo, User $checkedOutBy, $acceptance, $note, bool $firstTimeSending = true)
|
||||
{
|
||||
$this->item = $asset;
|
||||
$this->admin = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->target = $checkedOutTo;
|
||||
|
||||
// Location is a target option, but there are no emails currently associated with locations.
|
||||
if($this->target instanceof User){
|
||||
$this->target = $this->target->present()?->fullName();
|
||||
}
|
||||
else if($this->target instanceof Asset){
|
||||
$this->target = $this->target->assignedto?->present()?->fullName();
|
||||
}
|
||||
|
||||
$this->last_checkout = '';
|
||||
$this->expected_checkin = '';
|
||||
@@ -125,7 +116,7 @@ class CheckoutAssetMail extends Mailable
|
||||
private function getSubject(): string
|
||||
{
|
||||
if ($this->firstTimeSending) {
|
||||
return trans('mail.Asset_Checkout_Notification', ['tag' => $this->item->asset_tag]);
|
||||
return trans('mail.Asset_Checkout_Notification');
|
||||
}
|
||||
|
||||
return trans('mail.unaccepted_asset_reminder');
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
@@ -26,16 +25,9 @@ class CheckoutLicenseMail extends Mailable
|
||||
$this->item = $licenseSeat;
|
||||
$this->admin = $checkedOutBy;
|
||||
$this->note = $note;
|
||||
$this->target = $checkedOutTo;
|
||||
$this->acceptance = $acceptance;
|
||||
$this->settings = Setting::getSettings();
|
||||
$this->target = $checkedOutTo;
|
||||
|
||||
if($this->target instanceof User){
|
||||
$this->target = $this->target->present()?->fullName();
|
||||
}
|
||||
elseif($this->target instanceof Asset){
|
||||
$this->target = $this->target->assignedto?->present()?->fullName();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Presenters\Presentable;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Model for the Actionlog (the table that keeps a historical log of
|
||||
@@ -458,40 +457,38 @@ class Actionlog extends SnipeModel
|
||||
public function uploads_file_url()
|
||||
{
|
||||
|
||||
|
||||
|
||||
if (($this->action_type == 'accepted') || ($this->action_type == 'declined')) {
|
||||
return route('log.storedeula.download', ['filename' => $this->filename]);
|
||||
switch ($this->item_type) {
|
||||
case Accessory::class:
|
||||
return route('show.accessoryfile', [$this->item_id, $this->id]);
|
||||
case Asset::class:
|
||||
return route('show/assetfile', [$this->item_id, $this->id]);
|
||||
case AssetModel::class:
|
||||
return route('show/modelfile', [$this->item_id, $this->id]);
|
||||
case Consumable::class:
|
||||
return route('show/locationsfile', [$this->item_id, $this->id]);
|
||||
case Component::class:
|
||||
return route('show.componentfile', [$this->item_id, $this->id]);
|
||||
case License::class:
|
||||
return route('show.licensefile', [$this->item_id, $this->id]);
|
||||
case Location::class:
|
||||
return route('show/locationsfile', [$this->item_id, $this->id]);
|
||||
case User::class:
|
||||
return route('show/userfile', [$this->item_id, $this->id]);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
$object = Str::snake(str_plural(str_replace("App\Models\\", '', $this->item_type)));
|
||||
|
||||
if ($object == 'asset_models') {
|
||||
$object = 'models';
|
||||
}
|
||||
|
||||
return route('ui.files.show', [
|
||||
'object_type' => $object,
|
||||
'id' => $this->item_id,
|
||||
'file_id' => $this->id,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
public function uploads_file_path()
|
||||
{
|
||||
|
||||
if (($this->action_type == 'accepted') || ($this->action_type == 'declined')) {
|
||||
return 'private_uploads/eula-pdfs/'.$this->filename;
|
||||
}
|
||||
|
||||
switch ($this->item_type) {
|
||||
case Accessory::class:
|
||||
return 'private_uploads/accessories/'.$this->filename;
|
||||
case Asset::class:
|
||||
return 'private_uploads/assets/'.$this->filename;
|
||||
case AssetModel::class:
|
||||
return 'private_uploads/models/'.$this->filename;
|
||||
return 'private_uploads/assetmodels/'.$this->filename;
|
||||
case Consumable::class:
|
||||
return 'private_uploads/consumables/'.$this->filename;
|
||||
case Component::class:
|
||||
@@ -500,8 +497,6 @@ class Actionlog extends SnipeModel
|
||||
return 'private_uploads/licenses/'.$this->filename;
|
||||
case Location::class:
|
||||
return 'private_uploads/locations/'.$this->filename;
|
||||
case Maintenance::class:
|
||||
return 'private_uploads/maintenances/'.$this->filename;
|
||||
case User::class:
|
||||
return 'private_uploads/users/'.$this->filename;
|
||||
default:
|
||||
@@ -510,6 +505,11 @@ class Actionlog extends SnipeModel
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Manually sets $this->source for determineActionSource()
|
||||
public function setActionSource($source = null): void
|
||||
{
|
||||
|
||||
@@ -112,7 +112,7 @@ class Asset extends Depreciable
|
||||
'location_id' => ['nullable', 'exists:locations,id', 'fmcs_location'],
|
||||
'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'],
|
||||
'serial' => ['nullable', 'unique_undeleted:assets,serial'],
|
||||
'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:9999999999999'],
|
||||
'supplier_id' => ['nullable', 'exists:suppliers,id'],
|
||||
'asset_eol_date' => ['nullable', 'date'],
|
||||
@@ -206,17 +206,6 @@ class Asset extends Depreciable
|
||||
'model.manufacturer' => ['name'],
|
||||
];
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::forceDeleted(function (Asset $asset) {
|
||||
$asset->requests()->forceDelete();
|
||||
});
|
||||
|
||||
static::softDeleted(function (Asset $asset) {
|
||||
$asset->requests()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
// To properly set the expected checkin as Y-m-d
|
||||
public function setExpectedCheckinAttribute($value)
|
||||
{
|
||||
@@ -237,11 +226,7 @@ class Asset extends Depreciable
|
||||
|
||||
foreach ($this->model->fieldset->fields as $field) {
|
||||
|
||||
// this just casts booleans that may come through as strings to an actual boolean type
|
||||
// adding !$field->field_encrypted because when the encrypted value comes through it
|
||||
// screws things up for the encrypted validation rules (and the encrypted string
|
||||
// is not a valid boolean type)
|
||||
if ($field->format == 'BOOLEAN' && !$field->field_encrypted) {
|
||||
if ($field->format == 'BOOLEAN') {
|
||||
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
@@ -771,9 +756,9 @@ class Asset extends Depreciable
|
||||
* @since 1.0
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function maintenances()
|
||||
public function assetmaintenances()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Maintenance::class, 'asset_id')
|
||||
return $this->hasMany(\App\Models\AssetMaintenance::class, 'asset_id')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
@@ -4,34 +4,31 @@ namespace App\Models;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Traits\Searchable;
|
||||
use App\Presenters\Presentable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use App\Models\Traits\HasUploads;
|
||||
|
||||
/**
|
||||
* Model for Asset Maintenances.
|
||||
*
|
||||
* @version v1.0
|
||||
*/
|
||||
class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
class AssetMaintenance extends Model implements ICompanyableChild
|
||||
{
|
||||
use HasFactory;
|
||||
use HasUploads;
|
||||
use SoftDeletes;
|
||||
use CompanyableChildTrait;
|
||||
use ValidatingTrait;
|
||||
use Loggable, Presentable;
|
||||
|
||||
|
||||
|
||||
protected $table = 'maintenances';
|
||||
protected $table = 'asset_maintenances';
|
||||
protected $rules = [
|
||||
'asset_id' => 'required|integer',
|
||||
'supplier_id' => 'nullable|integer',
|
||||
'asset_maintenance_type' => 'required',
|
||||
'name' => 'required|max:100',
|
||||
'title' => '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',
|
||||
@@ -46,7 +43,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'title',
|
||||
'asset_id',
|
||||
'supplier_id',
|
||||
'asset_maintenance_type',
|
||||
@@ -67,7 +64,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
protected $searchableAttributes =
|
||||
[
|
||||
'name',
|
||||
'title',
|
||||
'notes',
|
||||
'asset_maintenance_type',
|
||||
'cost',
|
||||
@@ -103,14 +100,14 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
public static function getImprovementOptions()
|
||||
{
|
||||
return [
|
||||
trans('admin/maintenances/general.maintenance') => trans('admin/maintenances/general.maintenance'),
|
||||
trans('admin/maintenances/general.repair') => trans('admin/maintenances/general.repair'),
|
||||
trans('admin/maintenances/general.upgrade') => trans('admin/maintenances/general.upgrade'),
|
||||
trans('admin/maintenances/general.pat_test') => trans('admin/maintenances/general.pat_test'),
|
||||
trans('admin/maintenances/general.calibration') => trans('admin/maintenances/general.calibration'),
|
||||
trans('admin/maintenances/general.software_support') => trans('admin/maintenances/general.software_support'),
|
||||
trans('admin/maintenances/general.hardware_support') => trans('admin/maintenances/general.hardware_support'),
|
||||
trans('admin/maintenances/general.configuration_change') => trans('admin/maintenances/general.configuration_change'),
|
||||
trans('admin/asset_maintenances/general.maintenance') => trans('admin/asset_maintenances/general.maintenance'),
|
||||
trans('admin/asset_maintenances/general.repair') => trans('admin/asset_maintenances/general.repair'),
|
||||
trans('admin/asset_maintenances/general.upgrade') => trans('admin/asset_maintenances/general.upgrade'),
|
||||
trans('admin/asset_maintenances/general.pat_test') => trans('admin/asset_maintenances/general.pat_test'),
|
||||
trans('admin/asset_maintenances/general.calibration') => trans('admin/asset_maintenances/general.calibration'),
|
||||
trans('admin/asset_maintenances/general.software_support') => trans('admin/asset_maintenances/general.software_support'),
|
||||
trans('admin/asset_maintenances/general.hardware_support') => trans('admin/asset_maintenances/general.hardware_support'),
|
||||
trans('admin/asset_maintenances/general.configuration_change') => trans('admin/asset_maintenances/general.configuration_change'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -169,21 +166,6 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
return $this->belongsTo(\App\Models\Asset::class, 'asset_id')
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maintenance logs
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v8.2.2]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function assetlog()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
|
||||
->where('item_type', '=', self::class)
|
||||
->orderBy('created_at', 'desc')
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -205,11 +187,6 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
->withTrashed();
|
||||
}
|
||||
|
||||
public function getDisplayNameAttribute()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* -----------------------------------------------
|
||||
* BEGIN QUERY SCOPES
|
||||
@@ -226,7 +203,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderBySupplier($query, $order)
|
||||
{
|
||||
return $query->leftJoin('suppliers as suppliers_maintenances', 'maintenances.supplier_id', '=', 'suppliers_maintenances.id')
|
||||
return $query->leftJoin('suppliers as suppliers_maintenances', 'asset_maintenances.supplier_id', '=', 'suppliers_maintenances.id')
|
||||
->orderBy('suppliers_maintenances.name', $order);
|
||||
}
|
||||
|
||||
@@ -242,7 +219,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderByTag($query, $order)
|
||||
{
|
||||
return $query->leftJoin('assets', 'maintenances.asset_id', '=', 'assets.id')
|
||||
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
|
||||
->orderBy('assets.asset_tag', $order);
|
||||
}
|
||||
|
||||
@@ -256,7 +233,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderByAssetName($query, $order)
|
||||
{
|
||||
return $query->leftJoin('assets', 'maintenances.asset_id', '=', 'assets.id')
|
||||
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
|
||||
->orderBy('assets.name', $order);
|
||||
}
|
||||
|
||||
@@ -270,7 +247,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderByAssetSerial($query, $order)
|
||||
{
|
||||
return $query->leftJoin('assets', 'maintenances.asset_id', '=', 'assets.id')
|
||||
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
|
||||
->orderBy('assets.serial', $order);
|
||||
}
|
||||
|
||||
@@ -284,7 +261,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderStatusName($query, $order)
|
||||
{
|
||||
return $query->join('assets as maintained_asset', 'maintenances.asset_id', '=', 'maintained_asset.id')
|
||||
return $query->join('assets as maintained_asset', 'asset_maintenances.asset_id', '=', 'maintained_asset.id')
|
||||
->leftjoin('status_labels as maintained_asset_status', 'maintained_asset_status.id', '=', 'maintained_asset.status_id')
|
||||
->orderBy('maintained_asset_status.name', $order);
|
||||
}
|
||||
@@ -299,7 +276,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderLocationName($query, $order)
|
||||
{
|
||||
return $query->join('assets as maintained_asset', 'maintenances.asset_id', '=', 'maintained_asset.id')
|
||||
return $query->join('assets as maintained_asset', 'asset_maintenances.asset_id', '=', 'maintained_asset.id')
|
||||
->leftjoin('locations as maintained_asset_location', 'maintained_asset_location.id', '=', 'maintained_asset.location_id')
|
||||
->orderBy('maintained_asset_location.name', $order);
|
||||
}
|
||||
@@ -309,6 +286,6 @@ class Maintenance extends SnipeModel implements ICompanyableChild
|
||||
*/
|
||||
public function scopeOrderByCreatedBy($query, $order)
|
||||
{
|
||||
return $query->leftJoin('users as admin_sort', 'maintenances.created_by', '=', 'admin_sort.id')->select('maintenances.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
|
||||
return $query->leftJoin('users as admin_sort', 'asset_maintenances.created_by', '=', 'admin_sort.id')->select('asset_maintenances.*')->orderBy('admin_sort.first_name', $order)->orderBy('admin_sort.last_name', $order);
|
||||
}
|
||||
}
|
||||
@@ -98,16 +98,8 @@ class AssetModel extends SnipeModel
|
||||
'manufacturer' => ['name'],
|
||||
];
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::forceDeleted(function (AssetModel $assetModel) {
|
||||
$assetModel->requests()->forceDelete();
|
||||
});
|
||||
|
||||
static::softDeleted(function (AssetModel $assetModel) {
|
||||
$assetModel->requests()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the model -> assets relationship
|
||||
|
||||
@@ -2,13 +2,11 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class CheckoutRequest extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use SoftDeletes;
|
||||
protected $fillable = ['user_id'];
|
||||
protected $table = 'checkout_requests';
|
||||
|
||||
@@ -230,16 +230,11 @@ class Consumable extends SnipeModel
|
||||
*/
|
||||
public function getImageUrl()
|
||||
{
|
||||
// If there is a consumable image, use that
|
||||
if ($this->image) {
|
||||
return Storage::disk('public')->url(app('consumables_upload_path').$this->image);
|
||||
|
||||
// Otherwise check for a category image
|
||||
} elseif (($this->category) && ($this->category->image)) {
|
||||
return Storage::disk('public')->url(app('categories_upload_path').e($this->category->image));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,6 @@ class CustomField extends Model
|
||||
UniqueUndeletedTrait;
|
||||
|
||||
/**
|
||||
*
|
||||
* Custom field predfined formats
|
||||
*
|
||||
* @var array
|
||||
|
||||
@@ -3,19 +3,12 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Rules\AlphaEncrypted;
|
||||
use App\Rules\BooleanEncrypted;
|
||||
use App\Rules\DateEncrypted;
|
||||
use App\Rules\EmailEncrypted;
|
||||
use App\Rules\IPEncrypted;
|
||||
use App\Rules\IPv4Encrypted;
|
||||
use App\Rules\IPv6Encrypted;
|
||||
use App\Rules\MacEncrypted;
|
||||
use App\Rules\NumericEncrypted;
|
||||
use App\Rules\RegexEncrypted;
|
||||
use App\Rules\UrlEncrypted;
|
||||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
|
||||
class CustomFieldset extends Model
|
||||
@@ -106,7 +99,7 @@ class CustomFieldset extends Model
|
||||
* @since [v3.0]
|
||||
* @return array
|
||||
*/
|
||||
public function validation_rules(): array
|
||||
public function validation_rules()
|
||||
{
|
||||
$rules = [];
|
||||
foreach ($this->fields as $field) {
|
||||
@@ -128,65 +121,18 @@ class CustomFieldset extends Model
|
||||
|
||||
$rules[$field->db_column_name()] = $rule;
|
||||
|
||||
// this is to switch the rules to rules specially made for encrypted custom fields that decrypt the value before validating
|
||||
if ($field->field_encrypted) {
|
||||
$numericKey = array_search('numeric', $rules[$field->db_column_name()]);
|
||||
$alphaKey = array_search('alpha', $rules[$field->db_column_name()]);
|
||||
$emailKey = array_search('email', $rules[$field->db_column_name()]);
|
||||
$dateKey = array_search('date', $rules[$field->db_column_name()]);
|
||||
$urlKey = array_search('url', $rules[$field->db_column_name()]);
|
||||
$ipKey = array_search('ip', $rules[$field->db_column_name()]);
|
||||
$ipv4Key = array_search('ipv4', $rules[$field->db_column_name()]);
|
||||
$ipv6Key = array_search('ipv6', $rules[$field->db_column_name()]);
|
||||
$macKey = array_search('regex:/^[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}$/', $rules[$field->db_column_name()]);
|
||||
$booleanKey = array_search('boolean', $rules[$field->db_column_name()]);
|
||||
// find objects in array that start with "regex:"
|
||||
// collect because i couldn't figure how to do this
|
||||
// with array filter and get keys out of it
|
||||
$regexCollect = collect($rules[$field->db_column_name()]);
|
||||
$regexKeys = $regexCollect->filter(function ($value, $key) {
|
||||
return starts_with($value, 'regex:');
|
||||
})->keys()->values()->toArray();
|
||||
|
||||
switch ($field->format) {
|
||||
case 'NUMERIC':
|
||||
$rules[$field->db_column_name()][$numericKey] = new NumericEncrypted;
|
||||
break;
|
||||
case 'ALPHA':
|
||||
$rules[$field->db_column_name()][$alphaKey] = new AlphaEncrypted;
|
||||
break;
|
||||
case 'EMAIL':
|
||||
$rules[$field->db_column_name()][$emailKey] = new EmailEncrypted;
|
||||
break;
|
||||
case 'DATE':
|
||||
$rules[$field->db_column_name()][$dateKey] = new DateEncrypted;
|
||||
break;
|
||||
case 'URL':
|
||||
$rules[$field->db_column_name()][$urlKey] = new UrlEncrypted;
|
||||
break;
|
||||
case 'IP':
|
||||
$rules[$field->db_column_name()][$ipKey] = new IPEncrypted;
|
||||
break;
|
||||
case 'IPV4':
|
||||
$rules[$field->db_column_name()][$ipv4Key] = new IPv4Encrypted;
|
||||
break;
|
||||
case 'IPV6':
|
||||
$rules[$field->db_column_name()][$ipv6Key] = new IPv6Encrypted;
|
||||
break;
|
||||
case 'MAC':
|
||||
$rules[$field->db_column_name()][$macKey] = new MacEncrypted;
|
||||
break;
|
||||
case 'BOOLEAN':
|
||||
$rules[$field->db_column_name()][$booleanKey] = new BooleanEncrypted;
|
||||
break;
|
||||
case starts_with($field->format, 'regex'):
|
||||
foreach ($regexKeys as $regexKey) {
|
||||
$rules[$field->db_column_name()][$regexKey] = new RegexEncrypted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// these are to replace the standard 'numeric' and 'alpha' rules if the custom field is also encrypted.
|
||||
// the values need to be decrypted first, because encrypted strings are alphanumeric
|
||||
if ($field->format === 'NUMERIC' && $field->field_encrypted) {
|
||||
$numericKey = array_search('numeric', $rules[$field->db_column_name()]);
|
||||
$rules[$field->db_column_name()][$numericKey] = new NumericEncrypted;
|
||||
}
|
||||
|
||||
if ($field->format === 'ALPHA' && $field->field_encrypted) {
|
||||
$alphaKey = array_search('alpha', $rules[$field->db_column_name()]);
|
||||
$rules[$field->db_column_name()][$alphaKey] = new AlphaEncrypted;
|
||||
}
|
||||
|
||||
// add not_array to rules for all fields but checkboxes
|
||||
if ($field->element != 'checkbox') {
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Labels\Tapes\Dymo;
|
||||
|
||||
|
||||
class LabelWriter_11354 extends LabelWriter
|
||||
{
|
||||
private const BARCODE1D_HEIGHT = 3.00;
|
||||
private const BARCODE_MARGIN = 1.80;
|
||||
private const TAG_SIZE = 2.80;
|
||||
private const TITLE_SIZE = 2.80;
|
||||
private const TITLE_MARGIN = 0.50;
|
||||
private const FIELD_SIZE = 2.80;
|
||||
private const FIELD_MARGIN = 0.15;
|
||||
|
||||
public function getUnit()
|
||||
{
|
||||
return 'mm';
|
||||
}
|
||||
public function getWidth()
|
||||
{
|
||||
return 57;
|
||||
}
|
||||
public function getHeight()
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
public function getSupportAssetTag()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public function getSupport1DBarcode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public function getSupport2DBarcode()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public function getSupportFields()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
public function getSupportLogo()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public function getSupportTitle()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public function preparePDF($pdf)
|
||||
{
|
||||
}
|
||||
|
||||
public function write($pdf, $record)
|
||||
{
|
||||
$pa = $this->getPrintableArea();
|
||||
|
||||
$currentX = $pa->x1;
|
||||
$currentY = $pa->y1;
|
||||
$usableWidth = $pa->w;
|
||||
$usableHeight = $pa->h;
|
||||
|
||||
// Wide 1D barcode on top
|
||||
if ($record->has('barcode1d')) {
|
||||
static::write1DBarcode(
|
||||
$pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type,
|
||||
$currentX, $currentY, $usableWidth, self::BARCODE1D_HEIGHT
|
||||
);
|
||||
$currentY += self::BARCODE1D_HEIGHT + self::BARCODE_MARGIN;
|
||||
$usableHeight -= self::BARCODE1D_HEIGHT + self::BARCODE_MARGIN;
|
||||
}
|
||||
|
||||
// 2D Barcode in left column
|
||||
if ($record->has('barcode2d')) {
|
||||
$barcodeSize = $usableHeight - self::TAG_SIZE;
|
||||
|
||||
static::writeText(
|
||||
$pdf, $record->get('tag'),
|
||||
$currentX, $pa->y2 - self::TAG_SIZE,
|
||||
'freesans', 'b', self::TAG_SIZE, 'C',
|
||||
$barcodeSize, self::TAG_SIZE, true, 0
|
||||
);
|
||||
static::write2DBarcode(
|
||||
$pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type,
|
||||
$currentX, $currentY,
|
||||
$barcodeSize, $barcodeSize
|
||||
);
|
||||
$currentX += $barcodeSize + self::BARCODE_MARGIN;
|
||||
$usableWidth -= $barcodeSize + self::BARCODE_MARGIN;
|
||||
}
|
||||
|
||||
// Right column
|
||||
if ($record->has('title')) {
|
||||
static::writeText(
|
||||
$pdf, $record->get('title'),
|
||||
$currentX, $currentY,
|
||||
'freesans', 'b', self::TITLE_SIZE, 'L',
|
||||
$usableWidth, self::TITLE_SIZE, true, 0
|
||||
);
|
||||
$currentY += self::TITLE_SIZE + self::TITLE_MARGIN;
|
||||
}
|
||||
|
||||
foreach ($record->get('fields') as $field) {
|
||||
static::writeText(
|
||||
$pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'],
|
||||
$currentX, $currentY,
|
||||
'freesans', '', self::FIELD_SIZE, 'L',
|
||||
$usableWidth, self::FIELD_SIZE, true, 0, 0.3
|
||||
);
|
||||
$currentY += self::FIELD_SIZE + self::FIELD_MARGIN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ class SnipeModel extends Model
|
||||
*/
|
||||
public function setPurchaseCostAttribute($value)
|
||||
{
|
||||
if (is_numeric($value)) {
|
||||
if (is_float($value)) {
|
||||
//value is *already* a floating-point number. Just assign it directly
|
||||
$this->attributes['purchase_cost'] = $value;
|
||||
return;
|
||||
|
||||
@@ -153,21 +153,12 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
"primary" => AttributeMapping::constant(true)->ignoreWrite()
|
||||
]],
|
||||
|
||||
// Mobile and work phone numbers
|
||||
'phoneNumbers' => [
|
||||
[
|
||||
"value" => AttributeMapping::eloquent("phone"),
|
||||
"display" => null,
|
||||
"type" => AttributeMapping::constant("work")->ignoreWrite(),
|
||||
"primary" => AttributeMapping::constant(true)->ignoreWrite(),
|
||||
],
|
||||
[
|
||||
"value" => AttributeMapping::eloquent("mobile"),
|
||||
"display" => null,
|
||||
"type" => AttributeMapping::constant("mobile")->ignoreWrite(),
|
||||
"primary" => AttributeMapping::constant(false)->ignoreWrite()
|
||||
]
|
||||
],
|
||||
'phoneNumbers' => [[
|
||||
"value" => AttributeMapping::eloquent("phone"),
|
||||
"display" => null,
|
||||
"type" => AttributeMapping::constant("work")->ignoreWrite(),
|
||||
"primary" => AttributeMapping::constant(true)->ignoreWrite()
|
||||
]],
|
||||
|
||||
'ims' => [[
|
||||
"value" => null,
|
||||
|
||||
@@ -7,7 +7,7 @@ use App\Models\Traits\Searchable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use \Illuminate\Database\Eloquent\Relations\Relation;
|
||||
|
||||
class Supplier extends SnipeModel
|
||||
{
|
||||
use HasFactory;
|
||||
@@ -133,7 +133,7 @@ class Supplier extends SnipeModel
|
||||
* Establishes the supplier -> admin user relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @return Relation
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function adminuser()
|
||||
{
|
||||
@@ -147,9 +147,9 @@ class Supplier extends SnipeModel
|
||||
* @since [v1.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function maintenances(): Relation
|
||||
public function asset_maintenances()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Maintenance::class, 'supplier_id');
|
||||
return $this->hasMany(\App\Models\AssetMaintenance::class, 'supplier_id');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,7 +70,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
'manager_id',
|
||||
'password',
|
||||
'phone',
|
||||
'mobile',
|
||||
'notes',
|
||||
'state',
|
||||
'username',
|
||||
@@ -140,7 +139,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
'locale',
|
||||
'notes',
|
||||
'phone',
|
||||
'mobile',
|
||||
'state',
|
||||
'username',
|
||||
'website',
|
||||
@@ -185,17 +183,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
);
|
||||
}
|
||||
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::forceDeleted(function (User $user) {
|
||||
CheckoutRequest::where(['user_id' => $user->id])->forceDelete();
|
||||
});
|
||||
|
||||
static::softDeleted(function (User $user) {
|
||||
CheckoutRequest::where(['user_id' => $user->id])->delete();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public function isAvatarExternal()
|
||||
{
|
||||
@@ -411,9 +398,9 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
* @since [v4.0]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function maintenances()
|
||||
public function assetmaintenances()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Maintenance::class, 'user_id')->withTrashed();
|
||||
return $this->hasMany(\App\Models\AssetMaintenance::class, 'user_id')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -904,49 +891,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only admins and superusers
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
*/
|
||||
public function scopeOnlySuperAdmins($query)
|
||||
{
|
||||
|
||||
return $query->where('users.permissions', 'LIKE', '%"superuser":"1"%')
|
||||
->orWhere('users.permissions', 'LIKE', '%"superuser":1%')
|
||||
->orWhereHas(
|
||||
'groups', function ($query) {
|
||||
$query->where('permission_groups.permissions', 'LIKE', '%"superuser":"1"%')
|
||||
->orWhere('permission_groups.permissions', 'LIKE', '%"superuser":1%');
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return only admins and superusers
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
*/
|
||||
public function scopeOnlyAdminsAndSuperAdmins($query)
|
||||
{
|
||||
|
||||
return $query->where('users.permissions', 'LIKE', '%"superuser":"1"%')
|
||||
->orWhere('users.permissions', 'LIKE', '%"superuser":1%')
|
||||
->orWhere('users.permissions', 'LIKE', '%"admin":1%')
|
||||
->orWhere('users.permissions', 'LIKE', '%"admin":"1"%')
|
||||
->orWhereHas(
|
||||
'groups', function ($query) {
|
||||
$query->where('permission_groups.permissions', 'LIKE', '%"superuser":"1"%')
|
||||
->orWhere('permission_groups.permissions', 'LIKE', '%"superuser":1%')
|
||||
->orWhere('permission_groups.permissions', 'LIKE', '%"admin":1%')
|
||||
->orWhere('permission_groups.permissions', 'LIKE', '%"admin":"1"%');
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope to order on manager
|
||||
@@ -1020,6 +964,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the preferred locale for the user.
|
||||
*
|
||||
@@ -1058,6 +1003,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
public function scopeUserLocation($query, $location, $search)
|
||||
{
|
||||
|
||||
|
||||
return $query->where('location_id', '=', $location)
|
||||
->where('users.first_name', 'LIKE', '%' . $search . '%')
|
||||
->orWhere('users.email', 'LIKE', '%' . $search . '%')
|
||||
@@ -1070,6 +1016,9 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
->orWhere('users.username', 'LIKE', '%' . $search . '%')
|
||||
->orwhereRaw('CONCAT(users.first_name," ",users.last_name) LIKE \''.$search.'%\'');
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,6 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
||||
$this->assigned_to = $params['assigned_to'];
|
||||
$this->note = $params['note'];
|
||||
$this->company_name = $params['company_name'];
|
||||
$this->admin = $params['admin'] ?? null;
|
||||
$this->settings = Setting::getSettings();
|
||||
|
||||
}
|
||||
@@ -73,7 +72,6 @@ class AcceptanceAssetAcceptedNotification extends Notification
|
||||
'assigned_to' => $this->assigned_to,
|
||||
'company_name' => $this->company_name,
|
||||
'intro_text' => trans('mail.acceptance_asset_accepted'),
|
||||
'admin' => $this->admin,
|
||||
])
|
||||
->subject(trans('mail.acceptance_asset_accepted'));
|
||||
|
||||
|
||||
@@ -20,11 +20,7 @@ class ComponentObserver
|
||||
$logAction->item_type = Component::class;
|
||||
$logAction->item_id = $component->id;
|
||||
$logAction->created_at = date('Y-m-d H:i:s');
|
||||
$logAction->action_date = date('Y-m-d H:i:s');
|
||||
$logAction->created_by = auth()->id();
|
||||
if($component->imported) {
|
||||
$logAction->setActionSource('importer');
|
||||
}
|
||||
$logAction->logaction('update');
|
||||
}
|
||||
|
||||
@@ -41,7 +37,6 @@ class ComponentObserver
|
||||
$logAction->item_type = Component::class;
|
||||
$logAction->item_id = $component->id;
|
||||
$logAction->created_at = date('Y-m-d H:i:s');
|
||||
$logAction->action_date = date('Y-m-d H:i:s');
|
||||
$logAction->created_by = auth()->id();
|
||||
if($component->imported) {
|
||||
$logAction->setActionSource('importer');
|
||||
@@ -61,7 +56,6 @@ class ComponentObserver
|
||||
$logAction->item_type = Component::class;
|
||||
$logAction->item_id = $component->id;
|
||||
$logAction->created_at = date('Y-m-d H:i:s');
|
||||
$logAction->action_date = date('Y-m-d H:i:s');
|
||||
$logAction->created_by = auth()->id();
|
||||
$logAction->logaction('delete');
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\Asset;
|
||||
|
||||
class MaintenanceObserver
|
||||
{
|
||||
/**
|
||||
* Listen to the User created event.
|
||||
*
|
||||
* @param Maintenance $maintenance
|
||||
* @return void
|
||||
*/
|
||||
public function updated(Maintenance $maintenance)
|
||||
{
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Maintenance::class;
|
||||
$logAction->item_id = $maintenance->id;
|
||||
$logAction->target_type = Asset::class;
|
||||
$logAction->target_id = $maintenance->asset_id;
|
||||
$logAction->created_at = date('Y-m-d H:i:s');
|
||||
$logAction->action_date = date('Y-m-d H:i:s');
|
||||
$logAction->created_by = auth()->id();
|
||||
if($maintenance->imported) {
|
||||
$logAction->setActionSource('importer');
|
||||
}
|
||||
$logAction->logaction('update');
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to the Component created event when
|
||||
* a new component is created.
|
||||
*
|
||||
* @param Maintenance $maintenance
|
||||
* @return void
|
||||
*/
|
||||
public function created(Maintenance $maintenance)
|
||||
{
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Maintenance::class;
|
||||
$logAction->item_id = $maintenance->id;
|
||||
$logAction->target_type = Asset::class;
|
||||
$logAction->target_id = $maintenance->asset_id;
|
||||
$logAction->created_at = date('Y-m-d H:i:s');
|
||||
$logAction->action_date = date('Y-m-d H:i:s');
|
||||
$logAction->created_by = auth()->id();
|
||||
if($maintenance->imported) {
|
||||
$logAction->setActionSource('importer');
|
||||
}
|
||||
$logAction->logaction('create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to the Component deleting event.
|
||||
*
|
||||
* @param Maintenance $maintenance
|
||||
* @return void
|
||||
*/
|
||||
public function deleting(Maintenance $maintenance)
|
||||
{
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Maintenance::class;
|
||||
$logAction->item_id = $maintenance->id;
|
||||
$logAction->target_type = Asset::class;
|
||||
$logAction->target_id = $maintenance->asset_id;
|
||||
$logAction->created_at = date('Y-m-d H:i:s');
|
||||
$logAction->action_date = date('Y-m-d H:i:s');
|
||||
$logAction->created_by = auth()->id();
|
||||
$logAction->logaction('delete');
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Policies;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Models\Asset;
|
||||
|
||||
class AssetPolicy extends CheckoutablePermissionsPolicy
|
||||
{
|
||||
|
||||
@@ -85,7 +85,7 @@ abstract class SnipePermissionsPolicy
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can view the model.
|
||||
* Determine whether the user can view the accessory.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
@@ -101,7 +101,7 @@ abstract class SnipePermissionsPolicy
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can create model.
|
||||
* Determine whether the user can create accessories.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
@@ -112,7 +112,7 @@ abstract class SnipePermissionsPolicy
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
* Determine whether the user can update the accessory.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
@@ -124,7 +124,7 @@ abstract class SnipePermissionsPolicy
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the model.
|
||||
* Determine whether the user can update the accessory.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
@@ -135,7 +135,7 @@ abstract class SnipePermissionsPolicy
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the model.
|
||||
* Determine whether the user can delete the accessory.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
@@ -151,7 +151,7 @@ abstract class SnipePermissionsPolicy
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can manage the model.
|
||||
* Determine whether the user can manage the accessory.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace App\Presenters;
|
||||
/**
|
||||
* Class AssetModelPresenter
|
||||
*/
|
||||
class MaintenancesPresenter extends Presenter
|
||||
class AssetMaintenancesPresenter extends Presenter
|
||||
{
|
||||
/**
|
||||
* Json Column Layout for bootstrap table
|
||||
@@ -22,7 +22,7 @@ class MaintenancesPresenter extends Presenter
|
||||
'title' => trans('general.id'),
|
||||
'visible' => false,
|
||||
], [
|
||||
'field' => 'name',
|
||||
'field' => 'title',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
@@ -30,15 +30,6 @@ class MaintenancesPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'formatter' => 'maintenancesLinkFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'image',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.image'),
|
||||
'visible' => true,
|
||||
'formatter' => 'imageFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'company',
|
||||
'searchable' => true,
|
||||
@@ -51,7 +42,7 @@ class MaintenancesPresenter extends Presenter
|
||||
'field' => 'asset_name',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/table.asset_name'),
|
||||
'title' => trans('admin/asset_maintenances/table.asset_name'),
|
||||
'formatter' => 'assetNameLinkFormatter',
|
||||
], [
|
||||
'field' => 'asset_tag',
|
||||
@@ -98,35 +89,35 @@ class MaintenancesPresenter extends Presenter
|
||||
'field' => 'asset_maintenance_type',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/form.asset_maintenance_type'),
|
||||
'title' => trans('admin/asset_maintenances/form.asset_maintenance_type'),
|
||||
], [
|
||||
'field' => 'start_date',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/form.start_date'),
|
||||
'title' => trans('admin/asset_maintenances/form.start_date'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'completion_date',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/form.completion_date'),
|
||||
'title' => trans('admin/asset_maintenances/form.completion_date'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'notes',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/form.notes'),
|
||||
'title' => trans('admin/asset_maintenances/form.notes'),
|
||||
], [
|
||||
'field' => 'is_warranty',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/table.is_warranty'),
|
||||
'title' => trans('admin/asset_maintenances/table.is_warranty'),
|
||||
'formatter' => 'trueFalseFormatter'
|
||||
], [
|
||||
'field' => 'cost',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/maintenances/form.cost'),
|
||||
'title' => trans('admin/asset_maintenances/form.cost'),
|
||||
'class' => 'text-right',
|
||||
], [
|
||||
'field' => 'created_by',
|
||||
@@ -328,7 +328,7 @@ class AssetPresenter extends Presenter
|
||||
// name can break the listings page. - snipe
|
||||
foreach ($fields as $field) {
|
||||
$layout[] = [
|
||||
'field' => $field->db_column,
|
||||
'field' => 'custom_fields.'.$field->db_column,
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
|
||||
@@ -106,7 +106,7 @@ class HistoryPresenter extends Presenter
|
||||
'switchable' => true,
|
||||
'title' => trans('general.file_name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'fileNameFormatter',
|
||||
'formatter' => 'fileUploadNameFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'file_download',
|
||||
@@ -115,7 +115,7 @@ class HistoryPresenter extends Presenter
|
||||
'switchable' => true,
|
||||
'title' => trans('general.download'),
|
||||
'visible' => true,
|
||||
'formatter' => 'fileDownloadButtonsFormatter',
|
||||
'formatter' => 'fileUploadFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'note',
|
||||
|
||||
@@ -53,7 +53,6 @@ class LicensePresenter extends Presenter
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'title' => trans('admin/licenses/form.to_email'),
|
||||
'formatter' => 'emailFormatter',
|
||||
], [
|
||||
'field' => 'license_name',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -67,9 +67,7 @@ class LocationPresenter extends Presenter
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/locations/message.current_location'),
|
||||
'titleTooltip' => trans('admin/locations/message.current_location'),
|
||||
'visible' => true,
|
||||
'class' => 'css-house-laptop',
|
||||
], [
|
||||
'field' => 'rtd_assets_count',
|
||||
'searchable' => false,
|
||||
|
||||
@@ -18,7 +18,7 @@ class UploadedFilesPresenter extends Presenter
|
||||
$layout = [
|
||||
[
|
||||
'field' => 'id',
|
||||
'searchable' => true,
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.id'),
|
||||
@@ -30,7 +30,6 @@ class UploadedFilesPresenter extends Presenter
|
||||
'sortable' => false,
|
||||
'switchable' => false,
|
||||
'title' => trans('general.type'),
|
||||
'visible' => true,
|
||||
'formatter' => 'iconFormatter',
|
||||
],
|
||||
[
|
||||
@@ -39,17 +38,16 @@ class UploadedFilesPresenter extends Presenter
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.image'),
|
||||
'visible' => true,
|
||||
'formatter' => 'filePreviewFormatter',
|
||||
'formatter' => 'inlineImageFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'filename',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.file_name'),
|
||||
'visible' => true,
|
||||
'formatter' => 'fileNameFormatter',
|
||||
'formatter' => 'fileUploadNameFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'download',
|
||||
@@ -58,7 +56,7 @@ class UploadedFilesPresenter extends Presenter
|
||||
'switchable' => true,
|
||||
'title' => trans('general.download'),
|
||||
'visible' => true,
|
||||
'formatter' => 'fileDownloadButtonsFormatter',
|
||||
'formatter' => 'downloadOrOpenInNewWindowFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'note',
|
||||
@@ -70,10 +68,10 @@ class UploadedFilesPresenter extends Presenter
|
||||
],
|
||||
[
|
||||
'field' => 'created_by',
|
||||
'searchable' => true,
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'title' => trans('general.created_by'),
|
||||
'visible' => true,
|
||||
'visible' => false,
|
||||
'formatter' => 'usersLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
@@ -82,7 +80,7 @@ class UploadedFilesPresenter extends Presenter
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.created_at'),
|
||||
'visible' => true,
|
||||
'visible' => false,
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'available_actions',
|
||||
@@ -90,7 +88,6 @@ class UploadedFilesPresenter extends Presenter
|
||||
'sortable' => false,
|
||||
'switchable' => false,
|
||||
'title' => trans('table.actions'),
|
||||
'visible' => true,
|
||||
'formatter' => 'deleteUploadFormatter',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -124,15 +124,6 @@ class UserPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'formatter' => 'phoneFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'mobile',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/users/table.mobile'),
|
||||
'visible' => false,
|
||||
'formatter' => 'mobileFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'website',
|
||||
'searchable' => true,
|
||||
@@ -189,7 +180,7 @@ class UserPresenter extends Presenter
|
||||
'switchable' => false,
|
||||
'title' => trans('admin/users/table.username'),
|
||||
'visible' => true,
|
||||
'formatter' => 'usernameRoleLinkFormatter',
|
||||
'formatter' => 'usersLinkFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'employee_num',
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Models\Asset;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\User;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeSCIMConfig;
|
||||
@@ -18,7 +17,6 @@ use App\Observers\ComponentObserver;
|
||||
use App\Observers\ConsumableObserver;
|
||||
use App\Observers\LicenseObserver;
|
||||
use App\Observers\SettingObserver;
|
||||
use App\Observers\MaintenanceObserver;
|
||||
use Illuminate\Routing\UrlGenerator;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
@@ -69,7 +67,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
|
||||
Schema::defaultStringLength(191);
|
||||
Asset::observe(AssetObserver::class);
|
||||
Maintenance::observe(MaintenanceObserver::class);
|
||||
User::observe(UserObserver::class);
|
||||
Accessory::observe(AccessoryObserver::class);
|
||||
Component::observe(ComponentObserver::class);
|
||||
@@ -85,12 +82,6 @@ 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);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Maintenance;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
use App\Models\Company;
|
||||
@@ -413,14 +413,14 @@ class BreadcrumbsServiceProvider extends ServiceProvider
|
||||
->push(trans('general.create'), route('maintenances.create'))
|
||||
);
|
||||
|
||||
Breadcrumbs::for('maintenances.show', fn (Trail $trail, Maintenance $maintenance) =>
|
||||
Breadcrumbs::for('maintenances.show', fn (Trail $trail, AssetMaintenance $maintenance) =>
|
||||
$trail->parent('maintenances.index', route('maintenances.index'))
|
||||
->push($maintenance->name, route('maintenances.show', $maintenance))
|
||||
->push($maintenance->title, route('maintenances.show', $maintenance))
|
||||
);
|
||||
|
||||
Breadcrumbs::for('maintenances.edit', fn (Trail $trail, Maintenance $maintenance) =>
|
||||
Breadcrumbs::for('maintenances.edit', fn (Trail $trail, AssetMaintenance $maintenance) =>
|
||||
$trail->parent('maintenances.index', route('maintenances.index'))
|
||||
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $maintenance->name]), route('maintenances.edit', $maintenance))
|
||||
->push(trans('general.breadcrumb_button_actions.edit_item', ['name' => $maintenance->title]), route('maintenances.edit', $maintenance))
|
||||
);
|
||||
|
||||
|
||||
@@ -539,26 +539,6 @@ class BreadcrumbsServiceProvider extends ServiceProvider
|
||||
->push(trans('general.users'), route('users.index'))
|
||||
->push(trans('general.deleted_users'), route('users.index'))
|
||||
);
|
||||
} elseif ((request()->is('users*')) && (request()->admins=='true')) {
|
||||
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
|
||||
->push(trans('general.users'), route('users.index'))
|
||||
->push(trans('general.show_admins'), route('users.index'))
|
||||
);
|
||||
} elseif ((request()->is('users*')) && (request()->superadmins=='true')) {
|
||||
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
|
||||
->push(trans('general.users'), route('users.index'))
|
||||
->push(trans('general.show_superadmins'), route('users.index'))
|
||||
);
|
||||
} elseif ((request()->is('users*')) && (request()->activated=='0')) {
|
||||
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
|
||||
->push(trans('general.users'), route('users.index'))
|
||||
->push(trans('general.login_disabled'), route('users.index'))
|
||||
);
|
||||
} elseif ((request()->is('users*')) && (request()->activated=='1')) {
|
||||
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
|
||||
->push(trans('general.users'), route('users.index'))
|
||||
->push(trans('general.login_enabled'), route('users.index'))
|
||||
);
|
||||
} else {
|
||||
Breadcrumbs::for('users.index', fn(Trail $trail) => $trail->parent('home', route('home'))
|
||||
->push(trans('general.users'), route('users.index'))
|
||||
|
||||
@@ -31,7 +31,7 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
|
||||
|
||||
// Make sure the limit is actually set, is an integer and does not exceed system limits
|
||||
app()->singleton('api_limit_value', function () {
|
||||
\App::singleton('api_limit_value', function () {
|
||||
$limit = config('app.max_results');
|
||||
$int_limit = intval(request('limit'));
|
||||
|
||||
@@ -43,7 +43,7 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
});
|
||||
|
||||
// Make sure the offset is actually set and is an integer
|
||||
app()->singleton('api_offset_value', function () {
|
||||
\App::singleton('api_offset_value', function () {
|
||||
$offset = intval(request('offset'));
|
||||
return $offset;
|
||||
});
|
||||
@@ -57,121 +57,117 @@ class SettingsServiceProvider extends ServiceProvider
|
||||
// Model paths and URLs
|
||||
|
||||
|
||||
app()->singleton('eula_pdf_path', function () {
|
||||
\App::singleton('eula_pdf_path', function () {
|
||||
return 'eula_pdf_path/';
|
||||
});
|
||||
|
||||
app()->singleton('assets_upload_path', function () {
|
||||
\App::singleton('assets_upload_path', function () {
|
||||
return 'assets/';
|
||||
});
|
||||
|
||||
app()->singleton('maintenances_path', function () {
|
||||
return 'maintenances/';
|
||||
});
|
||||
|
||||
app()->singleton('audits_upload_path', function () {
|
||||
\App::singleton('audits_upload_path', function () {
|
||||
return 'audits/';
|
||||
});
|
||||
|
||||
app()->singleton('accessories_upload_path', function () {
|
||||
\App::singleton('accessories_upload_path', function () {
|
||||
return 'public/uploads/accessories/';
|
||||
});
|
||||
|
||||
app()->singleton('models_upload_path', function () {
|
||||
\App::singleton('models_upload_path', function () {
|
||||
return 'models/';
|
||||
});
|
||||
|
||||
app()->singleton('models_upload_url', function () {
|
||||
\App::singleton('models_upload_url', function () {
|
||||
return 'models/';
|
||||
});
|
||||
|
||||
// Categories
|
||||
app()->singleton('categories_upload_path', function () {
|
||||
\App::singleton('categories_upload_path', function () {
|
||||
return 'categories/';
|
||||
});
|
||||
|
||||
app()->singleton('categories_upload_url', function () {
|
||||
\App::singleton('categories_upload_url', function () {
|
||||
return 'categories/';
|
||||
});
|
||||
|
||||
// Locations
|
||||
app()->singleton('locations_upload_path', function () {
|
||||
\App::singleton('locations_upload_path', function () {
|
||||
return 'locations/';
|
||||
});
|
||||
|
||||
app()->singleton('locations_upload_url', function () {
|
||||
\App::singleton('locations_upload_url', function () {
|
||||
return 'locations/';
|
||||
});
|
||||
|
||||
// Users
|
||||
app()->singleton('users_upload_path', function () {
|
||||
\App::singleton('users_upload_path', function () {
|
||||
return 'avatars/';
|
||||
});
|
||||
|
||||
app()->singleton('users_upload_url', function () {
|
||||
\App::singleton('users_upload_url', function () {
|
||||
return 'users/';
|
||||
});
|
||||
|
||||
// Manufacturers
|
||||
app()->singleton('manufacturers_upload_path', function () {
|
||||
\App::singleton('manufacturers_upload_path', function () {
|
||||
return 'manufacturers/';
|
||||
});
|
||||
|
||||
app()->singleton('manufacturers_upload_url', function () {
|
||||
\App::singleton('manufacturers_upload_url', function () {
|
||||
return 'manufacturers/';
|
||||
});
|
||||
|
||||
// Suppliers
|
||||
app()->singleton('suppliers_upload_path', function () {
|
||||
\App::singleton('suppliers_upload_path', function () {
|
||||
return 'suppliers/';
|
||||
});
|
||||
|
||||
app()->singleton('suppliers_upload_url', function () {
|
||||
\App::singleton('suppliers_upload_url', function () {
|
||||
return 'suppliers/';
|
||||
});
|
||||
|
||||
// Departments
|
||||
app()->singleton('departments_upload_path', function () {
|
||||
\App::singleton('departments_upload_path', function () {
|
||||
return 'departments/';
|
||||
});
|
||||
|
||||
app()->singleton('departments_upload_url', function () {
|
||||
\App::singleton('departments_upload_url', function () {
|
||||
return 'departments/';
|
||||
});
|
||||
|
||||
// Company paths and URLs
|
||||
app()->singleton('companies_upload_path', function () {
|
||||
\App::singleton('companies_upload_path', function () {
|
||||
return 'companies/';
|
||||
});
|
||||
|
||||
app()->singleton('companies_upload_url', function () {
|
||||
\App::singleton('companies_upload_url', function () {
|
||||
return 'companies/';
|
||||
});
|
||||
|
||||
// Accessories paths and URLs
|
||||
app()->singleton('accessories_upload_path', function () {
|
||||
\App::singleton('accessories_upload_path', function () {
|
||||
return 'accessories/';
|
||||
});
|
||||
|
||||
app()->singleton('accessories_upload_url', function () {
|
||||
\App::singleton('accessories_upload_url', function () {
|
||||
return 'accessories/';
|
||||
});
|
||||
|
||||
// Consumables paths and URLs
|
||||
app()->singleton('consumables_upload_path', function () {
|
||||
\App::singleton('consumables_upload_path', function () {
|
||||
return 'consumables/';
|
||||
});
|
||||
|
||||
app()->singleton('consumables_upload_url', function () {
|
||||
\App::singleton('consumables_upload_url', function () {
|
||||
return 'consumables/';
|
||||
});
|
||||
|
||||
// Components paths and URLs
|
||||
app()->singleton('components_upload_path', function () {
|
||||
\App::singleton('components_upload_path', function () {
|
||||
return 'components/';
|
||||
});
|
||||
|
||||
app()->singleton('components_upload_url', function () {
|
||||
\App::singleton('components_upload_url', function () {
|
||||
return 'components/';
|
||||
});
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<?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;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,9 @@ namespace App\Rules;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class AlphaEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
@@ -20,7 +18,7 @@ class AlphaEncrypted implements ValidationRule
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateAlpha($attributeName, $decrypted, 'ascii') && !is_null($decrypted)) {
|
||||
if (!ctype_alpha($decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.alpha', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class BooleanEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
|
||||
if (!$this->validateBoolean($attributeName, $decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.ipv6', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class DateEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateDate($attributeName, $decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.date', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class EmailEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateEmail($attribute, $decrypted, []) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.email', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class IPEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateIp($attributeName, $decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.ip', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class IPv4Encrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateIpv4($attributeName, $decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.ipv4', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class IPv6Encrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateIpv6($attributeName, $decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.ipv6', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class MacEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateRegex($attributeName, $decrypted, ['/^[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}:[a-fA-F0-9]{2}$/']) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.mac_address', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,12 @@
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Egulias\EmailValidator\Validation\RFCValidation;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class NumericEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
@@ -20,10 +16,11 @@ class NumericEncrypted implements ValidationRule
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateNumeric($attributeName, $decrypted) && !is_null($decrypted)) {
|
||||
if (!is_numeric($decrypted) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.numeric', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class RegexEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string, ?string=): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
$field = CustomField::where('db_column', $attribute)->first();
|
||||
$regex = $field->format;
|
||||
$regex = str_replace('regex:', '', $regex);
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateRegex($attributeName, $decrypted, [$regex]) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.regex', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e->getMessage());
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Rules;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Validation\ValidationRule;
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
use Illuminate\Validation\Concerns\ValidatesAttributes;
|
||||
|
||||
class UrlEncrypted implements ValidationRule
|
||||
{
|
||||
use ValidatesAttributes;
|
||||
|
||||
/**
|
||||
* Run the validation rule.
|
||||
*
|
||||
* @param \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString $fail
|
||||
*/
|
||||
public function validate(string $attribute, mixed $value, Closure $fail): void
|
||||
{
|
||||
try {
|
||||
$attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute));
|
||||
$decrypted = Crypt::decrypt($value);
|
||||
if (!$this->validateUrl($attributeName, $decrypted, []) && !is_null($decrypted)) {
|
||||
$fail(trans('validation.url', ['attribute' => $attributeName]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
$fail(trans('general.something_went_wrong'));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@
|
||||
"doctrine/dbal": "^3.1",
|
||||
"doctrine/instantiator": "^1.3",
|
||||
"eduardokum/laravel-mail-auto-embed": "^2.0",
|
||||
"enshrined/svg-sanitize": "^0.22.0",
|
||||
"enshrined/svg-sanitize": "^0.16.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"fakerphp/faker": "^1.24",
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
@@ -84,7 +84,6 @@
|
||||
},
|
||||
"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",
|
||||
@@ -96,8 +95,7 @@
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"dont-discover": [
|
||||
"rollbar/rollbar-laravel",
|
||||
"laravel/telescope"
|
||||
"rollbar/rollbar-laravel"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
149
composer.lock
generated
149
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "41f2c8e1296de21aaf82d4b1bfbc1800",
|
||||
"content-hash": "75fb4f46ea0a488c2dd45d73eb2a9b9d",
|
||||
"packages": [
|
||||
{
|
||||
"name": "alek13/slack",
|
||||
@@ -1678,25 +1678,26 @@
|
||||
},
|
||||
{
|
||||
"name": "enshrined/svg-sanitize",
|
||||
"version": "0.22.0",
|
||||
"version": "0.16.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/darylldoyle/svg-sanitizer.git",
|
||||
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500"
|
||||
"reference": "239e257605e2141265b429e40987b2ee51bba4b4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500",
|
||||
"reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500",
|
||||
"url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/239e257605e2141265b429e40987b2ee51bba4b4",
|
||||
"reference": "239e257605e2141265b429e40987b2ee51bba4b4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"php": "^7.1 || ^8.0"
|
||||
"ezyang/htmlpurifier": "^4.16",
|
||||
"php": "^5.6 || ^7.0 || ^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.5 || ^8.5"
|
||||
"phpunit/phpunit": "^5.7 || ^6.5 || ^8.5"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -1717,9 +1718,9 @@
|
||||
"description": "An SVG sanitizer for PHP",
|
||||
"support": {
|
||||
"issues": "https://github.com/darylldoyle/svg-sanitizer/issues",
|
||||
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0"
|
||||
"source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.16.0"
|
||||
},
|
||||
"time": "2025-08-12T10:13:48+00:00"
|
||||
"time": "2023-03-20T10:51:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "erusev/parsedown",
|
||||
@@ -1771,6 +1772,67 @@
|
||||
},
|
||||
"time": "2019-12-30T22:54:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "ezyang/htmlpurifier",
|
||||
"version": "v4.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ezyang/htmlpurifier.git",
|
||||
"reference": "cb56001e54359df7ae76dc522d08845dc741621b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b",
|
||||
"reference": "cb56001e54359df7ae76dc522d08845dc741621b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"cerdic/css-tidy": "^1.7 || ^2.0",
|
||||
"simpletest/simpletest": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
"cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.",
|
||||
"ext-bcmath": "Used for unit conversion and imagecrash protection",
|
||||
"ext-iconv": "Converts text to and from non-UTF-8 encodings",
|
||||
"ext-tidy": "Used for pretty-printing HTML"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"library/HTMLPurifier.composer.php"
|
||||
],
|
||||
"psr-0": {
|
||||
"HTMLPurifier": "library/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/library/HTMLPurifier/Language/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-2.1-or-later"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Edward Z. Yang",
|
||||
"email": "admin@htmlpurifier.org",
|
||||
"homepage": "http://ezyang.com"
|
||||
}
|
||||
],
|
||||
"description": "Standards compliant HTML filter written in PHP",
|
||||
"homepage": "http://htmlpurifier.org/",
|
||||
"keywords": [
|
||||
"html"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/ezyang/htmlpurifier/issues",
|
||||
"source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0"
|
||||
},
|
||||
"time": "2024-11-01T03:51:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fakerphp/faker",
|
||||
"version": "v1.24.1",
|
||||
@@ -12883,75 +12945,6 @@
|
||||
],
|
||||
"time": "2025-06-10T22:06:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/telescope",
|
||||
"version": "v5.11.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/telescope.git",
|
||||
"reference": "62e1a21db3db3e7440e9ca02ffa3efce14d6b85e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/telescope/zipball/62e1a21db3db3e7440e9ca02ffa3efce14d6b85e",
|
||||
"reference": "62e1a21db3db3e7440e9ca02ffa3efce14d6b85e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"laravel/framework": "^8.37|^9.0|^10.0|^11.0|^12.0",
|
||||
"php": "^8.0",
|
||||
"symfony/console": "^5.3|^6.0|^7.0",
|
||||
"symfony/var-dumper": "^5.0|^6.0|^7.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-gd": "*",
|
||||
"guzzlehttp/guzzle": "^6.0|^7.0",
|
||||
"laravel/octane": "^1.4|^2.0|dev-develop",
|
||||
"orchestra/testbench": "^6.40|^7.37|^8.17|^9.0|^10.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.0|^10.5|^11.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Laravel\\Telescope\\TelescopeServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Telescope\\": "src/",
|
||||
"Laravel\\Telescope\\Database\\Factories\\": "database/factories/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
},
|
||||
{
|
||||
"name": "Mohamed Said",
|
||||
"email": "mohamed@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "An elegant debug assistant for the Laravel framework.",
|
||||
"keywords": [
|
||||
"debugging",
|
||||
"laravel",
|
||||
"monitoring"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/telescope/issues",
|
||||
"source": "https://github.com/laravel/telescope/tree/v5.11.2"
|
||||
},
|
||||
"time": "2025-08-16T00:52:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/container",
|
||||
"version": "5.1.0",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user