diff --git a/.env.example b/.env.example index 5ad08a4fa1..b85385d559 100644 --- a/.env.example +++ b/.env.example @@ -77,6 +77,7 @@ ALLOW_IFRAMING=false REFERRER_POLICY=same-origin ENABLE_CSP=false CORS_ALLOWED_ORIGINS=null +ENABLE_HSTS=false # -------------------------------------------- # OPTIONAL: CACHE SETTINGS diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..7ef56a0d5f --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,40 @@ +# Description + +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context, providing screenshots where practical. List any dependencies that are required for this change. + +Fixes # (issue) + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +# How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration + +- [ ] Test A +- [ ] Test B + +**Test Configuration**: +* PHP version: +* MySQL version +* Webserver version +* OS version + + +# Checklist: + +- [ ] I have read the Contributing documentation available here: https://snipe-it.readme.io/docs/contributing-overview +- [ ] I have formatted this PR according to the project guidelines: https://snipe-it.readme.io/docs/contributing-overview#pull-request-guidelines +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my own code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes diff --git a/README.md b/README.md index d9b7db5a1c..2e85a4ed60 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.org/snipe/snipe-it.svg?branch=master)](https://travis-ci.org/snipe/snipe-it) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![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-189-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) [![All Contributors](https://img.shields.io/badge/all_contributors-212-orange.svg?style=flat-square)](#contributors) [![Open Source Helpers](https://www.codetriage.com/snipe/snipe-it/badges/users.svg)](https://www.codetriage.com/snipe/snipe-it) @@ -114,6 +115,8 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
Martin Stub](http://martinstub.dk)
[🌍](#translation-stubben "Translation") | [
Meyer Flavio](https://github.com/meyerf99)
[🌍](#translation-meyerf99 "Translation") | [
Micael Rodrigues](https://github.com/MicaelRodrigues)
[🌍](#translation-MicaelRodrigues "Translation") | [
Mikael Rasmussen](http://rubixy.com/)
[🌍](#translation-mikaelssen "Translation") | [
IxFail](https://github.com/IxFail)
[🌍](#translation-IxFail "Translation") | [
Mohammed Fota](http://www.mohammedfota.com)
[🌍](#translation-MohammedFota "Translation") | [
Moayad Alserihi](https://github.com/omego)
[🌍](#translation-omego "Translation") | | [
saymd](https://github.com/saymd)
[🌍](#translation-saymd "Translation") | [
Patrik Larsson](https://nordsken.se)
[🌍](#translation-pooot "Translation") | [
drcryo](https://github.com/drcryo)
[🌍](#translation-drcryo "Translation") | [
pawel1615](https://github.com/pawel1615)
[🌍](#translation-pawel1615 "Translation") | [
bodrovics](https://github.com/bodrovics)
[🌍](#translation-bodrovics "Translation") | [
priatna](https://github.com/priatna)
[🌍](#translation-priatna "Translation") | [
Fan Jiang](https://amayume.net)
[🌍](#translation-ProfFan "Translation") | | [
ragnarcx](https://github.com/ragnarcx)
[🌍](#translation-ragnarcx "Translation") | [
Rein van Haaren](http://www.reinvanhaaren.nl/)
[🌍](#translation-reinvanhaaren "Translation") | [
Teguh Dwicaksana](http://dheche.songolimo.net)
[🌍](#translation-dheche "Translation") | [
fraccie](https://github.com/FRaccie)
[🌍](#translation-FRaccie "Translation") | [
vinzruzell](https://github.com/vinzruzell)
[🌍](#translation-vinzruzell "Translation") | [
Kevin Austin](http://kevinaustin.com)
[🌍](#translation-vipsystem "Translation") | [
Wira Sandy](http://azuraweb.xyz)
[🌍](#translation-wira-sandy "Translation") | +| [
Илья](https://github.com/GrayHoax)
[🌍](#translation-GrayHoax "Translation") | [
GodUseVPN](https://github.com/godusevpn)
[🌍](#translation-godusevpn "Translation") | [
周周](https://github.com/EngrZhou)
[🌍](#translation-EngrZhou "Translation") | [
Sam](https://github.com/takuy)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [
Azerothian](https://www.illisian.com.au)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [
Tim Farmer](https://github.com/timothyfarmer)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [
MariΓ‘n Skrip](https://github.com/mskrip)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") | +| [
Godfrey Martinez](https://github.com/Godmartinz)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") | [
bigtreeEdo](https://github.com/bigtreeEdo)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [
Colin McNeil](https://colinmcneil.me/)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [
JoKneeMo](https://github.com/JoKneeMo)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [
Joshi](http://www.redbridge.se)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [
Anthony Burns](https://github.com/anthonypburns)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") | [
Alexander Chibrikin](http://phpprofi.ru/)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=alek13 "Code") | | [
Илья](https://github.com/GrayHoax)
[🌍](#translation-GrayHoax "Translation") | [
GodUseVPN](https://github.com/godusevpn)
[🌍](#translation-godusevpn "Translation") | [
周周](https://github.com/EngrZhou)
[🌍](#translation-EngrZhou "Translation") | [
Sam](https://github.com/takuy)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [
Azerothian](https://www.illisian.com.au)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [
Wes Hulette](http://macfoo.wordpress.com/)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=jwhulette "Code") | [
patrict](https://github.com/patrict)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=patrict "Code") | | [
Dmitriy Minaev](https://github.com/VELIKII-DIVAN)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=VELIKII-DIVAN "Code") | [
liquidhorse](https://github.com/liquidhorse)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=liquidhorse "Code") | [
Jordi Boggiano](https://seld.be/)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=Seldaek "Code") | [
Ivan Nieto](https://github.com/inietov)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=inietov "Code") | [
Ben RUBSON](https://github.com/benrubson)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=benrubson "Code") | [
NMathar](https://github.com/NMathar)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=NMathar "Code") | [
Steffen](https://github.com/smb)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=smb "Code") | | [
Sxderp](https://github.com/Sxderp)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=Sxderp "Code") | [
fanta8897](https://github.com/fanta8897)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=fanta8897 "Code") | [
Andrey Bolonin](https://andreybolonin.com/phpconsulting/)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=andreybolonin "Code") | [
shinayoshi](http://www.shinayoshi.net/)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=shinayoshi "Code") | [
Hubert](https://github.com/reuser)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=reuser "Code") | [
KeenRivals](https://brashear.me)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=KeenRivals "Code") | [
omyno](https://github.com/omyno)
[πŸ’»](https://github.com/snipe/snipe-it/commits?author=omyno "Code") | diff --git a/app/Console/Commands/CheckinLicensesFromAllUsers.php b/app/Console/Commands/CheckinLicensesFromAllUsers.php new file mode 100644 index 0000000000..bcd8583eaf --- /dev/null +++ b/app/Console/Commands/CheckinLicensesFromAllUsers.php @@ -0,0 +1,95 @@ +option('license_id'); + $notify = $this->option('notify'); + + if (!$license_id) { + $this->error('ERROR: License ID is required.'); + return false; + } + + + if (!$license = License::where('id','=',$license_id)->first()) { + $this->error('Invalid license ID'); + return false; + } + + $this->info('Checking in ALL seats for '.$license->name); + + + $licenseSeats = LicenseSeat::where('license_id', '=', $license_id) + ->whereNotNull('assigned_to') + ->with('user') + ->get(); + + $this->info(' There are ' .$licenseSeats->count(). ' seats checked out: '); + + if (!$notify) { + $this->info('No mail will be sent.'); + } + + foreach ($licenseSeats as $seat) { + $this->info($seat->user->username .' has a license seat for '.$license->name); + $seat->assigned_to = null; + + if ($seat->save()) { + + // Override the email address so we don't notify on checkin + if (!$notify) { + $seat->user->email = null; + } + + // Log the checkin + $seat->logCheckin($seat->user, 'Checked in via cli tool'); + } + + + + + } + + + } +} diff --git a/app/Console/Commands/CheckoutLicenseToAllUsers.php b/app/Console/Commands/CheckoutLicenseToAllUsers.php new file mode 100644 index 0000000000..0855e5d084 --- /dev/null +++ b/app/Console/Commands/CheckoutLicenseToAllUsers.php @@ -0,0 +1,112 @@ +option('license_id'); + $notify = $this->option('notify'); + + if (!$license_id) { + $this->error('ERROR: License ID is required.'); + return false; + } + + + if (!$license = License::where('id','=',$license_id)->with('assignedusers')->first()) { + $this->error('Invalid license ID'); + return false; + } + + $users = User::whereNull('deleted_at')->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. '); + } + + $this->info('Checking out '.$users->count().' of '.$license->getAvailSeatsCountAttribute().' seats for '.$license->name); + + if (!$notify) { + $this->info('No mail will be sent.'); + } + + foreach ($users as $user) { + + // Check to make sure this user doesn't already have this license checked out + // to them + + if ($user->licenses->where('id', '=', $license_id)->count()) { + $this->info($user->username .' already has this license checked out to them. Skipping... '); + continue; + } + + + // If the license is valid, check that there is an available seat + if ($license->availCount()->count() < 1) { + $this->error('ERROR: No available seats'); + return false; + } + + $this->info($license->availCount()->count().' seats left'); + // Get the seat ID + $licenseSeat = $license->freeSeat(); + + + // Update the seat with checkout info, + $licenseSeat->assigned_to = $user->id; + if ($licenseSeat->save()) { + + // Temporarily null the user's email address so we don't send mail if we're not supposed to + if (!$notify) { + $user->email = null; + } + + // Log the checkout + $licenseSeat->logCheckout('Checked out via cli tool', $user); + $this->info('License '.$license_id.' seat '.$licenseSeat->id.' checked out to '.$user->username); + } + + } + + + + } +} diff --git a/app/Console/Commands/MergeUsersByUsername.php b/app/Console/Commands/MergeUsersByUsername.php new file mode 100644 index 0000000000..ded5d1986f --- /dev/null +++ b/app/Console/Commands/MergeUsersByUsername.php @@ -0,0 +1,109 @@ +whereNull('deleted_at')->get(); + + foreach ($users as $user) { + $parts = explode("@", $user->username); + $bad_users = User::where('username', '=', $parts[0])->whereNull('deleted_at')->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')->get(); + + foreach ($bad_users as $bad_user) { + $this->info($bad_user->username.' ('.$bad_user->id.') will be merged into '.$user->username.' ('.$user->id.') '); + + // Walk the list of assets + foreach ($bad_user->assets as $asset) { + $this->info( 'Updating asset '.$asset->asset_tag.' '.$asset->id.' to user '.$user->id); + $asset->assigned_to = $user->id; + $asset->save(); + } + + // Walk the list of licenses + foreach ($bad_user->licenses as $license) { + $this->info( 'Updating license '.$license->name.' '.$license->id.' to user '.$user->id); + $bad_user->licenses()->updateExistingPivot($license->id, ['assigned_to' => $user->id]); + } + + // Walk the list of consumables + foreach ($bad_user->consumables as $consumable) { + $this->info( 'Updating consumable '.$consumable->id.' to user '.$user->id); + $bad_user->consumables()->updateExistingPivot($consumable->id, ['assigned_to' => $user->id]); + } + + // Walk the list of accessories + foreach ($bad_user->accessories as $accessory) { + $this->info( 'Updating accessory '.$accessory->id.' to user '.$user->id); + $bad_user->accessories()->updateExistingPivot($accessory->id, ['assigned_to' => $user->id]); + } + + // Walk the list of logs + foreach ($bad_user->userlog as $log) { + $this->info( 'Updating action log record '.$log->id.' to user '.$user->id); + $log->target_id = $user->id; + $log->save(); + } + + // Update any manager IDs + $this->info( 'Updating managed user records to user '.$user->id); + User::where('manager_id', '=', $bad_user->id)->update(['manager_id' => $user->id]); + + + // Update location manager IDs + foreach ($bad_user->managedLocations as $managedLocation) { + $this->info( 'Updating managed location record '.$managedLocation->name.' to manager '.$user->id); + $managedLocation->manager_id = $user->id; + $managedLocation->save(); + } + + // Mark the user as deleted + $this->info( 'Marking the user as deleted'); + $bad_user->deleted_at = Carbon::now()->timestamp; + $bad_user->save(); + + + } + + } + + + } +} diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 5585f3a695..4c4e2a8a92 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -457,6 +457,7 @@ class AssetsController extends Controller $asset->supplier_id = $request->get('supplier_id', 0); $asset->requestable = $request->get('requestable', 0); $asset->rtd_location_id = $request->get('rtd_location_id', null); + $asset->location_id = $request->get('rtd_location_id', null); if ($request->has('image_source') && $request->input('image_source') != "") { $saved_image_path = Helper::processUploadedImage( diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index a3b785333f..b1d953b975 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -8,7 +8,9 @@ use App\Http\Transformers\ConsumablesTransformer; use App\Http\Transformers\SelectlistTransformer; use App\Models\Company; use App\Models\Consumable; -use Illuminate\Http\Request; +use App\Models\User; +use App\Http\Transformers\ConsumablesTransformer; +use App\Helpers\Helper; class ConsumablesController extends Controller { @@ -158,7 +160,7 @@ class ConsumablesController extends Controller return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.delete.success'))); } - /** + /** * Returns a JSON response containing details on the users associated with this consumable. * * @author [A. Gianotto] [] @@ -198,6 +200,57 @@ class ConsumablesController extends Controller return $data; } + /** + * Checkout a consumable + * + * @author [A. Gutierrez] [] + * @param int $id + * @since [v4.9.5] + * @return JsonResponse + */ + public function checkout(Request $request, $id) + { + // Check if the consumable exists + if (is_null($consumable = Consumable::find($id))) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/consumables/message.does_not_exist'))); + } + + $this->authorize('checkout', $consumable); + + if ($consumable->qty > 0) { + + // Check if the user exists + $assigned_to = $request->input('assigned_to'); + if (is_null($user = User::find($assigned_to))) { + // Return error message + return response()->json(Helper::formatStandardApiResponse('error', null, 'No user found')); + } + + // Update the consumable data + $consumable->assigned_to = e($assigned_to); + + $consumable->users()->attach($consumable->id, [ + 'consumable_id' => $consumable->id, + 'user_id' => $user->id, + 'assigned_to' => $assigned_to + ]); + + // Log checkout event + $logaction = $consumable->logCheckout(e($request->input('note')), $user); + $data['log_id'] = $logaction->id; + $data['eula'] = $consumable->getEula(); + $data['first_name'] = $user->first_name; + $data['item_name'] = $consumable->name; + $data['checkout_date'] = $logaction->created_at; + $data['note'] = $logaction->note; + $data['require_acceptance'] = $consumable->requireAcceptance(); + + return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success'))); + } + + return response()->json(Helper::formatStandardApiResponse('error', null, 'No consumables remaining')); + } + /** * Gets a paginated collection for the select2 menus * diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index 5f747726c9..a130eaa1db 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -78,6 +78,14 @@ class UsersController extends Controller $users = $users->where('users.location_id', '=', $request->input('location_id')); } + if ($request->filled('email')) { + $users = $users->where('users.email', '=', $request->input('email')); + } + + if ($request->filled('username')) { + $users = $users->where('users.username', '=', $request->input('username')); + } + if ($request->filled('group_id')) { $users = $users->ByGroup($request->get('group_id')); } diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 2f25deab92..3ed9940118 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -385,6 +385,7 @@ class LoginController extends Controller $request->session()->regenerate(true); + $request->session()->regenerate(true); Auth::logout(); if (!empty($sloRedirectUrl)) { diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index da3c5092b9..0045496791 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -17,15 +17,12 @@ class Kernel extends HttpKernel \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\FrameGuard::class, - \App\Http\Middleware\XssProtectHeader::class, - \App\Http\Middleware\ReferrerPolicyHeader::class, - \App\Http\Middleware\ContentSecurityPolicyHeader::class, - \App\Http\Middleware\NosniffGuard::class, \Fideloper\Proxy\TrustProxies::class, \App\Http\Middleware\CheckForSetup::class, \App\Http\Middleware\CheckForDebug::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, + \App\Http\Middleware\SecurityHeaders::class, + ]; /** diff --git a/app/Http/Middleware/ContentSecurityPolicyHeader.php b/app/Http/Middleware/ContentSecurityPolicyHeader.php deleted file mode 100644 index 45c87a59e3..0000000000 --- a/app/Http/Middleware/ContentSecurityPolicyHeader.php +++ /dev/null @@ -1,35 +0,0 @@ -headers->set('Content-Security-Policy', $policy); - return $response; - } -} diff --git a/app/Http/Middleware/FrameGuard.php b/app/Http/Middleware/FrameGuard.php deleted file mode 100644 index beb19f20f1..0000000000 --- a/app/Http/Middleware/FrameGuard.php +++ /dev/null @@ -1,24 +0,0 @@ -headers->set('X-Frame-Options', 'SAMEORIGIN', false); - } - return $response; - - } -} diff --git a/app/Http/Middleware/NosniffGuard.php b/app/Http/Middleware/NosniffGuard.php deleted file mode 100644 index 295f5e75af..0000000000 --- a/app/Http/Middleware/NosniffGuard.php +++ /dev/null @@ -1,21 +0,0 @@ -headers->set('X-Content-Type-Options', 'nosniff', false); - return $response; - } -} diff --git a/app/Http/Middleware/ReferrerPolicyHeader.php b/app/Http/Middleware/ReferrerPolicyHeader.php deleted file mode 100644 index 430ce45af3..0000000000 --- a/app/Http/Middleware/ReferrerPolicyHeader.php +++ /dev/null @@ -1,21 +0,0 @@ -headers->set('Referrer-Policy', config('app.referrer_policy')); - return $response; - } -} diff --git a/app/Http/Middleware/SecurityHeaders.php b/app/Http/Middleware/SecurityHeaders.php new file mode 100644 index 0000000000..ab88ec1b87 --- /dev/null +++ b/app/Http/Middleware/SecurityHeaders.php @@ -0,0 +1,122 @@ +removeUnwantedHeaders($this->unwantedHeaderList); + $response = $next($request); + + $response->headers->set('X-Content-Type-Options', 'nosniff'); + $response->headers->set('X-XSS-Protection', '1; mode=block'); + + // Ugh. Feature-Policy is dumb and clumsy and mostly irrelevant for Snipe-IT, + // since we don't provide any way to IFRAME anything in in the first place. + // There is currently no easy way to default ALL THE THINGS to 'none', but + // security audits will still ding you if you don't have this header, even + // though we don't allow IFRAMING in the first place. + // + // So for security and compliance sake, here we are. Sigh. + // + // See also: + // - https://developers.google.com/web/updates/2018/06/feature-policy + // - https://scotthelme.co.uk/a-new-security-header-feature-policy/ + // - https://github.com/w3c/webappsec-feature-policy/issues/189 + + $feature_policy[] = "accelerometer 'none'"; + $feature_policy[] = "ambient-light-sensor 'none'"; + $feature_policy[] = "animations 'none'"; + $feature_policy[] = "autoplay 'none'"; + $feature_policy[] = "battery 'none'"; + $feature_policy[] = "camera 'none'"; + $feature_policy[] = "display-capture 'none'"; + $feature_policy[] = "document-domain 'none'"; + $feature_policy[] = "encrypted-media 'none'"; + $feature_policy[] = "fullscreen 'none'"; + $feature_policy[] = "geolocation 'none'"; + $feature_policy[] = "gyroscope 'none'"; + $feature_policy[] = "legacy-image-formats 'none'"; + $feature_policy[] = "magnetometer 'none'"; + $feature_policy[] = "microphone 'none'"; + $feature_policy[] = "midi 'none'"; + $feature_policy[] = "oversized-images 'none'"; + $feature_policy[] = "payment 'none'"; + $feature_policy[] = "picture-in-picture 'none'"; + $feature_policy[] = "publickey-credentials 'none'"; + $feature_policy[] = "sync-xhr 'none'"; + $feature_policy[] = "unsized-media 'none'"; + $feature_policy[] = "usb 'none'"; + $feature_policy[] = "vibrate 'none'"; + $feature_policy[] = "wake-lock 'none'"; + $feature_policy[] = "xr-spatial-tracking 'none'"; + + $feature_policy = join(';', $feature_policy); + $response->headers->set('Feature-Policy', $feature_policy); + + + + // Defaults to same-origin if REFERRER_POLICY is not set in the .env + $response->headers->set('Referrer-Policy', config('app.referrer_policy')); + + // The .env var ALLOW_IFRAMING defaults to false (which disallows IFRAMING) + // if not present, but some unique cases require this to be enabled. + // For example, some IT depts have IFRAMED Snipe-IT into their IT portal + // for convenience so while it is normally disallowed, there is + // an override that exists. + + if (config('app.allow_iframing') == false) { + $response->headers->set('X-Frame-Options', 'DENY'); + } + + + // This defaults to false to maintain backwards compatibility for + // people who are not running Snipe-IT over TLS (shame, shame, shame!) + // Seriously though, please run Snipe-IT over TLS. Let's Encrypt is free. + // https://letsencrypt.org + + if (config('app.enable_hsts') === true) { + $response->headers->set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains'); + } + + // We have to exclude debug mode here because debugbar pulls from a CDN or two + // and it will break things. + + if ((config('app.debug')!='true') || (config('app.enable_csp')=='true')) { + $csp_policy[] = "default-src 'self'"; + $csp_policy[] = "style-src 'self' 'unsafe-inline'"; + $csp_policy[] = "script-src 'self' 'unsafe-inline' 'unsafe-eval'"; + $csp_policy[] = "connect-src 'self'"; + $csp_policy[] = "object-src 'none'"; + $csp_policy[] = "font-src 'self' data:"; + $csp_policy[] = "img-src 'self' data: gravatar.com maps.google.com maps.gstatic.com *.googleapis.com"; + $csp_policy = join(';', $csp_policy); + $response->headers->set('Content-Security-Policy', $csp_policy); + } + + return $response; + } + + private function removeUnwantedHeaders($headerList) + { + foreach ($headerList as $header) + header_remove($header); + } +} diff --git a/app/Http/Middleware/XssProtectHeader.php b/app/Http/Middleware/XssProtectHeader.php deleted file mode 100644 index 868d100f37..0000000000 --- a/app/Http/Middleware/XssProtectHeader.php +++ /dev/null @@ -1,22 +0,0 @@ -headers->set('X-XSS-Protection', $mode); - return $response; - } -} diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index d157b16ab0..6466c3b2d1 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -63,6 +63,10 @@ abstract class Importer 'full_name' => 'full name', 'email' => 'email', 'username' => 'username', + 'address' => 'address', + 'city' => 'city', + 'state' => 'state', + 'country' => 'country', 'jobtitle' => 'job title', 'employee_num' => 'employee number', 'phone_number' => 'phone number', diff --git a/app/Importer/UserImporter.php b/app/Importer/UserImporter.php index acbfab54f7..4fcf221cba 100644 --- a/app/Importer/UserImporter.php +++ b/app/Importer/UserImporter.php @@ -48,6 +48,10 @@ class UserImporter extends ItemImporter $this->item['email'] = $this->findCsvMatch($row, 'email'); $this->item['phone'] = $this->findCsvMatch($row, 'phone_number'); $this->item['jobtitle'] = $this->findCsvMatch($row, 'jobtitle'); + $this->item['address'] = $this->findCsvMatch($row, 'address'); + $this->item['city'] = $this->findCsvMatch($row, 'city'); + $this->item['state'] = $this->findCsvMatch($row, 'state'); + $this->item['country'] = $this->findCsvMatch($row, 'country'); $this->item['activated'] = ($this->fetchHumanBoolean($this->findCsvMatch($row, 'activated')) == 1) ? '1' : 0; $this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num'); $this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department')); diff --git a/app/Importer/import_mappings.md b/app/Importer/import_mappings.md index 0642241525..7899cf679a 100644 --- a/app/Importer/import_mappings.md +++ b/app/Importer/import_mappings.md @@ -7,13 +7,14 @@ | department_id | | User ? All | | item name | item_name | All | | image | image | Asset | -| department_id | | User ? All | +| email | | | | expiration date | expiration_date | License | | location | location | All | | notes | notes | All | | licensed to email | license_email | License | | licensed to name | license_name | License | | maintained | maintained | License | +| manager_id | | User | | manufacturer | manufacturer | All | | model name | asset_model | Asset | | model number | model_number | Asset | @@ -34,4 +35,8 @@ | name | | | | email | | | | username | | | +| address | address | User | +| city | city | User | +| state | state | User | +| country | country | User | diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 2a92c81a5a..9af62593d7 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -1094,7 +1094,7 @@ class Asset extends Depreciable $interval = $settings->audit_warning_days ?? 0; return $query->whereNotNull('assets.next_audit_date') - ->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $interval DAY) <= '".Carbon::now()."'") + ->whereRaw("DATE_SUB(".DB::getTablePrefix()."assets.next_audit_date, INTERVAL $interval DAY) <= '".Carbon::now()."'") ->where('assets.archived', '=', 0) ->NotArchived(); } diff --git a/app/Models/Company.php b/app/Models/Company.php index c81655029e..e6bd3dd773 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -126,9 +126,12 @@ final class Company extends SnipeModel } elseif (!static::isFullMultipleCompanySupportEnabled()) { return true; } else { - $current_user_company_id = Auth::user()->company_id; - $companyable_company_id = $companyable->company_id; - return ($current_user_company_id == null || $current_user_company_id == $companyable_company_id || Auth::user()->isSuperUser()); + if (Auth::user()) { + $current_user_company_id = Auth::user()->company_id; + $companyable_company_id = $companyable->company_id; + return ($current_user_company_id == null || $current_user_company_id == $companyable_company_id || Auth::user()->isSuperUser()); + } + } } diff --git a/app/Models/Loggable.php b/app/Models/Loggable.php index 1bb05b9298..bff1ac2e10 100644 --- a/app/Models/Loggable.php +++ b/app/Models/Loggable.php @@ -28,8 +28,9 @@ trait Loggable { $log = new Actionlog; $log = $this->determineLogItemType($log); - if(Auth::user()) + if (Auth::user()) { $log->user_id = Auth::user()->id; + } if (!isset($target)) { throw new \Exception('All checkout logs require a target.'); @@ -113,14 +114,45 @@ trait Loggable $log->location_id = null; $log->note = $note; - $log->action_date = $action_date; - - if (!$log->action_date) { - $log->action_date = date('Y-m-d H:i:s'); + if (Auth::user()) { + $log->user_id = Auth::user()->id; } - $log->user_id = Auth::user()->id; + $log->logaction('checkin from'); + $params = [ + 'target' => $target, + 'item' => $log->item, + 'admin' => $log->user, + 'note' => $note, + 'target_type' => $log->target_type, + 'settings' => $settings, + ]; + + + $checkinClass = null; + + if (method_exists($target, 'notify')) { + try { + $target->notify(new static::$checkinClass($params)); + } catch (\Exception $e) { + \Log::debug($e); + } + + } + + // Send to the admin, if settings dictate + $recipient = new \App\Models\Recipients\AdminRecipient(); + + if (($settings->admin_cc_email!='') && (static::$checkinClass!='')) { + try { + $recipient->notify(new static::$checkinClass($params)); + } catch (\Exception $e) { + \Log::debug($e); + } + + } + return $log; } diff --git a/app/Models/User.php b/app/Models/User.php index 109ad4f92d..ff886905fc 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -331,7 +331,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo */ public function userlog() { - return $this->hasMany('\App\Models\Actionlog', 'target_id')->orderBy('created_at', 'DESC')->withTrashed(); + return $this->hasMany('\App\Models\Actionlog', 'target_id')->where('target_type', '=', 'App\Models\User')->orderBy('created_at', 'DESC')->withTrashed(); } @@ -521,6 +521,18 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } elseif ($format=='firstname') { $username = str_slug($first_name); } + elseif ($format=='firstinitial.lastname') { + $username = str_slug(substr($first_name, 0, 1). '.' . str_slug($last_name)); + } + elseif ($format=='lastname_firstinitial') { + $username = str_slug($last_name).'_'.str_slug(substr($first_name, 0, 1)); + } + elseif ($format=='firstnamelastname') { + $username = str_slug($first_name) . str_slug($last_name); + } + elseif ($format=='firstnamelastinitial') { + $username = str_slug(($first_name.substr($last_name, 0, 1))); + } } $user['first_name'] = $first_name; diff --git a/app/Notifications/CheckinLicenseSeatNotification.php b/app/Notifications/CheckinLicenseSeatNotification.php index 07d5455b13..f9d4914c37 100644 --- a/app/Notifications/CheckinLicenseSeatNotification.php +++ b/app/Notifications/CheckinLicenseSeatNotification.php @@ -67,10 +67,18 @@ class CheckinLicenseSeatNotification extends Notification $botname = ($this->settings->slack_botname) ? $this->settings->slack_botname : 'Snipe-Bot' ; - $fields = [ - 'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - 'By' => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', - ]; + if ($admin) { + $fields = [ + 'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', + 'By' => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + ]; + } else { + $fields = [ + 'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', + 'By' => 'CLI tool', + ]; + } + diff --git a/app/Presenters/AssetPresenter.php b/app/Presenters/AssetPresenter.php index 4b791be0c1..5e009ebfa1 100644 --- a/app/Presenters/AssetPresenter.php +++ b/app/Presenters/AssetPresenter.php @@ -268,8 +268,11 @@ class AssetPresenter extends Presenter "searchable" => true, "sortable" => true, "switchable" => true, - "title" => ($field->field_encrypted=='1') ?' '.$field->name : $field->name, - "formatter" => "customFieldsFormatter" + "title" => $field->name, + "formatter"=> 'customFieldsFormatter', + "escape" => true, + "class" => ($field->field_encrypted=='1') ? 'css-padlock' : '', + "visible" => true, ]; } diff --git a/config/app.php b/config/app.php index b4c21884b3..9f1f03129b 100755 --- a/config/app.php +++ b/config/app.php @@ -197,19 +197,33 @@ return [ /* - |-------------------------------------------------------------------------- - | ALLOW I-FRAMING - |-------------------------------------------------------------------------- - | - | Normal users will never need to edit this. This option lets you run - | Snipe-IT within an I-Frame, which is normally disabled by default for - | security reasons, to prevent clickjacking. It should normally be set to false. - | - */ + |-------------------------------------------------------------------------- + | ALLOW I-FRAMING + |-------------------------------------------------------------------------- + | + | Normal users will never need to edit this. This option lets you run + | Snipe-IT within an I-Frame, which is normally disabled by default for + | security reasons, to prevent clickjacking. It should normally be set to false. + | + */ 'allow_iframing' => env('ALLOW_IFRAMING', false), + /* + |-------------------------------------------------------------------------- + | ENABLE HTTP Strict Transport Security (HSTS) + |-------------------------------------------------------------------------- + | + | This is set to default false for backwards compatibilty but should be + | set to true if the hosting environment allows it. + | + | See https://scotthelme.co.uk/hsts-the-missing-link-in-tls/ + | + */ + + 'enable_hsts' => env('ENABLE_HSTS', false), + /* |-------------------------------------------------------------------------- | REFERRER-POLICY diff --git a/public/css/overrides.css b/public/css/overrides.css index 0c23ba211b..50c9619ae8 100644 --- a/public/css/overrides.css +++ b/public/css/overrides.css @@ -1,2 +1,2 @@ -.skin-red .skin-purple .skin-blue .skin-black .skin-orange .skin-yellow .skin-green .skin-red-dark .skin-purple-dark .skin-blue-dark .skin-black-dark .skin-orange-dark .skin-yellow-dark .skin-green-dark .skin-contrast .main-header .logo{background-color:inherit}.main-header .logo{width:100%!important;white-space:nowrap;text-align:left;display:block;clear:both}.main-header .logo a:hover,.main-header .logoa:link,.main-header .logo a:visited{color:#fff}.huge{font-size:40px}.btn-file{position:relative;overflow:hidden}.dropdown-menu>li>a{color:#354044}#sort tr.cansort{border-radius:2px;padding:10px;background:#f4f4f4;margin-bottom:3px;border-left:2px solid #e6e7e8;color:#444;cursor:move}.user-image-inline{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px}.input-group .input-group-addon{background-color:#f4f4f4}a.accordion-header{color:#333}.dynamic-form-row{padding:10px;margin:20px}.handle{padding-left:10px}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;outline:none;background:#fff;cursor:inherit;display:block}.main-footer{font-size:13px}.main-header{max-height:150px}.navbar-nav>.user-menu>.dropdown-menu{width:inherit}.main-header .logo{padding:0 5px 0 15px}.sidebar-toggle{margin-left:-48px;z-index:100;background-color:inherit}.sidebar-toggle-mobile{z-index:100;width:50px;padding-top:10px}.main-header .sidebar-toggle:before{content:"\F0C9"}.direct-chat-contacts{padding:10px;height:150px}.select2-container{width:100%}.error input{color:#dd4b39;border:2px solid #dd4b39!important}.alert-msg,.error label{color:#dd4b39;display:block}.input-group[class*=col-]{padding-right:15px;padding-left:15px}.control-label.multiline{padding-top:10px}.btn-outline{color:inherit;background-color:transparent;-webkit-transition:all .5s;transition:all .5s}.btn-primary.btn-outline{color:#428bca}.btn-success.btn-outline{color:#5cb85c}.btn-info.btn-outline{color:#5bc0de}.btn-warning.btn-outline{color:#f0ad4e}.btn-danger.btn-outline{color:#d9534f}.btn-danger.btn-outline:hover,.btn-info.btn-outline:hover,.btn-primary.btn-outline:hover,.btn-success.btn-outline:hover,.btn-warning.btn-outline:hover{color:#fff}.slideout-menu{position:fixed;top:0;right:-250px;width:250px;height:100%;background:#333;z-index:100;margin-top:100px;color:#fff;padding:10px}.slideout-menu h3{position:relative;padding:5px;color:#fff;font-size:1.2em;font-weight:400;border-bottom:4px solid #222}.slideout-menu .slideout-menu-toggle{position:absolute;top:12px;right:10px;display:inline-block;padding:6px 9px 5px;font-family:Arial,sans-serif;font-weight:700;line-height:1;background:#222;color:#999;text-decoration:none;vertical-align:top}.slideout-menu .slideout-menu-toggle:hover{color:#fff}.slideout-menu ul{list-style:none;font-weight:300;border-top:1px solid #151515;border-bottom:1px solid #454545}.slideout-menu ul li{border-top:1px solid #454545;border-bottom:1px solid #151515}.slideout-menu ul li a{position:relative;display:block;padding:10px;color:#999;text-decoration:none}.slideout-menu ul li a:hover{background:#000;color:#fff}.slideout-menu ul li a i{position:absolute;top:15px;right:10px;opacity:.5}.btn-box-tool-lg{font-size:16px;color:orange}.bs-wizard{margin-top:20px;border-bottom:1px solid #e0e0e0;padding:0 0 10px}.bs-wizard>.bs-wizard-step{padding:0;position:relative}.bs-wizard>.bs-wizard-step .bs-wizard-stepnum{color:#595959;font-size:16px;margin-bottom:5px}.bs-wizard>.bs-wizard-step .bs-wizard-info{color:#999;font-size:14px}.bs-wizard>.bs-wizard-step>.bs-wizard-dot{position:absolute;width:30px;height:30px;display:block;background:#fbe8aa;top:45px;left:50%;margin-top:-15px;margin-left:-15px;border-radius:50%}.bs-wizard>.bs-wizard-step>.bs-wizard-dot:after{content:" ";width:14px;height:14px;background:#fbbd19;border-radius:50px;position:absolute;top:8px;left:8px}.bs-wizard>.bs-wizard-step>.progress{position:relative;border-radius:0;height:8px;-webkit-box-shadow:none;box-shadow:none;margin:20px 0}.bs-wizard>.bs-wizard-step>.progress>.progress-bar{width:0;-webkit-box-shadow:none;box-shadow:none;background:#fbe8aa}.bs-wizard>.bs-wizard-step.complete>.progress>.progress-bar{width:100%}.bs-wizard>.bs-wizard-step.active>.progress>.progress-bar{width:50%}.bs-wizard>.bs-wizard-step:first-child.active>.progress>.progress-bar{width:0}.bs-wizard>.bs-wizard-step:last-child.active>.progress>.progress-bar{width:100%}.bs-wizard>.bs-wizard-step.disabled>.bs-wizard-dot{background-color:#f5f5f5}.bs-wizard>.bs-wizard-step.disabled>.bs-wizard-dot:after{opacity:0}.bs-wizard>.bs-wizard-step:first-child>.progress{left:50%;width:50%}.bs-wizard>.bs-wizard-step:last-child>.progress{width:50%}.bs-wizard>.bs-wizard-step.disabled a.bs-wizard-dot{pointer-events:none}.left-navblock{display:inline-block;float:left;text-align:left;color:#fff;padding:0}.skin-red .skin-purple .skin-blue .skin-black .skin-orange .skin-yellow .skin-green .skin-red-dark .skin-purple-dark .skin-blue-dark .skin-black-dark .skin-orange-dark .skin-yellow-dark .skin-green-dark .skin-contrast .main-header .navbar .dropdown-menu li a{color:#333}a.logo.no-hover a:hover{background-color:transparent}.required{border-right:6px solid orange}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:13px}.sidebar-menu{font-size:14px;white-space:normal}@media print{a[href]:after{content:none}.tab-content>.tab-pane{display:block!important;opacity:1!important;visibility:visible!important}}.navbar-brand>img,img.navbar-brand-img{float:left;padding:5px 5px 5px 0;max-height:50px}.input-daterange{border-radius:0}.btn.bg-maroon,.btn.bg-purple{min-width:90px}[hidden]{display:none!important}#toolbar{margin-top:10px}#uploadPreview{border:1px solid grey}.icon-med{font-size:20px;color:#889195}#login-logo{padding-top:20px;padding-bottom:10px;max-width:200px}a.skip-main{left:-999px;position:absolute;top:auto;width:1px;height:1px;overflow:hidden;z-index:-999}a.skip-main:active,a.skip-main:focus{color:#fff;background-color:#000;left:auto;top:auto;width:30%;height:auto;overflow:auto;margin:10px 35%;padding:5px;border-radius:15px;border:4px solid #ff0;text-align:center;font-size:1.2em;z-index:999}h2{font-size:22px}h3{font-size:20px}h4{font-size:16px}.row-striped{vertical-align:top;line-height:2.6;padding:0;margin-left:20px;-webkit-box-sizing:border-box;box-sizing:border-box;display:table}.row-striped .row:nth-of-type(odd) div{background-color:#f9f9f9;border-top:1px solid #ddd;display:table-cell}.row-striped .row:nth-of-type(2n) div{background:#fff;border-top:1px solid #ddd;display:table-cell} +.skin-red .skin-purple .skin-blue .skin-black .skin-orange .skin-yellow .skin-green .skin-red-dark .skin-purple-dark .skin-blue-dark .skin-black-dark .skin-orange-dark .skin-yellow-dark .skin-green-dark .skin-contrast .main-header .logo{background-color:inherit}.main-header .logo{width:100%!important;white-space:nowrap;text-align:left;display:block;clear:both}.main-header .logo a:hover,.main-header .logoa:link,.main-header .logo a:visited{color:#fff}.huge{font-size:40px}.btn-file{position:relative;overflow:hidden}.dropdown-menu>li>a{color:#354044}#sort tr.cansort{border-radius:2px;padding:10px;background:#f4f4f4;margin-bottom:3px;border-left:2px solid #e6e7e8;color:#444;cursor:move}.user-image-inline{float:left;width:25px;height:25px;border-radius:50%;margin-right:10px}.input-group .input-group-addon{background-color:#f4f4f4}a.accordion-header{color:#333}.dynamic-form-row{padding:10px;margin:20px}.handle{padding-left:10px}.btn-file input[type=file]{position:absolute;top:0;right:0;min-width:100%;min-height:100%;font-size:100px;text-align:right;filter:alpha(opacity=0);opacity:0;outline:none;background:#fff;cursor:inherit;display:block}.main-footer{font-size:13px}.main-header{max-height:150px}.navbar-nav>.user-menu>.dropdown-menu{width:inherit}.main-header .logo{padding:0 5px 0 15px}.sidebar-toggle{margin-left:-48px;z-index:100;background-color:inherit}.sidebar-toggle-mobile{z-index:100;width:50px;padding-top:10px}.main-header .sidebar-toggle:before{content:"\F0C9"}.direct-chat-contacts{padding:10px;height:150px}.select2-container{width:100%}.error input{color:#dd4b39;border:2px solid #dd4b39!important}.alert-msg,.error label{color:#dd4b39;display:block}.input-group[class*=col-]{padding-right:15px;padding-left:15px}.control-label.multiline{padding-top:10px}.btn-outline{color:inherit;background-color:transparent;-webkit-transition:all .5s;transition:all .5s}.btn-primary.btn-outline{color:#428bca}.btn-success.btn-outline{color:#5cb85c}.btn-info.btn-outline{color:#5bc0de}.btn-warning.btn-outline{color:#f0ad4e}.btn-danger.btn-outline{color:#d9534f}.btn-danger.btn-outline:hover,.btn-info.btn-outline:hover,.btn-primary.btn-outline:hover,.btn-success.btn-outline:hover,.btn-warning.btn-outline:hover{color:#fff}.slideout-menu{position:fixed;top:0;right:-250px;width:250px;height:100%;background:#333;z-index:100;margin-top:100px;color:#fff;padding:10px}.slideout-menu h3{position:relative;padding:5px;color:#fff;font-size:1.2em;font-weight:400;border-bottom:4px solid #222}.slideout-menu .slideout-menu-toggle{position:absolute;top:12px;right:10px;display:inline-block;padding:6px 9px 5px;font-family:Arial,sans-serif;font-weight:700;line-height:1;background:#222;color:#999;text-decoration:none;vertical-align:top}.slideout-menu .slideout-menu-toggle:hover{color:#fff}.slideout-menu ul{list-style:none;font-weight:300;border-top:1px solid #151515;border-bottom:1px solid #454545}.slideout-menu ul li{border-top:1px solid #454545;border-bottom:1px solid #151515}.slideout-menu ul li a{position:relative;display:block;padding:10px;color:#999;text-decoration:none}.slideout-menu ul li a:hover{background:#000;color:#fff}.slideout-menu ul li a i{position:absolute;top:15px;right:10px;opacity:.5}.btn-box-tool-lg{font-size:16px;color:orange}.bs-wizard{margin-top:20px;border-bottom:1px solid #e0e0e0;padding:0 0 10px}.bs-wizard>.bs-wizard-step{padding:0;position:relative}.bs-wizard>.bs-wizard-step .bs-wizard-stepnum{color:#595959;font-size:16px;margin-bottom:5px}.bs-wizard>.bs-wizard-step .bs-wizard-info{color:#999;font-size:14px}.bs-wizard>.bs-wizard-step>.bs-wizard-dot{position:absolute;width:30px;height:30px;display:block;background:#fbe8aa;top:45px;left:50%;margin-top:-15px;margin-left:-15px;border-radius:50%}.bs-wizard>.bs-wizard-step>.bs-wizard-dot:after{content:" ";width:14px;height:14px;background:#fbbd19;border-radius:50px;position:absolute;top:8px;left:8px}.bs-wizard>.bs-wizard-step>.progress{position:relative;border-radius:0;height:8px;-webkit-box-shadow:none;box-shadow:none;margin:20px 0}.bs-wizard>.bs-wizard-step>.progress>.progress-bar{width:0;-webkit-box-shadow:none;box-shadow:none;background:#fbe8aa}.bs-wizard>.bs-wizard-step.complete>.progress>.progress-bar{width:100%}.bs-wizard>.bs-wizard-step.active>.progress>.progress-bar{width:50%}.bs-wizard>.bs-wizard-step:first-child.active>.progress>.progress-bar{width:0}.bs-wizard>.bs-wizard-step:last-child.active>.progress>.progress-bar{width:100%}.bs-wizard>.bs-wizard-step.disabled>.bs-wizard-dot{background-color:#f5f5f5}.bs-wizard>.bs-wizard-step.disabled>.bs-wizard-dot:after{opacity:0}.bs-wizard>.bs-wizard-step:first-child>.progress{left:50%;width:50%}.bs-wizard>.bs-wizard-step:last-child>.progress{width:50%}.bs-wizard>.bs-wizard-step.disabled a.bs-wizard-dot{pointer-events:none}.left-navblock{display:inline-block;float:left;text-align:left;color:#fff;padding:0}.skin-red .skin-purple .skin-blue .skin-black .skin-orange .skin-yellow .skin-green .skin-red-dark .skin-purple-dark .skin-blue-dark .skin-black-dark .skin-orange-dark .skin-yellow-dark .skin-green-dark .skin-contrast .main-header .navbar .dropdown-menu li a{color:#333}a.logo.no-hover a:hover{background-color:transparent}.required{border-right:6px solid orange}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:13px}.sidebar-menu{font-size:14px;white-space:normal}@media print{a[href]:after{content:none}.tab-content>.tab-pane{display:block!important;opacity:1!important;visibility:visible!important}}.navbar-brand>img,img.navbar-brand-img{float:left;padding:5px 5px 5px 0;max-height:50px}.input-daterange{border-radius:0}.btn.bg-maroon,.btn.bg-purple{min-width:90px}[hidden]{display:none!important}#toolbar{margin-top:10px}#uploadPreview{border:1px solid grey}.icon-med{font-size:20px;color:#889195}#login-logo{padding-top:20px;padding-bottom:10px;max-width:200px}a.skip-main{left:-999px;position:absolute;top:auto;width:1px;height:1px;overflow:hidden;z-index:-999}a.skip-main:active,a.skip-main:focus{color:#fff;background-color:#000;left:auto;top:auto;width:30%;height:auto;overflow:auto;margin:10px 35%;padding:5px;border-radius:15px;border:4px solid #ff0;text-align:center;font-size:1.2em;z-index:999}h2{font-size:22px}h3{font-size:20px}h4{font-size:16px}.row-striped{vertical-align:top;line-height:2.6;padding:0;margin-left:20px;-webkit-box-sizing:border-box;box-sizing:border-box;display:table}.row-striped .row:nth-of-type(odd) div{background-color:#f9f9f9;border-top:1px solid #ddd;display:table-cell}.row-striped .row:nth-of-type(2n) div{background:#fff;border-top:1px solid #ddd;display:table-cell}th.css-accessory>.th-inner,th.css-barcode>.th-inner,th.css-consumable>.th-inner,th.css-license>.th-inner{font-size:0;line-height:4!important;text-align:left;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}th.css-accessory>.th-inner:before,th.css-barcode>.th-inner:before,th.css-consumable>.th-inner:before,th.css-license>.th-inner:before,th.css-padlock>.th-inner:before{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:20px}th.css-padlock>.th-inner:before{content:"\F023";padding-right:2px}th.css-barcode>.th-inner:before{content:"\F02A"}th.css-license>.th-inner:before{content:"\F0C7"}th.css-consumable>.th-inner:before{content:"\F043"}th.css-accessory>.th-inner:before{content:"\F11C"} /*# sourceMappingURL=overrides.css.map*/ \ No newline at end of file diff --git a/public/css/overrides.css.map b/public/css/overrides.css.map index 8f69f597f4..bfec6b1f14 100644 --- a/public/css/overrides.css.map +++ b/public/css/overrides.css.map @@ -1 +1 @@ -{"version":3,"sources":["webpack:///./resources/assets/less/overrides.less"],"names":[],"mappings":"AAAA,6OAkBE,yBAEF,mBACE,qBACA,mBACA,gBACA,cACA,WACA,iFACE,WAGJ,MACE,eAGF,UACI,kBACA,gBAGJ,oBACI,cAIJ,iBACA,kBACA,aACA,mBACA,kBACA,8BACA,WACA,YAGA,mBACE,WACA,WACA,YACA,kBACA,kBAGF,gCACE,yBAGF,mBACI,WAGJ,kBACE,aACA,YAIF,QACE,kBAGF,2BACI,kBACA,MACA,QACA,eACA,gBACA,gBACA,iBACA,wBACA,UACA,aACA,gBACA,eACA,cAEJ,aACE,eAEF,aACE,iBAIF,sCACE,cAEF,mBACE,qBAIF,gBACE,kBACA,YACA,yBAGF,uBACE,YACA,WACA,iBAwBF,oCACE,eAAS,CAGX,sBACE,aACA,aAIF,mBACE,WAEF,aACE,cACA,mCAGF,wBACE,cACA,cAGF,0BACQ,mBACA,kBAEN,yBACI,iBAGN,aACE,cACA,6BACA,8CAGF,yBACE,cAGF,yBACE,cAGF,sBACE,cAGF,yBACE,cAGF,wBACE,cAGF,uJACE,WAGF,eACC,eACA,MACA,aACA,YACA,YACA,gBACA,YACC,iBACA,WACA,aAEF,kBACC,kBACA,YACA,WACA,gBACA,gBACA,6BAED,qCACC,kBACA,SACA,WACA,qBACA,oBACA,6BACA,gBACA,cACA,gBACA,WACA,qBACA,mBAED,2CACC,WAED,kBACC,gBACA,gBACA,6BACA,gCAED,qBACC,6BACA,gCAED,uBACC,kBACA,cACA,aACA,WACA,qBAED,6BACC,gBACA,WAED,yBACC,kBACA,SACA,WACA,WAGA,iBACE,eACA,aAKF,WAAY,gBAGA,gCAAkC,iBAC9C,2BAA8B,UAAY,kBAE1C,8CAAiD,cAAgB,eAAiB,kBAClF,2CAA8C,WAAa,eAC3D,0CAA+C,kBAAoB,WAAa,YAAc,cAAgB,mBAAqB,SAAW,SAAW,iBAAmB,kBAAoB,kBAChM,gDAAqD,YAAc,WAAa,YAAc,mBAAqB,mBAAqB,kBAAoB,QAAU,SACtK,qCAA0C,kBAAoB,gBAAoB,WAAa,wCAAkB,cACjH,mDAA0D,QAAW,wCAAkB,mBACvF,4DAAmE,WACnE,0DAAiE,UACjE,sEAA6E,QAC7E,qEAA4E,WAC5E,mDAAwD,yBACxD,yDAA8D,UAC9D,iDAAuD,SAAW,UAClE,gDAAsD,UACtD,oDAAuD,oBAGxD,eACE,qBACA,WACA,gBACA,WACA,UAIF,mQAkBE,WAGF,wBACC,6BAID,UACE,8BAGF,KACE,oIAIA,eAGF,cACE,eACA,mBAGF,aACE,cACE,aAGF,uBACE,wBACA,oBACA,8BAIJ,uCACE,WACA,sBACA,gBAGF,iBACE,gBAGF,8BACE,eAGF,SACE,uBAGF,SACE,gBAGF,eACE,qBACA,CAIF,UACE,eACA,cAGF,YACE,iBACA,oBACA,gBAIF,YACE,YACA,kBACA,SACA,UACA,WACA,gBACA,aAEF,qCACE,WACA,sBACA,UACA,SACA,UACA,YACA,cACA,gBACA,YACA,mBACA,sBACA,kBACA,gBACA,YAGF,GACE,eAGF,GACE,eAGF,GACE,eAIF,aACE,mBACA,gBACA,UACA,iBACA,oDAGA,cAIF,uCACE,yBACA,0BACA,mBAIF,sCACE,gBACA,0BACA","file":"css/overrides.css","sourcesContent":[".skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n\n.logo {\n background-color: inherit;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n &a:link, a:hover, a:visited {\n color: #fff\n }\n}\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu>li>a {\n color: #354044;\n}\n\n\n#sort tr.cansort {\nborder-radius: 2px;\npadding: 10px;\nbackground: #f4f4f4;\nmargin-bottom: 3px;\nborder-left: 2px solid #e6e7e8;\ncolor: #444;\ncursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=file] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n.main-footer {\n font-size: 13px;\n}\n.main-header {\n max-height: 150px;\n}\n\n\n.navbar-nav>.user-menu>.dropdown-menu {\n width: inherit;\n}\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n //color: inherit;\n}\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n\n.select2-container {\n width: 100%;\n}\n.error input {\n color: #dd4b39;\n border: 2px solid #dd4b39 !important;\n}\n\n.error label, .alert-msg {\n color: #dd4b39;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n }\n .control-label.multiline {\n padding-top: 10px;\n }\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all .5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline {\n color: #d9534f;\n}\n\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n\tposition: fixed;\n\ttop: 0;\n\tright: -250px;\n\twidth: 250px;\n\theight: 100%;\n\tbackground: #333;\n\tz-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n.slideout-menu h3 {\n\tposition: relative;\n\tpadding: 5px 5px;\n\tcolor: #fff;\n\tfont-size: 1.2em;\n\tfont-weight: 400;\n\tborder-bottom: 4px solid #222;\n}\n.slideout-menu .slideout-menu-toggle {\n\tposition: absolute;\n\ttop: 12px;\n\tright: 10px;\n\tdisplay: inline-block;\n\tpadding: 6px 9px 5px;\n\tfont-family: Arial, sans-serif;\n\tfont-weight: bold;\n\tline-height: 1;\n\tbackground: #222;\n\tcolor: #999;\n\ttext-decoration: none;\n\tvertical-align: top;\n}\n.slideout-menu .slideout-menu-toggle:hover {\n\tcolor: #fff;\n}\n.slideout-menu ul {\n\tlist-style: none;\n\tfont-weight: 300;\n\tborder-top: 1px solid #151515;\n\tborder-bottom: 1px solid #454545;\n}\n.slideout-menu ul li {\n\tborder-top: 1px solid #454545;\n\tborder-bottom: 1px solid #151515;\n}\n.slideout-menu ul li a {\n\tposition: relative;\n\tdisplay: block;\n\tpadding: 10px;\n\tcolor: #999;\n\ttext-decoration: none;\n}\n.slideout-menu ul li a:hover {\n\tbackground: #000;\n\tcolor: #fff;\n}\n.slideout-menu ul li a i {\n\tposition: absolute;\n\ttop: 15px;\n\tright: 10px;\n\topacity: .5;\n}\n\n .btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n }\n\n\n\n .bs-wizard {margin-top: 20px;}\n\n /*Form Wizard*/\n .bs-wizard {border-bottom: solid 1px #e0e0e0; padding: 0 0 10px 0;}\n .bs-wizard > .bs-wizard-step {padding: 0; position: relative;}\n .bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n .bs-wizard > .bs-wizard-step .bs-wizard-stepnum {color: #595959; font-size: 16px; margin-bottom: 5px;}\n .bs-wizard > .bs-wizard-step .bs-wizard-info {color: #999; font-size: 14px;}\n .bs-wizard > .bs-wizard-step > .bs-wizard-dot {position: absolute; width: 30px; height: 30px; display: block; background: #fbe8aa; top: 45px; left: 50%; margin-top: -15px; margin-left: -15px; border-radius: 50%;}\n .bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {content: ' '; width: 14px; height: 14px; background: #fbbd19; border-radius: 50px; position: absolute; top: 8px; left: 8px; }\n .bs-wizard > .bs-wizard-step > .progress {position: relative; border-radius: 0px; height: 8px; box-shadow: none; margin: 20px 0;}\n .bs-wizard > .bs-wizard-step > .progress > .progress-bar {width:0px; box-shadow: none; background: #fbe8aa;}\n .bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {width:100%;}\n .bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {width:50%;}\n .bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {width:0%;}\n .bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {width: 100%;}\n .bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {background-color: #f5f5f5;}\n .bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {opacity: 0;}\n .bs-wizard > .bs-wizard-step:first-child > .progress {left: 50%; width: 50%;}\n .bs-wizard > .bs-wizard-step:last-child > .progress {width: 50%;}\n .bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot{ pointer-events: none; }\n /*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n\n}\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n\n.required {\n border-right: 6px solid orange;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont,\n \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\",\n \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n@media print {\n a[href]:after {\n content: none;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n}\n\nimg.navbar-brand-img, .navbar-brand>img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange {\n border-radius: 0px;\n}\n\n.btn.bg-maroon, .btn.bg-purple{\n min-width:90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid\n}\n\n.icon-med {\n font-size: 20px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px\n}\n\n// accessibility skip link\na.skip-main {\n left:-999px;\n position:absolute;\n top:auto;\n width:1px;\n height:1px;\n overflow:hidden;\n z-index:-999;\n}\na.skip-main:focus, a.skip-main:active {\n color: #fff;\n background-color:#000;\n left: auto;\n top: auto;\n width: 30%;\n height: auto;\n overflow:auto;\n margin: 10px 35%;\n padding:5px;\n border-radius: 15px;\n border:4px solid yellow;\n text-align:center;\n font-size:1.2em;\n z-index:999;\n}\n\nh2 {\n font-size: 22px;\n}\n\nh3 {\n font-size: 20px;\n}\n\nh4 {\n font-size: 16px;\n}\n\n\n.row-striped {\n vertical-align: top;\n line-height: 2.6;\n padding: 0px;\n margin-left: 20px;\n box-sizing: border-box;\n //border-left: 1px solid #dddddd;\n //border-right: 1px solid #dddddd;\n display: table;\n\n}\n\n.row-striped .row:nth-of-type(odd) div {\n background-color: #f9f9f9;\n border-top: 1px solid #dddddd;\n display: table-cell;\n\n}\n\n.row-striped .row:nth-of-type(even) div {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n display: table-cell;\n}\n\n\n\n// WEBPACK FOOTER //\n// ./resources/assets/less/overrides.less"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack:///./resources/assets/less/overrides.less"],"names":[],"mappings":"AAAA,6OAkBE,yBAEF,mBACE,qBACA,mBACA,gBACA,cACA,WACA,iFACE,WAGJ,MACE,eAGF,UACI,kBACA,gBAGJ,oBACI,cAIJ,iBACA,kBACA,aACA,mBACA,kBACA,8BACA,WACA,YAGA,mBACE,WACA,WACA,YACA,kBACA,kBAGF,gCACE,yBAGF,mBACI,WAGJ,kBACE,aACA,YAIF,QACE,kBAGF,2BACI,kBACA,MACA,QACA,eACA,gBACA,gBACA,iBACA,wBACA,UACA,aACA,gBACA,eACA,cAEJ,aACE,eAEF,aACE,iBAIF,sCACE,cAEF,mBACE,qBAIF,gBACE,kBACA,YACA,yBAGF,uBACE,YACA,WACA,iBAwBF,oCACE,eAAS,CAGX,sBACE,aACA,aAIF,mBACE,WAEF,aACE,cACA,mCAGF,wBACE,cACA,cAGF,0BACQ,mBACA,kBAEN,yBACI,iBAGN,aACE,cACA,6BACA,8CAGF,yBACE,cAGF,yBACE,cAGF,sBACE,cAGF,yBACE,cAGF,wBACE,cAGF,uJACE,WAGF,eACC,eACA,MACA,aACA,YACA,YACA,gBACA,YACC,iBACA,WACA,aAEF,kBACC,kBACA,YACA,WACA,gBACA,gBACA,6BAED,qCACC,kBACA,SACA,WACA,qBACA,oBACA,6BACA,gBACA,cACA,gBACA,WACA,qBACA,mBAED,2CACC,WAED,kBACC,gBACA,gBACA,6BACA,gCAED,qBACC,6BACA,gCAED,uBACC,kBACA,cACA,aACA,WACA,qBAED,6BACC,gBACA,WAED,yBACC,kBACA,SACA,WACA,WAGA,iBACE,eACA,aAKF,WAAY,gBAGA,gCAAkC,iBAC9C,2BAA8B,UAAY,kBAE1C,8CAAiD,cAAgB,eAAiB,kBAClF,2CAA8C,WAAa,eAC3D,0CAA+C,kBAAoB,WAAa,YAAc,cAAgB,mBAAqB,SAAW,SAAW,iBAAmB,kBAAoB,kBAChM,gDAAqD,YAAc,WAAa,YAAc,mBAAqB,mBAAqB,kBAAoB,QAAU,SACtK,qCAA0C,kBAAoB,gBAAoB,WAAa,wCAAkB,cACjH,mDAA0D,QAAW,wCAAkB,mBACvF,4DAAmE,WACnE,0DAAiE,UACjE,sEAA6E,QAC7E,qEAA4E,WAC5E,mDAAwD,yBACxD,yDAA8D,UAC9D,iDAAuD,SAAW,UAClE,gDAAsD,UACtD,oDAAuD,oBAGxD,eACE,qBACA,WACA,gBACA,WACA,UAIF,mQAkBE,WAGF,wBACC,6BAID,UACE,8BAGF,KACE,oIAIA,eAGF,cACE,eACA,mBAGF,aACE,cACE,aAGF,uBACE,wBACA,oBACA,8BAIJ,uCACE,WACA,sBACA,gBAGF,iBACE,gBAGF,8BACE,eAGF,SACE,uBAGF,SACE,gBAGF,eACE,qBACA,CAIF,UACE,eACA,cAGF,YACE,iBACA,oBACA,gBAIF,YACE,YACA,kBACA,SACA,UACA,WACA,gBACA,aAEF,qCACE,WACA,sBACA,UACA,SACA,UACA,YACA,cACA,gBACA,YACA,mBACA,sBACA,kBACA,gBACA,YAGF,GACE,eAGF,GACE,eAGF,GACE,eAIF,aACE,mBACA,gBACA,UACA,iBACA,oDAGA,cAIF,uCACE,yBACA,0BACA,mBAIF,sCACE,gBACA,0BACA,mBAoBF,yGAKE,YACA,wBACA,gBACA,oBACA,mCACA,kCAIF,qKAOE,qBACA,6CACA,eAGF,gCAEE,gBACA,kBAGF,gCAEE,eAAS,CAGX,gCAEE,eAAS,CAGX,mCAEE,eAAS,CAGX,kCAEE,eAAS","file":"css/overrides.css","sourcesContent":[".skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n\n.logo {\n background-color: inherit;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n &a:link, a:hover, a:visited {\n color: #fff\n }\n}\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu>li>a {\n color: #354044;\n}\n\n\n#sort tr.cansort {\nborder-radius: 2px;\npadding: 10px;\nbackground: #f4f4f4;\nmargin-bottom: 3px;\nborder-left: 2px solid #e6e7e8;\ncolor: #444;\ncursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=file] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n.main-footer {\n font-size: 13px;\n}\n.main-header {\n max-height: 150px;\n}\n\n\n.navbar-nav>.user-menu>.dropdown-menu {\n width: inherit;\n}\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n //color: inherit;\n}\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n\n.select2-container {\n width: 100%;\n}\n.error input {\n color: #dd4b39;\n border: 2px solid #dd4b39 !important;\n}\n\n.error label, .alert-msg {\n color: #dd4b39;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n }\n .control-label.multiline {\n padding-top: 10px;\n }\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all .5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline {\n color: #d9534f;\n}\n\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n\tposition: fixed;\n\ttop: 0;\n\tright: -250px;\n\twidth: 250px;\n\theight: 100%;\n\tbackground: #333;\n\tz-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n.slideout-menu h3 {\n\tposition: relative;\n\tpadding: 5px 5px;\n\tcolor: #fff;\n\tfont-size: 1.2em;\n\tfont-weight: 400;\n\tborder-bottom: 4px solid #222;\n}\n.slideout-menu .slideout-menu-toggle {\n\tposition: absolute;\n\ttop: 12px;\n\tright: 10px;\n\tdisplay: inline-block;\n\tpadding: 6px 9px 5px;\n\tfont-family: Arial, sans-serif;\n\tfont-weight: bold;\n\tline-height: 1;\n\tbackground: #222;\n\tcolor: #999;\n\ttext-decoration: none;\n\tvertical-align: top;\n}\n.slideout-menu .slideout-menu-toggle:hover {\n\tcolor: #fff;\n}\n.slideout-menu ul {\n\tlist-style: none;\n\tfont-weight: 300;\n\tborder-top: 1px solid #151515;\n\tborder-bottom: 1px solid #454545;\n}\n.slideout-menu ul li {\n\tborder-top: 1px solid #454545;\n\tborder-bottom: 1px solid #151515;\n}\n.slideout-menu ul li a {\n\tposition: relative;\n\tdisplay: block;\n\tpadding: 10px;\n\tcolor: #999;\n\ttext-decoration: none;\n}\n.slideout-menu ul li a:hover {\n\tbackground: #000;\n\tcolor: #fff;\n}\n.slideout-menu ul li a i {\n\tposition: absolute;\n\ttop: 15px;\n\tright: 10px;\n\topacity: .5;\n}\n\n .btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n }\n\n\n\n .bs-wizard {margin-top: 20px;}\n\n /*Form Wizard*/\n .bs-wizard {border-bottom: solid 1px #e0e0e0; padding: 0 0 10px 0;}\n .bs-wizard > .bs-wizard-step {padding: 0; position: relative;}\n .bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n .bs-wizard > .bs-wizard-step .bs-wizard-stepnum {color: #595959; font-size: 16px; margin-bottom: 5px;}\n .bs-wizard > .bs-wizard-step .bs-wizard-info {color: #999; font-size: 14px;}\n .bs-wizard > .bs-wizard-step > .bs-wizard-dot {position: absolute; width: 30px; height: 30px; display: block; background: #fbe8aa; top: 45px; left: 50%; margin-top: -15px; margin-left: -15px; border-radius: 50%;}\n .bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {content: ' '; width: 14px; height: 14px; background: #fbbd19; border-radius: 50px; position: absolute; top: 8px; left: 8px; }\n .bs-wizard > .bs-wizard-step > .progress {position: relative; border-radius: 0px; height: 8px; box-shadow: none; margin: 20px 0;}\n .bs-wizard > .bs-wizard-step > .progress > .progress-bar {width:0px; box-shadow: none; background: #fbe8aa;}\n .bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {width:100%;}\n .bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {width:50%;}\n .bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {width:0%;}\n .bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {width: 100%;}\n .bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {background-color: #f5f5f5;}\n .bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {opacity: 0;}\n .bs-wizard > .bs-wizard-step:first-child > .progress {left: 50%; width: 50%;}\n .bs-wizard > .bs-wizard-step:last-child > .progress {width: 50%;}\n .bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot{ pointer-events: none; }\n /*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n\n}\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n\n.required {\n border-right: 6px solid orange;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont,\n \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\",\n \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n@media print {\n a[href]:after {\n content: none;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n}\n\nimg.navbar-brand-img, .navbar-brand>img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange {\n border-radius: 0px;\n}\n\n.btn.bg-maroon, .btn.bg-purple{\n min-width:90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid\n}\n\n.icon-med {\n font-size: 20px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px\n}\n\n// accessibility skip link\na.skip-main {\n left:-999px;\n position:absolute;\n top:auto;\n width:1px;\n height:1px;\n overflow:hidden;\n z-index:-999;\n}\na.skip-main:focus, a.skip-main:active {\n color: #fff;\n background-color:#000;\n left: auto;\n top: auto;\n width: 30%;\n height: auto;\n overflow:auto;\n margin: 10px 35%;\n padding:5px;\n border-radius: 15px;\n border:4px solid yellow;\n text-align:center;\n font-size:1.2em;\n z-index:999;\n}\n\nh2 {\n font-size: 22px;\n}\n\nh3 {\n font-size: 20px;\n}\n\nh4 {\n font-size: 16px;\n}\n\n\n.row-striped {\n vertical-align: top;\n line-height: 2.6;\n padding: 0px;\n margin-left: 20px;\n box-sizing: border-box;\n //border-left: 1px solid #dddddd;\n //border-right: 1px solid #dddddd;\n display: table;\n\n}\n\n.row-striped .row:nth-of-type(odd) div {\n background-color: #f9f9f9;\n border-top: 1px solid #dddddd;\n display: table-cell;\n\n}\n\n.row-striped .row:nth-of-type(even) div {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n display: table-cell;\n}\n\n\n\n\n/**\n\n COLUMN SELECTOR ICONS\n -----------------------------\n This is kind of weird, but it is necessary to prevent the column-selector code from barfing, since\n any HTML used in the UserPresenter \"title\" attribute breaks the column selector HTML.\n\n Instead, we use CSS to add the icon into the table header, which leaves the column selector\n \"title\" text as-is.\n\n See https://github.com/snipe/snipe-it/issues/7989\n\n */\n\nth.css-barcode > .th-inner,\nth.css-license > .th-inner,\nth.css-consumable > .th-inner,\nth.css-accessory > .th-inner\n{\n font-size: 0px;\n line-height: 4!important;\n text-align: left;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n\nth.css-padlock > .th-inner::before,\nth.css-barcode > .th-inner::before,\nth.css-license > .th-inner::before,\nth.css-consumable > .th-inner::before,\nth.css-accessory > .th-inner::before\n\n{\n display: inline-block;\n font: normal normal normal 14px/1 FontAwesome;\n font-size: 20px;\n}\n\nth.css-padlock > .th-inner::before\n{\n content: \"\\f023\";\n padding-right: 2px;\n}\n\nth.css-barcode > .th-inner::before\n{\n content: \"\\f02a\";\n}\n\nth.css-license > .th-inner::before\n{\n content: \"\\f0c7\";\n}\n\nth.css-consumable > .th-inner::before\n{\n content: \"\\f043\";\n}\n\nth.css-accessory > .th-inner::before\n{\n content: \"\\f11c\";\n}\n\n\n// WEBPACK FOOTER //\n// ./resources/assets/less/overrides.less"],"sourceRoot":""} \ No newline at end of file diff --git a/resources/assets/js/components/importer/importer-file.vue b/resources/assets/js/components/importer/importer-file.vue index 4bcad9cce0..8dba9fe5d9 100644 --- a/resources/assets/js/components/importer/importer-file.vue +++ b/resources/assets/js/components/importer/importer-file.vue @@ -1,15 +1,9 @@ - - + \ No newline at end of file diff --git a/resources/assets/js/components/passport/Clients.vue b/resources/assets/js/components/passport/Clients.vue index 936786a87a..ee5db67742 100644 --- a/resources/assets/js/components/passport/Clients.vue +++ b/resources/assets/js/components/passport/Clients.vue @@ -83,7 +83,7 @@ @@ -151,7 +151,7 @@ diff --git a/resources/assets/less/overrides.less b/resources/assets/less/overrides.less index 21f8fc5012..d189a90796 100644 --- a/resources/assets/less/overrides.less +++ b/resources/assets/less/overrides.less @@ -466,6 +466,74 @@ h4 { display: table-cell; } + + + +/** + + COLUMN SELECTOR ICONS + ----------------------------- + This is kind of weird, but it is necessary to prevent the column-selector code from barfing, since + any HTML used in the UserPresenter "title" attribute breaks the column selector HTML. + + Instead, we use CSS to add the icon into the table header, which leaves the column selector + "title" text as-is. + + See https://github.com/snipe/snipe-it/issues/7989 + + */ + +th.css-barcode > .th-inner, +th.css-license > .th-inner, +th.css-consumable > .th-inner, +th.css-accessory > .th-inner +{ + font-size: 0px; + line-height: 4!important; + text-align: left; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + + +th.css-padlock > .th-inner::before, +th.css-barcode > .th-inner::before, +th.css-license > .th-inner::before, +th.css-consumable > .th-inner::before, +th.css-accessory > .th-inner::before + +{ + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: 20px; +} + +th.css-padlock > .th-inner::before +{ + content: "\f023"; + padding-right: 2px; +} + +th.css-barcode > .th-inner::before +{ + content: "\f02a"; +} + +th.css-license > .th-inner::before +{ + content: "\f0c7"; +} + +th.css-consumable > .th-inner::before +{ + content: "\f043"; +} + +th.css-accessory > .th-inner::before +{ + content: "\f11c"; +} .small-box .inner { padding-left: 15px; padding-right: 15px; diff --git a/resources/lang/en-GB/general.php b/resources/lang/en-GB/general.php index 6efb25c645..8a4e332ad8 100644 --- a/resources/lang/en-GB/general.php +++ b/resources/lang/en-GB/general.php @@ -88,6 +88,9 @@ 'firstname_lastname_underscore_format' => 'First Name Last Name (jane_smith@example.com)', 'lastnamefirstinitial_format' => 'Last Name First Initial (smithj@example.com)', 'first' => 'First', + 'firstnamelastname' => 'First Name Last Name (janesmith@example.com)', + 'lastname_firstinitial' => 'Last Name First Initial (smith_j@example.com)', + 'firstinitial.lastname' => 'First Initial Last Name (j.smith@example.com)', 'first' => 'First', 'first_name' => 'First Name', 'first_name_format' => 'First Name (jane@example.com)', 'files' => 'Files', diff --git a/resources/lang/en/admin/licenses/message.php b/resources/lang/en/admin/licenses/message.php index 3e7ee486c7..87a7c3d0b9 100644 --- a/resources/lang/en/admin/licenses/message.php +++ b/resources/lang/en/admin/licenses/message.php @@ -8,6 +8,7 @@ return array( 'owner_doesnt_match_asset' => 'The asset you are trying to associate with this license is owned by somene other than the person selected in the assigned to dropdown.', 'assoc_users' => 'This license is currently checked out to a user and cannot be deleted. Please check the license in first, and then try deleting again. ', 'select_asset_or_person' => 'You must select an asset or a user, but not both.', + 'not_found' => 'License not found', 'create' => array( diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index 962bfb8341..27e456042a 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -91,6 +91,11 @@ 'lastnamefirstinitial_format' => 'Last Name First Initial (smithj@example.com)', 'firstintial_dot_lastname_format' => 'First Initial Last Name (j.smith@example.com)', 'first' => 'First', + 'firstnamelastname' => 'First Name Last Name (janesmith@example.com)', + 'lastname_firstinitial' => 'Last Name First Initial (smith_j@example.com)', + 'firstinitial.lastname' => 'First Initial Last Name (j.smith@example.com)', + 'firstnamelastinitial' => 'First Name Last Initial (janes@example.com)', + 'first' => 'First', 'first_name' => 'First Name', 'first_name_format' => 'First Name (jane@example.com)', 'files' => 'Files', diff --git a/resources/macros/macros.php b/resources/macros/macros.php index 40b0921c6d..5474db204a 100644 --- a/resources/macros/macros.php +++ b/resources/macros/macros.php @@ -464,11 +464,14 @@ Form::macro('username_format', function ($name = "username_format", $selected = $formats = array( 'firstname.lastname' => trans('general.firstname_lastname_format'), - 'firstname_lastname' => trans('general.firstname_lastname_underscore_format'), - 'filastname' => trans('general.filastname_format'), - 'firstintial.lastname' => trans('general.firstintial_dot_lastname_format'), 'firstname' => trans('general.first_name_format'), + 'filastname' => trans('general.filastname_format'), 'lastnamefirstinitial' => trans('general.lastnamefirstinitial_format'), + 'firstname_lastname' => trans('general.firstname_lastname_underscore_format'), + 'firstinitial.lastname' => trans('general.firstinitial.lastname'), + 'lastname_firstinitial' => trans('general.lastname_firstinitial'), + 'firstnamelastname' => trans('general.firstnamelastname'), + 'firstnamelastinitial' => trans('general.firstnamelastinitial') ); $select = ' - Generate + Generate
-
+
diff --git a/resources/views/reports/activity.blade.php b/resources/views/reports/activity.blade.php index ac01ddfe16..a580386b8c 100644 --- a/resources/views/reports/activity.blade.php +++ b/resources/views/reports/activity.blade.php @@ -37,7 +37,7 @@ - Icon + Icon {{ trans('general.date') }} {{ trans('general.admin') }} {{ trans('general.action') }} diff --git a/resources/views/users/bulk-edit.blade.php b/resources/views/users/bulk-edit.blade.php index b62a73b2a2..6f401c8767 100644 --- a/resources/views/users/bulk-edit.blade.php +++ b/resources/views/users/bulk-edit.blade.php @@ -55,6 +55,15 @@ + +
+ +
+ + {!! $errors->first('city', '') !!} +
+
+
diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php index 4ca154a596..b28a3fdc9b 100755 --- a/resources/views/users/index.blade.php +++ b/resources/views/users/index.blade.php @@ -15,66 +15,6 @@ @section('header_right') - - @can('create', \App\Models\User::class) @if ($snipeSettings->ldap_enabled == 1) LDAP Sync @@ -153,6 +93,7 @@ @section('moar_scripts') + @include ('partials.bootstrap-table') diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index 3194a90bbf..6fb5dec20f 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -142,11 +142,31 @@ {{ trans('admin/users/table.name') }} {{ $user->present()->fullName() }} + {{ trans('admin/users/table.username') }} {{ $user->username }} + @if (($user->address) || ($user->city) || ($user->state) || ($user->country)) + + {{ trans('general.address') }} + + @if ($user->address) + {{ $user->address }}
+ @endif + @if ($user->city) + {{ $user->city }} + @endif + @if ($user->state) + {{ $user->state }} + @endif + @if ($user->country) + {{ $user->country }} + @endif + + + @endif {{ trans('general.groups') }} @@ -244,6 +264,13 @@ {{ trans('general.login_enabled') }} {{ ($user->activated=='1') ? trans('general.yes') : trans('general.no') }} + @if ($user->ldap_import!='1') + + LDAP + {{ trans('general.yes') }} + + @endif + @if ($user->activated=='1') @@ -278,6 +305,13 @@ @endif + @if ($user->notes) + + {{ trans('admin/users/table.notes') }} + {{ $user->notes }} + + @endif +
@@ -541,7 +575,7 @@ }'> - Icon + Icon {{ trans('general.date') }} {{ trans('general.admin') }} {{ trans('general.action') }} diff --git a/routes/api.php b/routes/api.php index 058c52bbb3..ee5fe63191 100644 --- a/routes/api.php +++ b/routes/api.php @@ -233,12 +233,21 @@ Route::group(['prefix' => 'v1','namespace' => 'Api', 'middleware' => 'auth:api'] ] ); // Consumables resource - Route::get('consumables/view/{id}/users', - [ - 'as' => 'api.consumables.showUsers', - 'uses' => 'ConsumablesController@getDataView' - ] - ); + Route::group(['prefix' => 'consumables'], function () { + Route::get('view/{id}/users', + [ + 'as' => 'api.consumables.showUsers', + 'uses' => 'ConsumablesController@getDataView' + ] + ); + + Route::post('{consumable}/checkout', + [ + 'as' => 'api.consumables.checkout', + 'uses' => 'ConsumablesController@checkout' + ] + ); + }); /*--- Depreciations API ---*/ diff --git a/routes/web/fields.php b/routes/web/fields.php index d95f8e5546..a2fedcfd93 100644 --- a/routes/web/fields.php +++ b/routes/web/fields.php @@ -17,7 +17,6 @@ Route::group([ 'prefix' => 'fields','middleware' => ['auth'] ], function () { 'as' => 'fields.optional'] ); - Route::get('{field_id}/fieldset/{fieldset_id}/disassociate', ['uses' => 'CustomFieldsController@deleteFieldFromFieldset', 'as' => 'fields.disassociate'] diff --git a/snipeit.sh b/snipeit.sh index d70365e4f0..bd4b1b80e8 100755 --- a/snipeit.sh +++ b/snipeit.sh @@ -438,7 +438,7 @@ case $distro in fi ;; ubuntu) - if [ "$version" == "18.04" ]; then + if [ "$version" -ge "18.04" ]; then # Install for Ubuntu 18.04 tzone=$(cat /etc/timezone) diff --git a/tests/unit/UserTest.php b/tests/unit/UserTest.php index 6624363b6d..85ae9054d0 100644 --- a/tests/unit/UserTest.php +++ b/tests/unit/UserTest.php @@ -33,7 +33,7 @@ class UserTest extends BaseTest $fullname = "Natalia Allanovna Romanova-O'Shostakova"; $expected_firstname = 'Natalia'; $expected_lastname = "Allanovna Romanova-O'Shostakova"; - $user = User::generateFormattedNameFromFullName($fullname, 'firstname'); + $user = User::generateFormattedNameFromFullName('firstname', $fullname); $this->assertEquals($expected_firstname, $user['first_name']); $this->assertEquals($expected_lastname, $user['last_name']); } @@ -74,7 +74,7 @@ class UserTest extends BaseTest public function testFirstInitialUnderscoreLastName() { $fullname = "Natalia Allanovna Romanova-O'Shostakova"; - $expected_username = 'natalia_allanovna-romanova-oshostakova'; + $expected_username = 'n_allanovna-romanova-oshostakova'; $user = User::generateFormattedNameFromFullName($fullname, 'firstname_lastname'); $this->assertEquals($expected_username, $user['username']); } @@ -83,9 +83,36 @@ class UserTest extends BaseTest { $fullname = "Natalia"; $expected_username = 'natalia'; - $user = User::generateFormattedNameFromFullName($fullname, 'firstname_lastname'); + $user = User::generateFormattedNameFromFullName('firstname_lastname', $fullname); + $this->assertEquals($expected_username, $user['username']); + } + public function firstInitialDotLastname() + { + $fullname = "Natalia Allanovna Romanova-O'Shostakova"; + $expected_username = 'n.allanovnaromanovaoshostakova'; + $user = User::generateFormattedNameFromFullName($fullname, 'firstinitial.lastname'); + $this->assertEquals($expected_username, $user['username']); + } + public function lastNameUnderscoreFirstInitial() + { + $fullname = "Natalia Allanovna Romanova-O'Shostakova"; + $expected_username = 'allanovnaromanovaoshostakova_n'; + $user = User::generateFormattedNameFromFullName($fullname, 'lastname_firstinitial'); + $this->assertEquals($expected_username, $user['username']); + } + public function firstNameLastName() + { + $fullname = "Natalia Allanovna Romanova-O'Shostakova"; + $expected_username = 'nataliaallanovnaromanovaoshostakova'; + $user = User::generateFormattedNameFromFullName($fullname, 'firstnamelastname)'; + $this->assertEquals($expected_username, $user['username']); + } + public function firstNameLastInitial() + { + $fullname = "Natalia Allanovna Romanova-O'Shostakova"; + $expected_username = 'nataliaa'; + $user = User::generateFormattedNameFromFullName($fullname, 'firstnamelastinitial'); $this->assertEquals($expected_username, $user['username']); } - }