Merge branch 'develop' into fix/test-suite

This commit is contained in:
Marcus Moore 2023-02-28 09:48:48 -08:00
commit 589a5d0d8b
No known key found for this signature in database
1004 changed files with 8683 additions and 3252 deletions

View file

@ -2837,6 +2837,15 @@
"contributions": [
"code"
]
},
{
"login": "AndrewSav",
"name": "Andrew Savinykh",
"avatar_url": "https://avatars.githubusercontent.com/u/658865?v=4",
"profile": "https://github.com/AndrewSav",
"contributions": [
"code"
]
}
]
}

1
.gitignore vendored
View file

@ -3,6 +3,7 @@
.env
.env.dusk.*
!.env.dusk.example
phpstan.neon
.idea
/bin/
/bootstrap/compiled.php

View file

@ -1,5 +1,5 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-312-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
[![All Contributors](https://img.shields.io/badge/all_contributors-313-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
@ -140,7 +140,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") | [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") | [<img src="https://avatars.githubusercontent.com/u/7991086?v=4" width="110px;"/><br /><sub>Daniel Reeder</sub>](https://github.com/reederda)<br />[🌍](#translation-reederda "Translation") [🌍](#translation-reederda "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=reederda "Code") | [<img src="https://avatars.githubusercontent.com/u/109422491?v=4" width="110px;"/><br /><sub>vickyjaura183</sub>](https://github.com/vickyjaura183)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vickyjaura183 "Code") |
| [<img src="https://avatars.githubusercontent.com/u/32363424?v=4" width="110px;"/><br /><sub>Peace</sub>](https://github.com/julian-piehl)<br />[💻](https://github.com/snipe/snipe-it/commits?author=julian-piehl "Code") | [<img src="https://avatars.githubusercontent.com/u/231528?v=4" width="110px;"/><br /><sub>Kyle Gordon</sub>](https://github.com/kylegordon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kylegordon "Code") | [<img src="https://avatars.githubusercontent.com/u/53009155?v=4" width="110px;"/><br /><sub>Katharina Drexel</sub>](http://www.bfh.ch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sunflowerbofh "Code") | [<img src="https://avatars.githubusercontent.com/u/1931963?v=4" width="110px;"/><br /><sub>David Sferruzza</sub>](https://david.sferruzza.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dsferruzza "Code") | [<img src="https://avatars.githubusercontent.com/u/19511639?v=4" width="110px;"/><br /><sub>Rick Nelson</sub>](https://github.com/rnelsonee)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rnelsonee "Code") | [<img src="https://avatars.githubusercontent.com/u/94169344?v=4" width="110px;"/><br /><sub>BasO12</sub>](https://github.com/BasO12)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BasO12 "Code") | [<img src="https://avatars.githubusercontent.com/u/111710123?v=4" width="110px;"/><br /><sub>Vautia</sub>](https://github.com/Vautia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Vautia "Code") |
| [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") | [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") | [<img src="https://avatars.githubusercontent.com/u/56871540?v=4" width="110px;"/><br /><sub>Lukas Fehling</sub>](https://github.com/lukasfehling)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukasfehling "Code") | [<img src="https://avatars.githubusercontent.com/u/1975990?v=4" width="110px;"/><br /><sub>Fernando Almeida</sub>](https://github.com/fernando-almeida)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fernando-almeida "Code") |
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") |
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") | [<img src="https://avatars.githubusercontent.com/u/658865?v=4" width="110px;"/><br /><sub>Andrew Savinykh</sub>](https://github.com/AndrewSav)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AndrewSav "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View file

@ -56,7 +56,7 @@ class CheckoutLicenseToAllUsers extends Command
return false;
}
$users = User::whereNull('deleted_at')->with('licenses')->get();
$users = User::whereNull('deleted_at')->where('autoassign_licenses', '==', 1)->with('licenses')->get();
if ($users->count() > $license->getAvailSeatsCountAttribute()) {
$this->info('You do not have enough free seats to complete this task, so we will check out as many as we can. ');

View file

@ -3,14 +3,29 @@
namespace App\Console\Commands;
use Illuminate\Console\Command;
use \App\Models\User;
class CreateAdmin extends Command
{
/** @mixin User **/
/**
* The name and signature of the console command.
*
* @var string
* App\Console\CreateAdmin
* @property mixed $first_name
* @property string $last_name
* @property string $username
* @property string $email
* @property string $permissions
* @property string $password
* @property boolean $activated
* @property boolean $show_in_list
* @property \Illuminate\Support\Carbon|null $created_at
* @property mixed $created_by
*/
protected $signature = 'snipeit:create-admin {--first_name=} {--last_name=} {--email=} {--username=} {--password=} {show_in_list?}';
/**
@ -30,11 +45,7 @@ class CreateAdmin extends Command
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$first_name = $this->option('first_name');
@ -47,7 +58,7 @@ class CreateAdmin extends Command
if (($first_name == '') || ($last_name == '') || ($username == '') || ($email == '') || ($password == '')) {
$this->info('ERROR: All fields are required.');
} else {
$user = new \App\Models\User;
$user = new User;
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->username = $username;

View file

@ -74,7 +74,7 @@ class LdapSync extends Command
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
LOG::info($e);
Log::info($e);
return [];
}
@ -84,7 +84,7 @@ class LdapSync extends Command
try {
if ($this->option('base_dn') != '') {
$search_base = $this->option('base_dn');
LOG::debug('Importing users from specified base DN: \"'.$search_base.'\".');
Log::debug('Importing users from specified base DN: \"'.$search_base.'\".');
} else {
$search_base = null;
}
@ -98,7 +98,7 @@ class LdapSync extends Command
$json_summary = ['error' => true, 'error_message' => $e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
LOG::info($e);
Log::info($e);
return [];
}
@ -108,16 +108,16 @@ class LdapSync extends Command
if ($this->option('location') != '') {
$location = Location::where('name', '=', $this->option('location'))->first();
LOG::debug('Location name '.$this->option('location').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
Log::debug('Location name '.$this->option('location').' passed');
Log::debug('Importing to '.$location->name.' ('.$location->id.')');
} elseif ($this->option('location_id') != '') {
$location = Location::where('id', '=', $this->option('location_id'))->first();
LOG::debug('Location ID '.$this->option('location_id').' passed');
LOG::debug('Importing to '.$location->name.' ('.$location->id.')');
Log::debug('Location ID '.$this->option('location_id').' passed');
Log::debug('Importing to '.$location->name.' ('.$location->id.')');
}
if (! isset($location)) {
LOG::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
Log::debug('That location is invalid or a location was not provided, so no location will be assigned by default.');
}
/* Process locations with explicitly defined OUs, if doing a full import. */
@ -133,7 +133,7 @@ class LdapSync extends Command
array_multisort($ldap_ou_lengths, SORT_ASC, $ldap_ou_locations);
if (count($ldap_ou_locations) > 0) {
LOG::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
Log::debug('Some locations have special OUs set. Locations will be automatically set for users in those OUs.');
}
// Inject location information fields
@ -151,7 +151,7 @@ class LdapSync extends Command
$json_summary = ['error' => true, 'error_message' => trans('admin/users/message.error.ldap_could_not_search').' Location: '.$ldap_loc['name'].' (ID: '.$ldap_loc['id'].') cannot connect to "'.$ldap_loc['ldap_ou'].'" - '.$e->getMessage(), 'summary' => []];
$this->info(json_encode($json_summary));
}
LOG::info($e);
Log::info($e);
return [];
}
@ -197,18 +197,18 @@ class LdapSync extends Command
for ($i = 0; $i < $results['count']; $i++) {
$item = [];
$item['username'] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : '';
$item['employee_number'] = isset($results[$i][$ldap_result_emp_num][0]) ? $results[$i][$ldap_result_emp_num][0] : '';
$item['lastname'] = isset($results[$i][$ldap_result_last_name][0]) ? $results[$i][$ldap_result_last_name][0] : '';
$item['firstname'] = isset($results[$i][$ldap_result_first_name][0]) ? $results[$i][$ldap_result_first_name][0] : '';
$item['email'] = isset($results[$i][$ldap_result_email][0]) ? $results[$i][$ldap_result_email][0] : '';
$item['ldap_location_override'] = isset($results[$i]['ldap_location_override']) ? $results[$i]['ldap_location_override'] : '';
$item['location_id'] = isset($results[$i]['location_id']) ? $results[$i]['location_id'] : '';
$item['telephone'] = isset($results[$i][$ldap_result_phone][0]) ? $results[$i][$ldap_result_phone][0] : '';
$item['jobtitle'] = isset($results[$i][$ldap_result_jobtitle][0]) ? $results[$i][$ldap_result_jobtitle][0] : '';
$item['country'] = isset($results[$i][$ldap_result_country][0]) ? $results[$i][$ldap_result_country][0] : '';
$item['department'] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : '';
$item['manager'] = isset($results[$i][$ldap_result_manager][0]) ? $results[$i][$ldap_result_manager][0] : '';
$item['username'] = $results[$i][$ldap_result_username][0] ?? '';
$item['employee_number'] = $results[$i][$ldap_result_emp_num][0] ?? '';
$item['lastname'] = $results[$i][$ldap_result_last_name][0] ?? '';
$item['firstname'] = $results[$i][$ldap_result_first_name][0] ?? '';
$item['email'] = $results[$i][$ldap_result_email][0] ?? '';
$item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? '';
$item['location_id'] = $results[$i]['location_id'] ?? '';
$item['telephone'] = $results[$i][$ldap_result_phone][0] ?? '';
$item['jobtitle'] = $results[$i][$ldap_result_jobtitle][0] ?? '';
$item['country'] = $results[$i][$ldap_result_country][0] ?? '';
$item['department'] = $results[$i][$ldap_result_dept][0] ?? '';
$item['manager'] = $results[$i][$ldap_result_manager][0] ?? '';
$department = Department::firstOrCreate([

View file

@ -41,7 +41,9 @@ class Handler extends ExceptionHandler
public function report(Throwable $exception)
{
if ($this->shouldReport($exception)) {
\Log::error($exception);
if (class_exists(\Log::class)) {
\Log::error($exception);
}
return parent::report($exception);
}
}

View file

@ -26,7 +26,10 @@ class AccessoriesController extends Controller
*/
public function index(Request $request)
{
$this->authorize('view', Accessory::class);
if ($request->user()->cannot('reports.view')) {
$this->authorize('view', Accessory::class);
}
// This array is what determines which fields should be allowed to be sorted on ON the table itself, no relations
// Relations will be handled in query scopes a little further down.

View file

@ -857,7 +857,8 @@ class AssetsController extends Controller
$checkout_at = request('checkout_at', date('Y-m-d H:i:s'));
$expected_checkin = request('expected_checkin', null);
$note = request('note', null);
$asset_name = request('name', null);
// Using `->has` preserves the asset name if the name parameter was not included in request.
$asset_name = request()->has('name') ? request('name') : $asset->name;
// Set the location ID to the RTD location id if there is one
// Wait, why are we doing this? This overrides the stuff we set further up, which makes no sense.

View file

@ -10,6 +10,7 @@ use App\Models\Asset;
use App\Models\Company;
use App\Models\Import;
use Artisan;
use Illuminate\Database\Eloquent\JsonEncodingException;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Storage;
@ -35,7 +36,7 @@ class ImportController extends Controller
* Process and store a CSV upload file.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
* @return \Illuminate\Http\JsonResponse
*/
public function store()
{
@ -56,7 +57,7 @@ class ImportController extends Controller
'text/tsv', ])) {
$results['error'] = 'File type must be CSV. Uploaded file is '.$file->getMimeType();
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 500);
return response()->json(Helper::formatStandardApiResponse('error', null, $results['error']), 422);
}
//TODO: is there a lighter way to do this?
@ -64,7 +65,19 @@ class ImportController extends Controller
ini_set('auto_detect_line_endings', '1');
}
$reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak?
$import->header_row = $reader->fetchOne(0);
try {
$import->header_row = $reader->fetchOne(0);
} catch (JsonEncodingException $e) {
return response()->json(
Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.import.header_row_has_malformed_characters')
),
422
);
}
//duplicate headers check
$duplicate_headers = [];
@ -82,11 +95,22 @@ class ImportController extends Controller
}
}
if (count($duplicate_headers) > 0) {
return response()->json(Helper::formatStandardApiResponse('error', null, implode('; ', $duplicate_headers)), 500); //should this be '4xx'?
return response()->json(Helper::formatStandardApiResponse('error', null, implode('; ', $duplicate_headers)),422);
}
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->fetchOne(1);
try {
// Grab the first row to display via ajax as the user picks fields
$import->first_row = $reader->fetchOne(1);
} catch (JsonEncodingException $e) {
return response()->json(
Helper::formatStandardApiResponse(
'error',
null,
trans('admin/hardware/message.import.content_row_has_malformed_characters')
),
422
);
}
$date = date('Y-m-d-his');
$fixed_filename = str_slug($file->getClientOriginalName());
@ -108,12 +132,12 @@ class ImportController extends Controller
}
$results = (new ImportsTransformer)->transformImports($results);
return [
return response()->json([
'files' => $results,
];
]);
}
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.feature_disabled')), 500);
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.feature_disabled')), 422);
}
/**

View file

@ -57,8 +57,12 @@ class ReportsController extends Controller
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
$order = ($request->input('order') == 'asc') ? 'asc' : 'desc';
$offset = request('offset', 0);
$limit = request('limit', 50);
$total = $actionlogs->count();
// Check to make sure the limit is not higher than the max allowed
((config('app.max_results') >= $request->input('limit')) && ($request->filled('limit'))) ? $limit = $request->input('limit') : $limit = config('app.max_results');
$actionlogs = $actionlogs->orderBy($sort, $order)->skip($offset)->take($limit)->get();
return response()->json((new ActionlogsTransformer)->transformActionlogs($actionlogs, $total), 200, ['Content-Type' => 'application/json;charset=utf8'], JSON_UNESCAPED_UNICODE);

View file

@ -143,47 +143,6 @@ class SettingsController extends Controller
}
public function slacktest(SlackSettingsRequest $request)
{
$validator = Validator::make($request->all(), [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:https://hooks.slack.com/|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
]);
if ($validator->fails()) {
return response()->json(['message' => 'Validation failed', 'errors' => $validator->errors()], 422);
}
// If validation passes, continue to the curl request
$slack = new Client([
'base_url' => e($request->input('slack_endpoint')),
'defaults' => [
'exceptions' => false,
],
]);
$payload = json_encode(
[
'channel' => e($request->input('slack_channel')),
'text' => trans('general.slack_test_msg'),
'username' => e($request->input('slack_botname')),
'icon_emoji' => ':heart:',
]);
try {
$slack->post($request->input('slack_endpoint'), ['body' => $payload]);
return response()->json(['message' => 'Success'], 200);
} catch (\Exception $e) {
return response()->json(['message' => 'Please check the channel name and webhook endpoint URL ('.e($request->input('slack_endpoint')).'). Slack responded with: '.$e->getMessage()], 400);
}
//}
return response()->json(['message' => 'Something went wrong :( '], 400);
}
/**
* Test the email configuration
*

View file

@ -246,6 +246,7 @@ class UsersController extends Controller
'two_factor_optin',
'two_factor_enrolled',
'remote',
'vip',
'start_date',
'end_date',
];
@ -286,9 +287,11 @@ class UsersController extends Controller
$users = Company::scopeCompanyables($users);
if ($request->filled('search')) {
$users = $users->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
$users = $users->where(function ($query) use ($request) {
$query->SimpleNameSearch($request->get('search'))
->orWhere('username', 'LIKE', '%'.$request->get('search').'%')
->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%');
});
}
$users = $users->orderBy('last_name', 'asc')->orderBy('first_name', 'asc');

View file

@ -27,7 +27,7 @@ class AssetCheckoutController extends Controller
public function create($assetId)
{
// Check if the asset exists
if (is_null($asset = Asset::find(e($assetId)))) {
if (is_null($asset = Asset::with('company')->find(e($assetId)))) {
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
}

View file

@ -288,7 +288,8 @@ class BulkAssetsController extends Controller
foreach ($asset_ids as $asset_id) {
$asset = Asset::findOrFail($asset_id);
$this->authorize('checkout', $asset);
$error = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), null);
$error = $asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $asset->name, null);
if ($target->location_id != '') {
$asset->location_id = $target->location_id;

View file

@ -109,9 +109,9 @@ class CustomFieldsController extends Controller
if ($request->filled('custom_format')) {
$field->format = e($request->get('custom_format'));
$field->format = $request->get('custom_format');
} else {
$field->format = e($request->get('format'));
$field->format = $request->get('format');
}
if ($field->save()) {

View file

@ -169,7 +169,7 @@ class CustomFieldsetsController extends Controller
*/
public function destroy($id)
{
$fieldset = CustomField::find($id);
$fieldset = CustomFieldset::find($id);
$this->authorize('delete', $fieldset);

View file

@ -17,7 +17,7 @@ class ModalController extends Controller
* @author [A. Gianotto] [<snipe@snipe.net]
* @return View
*/
function show ($type, $itemId = null) {
public function show ($type, $itemId = null) {
// These values should correspond to a file in resources/views/modals/
$allowed_types = [

View file

@ -51,9 +51,8 @@ class ReportsController extends Controller
public function getAccessoryReport()
{
$this->authorize('reports.view');
$accessories = Accessory::orderBy('created_at', 'DESC')->with('company')->get();
return view('reports/accessories', compact('accessories'));
return view('reports/accessories');
}
/**
@ -1120,8 +1119,6 @@ class ReportsController extends Controller
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
$rows[] = implode(',', $row);
} else {
// Log the error maybe?
}
}

View file

@ -679,33 +679,6 @@ class SettingsController extends Controller
return view('settings.slack', compact('setting'));
}
/**
* Return a form to allow a super admin to update settings.
*
* @author [A. Gianotto] [<snipe@snipe.net>]
*
* @since [v1.0]
*
* @return View
*/
public function postSlack(SlackSettingsRequest $request)
{
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
$setting->slack_endpoint = $request->input('slack_endpoint');
$setting->slack_channel = $request->input('slack_channel');
$setting->slack_botname = $request->input('slack_botname');
if ($setting->save()) {
return redirect()->route('settings.index')
->with('success', trans('admin/settings/message.update.success'));
}
return redirect()->back()->withInput()->withErrors($setting->getErrors());
}
/**
* Return a form to allow a super admin to update settings.
*
@ -807,7 +780,7 @@ class SettingsController extends Controller
*/
public function getPhpInfo()
{
if (true === config('app.debug')) {
if (config('app.debug') === true) {
return view('settings.phpinfo');
}

View file

@ -121,6 +121,7 @@ class UsersController extends Controller
$user->created_by = Auth::user()->id;
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses= $request->input('autoassign_licenses', 1);
// Strip out the superuser permission if the user isn't a superadmin
$permissions_array = $request->input('permission');
@ -271,9 +272,11 @@ class UsersController extends Controller
$user->activated = $request->input('activated', 0);
$user->zip = $request->input('zip', null);
$user->remote = $request->input('remote', 0);
$user->vip = $request->input('vip', 0);
$user->website = $request->input('website', null);
$user->start_date = $request->input('start_date', null);
$user->end_date = $request->input('end_date', null);
$user->autoassign_licenses = $request->input('autoassign_licenses', 1);
// Update the location of any assets checked out to this user
Asset::where('assigned_type', User::class)

View file

@ -0,0 +1,95 @@
<?php
namespace App\Http\Livewire;
use GuzzleHttp\Client;
use Livewire\Component;
use App\Models\Setting;
class SlackSettingsForm extends Component
{
public $slack_endpoint;
public $slack_channel;
public $slack_botname;
public $isDisabled ='disabled' ;
public Setting $setting;
protected $rules = [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:https://hooks.slack.com/|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
'slack_botname' => 'string|nullable',
];
public function mount(){
$this->setting = Setting::getSettings();
$this->slack_endpoint = $this->setting->slack_endpoint;
$this->slack_channel = $this->setting->slack_channel;
$this->slack_botname = $this->setting->slack_botname;
}
public function updated($field){
$this->validateOnly($field ,$this->rules);
}
public function render()
{
if(empty($this->slack_channel || $this->slack_endpoint)){
$this->isDisabled= 'disabled';
}
if(empty($this->slack_endpoint && $this->slack_channel)){
$this->isDisabled= '';
}
return view('livewire.slack-settings-form');
}
public function testSlack(){
$slack = new Client([
'base_url' => e($this->slack_endpoint),
'defaults' => [
'exceptions' => false,
],
]);
$payload = json_encode(
[
'channel' => e($this->slack_channel),
'text' => trans('general.slack_test_msg'),
'username' => e($this->slack_botname),
'icon_emoji' => ':heart:',
]);
try {
$slack->post($this->slack_endpoint, ['body' => $payload]);
$this->isDisabled='';
return session()->flash('success' , 'Your Slack Integration works!');
} catch (\Exception $e) {
$this->isDisabled= 'disabled';
return session()->flash('error' , trans('admin/settings/message.slack.error', ['error_message' => $e->getMessage()]));
}
//}
return session()->flash('message' , trans('admin/settings/message.slack.error_misc'));
}
public function submit()
{
$this->validate($this->rules);
$this->setting->slack_endpoint = $this->slack_endpoint;
$this->setting->slack_channel = $this->slack_channel;
$this->setting->slack_botname = $this->slack_botname;
$this->setting->save();
session()->flash('save',trans('admin/settings/message.update.success'));
}
}

View file

@ -11,7 +11,7 @@ class CheckForTwoFactor
/**
* Routes to ignore for Two Factor Auth
*/
const IGNORE_ROUTES = ['two-factor', 'two-factor-enroll', 'setup', 'logout'];
public const IGNORE_ROUTES = ['two-factor', 'two-factor-enroll', 'setup', 'logout'];
/**
* Handle an incoming request.

View file

@ -39,14 +39,12 @@ class SaveUserRequest extends FormRequest
// Brand new user
case 'POST':
{
$rules['first_name'] = 'required|string|min:1';
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
if ($this->request->get('ldap_import') == false) {
$rules['password'] = Setting::passwordComplexityRulesSaving('store').'|confirmed';
}
break;
}
// Save all fields
case 'PUT':
@ -57,12 +55,11 @@ class SaveUserRequest extends FormRequest
// Save only what's passed
case 'PATCH':
{
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
break;
}
default:break;
default:
break;
}
return $rules;

View file

@ -1,33 +0,0 @@
<?php
namespace App\Http\Requests;
class SlackSettingsRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'slack_endpoint' => 'url|required_with:slack_channel|starts_with:"https://hooks.slack.com"|nullable',
'slack_channel' => 'required_with:slack_endpoint|starts_with:#|nullable',
'slack_botname' => 'string|nullable',
];
}
}

View file

@ -60,12 +60,14 @@ class ActionlogsTransformer
if ($actionlog->action_type == 'accepted') {
$file_url = route('log.storedeula.download', ['filename' => $actionlog->filename]);
} else {
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $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', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
if ($actionlog->item) {
if ($actionlog->itemType() == 'asset') {
$file_url = route('show/assetfile', ['assetId' => $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', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
}
}
}
}

View file

@ -4,7 +4,7 @@ namespace App\Http\Transformers;
use App\Helpers\Helper;
use App\Models\AssetModel;
use Gate;
use Illuminate\Support\Facades\Gate;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Storage;

View file

@ -74,7 +74,7 @@ class ItemImporter extends Importer
$this->item['purchase_date'] = null;
if ($this->findCsvMatch($row, 'purchase_date') != '') {
$this->item['purchase_date'] = date('Y-m-d 00:00:01', strtotime($this->findCsvMatch($row, 'purchase_date')));
$this->item['purchase_date'] = date('Y-m-d', strtotime($this->findCsvMatch($row, 'purchase_date')));
}
$this->item['last_audit_date'] = null;

View file

@ -80,6 +80,11 @@ class LicenseImporter extends ItemImporter
$checkout_target = $this->item['checkout_target'];
$asset = Asset::where('asset_tag', $asset_tag)->first();
$targetLicense = $license->freeSeat();
if (is_null($targetLicense)){
return;
}
if ($checkout_target) {
$targetLicense->assigned_to = $checkout_target->id;
$targetLicense->user_id = Auth::id();

View file

@ -63,6 +63,7 @@ class Accessory extends SnipeModel
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'purchase_date' => 'date_format:Y-m-d|nullable',
];

View file

@ -34,9 +34,9 @@ class Asset extends Depreciable
use CompanyableTrait;
use HasFactory, Loggable, Requestable, Presentable, SoftDeletes, ValidatingTrait, UniqueUndeletedTrait, UniqueSerialTrait;
const LOCATION = 'location';
const ASSET = 'asset';
const USER = 'user';
public const LOCATION = 'location';
public const ASSET = 'asset';
public const USER = 'user';
use Acceptable;
@ -84,11 +84,11 @@ class Asset extends Depreciable
protected $casts = [
'purchase_date' => 'datetime',
'purchase_date' => 'date',
'last_checkout' => 'datetime',
'expected_checkin' => 'datetime',
'expected_checkin' => 'date',
'last_audit_date' => 'datetime',
'next_audit_date' => 'datetime',
'next_audit_date' => 'date',
'model_id' => 'integer',
'status_id' => 'integer',
'company_id' => 'integer',
@ -105,16 +105,14 @@ class Asset extends Depreciable
'company_id' => 'integer|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',
'last_checkout' => 'date_format:Y-m-d H:i:s|nullable',
'expected_checkin' => 'date|nullable',
'location_id' => 'exists:locations,id|nullable',
'rtd_location_id' => 'exists:locations,id|nullable',
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
'status' => 'integer',
'purchase_date' => 'date|date_format:Y-m-d|nullable',
'serial' => 'unique_serial|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'next_audit_date' => 'date|nullable',
'last_audit_date' => 'date|nullable',
'supplier_id' => 'exists:suppliers,id|nullable',
];
@ -145,6 +143,9 @@ class Asset extends Depreciable
'last_checkout',
'expected_checkin',
'byod',
'last_audit_date',
'next_audit_date',
];
use Searchable;
@ -185,6 +186,14 @@ class Asset extends Depreciable
'model.manufacturer' => ['name'],
];
// To properly set the expected checkin as Y-m-d
public function setExpectedCheckinAttribute($value)
{
if ($value == '') {
$value = null;
}
$this->attributes['expected_checkin'] = $value;
}
/**
* This handles the custom field validation for assets
@ -1632,9 +1641,9 @@ class Asset extends Depreciable
*/
public function scopeOrderManufacturer($query, $order)
{
return $query->join('models', 'assets.model_id', '=', 'models.id')
->join('manufacturers', 'models.manufacturer_id', '=', 'manufacturers.id')
->orderBy('manufacturers.name', $order);
return $query->join('models as order_asset_model', 'assets.model_id', '=', 'order_asset_model.id')
->join('manufacturers as manufacturer_order', 'order_asset_model.manufacturer_id', '=', 'manufacturer_order.id')
->orderBy('manufacturer_order.name', $order);
}
/**

View file

@ -16,12 +16,19 @@ class CheckoutAcceptance extends Model
'declined_at' => 'datetime',
];
// Get the mail recipient from the config
public function routeNotificationForMail(): string
/**
* Get the mail recipient from the config
*
* @return mixed|string|null
*/
public function routeNotificationForMail()
{
// At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications.
return (config('mail.reply_to.address')) ? config('mail.reply_to.address') : '' ;
$recipients_string = explode(',', Setting::getSettings()->alert_email);
$recipients = array_map('trim', $recipients_string);
return array_filter($recipients);
}
/**

View file

@ -35,7 +35,7 @@ class Component extends SnipeModel
'category_id' => 'required|integer|exists:categories,id',
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_date' => 'date|nullable',
'purchase_date' => 'date_format:Y-m-d|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
];

View file

@ -41,6 +41,7 @@ class Consumable extends SnipeModel
'company_id' => 'integer|nullable',
'min_amt' => 'integer|min:0|nullable',
'purchase_cost' => 'numeric|nullable|gte:0',
'purchase_date' => 'date_format:Y-m-d|nullable',
];
/**

View file

@ -21,7 +21,7 @@ class CustomField extends Model
*
* @var array
*/
const PREDEFINED_FORMATS = [
public const PREDEFINED_FORMATS = [
'ANY' => '',
'CUSTOM REGEX' => '',
'ALPHA' => 'alpha',

View file

@ -217,16 +217,16 @@ class Ldap extends Model
$ldap_result_manager = Setting::getSettings()->ldap_manager;
// Get LDAP user data
$item = [];
$item['username'] = isset($ldapattributes[$ldap_result_username][0]) ? $ldapattributes[$ldap_result_username][0] : '';
$item['employee_number'] = isset($ldapattributes[$ldap_result_emp_num][0]) ? $ldapattributes[$ldap_result_emp_num][0] : '';
$item['lastname'] = isset($ldapattributes[$ldap_result_last_name][0]) ? $ldapattributes[$ldap_result_last_name][0] : '';
$item['firstname'] = isset($ldapattributes[$ldap_result_first_name][0]) ? $ldapattributes[$ldap_result_first_name][0] : '';
$item['email'] = isset($ldapattributes[$ldap_result_email][0]) ? $ldapattributes[$ldap_result_email][0] : '';
$item['telephone'] = isset($ldapattributes[$ldap_result_phone][0]) ? $ldapattributes[$ldap_result_phone][0] : '';
$item['jobtitle'] = isset($ldapattributes[$ldap_result_jobtitle][0]) ? $ldapattributes[$ldap_result_jobtitle][0] : '';
$item['country'] = isset($ldapattributes[$ldap_result_country][0]) ? $ldapattributes[$ldap_result_country][0] : '';
$item['department'] = isset($ldapattributes[$ldap_result_dept][0]) ? $ldapattributes[$ldap_result_dept][0] : '';
$item['manager'] = isset($ldapattributes[$ldap_result_manager][0]) ? $ldapattributes[$ldap_result_manager][0] : '';
$item['username'] = $ldapattributes[$ldap_result_username][0] ?? '';
$item['employee_number'] = $ldapattributes[$ldap_result_emp_num][0] ?? '';
$item['lastname'] = $ldapattributes[$ldap_result_last_name][0] ?? '';
$item['firstname'] = $ldapattributes[$ldap_result_first_name][0] ?? '';
$item['email'] = $ldapattributes[$ldap_result_email][0] ?? '';
$item['telephone'] = $ldapattributes[$ldap_result_phone][0] ?? '';
$item['jobtitle'] = $ldapattributes[$ldap_result_jobtitle][0] ?? '';
$item['country'] = $ldapattributes[$ldap_result_country][0] ?? '';
$item['department'] = $ldapattributes[$ldap_result_dept][0] ?? '';
$item['manager'] = $ldapattributes[$ldap_result_manager][0] ?? '';
return $item;
}

View file

@ -36,7 +36,6 @@ class License extends Depreciable
'purchase_date' => 'datetime',
'expiration_date' => 'datetime',
'termination_date' => 'datetime',
'seats' => 'integer',
'category_id' => 'integer',
'company_id' => 'integer',
];
@ -50,6 +49,9 @@ class License extends Depreciable
'category_id' => 'required|exists:categories,id',
'company_id' => 'integer|nullable',
'purchase_cost'=> 'numeric|nullable|gte:0',
'purchase_date' => 'date_format:Y-m-d|nullable',
'expiration_date' => 'date_format:Y-m-d|nullable',
'termination_date' => 'date_format:Y-m-d|nullable',
];
/**
@ -365,7 +367,7 @@ class License extends Depreciable
*/
public function assignedusers()
{
return $this->belongsToMany(\App\Models\User::class, 'license_seats', 'assigned_to', 'license_id');
return $this->belongsToMany(\App\Models\User::class, 'license_seats', 'license_id', 'assigned_to');
}
/**

View file

@ -31,7 +31,7 @@ class Setting extends Model
*
* @var string
*/
const SETUP_CHECK_KEY = 'snipeit_setup_check';
public const SETUP_CHECK_KEY = 'snipeit_setup_check';
/**
* Whether the model should inject it's identifier to the unique
@ -83,6 +83,9 @@ class Setting extends Model
'email_domain',
'email_format',
'username_format',
'slack_endpoint',
'slack_channel',
'slack_botname',
];
/**

View file

@ -164,7 +164,7 @@ trait Searchable
}
// I put this here because I only want to add the concat one time in the end of the user relation search
if($relation == 'user') {
$query->orWhereRaw('CONCAT (users.first_name, " ", users.last_name) LIKE ?', ["%$term%"]);
$query->orWhereRaw('CONCAT (users.first_name, " ", users.last_name) LIKE ?', ["%{$term}%"]);
}
});
}
@ -195,7 +195,7 @@ trait Searchable
*/
private function getSearchableAttributes()
{
return isset($this->searchableAttributes) ? $this->searchableAttributes : [];
return $this->searchableAttributes ?? [];
}
/**
@ -205,7 +205,7 @@ trait Searchable
*/
private function getSearchableRelations()
{
return isset($this->searchableRelations) ? $this->searchableRelations : [];
return $this->searchableRelations ?? [];
}
/**

View file

@ -64,6 +64,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'scim_externalid',
'avatar',
'gravatar',
'vip',
];
protected $casts = [
@ -71,6 +72,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'manager_id' => 'integer',
'location_id' => 'integer',
'company_id' => 'integer',
'vip' => 'boolean',
];
@ -98,8 +100,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
'website' => 'url|nullable|max:191',
'manager_id' => 'nullable|exists:users,id|cant_manage_self',
'location_id' => 'exists:locations,id|nullable',
'start_date' => 'nullable|date',
'end_date' => 'nullable|date|after_or_equal:start_date',
'start_date' => 'nullable|date_format:Y-m-d',
'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:start_date',
];
/**
@ -285,7 +287,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
*/
public function assets()
{
return $this->morphMany(\App\Models\Asset::class, 'assigned', 'assigned_type', 'assigned_to')->withTrashed();
return $this->morphMany(\App\Models\Asset::class, 'assigned', 'assigned_type', 'assigned_to')->withTrashed()->orderBy('id');
}
/**
@ -313,7 +315,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
public function accessories()
{
return $this->belongsToMany(\App\Models\Accessory::class, 'accessories_users', 'assigned_to', 'accessory_id')
->withPivot('id', 'created_at', 'note')->withTrashed();
->withPivot('id', 'created_at', 'note')->withTrashed()->orderBy('accessory_id');
}
/**
@ -657,7 +659,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
{
$query = $query->where('first_name', 'LIKE', '%'.$search.'%')
->orWhere('last_name', 'LIKE', '%'.$search.'%')
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$search%"]);
->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%{$search}%"]);
return $query;
}
@ -673,7 +675,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
public function advancedTextSearch(Builder $query, array $terms) {
foreach($terms as $term) {
$query = $query->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%$term%"]);
$query = $query->orWhereRaw('CONCAT('.DB::getTablePrefix().'users.first_name," ",'.DB::getTablePrefix().'users.last_name) LIKE ?', ["%{$term}%"]);
}
return $query;

View file

@ -40,12 +40,17 @@ class AcceptanceAssetAcceptedNotification extends Notification
public function via()
{
$notifyBy[] = 'mail';
$notifyBy = ['mail'];
return $notifyBy;
}
public function shouldSend($notifiable, $channel)
{
return $this->settings->alerts_enabled && ! empty($this->settings->alert_email);
}
/**
* Get the mail representation of the notification.
*

View file

@ -38,12 +38,17 @@ class AcceptanceAssetDeclinedNotification extends Notification
*/
public function via($notifiable)
{
$notifyBy[] = 'mail';
$notifyBy = ['mail'];
return $notifyBy;
}
public function shouldSend($notifiable, $channel)
{
return $this->settings->alerts_enabled && ! empty($this->settings->alert_email);
}
/**
* Get the mail representation of the notification.
*

View file

@ -44,7 +44,7 @@ class CurrentInventory extends Notification
'accessories' => $this->user->accessories,
'licenses' => $this->user->licenses,
])
->subject('Inventory Report');
->subject(trans('mail.inventory_report'));
return $message;
}

View file

@ -32,7 +32,7 @@ class InventoryAlert extends Notification
*/
public function via()
{
$notifyBy[] = 'mail';
$notifyBy = ['mail'];
return $notifyBy;
}

View file

@ -40,7 +40,7 @@ class SendUpcomingAuditNotification extends Notification
*/
public function toMail()
{
$message = (new MailMessage)->markdown('notifications.markdown.upcoming-audits',
$message = (new MailMessage())->markdown('notifications.markdown.upcoming-audits',
[
'assets' => $this->assets,
'threshold' => $this->threshold,

View file

@ -44,7 +44,7 @@ class WelcomeNotification extends Notification
*/
public function toMail()
{
return (new MailMessage)
return (new MailMessage())
->subject(trans('mail.welcome', ['name' => $this->_data['first_name'].' '.$this->_data['last_name']]))
->markdown('notifications.Welcome', $this->_data);
}

View file

@ -85,6 +85,15 @@ class UserPresenter extends Presenter
'visible' => true,
'formatter' => 'usersLinkFormatter',
],
[
'field' => 'vip',
'searchable' => false,
'sortable' => true,
'switchable' => true,
'title' => trans('admin/users/general.vip_label'),
'visible' => false,
'formatter' => 'trueFalseFormatter',
],
[
'field' => 'remote',
'searchable' => false,
@ -346,8 +355,7 @@ class UserPresenter extends Presenter
public function emailLink()
{
if ($this->email) {
return '<a href="mailto:'.$this->email.'">'.$this->email.'</a>'
.'<a href="mailto:'.$this->email.'" class="hidden-xs hidden-sm"><i class="far fa-envelope"></i></a>';
return '<a href="mailto:'.$this->email.'">'.$this->email.'</a><a href="mailto:'.$this->email.'" class="hidden-xs hidden-sm"><i class="far fa-envelope"></i></a>';
}
return '';

View file

@ -22,7 +22,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
*/
class Saml
{
const DATA_SESSION_KEY = '_samlData';
public const DATA_SESSION_KEY = '_samlData';
/**
* OneLogin_Saml2_Auth instance.
@ -308,12 +308,9 @@ class Saml
*/
public function samlLogin($data)
{
$setting = Setting::getSettings();
$this->saveDataToSession($data);
$this->loadDataFromSession();
$username = $this->getUsername();
return User::where('username', '=', $username)->whereNull('deleted_at')->where('activated', '=', '1')->first();
}

View file

@ -61,12 +61,13 @@
"nunomaduro/collision": "^5.4",
"onelogin/php-saml": "^3.4",
"paragonie/constant_time_encoding": "^2.3",
"symfony/polyfill-mbstring": "^1.22",
"paragonie/sodium_compat": "^1.19",
"phpdocumentor/reflection-docblock": "^5.1",
"phpspec/prophecy": "^1.10",
"pragmarx/google2fa-laravel": "^1.3",
"rollbar/rollbar-laravel": "^7.0",
"spatie/laravel-backup": "^6.16",
"symfony/polyfill-mbstring": "^1.22",
"tecnickcom/tc-lib-barcode": "^1.15",
"unicodeveloper/laravel-password": "^1.0",
"watson/validating": "^6.1"
@ -75,11 +76,14 @@
"fakerphp/faker": "^1.16",
"laravel/dusk": "^6.25",
"mockery/mockery": "^1.4",
"nunomaduro/larastan": "^1.0",
"nunomaduro/phpinsights": "^2.7",
"phpunit/php-token-stream": "^3.1",
"phpunit/phpunit": "^9.0",
"squizlabs/php_codesniffer": "^3.5",
"symfony/css-selector": "^4.4",
"symfony/dom-crawler": "^4.4"
"symfony/dom-crawler": "^4.4",
"vimeo/psalm": "^5.6"
},
"extra": {
"laravel": {

2954
composer.lock generated

File diff suppressed because it is too large Load diff

128
config/insights.php Normal file
View file

@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
use NunoMaduro\PhpInsights\Domain\Insights\ForbiddenDefineFunctions;
use NunoMaduro\PhpInsights\Domain\Insights\ForbiddenFinalClasses;
use NunoMaduro\PhpInsights\Domain\Insights\ForbiddenNormalClasses;
use NunoMaduro\PhpInsights\Domain\Insights\ForbiddenPrivateMethods;
use NunoMaduro\PhpInsights\Domain\Insights\ForbiddenTraits;
use NunoMaduro\PhpInsights\Domain\Metrics\Architecture\Classes;
use SlevomatCodingStandard\Sniffs\Commenting\UselessFunctionDocCommentSniff;
use SlevomatCodingStandard\Sniffs\Namespaces\AlphabeticallySortedUsesSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\DeclareStrictTypesSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\DisallowMixedTypeHintSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\ParameterTypeHintSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\PropertyTypeHintSniff;
use SlevomatCodingStandard\Sniffs\TypeHints\ReturnTypeHintSniff;
return [
/*
|--------------------------------------------------------------------------
| Default Preset
|--------------------------------------------------------------------------
|
| This option controls the default preset that will be used by PHP Insights
| to make your code reliable, simple, and clean. However, you can always
| adjust the `Metrics` and `Insights` below in this configuration file.
|
| Supported: "default", "laravel", "symfony", "magento2", "drupal"
|
*/
'preset' => 'laravel',
/*
|--------------------------------------------------------------------------
| IDE
|--------------------------------------------------------------------------
|
| This options allow to add hyperlinks in your terminal to quickly open
| files in your favorite IDE while browsing your PhpInsights report.
|
| Supported: "textmate", "macvim", "emacs", "sublime", "phpstorm",
| "atom", "vscode".
|
| If you have another IDE that is not in this list but which provide an
| url-handler, you could fill this config with a pattern like this:
|
| myide://open?url=file://%f&line=%l
|
*/
'ide' => null,
/*
|--------------------------------------------------------------------------
| Configuration
|--------------------------------------------------------------------------
|
| Here you may adjust all the various `Insights` that will be used by PHP
| Insights. You can either add, remove or configure `Insights`. Keep in
| mind that all added `Insights` must belong to a specific `Metric`.
|
*/
'exclude' => [
// 'path/to/directory-or-file'
],
'add' => [
Classes::class => [
ForbiddenFinalClasses::class,
],
],
'remove' => [
AlphabeticallySortedUsesSniff::class,
DeclareStrictTypesSniff::class,
DisallowMixedTypeHintSniff::class,
ForbiddenDefineFunctions::class,
ForbiddenNormalClasses::class,
ForbiddenTraits::class,
ParameterTypeHintSniff::class,
PropertyTypeHintSniff::class,
ReturnTypeHintSniff::class,
UselessFunctionDocCommentSniff::class,
],
'config' => [
ForbiddenPrivateMethods::class => [
'title' => 'The usage of private methods is not idiomatic in Laravel.',
],
],
/*
|--------------------------------------------------------------------------
| Requirements
|--------------------------------------------------------------------------
|
| Here you may define a level you want to reach per `Insights` category.
| When a score is lower than the minimum level defined, then an error
| code will be returned. This is optional and individually defined.
|
*/
'requirements' => [
// 'min-quality' => 0,
// 'min-complexity' => 0,
// 'min-architecture' => 0,
// 'min-style' => 0,
// 'disable-security-check' => false,
],
/*
|--------------------------------------------------------------------------
| Threads
|--------------------------------------------------------------------------
|
| Here you may adjust how many threads (core) PHPInsights can use to perform
| the analyse. This is optional, don't provide it and the tool will guess
| the max core number available. It accepts null value or integer > 0.
|
*/
'threads' => null,
];

View file

@ -1,5 +1,4 @@
<?php
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
@ -113,6 +112,13 @@ $config = [
'handler' => \Rollbar\Laravel\MonologHandler::class,
'access_token' => env('ROLLBAR_TOKEN'),
'level' => env('ROLLBAR_LEVEL', 'error'),
'check_ignore' => function($isUncaught, $args, $payload) {
if (App::environment('production') && is_object($args) && get_class($args) == Rollbar\ErrorWrapper::class && $args->errorLevel == E_WARNING ) {
\Log::info("IGNORING E_WARNING in production mode: ".$args->getMessage());
return true; // "TRUE - you should ignore it!"
}
return false;
},
],
],

View file

@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v6.0.14',
'full_app_version' => 'v6.0.14 - build 9161-g799c9c910',
'build_version' => '9161',
'full_app_version' => 'v6.0.14 - build 9599-g1415c8c6e',
'build_version' => '9599',
'prerelease_version' => '',
'hash_version' => 'g799c9c910',
'full_hash' => 'v6.0.14-117-g799c9c910',
'branch' => 'master',
'hash_version' => 'g1415c8c6e',
'full_hash' => 'v6.0.14-555-g1415c8c6e',
'branch' => 'develop',
);

View file

@ -44,7 +44,7 @@ class AssetFactory extends Factory
'user_id' => 1,
'asset_tag' => $this->faker->unixTime('now'),
'notes' => 'Created by DB seeder',
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d'),
'purchase_cost' => $this->faker->randomFloat(2, '299.99', '2999.99'),
'order_number' => $this->faker->numberBetween(1000000, 50000000),
'supplier_id' => Supplier::factory(),

View file

@ -52,4 +52,13 @@ class SettingFactory extends Factory
'email_domain' => 'test.com',
];
}
public function withMultipleFullCompanySupport()
{
return $this->state(function () {
return [
'full_multiple_companies_support' => 1,
];
});
}
}

View file

@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddsShouldAutoassignBoolToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('autoassign_licenses')->nullable(false)->default(1);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('autoassign_licenses');
});
}
}

View file

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddVipToUsers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->boolean('vip')->nullable()->default(0);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
if (Schema::hasColumn('users', 'vip')) {
$table->dropColumn('vip');
}
});
}
}

View file

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Models\CustomField;
class FixUnescapedCustomfieldsFormat extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
$customfields = CustomField::where('format', 'LIKE', '%&%')->get();
foreach($customfields as $customfield){
$customfield->update(['format' => html_entity_decode($customfield->format)]);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

6
package-lock.json generated
View file

@ -2033,9 +2033,9 @@
}
},
"acorn": {
"version": "8.8.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz",
"integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w=="
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw=="
},
"acorn-import-assertions": {
"version": "1.8.0",

View file

@ -25,7 +25,7 @@
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.2.1",
"acorn": "^8.8.0",
"acorn": "^8.8.2",
"acorn-import-assertions": "^1.8.0",
"admin-lte": "^2.4.18",
"ajv": "^6.12.6",

12
phpstan.neon.dist Normal file
View file

@ -0,0 +1,12 @@
includes:
- ./vendor/nunomaduro/larastan/extension.neon
parameters:
paths:
- app
- config
- database/migrations
- resources/lang
- resources/views
level: 4

8
phpstan.neon.example Normal file
View file

@ -0,0 +1,8 @@
# Copy this file to "phpstan.neon" and update the parameters section as needed
includes:
- phpstan.neon.dist
parameters:
# https://phpstan.org/user-guide/output-format#opening-file-in-an-editor
editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%'

18
psalm.xml Normal file
View file

@ -0,0 +1,18 @@
<?xml version="1.0"?>
<psalm
errorLevel="7"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
findUnusedBaselineEntry="true"
>
<projectFiles>
<directory name="app" />
<directory name="database/factories" />
<directory name="database/seeders" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>
</psalm>

View file

@ -13,7 +13,8 @@ return array(
'update' => array(
'error' => 'Kategorie is nie opgedateer nie, probeer asseblief weer',
'success' => 'Kategorie suksesvol opgedateer.'
'success' => 'Kategorie suksesvol opgedateer.',
'cannot_change_category_type' => 'You cannot change the category type once it has been created',
),
'delete' => array(

View file

@ -12,4 +12,5 @@ return array(
'remaining' => 'oorblywende',
'total' => 'totale',
'update' => 'Opdateer komponent',
'checkin_limit' => 'Amount checked in must be equal to or less than :assigned_qty'
);

View file

@ -27,6 +27,9 @@ return [
'used_by_models' => 'Gebruik deur modelle',
'order' => 'Orde',
'create_fieldset' => 'Nuwe Fieldset',
'update_fieldset' => 'Update Fieldset',
'fieldset_does_not_exist' => 'Fieldset :id does not exist',
'fieldset_updated' => 'Fieldset updated',
'create_fieldset_title' => 'Create a new fieldset',
'create_field' => 'Nuwe aangepaste veld',
'create_field_title' => 'Create a new custom field',

View file

@ -14,6 +14,8 @@ return [
'deleted' => 'This asset has been deleted.',
'edit' => 'Wysig bate',
'model_deleted' => 'This Assets model has been deleted. You must restore the model before you can restore the Asset.',
'model_invalid' => 'The Model of this Asset is invalid.',
'model_invalid_fix' => 'The Asset should be edited to correct this before attempting to check it in or out.',
'requestable' => 'Requestable',
'requested' => 'versoek',
'not_requestable' => 'Not Requestable',

View file

@ -48,6 +48,8 @@ return [
'success' => 'Jou lêer is ingevoer',
'file_delete_success' => 'Jou lêer is suksesvol verwyder',
'file_delete_error' => 'Die lêer kon nie uitgevee word nie',
'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters',
'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters',
],

View file

@ -3,6 +3,8 @@
return array(
'does_not_exist' => 'Model bestaan nie.',
'no_association' => 'NO MODEL ASSOCIATED.',
'no_association_fix' => 'This will break things in weird and horrible ways. Edit this asset now to assign it a model.',
'assoc_users' => 'Hierdie model word tans geassosieer met een of meer bates en kan nie verwyder word nie. Verwyder asseblief die bates en probeer dan weer uitvee.',

View file

@ -77,6 +77,7 @@ return [
'ldap' => 'LDAP',
'ldap_default_group' => 'Default Permissions Group',
'ldap_default_group_info' => 'Select a group to assign to newly synced users. Remember that a user takes on the permissions of the group they are assigned.',
'no_default_group' => 'No Default Group',
'ldap_help' => 'LDAP/Active Directory',
'ldap_client_tls_key' => 'LDAP Client TLS Key',
'ldap_client_tls_cert' => 'LDAP Client-Side TLS Certificate',

View file

@ -38,6 +38,7 @@ return [
'success_pt1' => 'Success! Check the ',
'success_pt2' => ' channel for your test message, and be sure to click SAVE below to store your settings.',
'500' => '500 Server Error.',
'error' => 'Something went wrong.',
'error' => 'Something went wrong. Slack responded with: :error_message',
'error_misc' => 'Something went wrong. :( ',
]
];

View file

@ -3,6 +3,7 @@
return [
'accessories' => 'bykomstighede',
'activated' => 'geaktiveer',
'accepted_date' => 'Date Accepted',
'accessory' => 'Bykomstigheid',
'accessory_report' => 'Toebehoreverslag',
'action' => 'aksie',
@ -27,7 +28,13 @@ return [
'audit' => 'oudit',
'audit_report' => 'Ouditlogboek',
'assets' => 'bates',
'assets_audited' => 'assets audited',
'assets_checked_in_count' => 'assets checked in',
'assets_checked_out_count' => 'assets checked out',
'asset_deleted_warning' => 'This asset has been deleted. You must restore it before you can assign it to someone.',
'assigned_date' => 'Date Assigned',
'assigned_to' => 'Assigned to :name',
'assignee' => 'Assigned to',
'avatar_delete' => 'Verwyder Avatar',
'avatar_upload' => 'Laai avatar op',
'back' => 'terug',
@ -39,6 +46,8 @@ return [
'bulk_delete' => 'Bulk Delete',
'bulk_actions' => 'Bulk Actions',
'bulk_checkin_delete' => 'Bulk Checkin Items from Users',
'byod' => 'BYOD',
'byod_help' => 'This device is owned by the user',
'bystatus' => 'by Status',
'cancel' => 'kanselleer',
'categories' => 'kategorieë',
@ -385,7 +394,15 @@ return [
'start_date' => 'Start Date',
'end_date' => 'End Date',
'alt_uploaded_image_thumbnail' => 'Uploaded thumbnail',
'placeholder_kit' => 'Select a kit'
'placeholder_kit' => 'Select a kit',
'file_not_found' => 'File not found',
'preview_not_available' => '(no preview)',
'setup' => 'Setup',
'pre_flight' => 'Pre-Flight',
'skip_to_main_content' => 'Skip to main content',
'toggle_navigation' => 'Toggle navigation',
'alerts' => 'Alerts',
'tasks_view_all' => 'View all tasks',

View file

@ -256,6 +256,7 @@ return [
'UK'=>'Scotland',
'SB'=>'Solomon Islands',
'SC'=>'Seychelles',
'SS'=>'South Sudan',
'SD'=>'Sudan',
'SE'=>'Sweden',
'SG'=>'Singapore',

View file

@ -43,6 +43,7 @@ return [
'login_first_admin' => 'Teken in op jou nuwe Snipe-IT-installasie deur die volgende inligting te gebruik:',
'login' => 'Teken aan:',
'Low_Inventory_Report' => 'Lae voorraadverslag',
'inventory_report' => 'Inventory Report',
'min_QTY' => 'Min QTY',
'name' => 'naam',
'new_item_checked' => '\'N Nuwe item is onder u naam nagegaan, besonderhede is hieronder.',
@ -78,4 +79,5 @@ return [
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'your_assets' => 'View Your Assets',
'rights_reserved' => 'All rights reserved.',
];

View file

@ -103,17 +103,6 @@ return [
],
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
@ -131,6 +120,18 @@ return [
'hashed_pass' => 'Jou huidige wagwoord is verkeerd',
'dumbpwd' => 'Daardie wagwoord is te algemeen.',
'statuslabel_type' => 'U moet \'n geldige statusetiket tipe kies',
// date_format validation with slightly less stupid messages. It duplicates a lot, but it gets the job done :(
// We use this because the default error message for date_format is reflects php Y-m-d, which non-PHP
// people won't know how to format.
'purchase_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'last_audit_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD hh:mm:ss format',
'expiration_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'termination_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'expected_checkin.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'start_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'end_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
],
/*

View file

@ -13,7 +13,8 @@ return array(
'update' => array(
'error' => 'Category was not updated, please try again',
'success' => 'Category updated successfully.'
'success' => 'Category updated successfully.',
'cannot_change_category_type' => 'You cannot change the category type once it has been created',
),
'delete' => array(

View file

@ -12,4 +12,5 @@ return array(
'remaining' => 'Remaining',
'total' => 'Total',
'update' => 'Update Component',
'checkin_limit' => 'Amount checked in must be equal to or less than :assigned_qty'
);

View file

@ -27,6 +27,9 @@ return [
'used_by_models' => 'Used By Models',
'order' => 'Order',
'create_fieldset' => 'New Fieldset',
'update_fieldset' => 'Update Fieldset',
'fieldset_does_not_exist' => 'Fieldset :id does not exist',
'fieldset_updated' => 'Fieldset updated',
'create_fieldset_title' => 'Create a new fieldset',
'create_field' => 'New Custom Field',
'create_field_title' => 'Create a new custom field',

View file

@ -14,6 +14,8 @@ return [
'deleted' => 'This asset has been deleted.',
'edit' => 'Edit Asset',
'model_deleted' => 'This Assets model has been deleted. You must restore the model before you can restore the Asset.',
'model_invalid' => 'The Model of this Asset is invalid.',
'model_invalid_fix' => 'The Asset should be edited to correct this before attempting to check it in or out.',
'requestable' => 'Requestable',
'requested' => 'Requested',
'not_requestable' => 'Not Requestable',

View file

@ -49,6 +49,8 @@ return [
'success' => 'Your file has been imported',
'file_delete_success' => 'Your file has been been successfully deleted',
'file_delete_error' => 'The file was unable to be deleted',
'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters',
'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters',
],

View file

@ -3,6 +3,8 @@
return array(
'does_not_exist' => 'Model does not exist.',
'no_association' => 'NO MODEL ASSOCIATED.',
'no_association_fix' => 'This will break things in weird and horrible ways. Edit this asset now to assign it a model.',
'assoc_users' => 'This model is currently associated with one or more assets and cannot be deleted. Please delete the assets, and then try deleting again. ',

View file

@ -77,6 +77,7 @@ return [
'ldap' => 'LDAP',
'ldap_default_group' => 'Default Permissions Group',
'ldap_default_group_info' => 'Select a group to assign to newly synced users. Remember that a user takes on the permissions of the group they are assigned.',
'no_default_group' => 'No Default Group',
'ldap_help' => 'LDAP/Active Directory',
'ldap_client_tls_key' => 'LDAP Client TLS Key',
'ldap_client_tls_cert' => 'LDAP Client-Side TLS Certificate',

View file

@ -38,6 +38,7 @@ return [
'success_pt1' => 'Success! Check the ',
'success_pt2' => ' channel for your test message, and be sure to click SAVE below to store your settings.',
'500' => '500 Server Error.',
'error' => 'Something went wrong.',
'error' => 'Something went wrong. Slack responded with: :error_message',
'error_misc' => 'Something went wrong. :( ',
]
];

View file

@ -3,6 +3,7 @@
return [
'accessories' => 'Accessories',
'activated' => 'Activated',
'accepted_date' => 'Date Accepted',
'accessory' => 'Accessory',
'accessory_report' => 'Accessory Report',
'action' => 'Action',
@ -27,7 +28,13 @@ return [
'audit' => 'Audit',
'audit_report' => 'Audit Log',
'assets' => 'Assets',
'assets_audited' => 'assets audited',
'assets_checked_in_count' => 'assets checked in',
'assets_checked_out_count' => 'assets checked out',
'asset_deleted_warning' => 'This asset has been deleted. You must restore it before you can assign it to someone.',
'assigned_date' => 'Date Assigned',
'assigned_to' => 'Assigned to :name',
'assignee' => 'Assigned to',
'avatar_delete' => 'Delete Avatar',
'avatar_upload' => 'Upload Avatar',
'back' => 'Back',
@ -39,6 +46,8 @@ return [
'bulk_delete' => 'Bulk Delete',
'bulk_actions' => 'Bulk Actions',
'bulk_checkin_delete' => 'Bulk Checkin Items from Users',
'byod' => 'BYOD',
'byod_help' => 'This device is owned by the user',
'bystatus' => 'by Status',
'cancel' => 'Cancel',
'categories' => 'Categories',
@ -385,7 +394,15 @@ return [
'start_date' => 'Start Date',
'end_date' => 'End Date',
'alt_uploaded_image_thumbnail' => 'Uploaded thumbnail',
'placeholder_kit' => 'Select a kit'
'placeholder_kit' => 'Select a kit',
'file_not_found' => 'File not found',
'preview_not_available' => '(no preview)',
'setup' => 'Setup',
'pre_flight' => 'Pre-Flight',
'skip_to_main_content' => 'Skip to main content',
'toggle_navigation' => 'Toggle navigation',
'alerts' => 'Alerts',
'tasks_view_all' => 'View all tasks',

View file

@ -256,6 +256,7 @@ return [
'UK'=>'Scotland',
'SB'=>'Solomon Islands',
'SC'=>'Seychelles',
'SS'=>'South Sudan',
'SD'=>'Sudan',
'SE'=>'Sweden',
'SG'=>'Singapore',

View file

@ -43,6 +43,7 @@ return [
'login_first_admin' => 'Login to your new Snipe-IT installation using the credentials below:',
'login' => 'Login:',
'Low_Inventory_Report' => 'Low Inventory Report',
'inventory_report' => 'Inventory Report',
'min_QTY' => 'Min QTY',
'name' => 'Name',
'new_item_checked' => 'A new item has been checked out under your name, details are below.',
@ -79,4 +80,5 @@ return [
'Expected_Checkin_Notification' => 'Reminder: :name checkin deadline approaching',
'Expected_Checkin_Date' => 'An asset checked out to you is due to be checked back in on :date',
'your_assets' => 'View Your Assets',
'rights_reserved' => 'All rights reserved.',
];

View file

@ -103,17 +103,6 @@ return [
],
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
@ -131,6 +120,18 @@ return [
'hashed_pass' => 'Your current password is incorrect',
'dumbpwd' => 'That password is too common.',
'statuslabel_type' => 'You must select a valid status label type',
// date_format validation with slightly less stupid messages. It duplicates a lot, but it gets the job done :(
// We use this because the default error message for date_format is reflects php Y-m-d, which non-PHP
// people won't know how to format.
'purchase_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'last_audit_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD hh:mm:ss format',
'expiration_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'termination_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'expected_checkin.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'start_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'end_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
],
/*

View file

@ -13,7 +13,8 @@ return array(
'update' => array(
'error' => 'لقد فشل تحديث التصنيف، الرجاء المحاولة مرة أخرى',
'success' => 'تم تحديث التصنيف بنجاح.'
'success' => 'تم تحديث التصنيف بنجاح.',
'cannot_change_category_type' => 'You cannot change the category type once it has been created',
),
'delete' => array(

View file

@ -12,4 +12,5 @@ return array(
'remaining' => 'المتبقية',
'total' => 'المجموع',
'update' => 'تحديث مكون',
'checkin_limit' => 'Amount checked in must be equal to or less than :assigned_qty'
);

View file

@ -27,6 +27,9 @@ return [
'used_by_models' => 'مستخدم في الموديلات',
'order' => 'طلب',
'create_fieldset' => 'مجموعة حقول جديدة',
'update_fieldset' => 'Update Fieldset',
'fieldset_does_not_exist' => 'Fieldset :id does not exist',
'fieldset_updated' => 'Fieldset updated',
'create_fieldset_title' => 'Create a new fieldset',
'create_field' => 'حقل جديد مخصص',
'create_field_title' => 'Create a new custom field',

View file

@ -14,6 +14,8 @@ return [
'deleted' => 'تم حذف هذا الأصل.',
'edit' => 'تعديل الأصل',
'model_deleted' => 'تم حذف موديل الأصول هذا. يجب استعادة الموديل قبل أن تتمكن من استعادة الأصل.',
'model_invalid' => 'The Model of this Asset is invalid.',
'model_invalid_fix' => 'The Asset should be edited to correct this before attempting to check it in or out.',
'requestable' => 'قابل للطلب',
'requested' => 'تم الطلب',
'not_requestable' => 'Not Requestable',

View file

@ -48,6 +48,8 @@ return [
'success' => 'تم استيراد الملف الخاص بك',
'file_delete_success' => 'تم حذف ملفك بنجاح',
'file_delete_error' => 'تعذر حذف الملف',
'header_row_has_malformed_characters' => 'One or more attributes in the header row contain malformed UTF-8 characters',
'content_row_has_malformed_characters' => 'One or more attributes in the first row of content contain malformed UTF-8 characters',
],

View file

@ -3,6 +3,8 @@
return array(
'does_not_exist' => 'الموديل غير موجود.',
'no_association' => 'NO MODEL ASSOCIATED.',
'no_association_fix' => 'This will break things in weird and horrible ways. Edit this asset now to assign it a model.',
'assoc_users' => 'هذا الموديل مرتبط حاليا بواحد أو أكثر من الأصول ولا يمكن حذفه. يرجى حذف الأصول، ثم محاولة الحذف مرة أخرى. ',

View file

@ -77,6 +77,7 @@ return [
'ldap' => 'LDAP',
'ldap_default_group' => 'Default Permissions Group',
'ldap_default_group_info' => 'Select a group to assign to newly synced users. Remember that a user takes on the permissions of the group they are assigned.',
'no_default_group' => 'No Default Group',
'ldap_help' => 'LDAP/Active Directory',
'ldap_client_tls_key' => 'LDAP Client TLS Key',
'ldap_client_tls_cert' => 'LDAP Client-Side TLS Certificate',

View file

@ -38,6 +38,7 @@ return [
'success_pt1' => 'Success! Check the ',
'success_pt2' => ' channel for your test message, and be sure to click SAVE below to store your settings.',
'500' => '500 Server Error.',
'error' => 'Something went wrong.',
'error' => 'Something went wrong. Slack responded with: :error_message',
'error_misc' => 'Something went wrong. :( ',
]
];

View file

@ -3,6 +3,7 @@
return [
'accessories' => 'ملحقات',
'activated' => 'مفعل',
'accepted_date' => 'Date Accepted',
'accessory' => 'ملحق',
'accessory_report' => 'تقرير الملحقات',
'action' => 'الإجراء',
@ -27,7 +28,13 @@ return [
'audit' => 'تدقيق',
'audit_report' => 'سجل التدقيق',
'assets' => 'الأصول',
'assets_audited' => 'assets audited',
'assets_checked_in_count' => 'assets checked in',
'assets_checked_out_count' => 'assets checked out',
'asset_deleted_warning' => 'This asset has been deleted. You must restore it before you can assign it to someone.',
'assigned_date' => 'Date Assigned',
'assigned_to' => 'مسنَدة إلى :name',
'assignee' => 'Assigned to',
'avatar_delete' => 'حذف الصورة الرمزية',
'avatar_upload' => 'رفع صورة رمزية',
'back' => 'الرجوع للخلف',
@ -39,6 +46,8 @@ return [
'bulk_delete' => 'حذف بالجملة',
'bulk_actions' => 'مجموعة إجراءات',
'bulk_checkin_delete' => 'Bulk Checkin Items from Users',
'byod' => 'BYOD',
'byod_help' => 'This device is owned by the user',
'bystatus' => 'حسب الحالة',
'cancel' => 'إلغاء',
'categories' => 'التصنيفات',
@ -385,7 +394,15 @@ return [
'start_date' => 'Start Date',
'end_date' => 'End Date',
'alt_uploaded_image_thumbnail' => 'Uploaded thumbnail',
'placeholder_kit' => 'Select a kit'
'placeholder_kit' => 'Select a kit',
'file_not_found' => 'File not found',
'preview_not_available' => '(no preview)',
'setup' => 'Setup',
'pre_flight' => 'Pre-Flight',
'skip_to_main_content' => 'Skip to main content',
'toggle_navigation' => 'Toggle navigation',
'alerts' => 'Alerts',
'tasks_view_all' => 'View all tasks',

View file

@ -256,6 +256,7 @@ return [
'UK'=>'Scotland',
'SB'=>'Solomon Islands',
'SC'=>'Seychelles',
'SS'=>'South Sudan',
'SD'=>'Sudan',
'SE'=>'Sweden',
'SG'=>'Singapore',

View file

@ -43,6 +43,7 @@ return [
'login_first_admin' => 'قم بتسجيل الدخول إلى التثبيت الجديد من Snipe-IT باستخدام البيانات أدناه:',
'login' => 'تسجيل الدخول:',
'Low_Inventory_Report' => 'تقرير المخزون المنخفض',
'inventory_report' => 'Inventory Report',
'min_QTY' => 'دقيقة الكمية',
'name' => 'اسم',
'new_item_checked' => 'تم فحص عنصر جديد تحت اسمك، التفاصيل أدناه.',
@ -78,4 +79,5 @@ return [
'Expected_Checkin_Notification' => 'تذكير: تاريخ تحقق :name يقترب من الموعد النهائي',
'Expected_Checkin_Date' => 'من المقرر أن يتم التحقق من الأصول التي تم إخراجها إليك في :date',
'your_assets' => 'عرض الأصول الخاصة بك',
'rights_reserved' => 'All rights reserved.',
];

View file

@ -103,17 +103,6 @@ return [
],
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
@ -131,6 +120,18 @@ return [
'hashed_pass' => 'كلمة المرور الحالية غير صحيحة',
'dumbpwd' => 'كلمة المرور هذه شائعة جدا.',
'statuslabel_type' => 'يجب تحديد نوع تسمية حالة صالح',
// date_format validation with slightly less stupid messages. It duplicates a lot, but it gets the job done :(
// We use this because the default error message for date_format is reflects php Y-m-d, which non-PHP
// people won't know how to format.
'purchase_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'last_audit_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD hh:mm:ss format',
'expiration_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'termination_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'expected_checkin.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'start_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
'end_date.date_format' => 'The :attribute must be a valid date in YYYY-MM-DD format',
],
/*

View file

@ -13,7 +13,8 @@ return array(
'update' => array(
'error' => 'Категорията не беше обновена. Моля опитайте отново',
'success' => 'Категорията е обновена успешно.'
'success' => 'Категорията е обновена успешно.',
'cannot_change_category_type' => 'You cannot change the category type once it has been created',
),
'delete' => array(

Some files were not shown because too many files have changed in this diff Show more