Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
141b0b410b | ||
|
|
d40f06373e | ||
|
|
56753fa4cd | ||
|
|
8a7bafb575 | ||
|
|
82f91cb944 | ||
|
|
41b226e5fc | ||
|
|
ae6048a6ea | ||
|
|
ef41e0060a | ||
|
|
a0f3fc6d76 | ||
|
|
74e647fea7 | ||
|
|
55ee90b25d | ||
|
|
eec445fcf5 | ||
|
|
cef22c3158 | ||
|
|
61fb38087e | ||
|
|
0e93495ca2 | ||
|
|
444e250609 | ||
|
|
77a6f6f400 | ||
|
|
15bfd07f30 | ||
|
|
fecf8015a1 | ||
|
|
79ab0d8dc2 | ||
|
|
b4b6d6b571 | ||
|
|
8c73a47afb | ||
|
|
f82ffe378c | ||
|
|
984c2a8fd4 | ||
|
|
6736b1c4e7 | ||
|
|
d409be6d43 | ||
|
|
e1b33f3087 | ||
|
|
740d5a6846 | ||
|
|
d19df4ded8 | ||
|
|
03a4512406 | ||
|
|
de992e4df3 | ||
|
|
a85251aa83 | ||
|
|
26a1181765 | ||
|
|
cef030cf55 | ||
|
|
2bfa05fd2d | ||
|
|
30904dd019 | ||
|
|
1d0d25db37 | ||
|
|
cbff66c9db | ||
|
|
27231d49ea |
@@ -66,6 +66,7 @@ SECURE_COOKIES=false
|
||||
# --------------------------------------------
|
||||
REFERRER_POLICY=same-origin
|
||||
ENABLE_CSP=false
|
||||
CORS_ALLOWED_ORIGINS=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: CACHE SETTINGS
|
||||
|
||||
@@ -48,60 +48,90 @@ class ImportLocations extends Command
|
||||
$filename = $this->argument('filename');
|
||||
$csv = Reader::createFromPath(storage_path('private_uploads/imports/').$filename, 'r');
|
||||
$this->info('Attempting to process: '.storage_path('private_uploads/imports/').$filename);
|
||||
$csv->setOffset(1); //because we don't want to insert the header
|
||||
$csv->setHeaderOffset(0); //because we don't want to insert the header
|
||||
$results = $csv->getRecords();
|
||||
|
||||
// Import parent location names first if they don't exist
|
||||
foreach ($results as $parent_index => $parent_row) {
|
||||
|
||||
$parent_name = trim($parent_row['Parent Name']);
|
||||
// First create any parents if they don't exist
|
||||
|
||||
if ($parent_name!='') {
|
||||
if (array_key_exists('Parent Name', $parent_row)) {
|
||||
$parent_name = trim($parent_row['Parent Name']);
|
||||
if (array_key_exists('Name', $parent_row)) {
|
||||
$this->info('- Parent: ' . $parent_name . ' in row as: ' . trim($parent_row['Parent Name']));
|
||||
}
|
||||
|
||||
// Save parent location name
|
||||
// This creates a sort of name-stub that we'll update later on in this script
|
||||
$parent_location = Location::firstOrCreate(array('name' => $parent_name));
|
||||
$this->info('Parent for '.$parent_row['Name'].' is '.$parent_name.'. Attempting to save '.$parent_name.'.');
|
||||
if (array_key_exists('Name', $parent_row)) {
|
||||
$this->info('Parent for ' . $parent_row['Name'] . ' is ' . $parent_name . '. Attempting to save ' . $parent_name . '.');
|
||||
}
|
||||
|
||||
// Check if the record was updated or created.
|
||||
// This is mostly for clearer debugging.
|
||||
if ($parent_location->exists) {
|
||||
$this->info('- Parent location '.$parent_name.' already exists.');
|
||||
$this->info('- Parent location '.$parent_name.' already exists.');
|
||||
} else {
|
||||
$this->info('- Parent location '.$parent_name.' was created.');
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->info('- No parent location for '.$parent_row['Name'].' provided.');
|
||||
$this->info('- No Parent Name provided, so no parent location will be created.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$this->info('----- Parents Created.... backfilling additional details... --------');
|
||||
// Loop through ALL records and add/update them if there are additional fields
|
||||
// besides name
|
||||
foreach ($results as $index => $row) {
|
||||
|
||||
if (array_key_exists('Parent Name', $row)) {
|
||||
$parent_name = trim($row['Parent Name']);
|
||||
}
|
||||
|
||||
// Set the location attributes to save
|
||||
$location = Location::firstOrNew(array('name' => trim($row['Name'])));
|
||||
$location->name = trim($row['Name']);
|
||||
$location->currency = trim($row['Currency']);
|
||||
$location->address = trim($row['Address 1']);
|
||||
$location->address2 = trim($row['Address 2']);
|
||||
$location->city = trim($row['City']);
|
||||
$location->state = trim($row['State']);
|
||||
$location->zip = trim($row['Zip']);
|
||||
$location->country = trim($row['Country']);
|
||||
$location->ldap_ou = trim($row['OU']);
|
||||
if (array_key_exists('Name', $row)) {
|
||||
$location = Location::firstOrNew(array('name' => trim($row['Name'])));
|
||||
$location->name = trim($row['Name']);
|
||||
$this->info('Checking location: '.$location->name);
|
||||
} else {
|
||||
$this->error('Location name is required and is missing from at least one row in this dataset. Check your CSV for extra trailing rows and try again.');
|
||||
return false;
|
||||
}
|
||||
if (array_key_exists('Currency', $row)) {
|
||||
$location->currency = trim($row['Currency']);
|
||||
}
|
||||
if (array_key_exists('Address 1', $row)) {
|
||||
$location->address = trim($row['Address 1']);
|
||||
}
|
||||
if (array_key_exists('Address 2', $row)) {
|
||||
$location->address2 = trim($row['Address 2']);
|
||||
}
|
||||
if (array_key_exists('City', $row)) {
|
||||
$location->city = trim($row['City']);
|
||||
}
|
||||
if (array_key_exists('State', $row)) {
|
||||
$location->state = trim($row['State']);
|
||||
}
|
||||
if (array_key_exists('Zip', $row)) {
|
||||
$location->zip = trim($row['Zip']);
|
||||
}
|
||||
if (array_key_exists('Country', $row)) {
|
||||
$location->country = trim($row['Country']);
|
||||
}
|
||||
if (array_key_exists('Country', $row)) {
|
||||
$location->ldap_ou = trim($row['OU']);
|
||||
}
|
||||
|
||||
$this->info('Checking location: '.$location->name);
|
||||
|
||||
// If a parent name nis provided, we created it earlier in the script,
|
||||
// If a parent name is provided, we created it earlier in the script,
|
||||
// so let's grab that ID
|
||||
if ($parent_name) {
|
||||
$this->info('-- Searching for Parent Name: '.$parent_name);
|
||||
$parent = Location::where('name', '=', $parent_name)->first();
|
||||
$location->parent_id = $parent->id;
|
||||
$this->info('Parent ID: '.$parent->id);
|
||||
$this->info('Parent: '.$parent_name.' - ID: '.$parent->id);
|
||||
}
|
||||
|
||||
// Make sure the more advanced (non-name) fields pass validation
|
||||
|
||||
@@ -33,7 +33,7 @@ class Purge extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Purge all soft-deleted deleted records in the database. This will rewrite history for items that have been edited, or checked in or out. It will also reqrite history for users associated with deleted items.';
|
||||
protected $description = 'Purge all soft-deleted deleted records in the database. This will rewrite history for items that have been edited, or checked in or out. It will also rewrite history for users associated with deleted items.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
|
||||
126
app/Console/Commands/ReEncodeCustomFieldNames.php
Normal file
126
app/Console/Commands/ReEncodeCustomFieldNames.php
Normal file
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class ReEncodeCustomFieldNames extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:regenerate-fieldnames';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This utility will regenerate the column names for custom fields. It should typically only be needed when a PHP upgrade changed the behavior of the unicode conversion between versions.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* All three of these things must match for the custom fields system to work as expected:
|
||||
*
|
||||
* - what the system thinks the output of $field->convertUnicodeDbSlug() is
|
||||
* - the actual db_column name in the customfields table
|
||||
* - the physical column name that was created on the assets table
|
||||
*
|
||||
* For some people who upgraded their version of PHP, the unicode converter now behaves
|
||||
* differently in than it did when their custom fields were first created, specifically as it
|
||||
* relates to handling slashes, ampersands, etc. This can result in the field names no longer
|
||||
* matching up, as an older version of the PHP extension simply dropped slashes, etc, while the
|
||||
* newer version of the PHP extension will convert them to underscores.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
if ($this->confirm('This will regenerate all of the custom field database fieldnames in your database. THIS WILL CHANGE YOUR SCHEMA AND SHOULD NOT BE DONE WITHOUT MAKING A BACKUP FIRST. Do you wish to continue?'))
|
||||
{
|
||||
|
||||
/** Get all of the custom fields */
|
||||
$fields = CustomField::get();
|
||||
|
||||
$asset_columns = \DB::getSchemaBuilder()->getColumnListing('assets');
|
||||
$custom_field_columns = array();
|
||||
|
||||
/** Loop through the columns on the assets table */
|
||||
foreach ($asset_columns as $asset_column) {
|
||||
|
||||
/** Add ones that start with _snipeit_ to an array for handling */
|
||||
if (strpos($asset_column, '_snipeit_') === 0) {
|
||||
|
||||
/**
|
||||
* Get the ID of the custom field based on the fieldname.
|
||||
* For example, in _snipeit_mac_address_1, we grab the 1 because we know
|
||||
* that's the ID of the custom field that created the column.
|
||||
* Then use that ID as the array key for use comparing the actual assets field name
|
||||
* and the db_column value from the custom fields table.
|
||||
*/
|
||||
$last_part = substr(strrchr($asset_column, "_snipeit_"), 1);
|
||||
$custom_field_columns[$last_part] = $asset_column;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($fields as $field) {
|
||||
|
||||
$this->info($field->name .' ('.$field->id.') column should be '. $field->convertUnicodeDbSlug().'');
|
||||
|
||||
/** The assets table has the column it should have, all is well */
|
||||
if (\Schema::hasColumn('assets', $field->convertUnicodeDbSlug()))
|
||||
{
|
||||
$this->info('-- ✓ This field exists - all good');
|
||||
|
||||
/**
|
||||
* There is a mismatch between the fieldname on the assets table and
|
||||
* what $field->convertUnicodeDbSlug() is *now* expecting.
|
||||
*/
|
||||
} else {
|
||||
$this->warn('-- X Field mismatch: updating... ');
|
||||
|
||||
/** Make sure the custom_field_columns array has the ID */
|
||||
if (array_key_exists($field->id, $custom_field_columns)) {
|
||||
|
||||
/**
|
||||
* Update the asset schema to the corrected fieldname that will be recognized by the
|
||||
* system elsewhere that we use $field->convertUnicodeDbSlug()
|
||||
*/
|
||||
\Schema::table('assets', function($table) use ($custom_field_columns, $field) {
|
||||
$table->renameColumn($custom_field_columns[$field->id], $field->convertUnicodeDbSlug());
|
||||
});
|
||||
|
||||
$this->warn('-- ✓ Field updated from '.$custom_field_columns[$field->id].' to '.$field->convertUnicodeDbSlug());
|
||||
|
||||
} else {
|
||||
$this->warn('-- X WARNING: There is no field on the assets table ending in '.$field->id.'. This may require more in-depth investigation and may mean the schema was altered manually.');
|
||||
}
|
||||
}
|
||||
|
||||
/** Update the db_column property in the custom fields table, just in case it doesn't match the other
|
||||
* things.
|
||||
*/
|
||||
$field->db_column = $field->convertUnicodeDbSlug();
|
||||
$field->save();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console;
|
||||
|
||||
use App\Console\Commands\ImportLocations;
|
||||
use App\Console\Commands\RestoreDeletedUsers;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
@@ -34,6 +35,7 @@ class Kernel extends ConsoleKernel
|
||||
Commands\RestoreDeletedUsers::class,
|
||||
Commands\SendUpcomingAuditReport::class,
|
||||
Commands\ImportLocations::class,
|
||||
Commands\ReEncodeCustomFieldNames::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,10 +67,6 @@ class Handler extends ExceptionHandler
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $className . ' not found'), 200);
|
||||
}
|
||||
|
||||
if ($e instanceof \Illuminate\Validation\ValidationException) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $e->response['messages'], 400));
|
||||
}
|
||||
|
||||
if ($this->isHttpException($e)) {
|
||||
|
||||
$statusCode = $e->getStatusCode();
|
||||
@@ -85,11 +81,6 @@ class Handler extends ExceptionHandler
|
||||
|
||||
}
|
||||
}
|
||||
// Try to parse 500 Errors in a bit nicer way when debug is enabled.
|
||||
if (config('app.debug')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, "An Error has occured! " . $e->getMessage()), 500);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +119,6 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
protected function invalidJson($request, ValidationException $exception)
|
||||
{
|
||||
return response()->json($exception->errors(), $exception->status);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $exception->errors(), 400));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ class ConsumablesController extends Controller
|
||||
{
|
||||
$consumable = Consumable::with(array('consumableAssignments'=>
|
||||
function ($query) {
|
||||
$query->orderBy('created_at', 'DESC');
|
||||
$query->orderBy($query->getModel()->getTable().'.created_at', 'DESC');
|
||||
},
|
||||
'consumableAssignments.admin'=> function ($query) {
|
||||
},
|
||||
|
||||
@@ -38,7 +38,7 @@ class SettingsController extends Controller
|
||||
//return response()->json(['message' => $e->getMessage()], 500);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Connection failed');
|
||||
\Log::debug('Connection failed but we cannot debug it any further on our end.');
|
||||
return response()->json(['message' => $e->getMessage()], 600);
|
||||
}
|
||||
|
||||
|
||||
@@ -260,12 +260,21 @@ class UsersController extends Controller
|
||||
|
||||
if ($user->save()) {
|
||||
|
||||
// Sync group memberships:
|
||||
// This was changed in Snipe-IT v4.6.x to 4.7, since we upgraded to Laravel 5.5
|
||||
// which changes the behavior of has vs filled.
|
||||
// The $request->has method will now return true even if the input value is an empty string or null.
|
||||
// A new $request->filled method has was added that provides the previous behavior of the has method.
|
||||
|
||||
// Check if the request has groups passed and has a value
|
||||
if ($request->filled('groups')) {
|
||||
$user->groups()->sync($request->input('groups'));
|
||||
} else {
|
||||
// The groups field has been passed but it is null, so we should blank it out
|
||||
} elseif ($request->has('groups')) {
|
||||
$user->groups()->sync(array());
|
||||
}
|
||||
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new UsersTransformer)->transformUser($user), trans('admin/users/message.success.update')));
|
||||
}
|
||||
|
||||
@@ -287,10 +296,23 @@ class UsersController extends Controller
|
||||
$this->authorize('delete', $user);
|
||||
|
||||
|
||||
if ($user->assets()->count() > 0) {
|
||||
if (($user->assets) && ($user->assets->count() > 0)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete_has_assets')));
|
||||
}
|
||||
|
||||
if (($user->licenses) && ($user->licenses->count() > 0)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->licenses->count() . ' license(s) associated with them and cannot be deleted.'));
|
||||
}
|
||||
|
||||
if (($user->accessories) && ($user->accessories->count() > 0)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->accessories->count() . ' accessories associated with them.'));
|
||||
}
|
||||
|
||||
if (($user->managedLocations()) && ($user->managedLocations()->count() > 0)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'This user still has ' . $user->managedLocations()->count() . ' locations that they manage.'));
|
||||
}
|
||||
|
||||
|
||||
if ($user->delete()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/users/message.success.delete')));
|
||||
}
|
||||
|
||||
@@ -865,7 +865,7 @@ class SettingsController extends Controller
|
||||
$setting->ldap_server = $request->input('ldap_server');
|
||||
$setting->ldap_server_cert_ignore = $request->input('ldap_server_cert_ignore', false);
|
||||
$setting->ldap_uname = $request->input('ldap_uname');
|
||||
if (Input::has('ldap_pword')) {
|
||||
if (Input::filled('ldap_pword')) {
|
||||
$setting->ldap_pword = Crypt::encrypt($request->input('ldap_pword'));
|
||||
}
|
||||
$setting->ldap_basedn = $request->input('ldap_basedn');
|
||||
|
||||
@@ -340,25 +340,25 @@ class UsersController extends Controller
|
||||
// Check if we are not trying to delete ourselves
|
||||
if ($user->id === Auth::user()->id) {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->assets()->count() . ' assets associated with them.');
|
||||
return redirect()->route('users.index')->with('error', 'You cannot delete yourself.');
|
||||
}
|
||||
|
||||
if ($user->assets->count() > 0) {
|
||||
if (($user->assets) && ($user->assets->count() > 0)) {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . count($user->assets->count()) . ' assets associated with them.');
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->assets->count() . ' assets associated with them. Use the Checkin and Delete button on the user profile to check these items back in and delete this user.');
|
||||
}
|
||||
|
||||
if ($user->licenses()->count() > 0) {
|
||||
if (($user->licenses) && ($user->licenses->count() > 0)) {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->assets()->count() . ' assets associated with them.');
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->licenses->count() . ' license(s associated with them. Use the Checkin and Delete button on the user profile to check these items back in and delete this user.');
|
||||
}
|
||||
|
||||
if ($user->accessories()->count() > 0) {
|
||||
if (($user->accessories) && ($user->accessories->count() > 0)) {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->accessories()->count() . ' accessories associated with them.');
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->accessories->count() . ' accessories associated with them. Use the Checkin and Delete button on the user profile to check these items back in and delete this user.');
|
||||
}
|
||||
|
||||
if ($user->managedLocations()->count() > 0) {
|
||||
if (($user->managedLocations()) && ($user->managedLocations()->count() > 0)) {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->managedLocations()->count() . ' locations that they manage.');
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ class Kernel extends HttpKernel
|
||||
],
|
||||
|
||||
'api' => [
|
||||
\Barryvdh\Cors\HandleCors::class,
|
||||
'throttle:120,1',
|
||||
'auth:api',
|
||||
],
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace App\Http\Requests;
|
||||
|
||||
use App\Models\AssetModel;
|
||||
use Session;
|
||||
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
|
||||
@@ -32,7 +32,7 @@ class AssetRequest extends Request
|
||||
'model_id' => 'required|integer|exists:models,id',
|
||||
'status_id' => 'required|integer|exists:status_labels,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'warranty_months' => 'numeric|nullable',
|
||||
'warranty_months' => 'numeric|nullable|digits_between:0,240',
|
||||
'physical' => 'integer|nullable',
|
||||
'checkout_date' => 'date',
|
||||
'checkin_date' => 'date',
|
||||
@@ -48,7 +48,7 @@ class AssetRequest extends Request
|
||||
|
||||
$rules['asset_tag'] = ($settings->auto_increment_assets == '1') ? 'max:255' : 'required';
|
||||
|
||||
if($this->request->get('model_id') != '') {
|
||||
if ($this->request->get('model_id') != '') {
|
||||
$model = AssetModel::find($this->request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
@@ -60,13 +60,6 @@ class AssetRequest extends Request
|
||||
|
||||
}
|
||||
|
||||
public function response(array $errors)
|
||||
{
|
||||
$this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag)
|
||||
->put('default', new \Illuminate\Support\MessageBag($errors)));
|
||||
\Input::flash();
|
||||
return parent::response($errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a failed validation attempt.
|
||||
@@ -76,13 +69,17 @@ class AssetRequest extends Request
|
||||
* @param \Illuminate\Contracts\Validation\Validator $validator
|
||||
* @return void
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
* @throws \Illuminate\Http\Exceptions\HttpResponseException
|
||||
*/
|
||||
protected function failedValidation(Validator $validator)
|
||||
{
|
||||
return response()->json([
|
||||
'message' => 'The given data is invalid',
|
||||
'errors' => $validator->errors()
|
||||
], 422);
|
||||
$this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag)
|
||||
->put('default', new \Illuminate\Support\MessageBag($validator->errors()->toArray())));
|
||||
\Input::flash();
|
||||
throw new HttpResponseException(response()->json([
|
||||
'status' => 'error',
|
||||
'messages' => $validator->errors(),
|
||||
'payload' => null
|
||||
], 422));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\Exceptions\HttpResponseException;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
|
||||
class SaveUserRequest extends Request
|
||||
class SaveUserRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
@@ -62,4 +64,5 @@ class SaveUserRequest extends Request
|
||||
return $rules;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ class Asset extends Depreciable
|
||||
'model_id' => 'required|integer|exists:models,id',
|
||||
'status_id' => 'required|integer|exists:status_labels,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'warranty_months' => 'numeric|nullable',
|
||||
'warranty_months' => 'numeric|nullable|digits_between:0,240',
|
||||
'physical' => 'numeric|max:1|nullable',
|
||||
'checkout_date' => 'date|max:10|min:10|nullable',
|
||||
'checkin_date' => 'date|max:10|min:10|nullable',
|
||||
@@ -866,8 +866,10 @@ class Asset extends Depreciable
|
||||
|
||||
public function scopeDueOrOverdueForAudit($query, $settings)
|
||||
{
|
||||
$interval = $settings->audit_warning_days ?? 0;
|
||||
|
||||
return $query->whereNotNull('assets.next_audit_date')
|
||||
->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'")
|
||||
->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $interval DAY) <= '".Carbon::now()."'")
|
||||
->where('assets.archived', '=', 0)
|
||||
->NotArchived();
|
||||
}
|
||||
|
||||
@@ -80,7 +80,13 @@ final class Company extends SnipeModel
|
||||
}
|
||||
|
||||
$table = ($table_name) ? DB::getTablePrefix().$table_name."." : '';
|
||||
return $query->where($table.$column, '=', $company_id);
|
||||
|
||||
if(\Schema::hasColumn($query->getModel()->getTable(), $column)){
|
||||
return $query->where($table.$column, '=', $company_id);
|
||||
} else {
|
||||
return $query->join('users as users_comp', 'users_comp.id', 'user_id')->where('users_comp.company_id', '=', $company_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function getIdFromInput($unescaped_input)
|
||||
|
||||
@@ -7,10 +7,10 @@ use Watson\Validating\ValidatingTrait;
|
||||
|
||||
class Group extends SnipeModel
|
||||
{
|
||||
protected $table = 'groups';
|
||||
protected $table = 'permission_groups';
|
||||
|
||||
public $rules = array(
|
||||
'name' => 'required|min:3|max:255',
|
||||
'name' => 'required|min:2|max:255',
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -491,7 +491,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
|
||||
|
||||
public function scopeByGroup($query, $id) {
|
||||
return $query->whereHas('groups', function ($query) use ($id) {
|
||||
$query->where('groups.id', '=', $id);
|
||||
$query->where('permission_groups.id', '=', $id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"type": "project",
|
||||
"require": {
|
||||
"php": ">=7.1.2",
|
||||
"barryvdh/laravel-cors": "^0.11.3",
|
||||
"barryvdh/laravel-debugbar": "^3.2",
|
||||
"doctrine/cache": "^1.8",
|
||||
"doctrine/common": "^2.10",
|
||||
@@ -31,7 +32,7 @@
|
||||
"pragmarx/google2fa": "^5.0",
|
||||
"pragmarx/google2fa-laravel": "^1.0",
|
||||
"predis/predis": "^1.1",
|
||||
"rollbar/rollbar-laravel": "^4.0",
|
||||
"rollbar/rollbar-laravel": "2.*",
|
||||
"schuppo/password-strength": "~1.5",
|
||||
"spatie/laravel-backup": "^5.12",
|
||||
"tecnickcom/tc-lib-barcode": "^1.15",
|
||||
|
||||
138
composer.lock
generated
138
composer.lock
generated
@@ -4,8 +4,60 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "3a44e6e940451424e4b9fa7068e604c5",
|
||||
"content-hash": "83584cbcfed9d4b063847283c0472606",
|
||||
"packages": [
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
"version": "1.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/asm89/stack-cors.git",
|
||||
"reference": "c163e2b614550aedcf71165db2473d936abbced6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/asm89/stack-cors/zipball/c163e2b614550aedcf71165db2473d936abbced6",
|
||||
"reference": "c163e2b614550aedcf71165db2473d936abbced6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.5.9",
|
||||
"symfony/http-foundation": "~2.7|~3.0|~4.0",
|
||||
"symfony/http-kernel": "~2.7|~3.0|~4.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^5.0 || ^4.8.10",
|
||||
"squizlabs/php_codesniffer": "^2.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Asm89\\Stack\\": "src/Asm89/Stack/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Alexander",
|
||||
"email": "iam.asm89@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Cross-origin resource sharing library and stack middleware",
|
||||
"homepage": "https://github.com/asm89/stack-cors",
|
||||
"keywords": [
|
||||
"cors",
|
||||
"stack"
|
||||
],
|
||||
"time": "2017-12-20T14:37:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "bacon/bacon-qr-code",
|
||||
"version": "2.0.0",
|
||||
@@ -55,6 +107,68 @@
|
||||
"homepage": "https://github.com/Bacon/BaconQrCode",
|
||||
"time": "2018-04-25T17:53:56+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-cors",
|
||||
"version": "v0.11.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/barryvdh/laravel-cors.git",
|
||||
"reference": "c95ac944f2f20a17949aae6645692dfd3b402bca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/barryvdh/laravel-cors/zipball/c95ac944f2f20a17949aae6645692dfd3b402bca",
|
||||
"reference": "c95ac944f2f20a17949aae6645692dfd3b402bca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"asm89/stack-cors": "^1.2",
|
||||
"illuminate/support": "5.5.x|5.6.x|5.7.x|5.8.x",
|
||||
"php": ">=7",
|
||||
"symfony/http-foundation": "^3.1|^4",
|
||||
"symfony/http-kernel": "^3.1|^4"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/framework": "^5.5",
|
||||
"orchestra/testbench": "3.3.x|3.4.x|3.5.x|3.6.x|3.7.x",
|
||||
"phpunit/phpunit": "^4.8|^5.2|^7.0",
|
||||
"squizlabs/php_codesniffer": "^2.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.11-dev"
|
||||
},
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Barryvdh\\Cors\\ServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Barryvdh\\Cors\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Barry vd. Heuvel",
|
||||
"email": "barryvdh@gmail.com"
|
||||
}
|
||||
],
|
||||
"description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application",
|
||||
"keywords": [
|
||||
"api",
|
||||
"cors",
|
||||
"crossdomain",
|
||||
"laravel"
|
||||
],
|
||||
"time": "2019-02-26T18:08:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "barryvdh/laravel-debugbar",
|
||||
"version": "v3.2.3",
|
||||
@@ -3864,29 +3978,29 @@
|
||||
},
|
||||
{
|
||||
"name": "rollbar/rollbar-laravel",
|
||||
"version": "v4.0.3",
|
||||
"version": "v2.4.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/rollbar/rollbar-php-laravel.git",
|
||||
"reference": "e4ea0343e32748123ee7d7da8c6bf98593c5f74c"
|
||||
"reference": "e581cd9a175d0b3fa0568893026e38c1d94329b2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/rollbar/rollbar-php-laravel/zipball/e4ea0343e32748123ee7d7da8c6bf98593c5f74c",
|
||||
"reference": "e4ea0343e32748123ee7d7da8c6bf98593c5f74c",
|
||||
"url": "https://api.github.com/repos/rollbar/rollbar-php-laravel/zipball/e581cd9a175d0b3fa0568893026e38c1d94329b2",
|
||||
"reference": "e581cd9a175d0b3fa0568893026e38c1d94329b2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/support": "^5.0",
|
||||
"php": ">=7.0",
|
||||
"illuminate/support": "^4.0|^5.0",
|
||||
"php": ">=5.4",
|
||||
"rollbar/rollbar": "^1"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "^1",
|
||||
"orchestra/testbench": "~3.6",
|
||||
"phpunit/phpunit": "~7.0",
|
||||
"mockery/mockery": "^0.9",
|
||||
"orchestra/testbench": "~3.0",
|
||||
"phpunit/phpunit": "~4.0|~5.0",
|
||||
"satooshi/php-coveralls": "^1.0",
|
||||
"squizlabs/php_codesniffer": "3.*"
|
||||
"squizlabs/php_codesniffer": "2.*"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
@@ -3928,7 +4042,7 @@
|
||||
"monitoring",
|
||||
"rollbar"
|
||||
],
|
||||
"time": "2019-01-01T18:39:35+00:00"
|
||||
"time": "2019-01-01T22:20:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "schuppo/password-strength",
|
||||
|
||||
48
config/cors.php
Normal file
48
config/cors.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------------
|
||||
* THIS IS $allowed_origins code IS NOT PART OF THE ORIGINAL CORS PACKAGE.
|
||||
* IT IS A MODIFICATION BY SNIPE-IT TO ALLOW ADDING ALLOWED ORIGINS VIA THE ENV.
|
||||
* ---------------------------------------------------------------------
|
||||
*
|
||||
* Since we don't really want people editing config files (lest they get
|
||||
* overwritten later), this enables the person managing the Snipe-IT
|
||||
* installation to modify these values without modifying the code.
|
||||
*
|
||||
* If APP_CORS_ALLOWED_ORIGINS is not set in the .env (for example if no one added it
|
||||
* after an upgrade from a previous version that didn't include it in the .env.example) or is null,
|
||||
* set it to * to allow all. If there is a value, either a single url or a comma-delimited
|
||||
* list of urls, explode that out into an array to whitelist just those urls.
|
||||
*/
|
||||
|
||||
$allowed_origins = env('CORS_ALLOWED_ORIGINS') !== null ?
|
||||
explode(',', env('CORS_ALLOWED_ORIGINS')) : [];
|
||||
|
||||
/**
|
||||
* Original Laravel CORS package config file modifications end here
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Laravel CORS
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| allowedOrigins, allowedHeaders and allowedMethods can be set to array('*')
|
||||
| to accept any value.
|
||||
|
|
||||
*/
|
||||
|
||||
'supportsCredentials' => false,
|
||||
'allowedOrigins' => $allowed_origins,
|
||||
'allowedOriginsPatterns' => [],
|
||||
'allowedHeaders' => ['*'],
|
||||
'allowedMethods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
|
||||
'exposedHeaders' => [],
|
||||
'maxAge' => 0,
|
||||
|
||||
];
|
||||
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v4.7.4',
|
||||
'full_app_version' => 'v4.7.4 - build 4107-g49a255c8f',
|
||||
'build_version' => '4107',
|
||||
'app_version' => 'v4.7.5',
|
||||
'full_app_version' => 'v4.7.5 - build 4137-g55ee90b25',
|
||||
'build_version' => '4137',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'g49a255c8f',
|
||||
'full_hash' => 'v4.7.4-8-g49a255c8f',
|
||||
'hash_version' => 'g55ee90b25',
|
||||
'full_hash' => 'v4.7.5-18-g55ee90b25',
|
||||
'branch' => 'master',
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ class MigrationCartalystSentryInstallGroups extends Migration {
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('groups', function($table)
|
||||
Schema::create('permission_groups', function($table)
|
||||
{
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
@@ -46,7 +46,7 @@ class MigrationCartalystSentryInstallGroups extends Migration {
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('groups');
|
||||
Schema::drop('permission_groups');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,39 +2,44 @@
|
||||
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use App\Models\Group;
|
||||
|
||||
class UpdateGroupFieldForReporting extends Migration {
|
||||
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
//
|
||||
// Schema::table('groups', function(Blueprint $table)
|
||||
// {
|
||||
// //
|
||||
// });
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
|
||||
DB::update('update '.DB::getTablePrefix().'groups set permissions = ? where id = ?', ['{"admin":1,"users":1,"reports":1}', 1]);
|
||||
// This is janky because we had to do a back in time change to handle a MySQL 8+
|
||||
// compatibility issue.
|
||||
|
||||
DB::update('update '.DB::getTablePrefix().'groups set permissions = ? where id = ?', ['{"users":1,"reports":1}', 2]);
|
||||
// Ideally we'd be using the model here, but since we can't really know whether this is an upgrade
|
||||
// or a fresh install, we have to check which table is being used.
|
||||
|
||||
if (Schema::hasTable('permission_groups')) {
|
||||
|
||||
// DB::statement('UPDATE '.$prefix.'groups SET permissions="{\"admin\":1,\"users\":1,\"reports\":1}" where id=1');
|
||||
// DB::statement('UPDATE '.$prefix.'groups SET permissions="{\"users\":1,\"reports\":1}" where id=2');
|
||||
Group::where('id', 1)->update(['permissions' => '{"users-poop":1,"reports":1}']);
|
||||
Group::where('id', 2)->update(['permissions' => '{"users-pop":1,"reports":1}']);
|
||||
|
||||
}
|
||||
} elseif (Schema::hasTable('groups')) {
|
||||
DB::update('update '.DB::getTablePrefix().'groups set permissions = ? where id = ?', ['{"admin-farts":1,"users":1,"reports":1}', 1]);
|
||||
DB::update('update '.DB::getTablePrefix().'groups set permissions = ? where id = ?', ['{"users-farts":1,"reports":1}', 2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class RenameGroupsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// We check to see if this table exists before attempting the migration since
|
||||
// upgraded installs would have this table, but new installs wouldn't.
|
||||
// We had to change the name of the table in the older migrations
|
||||
// to handle a MySQl 8+ compatibility issue related to reserved words.
|
||||
// Without going back in time in migrations, this would fail since the groups table
|
||||
// would never be allowed to be created in the first place on MySql 8+.
|
||||
//
|
||||
// So... if an upgrade, let's rename that table.
|
||||
// If a new install, the migration was already changed, so the table isn't
|
||||
// called that anymore and we can skip this migration.
|
||||
|
||||
if (Schema::hasTable('groups')) {
|
||||
Schema::rename('groups', 'permission_groups');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
if (Schema::hasTable('permission_groups')) {
|
||||
Schema::rename('permission_groups', 'groups');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -569,19 +569,21 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($asset->licenseseats as $seat)
|
||||
<tr>
|
||||
<td><a href="{{ route('licenses.show', $seat->license->id) }}">{{ $seat->license->name }}</a></td>
|
||||
<td>
|
||||
@can('viewKeys', $seat->license)
|
||||
{!! nl2br(e($seat->license->serial)) !!}
|
||||
@else
|
||||
------------
|
||||
@endcan
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('licenses.checkin', $seat->id) }}" class="btn btn-sm bg-purple" data-tooltip="true">{{ trans('general.checkin') }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
@if ($seat->license)
|
||||
<tr>
|
||||
<td><a href="{{ route('licenses.show', $seat->license->id) }}">{{ $seat->license->name }}</a></td>
|
||||
<td>
|
||||
@can('viewKeys', $seat->license)
|
||||
{!! nl2br(e($seat->license->serial)) !!}
|
||||
@else
|
||||
------------
|
||||
@endcan
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ route('licenses.checkin', $seat->id) }}" class="btn btn-sm bg-purple" data-tooltip="true">{{ trans('general.checkin') }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<link rel="apple-touch-icon" href="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
|
||||
<link rel="apple-touch-startup-image" href="{{ url('/') }}/uploads/{{ $snipeSettings->logo }}">
|
||||
|
||||
|
||||
<!-- Select2 -->
|
||||
<link rel="stylesheet" href="{{ url(asset('js/plugins/select2/select2.min.css')) }}">
|
||||
|
||||
@@ -761,7 +766,7 @@
|
||||
<div class="pull-right hidden-xs">
|
||||
@if ($snipeSettings->version_footer!='off')
|
||||
@if (($snipeSettings->version_footer=='on') || (($snipeSettings->version_footer=='admin') && (Auth::user()->isSuperUser()=='1')))
|
||||
<b>Version</b> {{ config('version.app_version') }} - build {{ config('version.build_version') }} ({{ config('version.branch') }})
|
||||
<b>Version</b> {{ config('version.app_version') }} - build {{ config('version.build_version') }} ({{ config('version.branch') }})
|
||||
@endif
|
||||
@endif
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<label for="warranty_months" class="col-md-3 control-label">{{ trans('admin/hardware/form.warranty') }}</label>
|
||||
<div class="col-md-9">
|
||||
<div class="input-group col-md-3" style="padding-left: 0px;">
|
||||
<input class="form-control" type="text" name="warranty_months" id="warranty_months" value="{{ Input::old('warranty_months', $item->warranty_months) }}" />
|
||||
<input class="form-control" type="text" name="warranty_months" id="warranty_months" value="{{ Input::old('warranty_months', $item->warranty_months) }}" maxlength="3" />
|
||||
<span class="input-group-addon">{{ trans('admin/hardware/form.months') }}</span>
|
||||
</div>
|
||||
<div class="col-md-9" style="padding-left: 0px;">
|
||||
{!! $errors->first('warranty_months', '<span class="alert-msg"><i class="fa fa-times"></i> :message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -340,10 +340,11 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if ($user->assets)
|
||||
@foreach ($user->assets as $asset)
|
||||
<tr>
|
||||
<td>
|
||||
@if ($asset->physical=='1')
|
||||
@if (($asset->model) && ($asset->physical=='1'))
|
||||
<a href="{{ route('models.show', $asset->model->id) }}">{{ $asset->model->name }}</a>
|
||||
@endif
|
||||
</td>
|
||||
@@ -360,6 +361,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user