Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9e19468e5 | |||
| 5b68a321a6 | |||
| 37568ae9ec | |||
| 32ad9050cf | |||
| 01a832169c | |||
| 3c6883489c | |||
| bcad49ce79 | |||
| b5acca89d7 | |||
| e52919cf1b | |||
| 29f3a5c48f | |||
| 134e8e6fb9 | |||
| 714576be45 | |||
| 5128992940 | |||
| 0291323502 | |||
| e0f6f9b839 | |||
| f1a6308002 | |||
| b999c50a2e | |||
| e3906b245c | |||
| 9ca20e4964 | |||
| 456a74d88c | |||
| 799c059070 | |||
| c62d43a778 | |||
| b725bd0fae | |||
| e0644dbbf6 | |||
| 5b6925b00c | |||
| df17a859bf | |||
| 24c43056ba | |||
| 606b7e905d | |||
| d73ddad477 | |||
| 9a39cf721e | |||
| 7410b16835 | |||
| 8994f3e15e | |||
| d23f1a77ca | |||
| e955c983a3 | |||
| b09e7d19b3 | |||
| 2fa17ac185 | |||
| 3b1e46f72b | |||
| 0c1a1de2a2 | |||
| 20c9ae5818 | |||
| eed41e4549 | |||
| b750f4754f | |||
| c17a06792a | |||
| 4f76cc6cfb | |||
| b905154373 | |||
| daf748e531 | |||
| 799a93c46a | |||
| 34aa12e229 | |||
| 897757bd04 | |||
| c7125c3937 | |||
| 81a6332889 | |||
| 6e563f6e4b | |||
| 5320f5c67c | |||
| 7f69ae953b | |||
| 17f6fbabfa | |||
| c79f8c1baf | |||
| e7a820f7c9 | |||
| 12c92e30b7 | |||
| fd10b755b0 | |||
| dbbb7680d9 | |||
| cf0dd5bbad | |||
| 25e53d8c7f | |||
| 89d433b41a | |||
| e2570ada6f | |||
| 45afe725a1 | |||
| 536401fe0f | |||
| ec6ed256fb | |||
| 2aaa7bed2d | |||
| cc9f1577a4 | |||
| ab1fe8be0c | |||
| 339bdddc38 | |||
| 35b9cf4b70 | |||
| 7ccb41371e | |||
| 2e60a457bf | |||
| 2390d2160b | |||
| 00b051b8c7 | |||
| 05b3a9ad7e | |||
| 4fb880384f | |||
| 43042ad841 | |||
| a716382ac4 | |||
| 36c8f7f4f1 | |||
| b42801f6ae | |||
| 946129f206 | |||
| b941ef1e08 | |||
| d1aa11ec89 | |||
| de4934f21d | |||
| b10076b015 | |||
| af06e42056 | |||
| 9a2440dc4b | |||
| 2ac1c1636c | |||
| 004ecad059 | |||
| beae8efb21 | |||
| 9839e5e566 | |||
| d14ab7e3e1 | |||
| e7f74d94c1 | |||
| e97cf011b6 | |||
| ed23505054 | |||
| 001e721530 | |||
| 8210da6e82 | |||
| f88683766b | |||
| e4385c0f8c | |||
| 0550fe0ffa | |||
| 7fb3a9b82c | |||
| ecb1e87fe6 | |||
| f43df5f041 | |||
| 95cc48e422 | |||
| 9a2ed804ca | |||
| d20fad28e5 | |||
| ae813ddf75 | |||
| bb42109c0c | |||
| f46ecf8ec0 | |||
| b9e821c0e6 | |||
| 9ee28c7513 | |||
| 1a8ba06702 | |||
| 0fd232e70d | |||
| ee4d69b1c5 | |||
| d1ad111949 | |||
| 31c5350941 | |||
| 7eb70e17e0 | |||
| 3dfcb46991 | |||
| 96eb96f964 | |||
| a2f08bd3ba | |||
| e009fbe59f | |||
| 5bb4f271aa | |||
| 154db9a416 | |||
| cf9d0201e0 | |||
| 7ebd21bc04 | |||
| 5707df0239 | |||
| 197a84be94 | |||
| b4fa4c77d7 | |||
| cfec142c3b |
@@ -1722,6 +1722,15 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "alek13",
|
||||
"name": "Alexander Chibrikin",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/1972329?v=4",
|
||||
"profile": "http://phpprofi.ru/",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -71,6 +71,7 @@ ALLOW_IFRAMING=false
|
||||
REFERRER_POLICY=same-origin
|
||||
ENABLE_CSP=false
|
||||
CORS_ALLOWED_ORIGINS=null
|
||||
ENABLE_HSTS=false
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: CACHE SETTINGS
|
||||
|
||||
@@ -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
|
||||
@@ -1,5 +1,5 @@
|
||||
[](https://travis-ci.org/snipe/snipe-it) [](https://crowdin.com/project/snipe-it) [](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeitapp) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[](#contributors) [](https://www.codetriage.com/snipe/snipe-it)
|
||||
[](#contributors) [](https://www.codetriage.com/snipe/snipe-it)
|
||||
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
@@ -106,7 +106,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<img src="https://avatars0.githubusercontent.com/u/1680266?v=4" width="110px;"/><br /><sub>saymd</sub>](https://github.com/saymd)<br />[🌍](#translation-saymd "Translation") | [<img src="https://avatars0.githubusercontent.com/u/1826808?v=4" width="110px;"/><br /><sub>Patrik Larsson</sub>](https://nordsken.se)<br />[🌍](#translation-pooot "Translation") | [<img src="https://avatars1.githubusercontent.com/u/20584746?v=4" width="110px;"/><br /><sub>drcryo</sub>](https://github.com/drcryo)<br />[🌍](#translation-drcryo "Translation") | [<img src="https://avatars1.githubusercontent.com/u/19408004?v=4" width="110px;"/><br /><sub>pawel1615</sub>](https://github.com/pawel1615)<br />[🌍](#translation-pawel1615 "Translation") | [<img src="https://avatars2.githubusercontent.com/u/23340468?v=4" width="110px;"/><br /><sub>bodrovics</sub>](https://github.com/bodrovics)<br />[🌍](#translation-bodrovics "Translation") | [<img src="https://avatars0.githubusercontent.com/u/3257654?v=4" width="110px;"/><br /><sub>priatna</sub>](https://github.com/priatna)<br />[🌍](#translation-priatna "Translation") | [<img src="https://avatars1.githubusercontent.com/u/5358374?v=4" width="110px;"/><br /><sub>Fan Jiang</sub>](https://amayume.net)<br />[🌍](#translation-ProfFan "Translation") |
|
||||
| [<img src="https://avatars1.githubusercontent.com/u/22555451?v=4" width="110px;"/><br /><sub>ragnarcx</sub>](https://github.com/ragnarcx)<br />[🌍](#translation-ragnarcx "Translation") | [<img src="https://avatars2.githubusercontent.com/u/18654582?v=4" width="110px;"/><br /><sub>Rein van Haaren</sub>](http://www.reinvanhaaren.nl/)<br />[🌍](#translation-reinvanhaaren "Translation") | [<img src="https://avatars1.githubusercontent.com/u/386672?v=4" width="110px;"/><br /><sub>Teguh Dwicaksana</sub>](http://dheche.songolimo.net)<br />[🌍](#translation-dheche "Translation") | [<img src="https://avatars2.githubusercontent.com/u/2572552?v=4" width="110px;"/><br /><sub>fraccie</sub>](https://github.com/FRaccie)<br />[🌍](#translation-FRaccie "Translation") | [<img src="https://avatars0.githubusercontent.com/u/35182720?v=4" width="110px;"/><br /><sub>vinzruzell</sub>](https://github.com/vinzruzell)<br />[🌍](#translation-vinzruzell "Translation") | [<img src="https://avatars1.githubusercontent.com/u/7883603?v=4" width="110px;"/><br /><sub>Kevin Austin</sub>](http://kevinaustin.com)<br />[🌍](#translation-vipsystem "Translation") | [<img src="https://avatars3.githubusercontent.com/u/3861828?v=4" width="110px;"/><br /><sub>Wira Sandy</sub>](http://azuraweb.xyz)<br />[🌍](#translation-wira-sandy "Translation") |
|
||||
| [<img src="https://avatars2.githubusercontent.com/u/8663789?v=4" width="110px;"/><br /><sub>Илья</sub>](https://github.com/GrayHoax)<br />[🌍](#translation-GrayHoax "Translation") | [<img src="https://avatars3.githubusercontent.com/u/30119111?v=4" width="110px;"/><br /><sub>GodUseVPN</sub>](https://github.com/godusevpn)<br />[🌍](#translation-godusevpn "Translation") | [<img src="https://avatars1.githubusercontent.com/u/745576?v=4" width="110px;"/><br /><sub>周周</sub>](https://github.com/EngrZhou)<br />[🌍](#translation-EngrZhou "Translation") | [<img src="https://avatars3.githubusercontent.com/u/1631095?v=4" width="110px;"/><br /><sub>Sam</sub>](https://github.com/takuy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=takuy "Code") | [<img src="https://avatars1.githubusercontent.com/u/264022?v=4" width="110px;"/><br /><sub>Azerothian</sub>](https://www.illisian.com.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Azerothian "Code") | [<img src="https://avatars1.githubusercontent.com/u/7632599?v=4" width="110px;"/><br /><sub>Tim Farmer</sub>](https://github.com/timothyfarmer)<br />[💻](https://github.com/snipe/snipe-it/commits?author=timothyfarmer "Code") | [<img src="https://avatars0.githubusercontent.com/u/17459600?v=4" width="110px;"/><br /><sub>Marián Skrip</sub>](https://github.com/mskrip)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mskrip "Code") |
|
||||
| [<img src="https://avatars2.githubusercontent.com/u/47435081?v=4" width="110px;"/><br /><sub>Godfrey Martinez</sub>](https://github.com/Godmartinz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") | [<img src="https://avatars1.githubusercontent.com/u/2075128?v=4" width="110px;"/><br /><sub>bigtreeEdo</sub>](https://github.com/bigtreeEdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [<img src="https://avatars0.githubusercontent.com/u/5000430?v=4" width="110px;"/><br /><sub>Colin McNeil</sub>](https://colinmcneil.me/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [<img src="https://avatars0.githubusercontent.com/u/421625?v=4" width="110px;"/><br /><sub>JoKneeMo</sub>](https://github.com/JoKneeMo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [<img src="https://avatars0.githubusercontent.com/u/54849013?v=4" width="110px;"/><br /><sub>Joshi</sub>](http://www.redbridge.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [<img src="https://avatars2.githubusercontent.com/u/15731458?v=4" width="110px;"/><br /><sub>Anthony Burns</sub>](https://github.com/anthonypburns)<br />[💻](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") |
|
||||
| [<img src="https://avatars2.githubusercontent.com/u/47435081?v=4" width="110px;"/><br /><sub>Godfrey Martinez</sub>](https://github.com/Godmartinz)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Godmartinz "Code") | [<img src="https://avatars1.githubusercontent.com/u/2075128?v=4" width="110px;"/><br /><sub>bigtreeEdo</sub>](https://github.com/bigtreeEdo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bigtreeEdo "Code") | [<img src="https://avatars0.githubusercontent.com/u/5000430?v=4" width="110px;"/><br /><sub>Colin McNeil</sub>](https://colinmcneil.me/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ColinMcNeil "Code") | [<img src="https://avatars0.githubusercontent.com/u/421625?v=4" width="110px;"/><br /><sub>JoKneeMo</sub>](https://github.com/JoKneeMo)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JoKneeMo "Code") | [<img src="https://avatars0.githubusercontent.com/u/54849013?v=4" width="110px;"/><br /><sub>Joshi</sub>](http://www.redbridge.se)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joshi-redbridge "Code") | [<img src="https://avatars2.githubusercontent.com/u/15731458?v=4" width="110px;"/><br /><sub>Anthony Burns</sub>](https://github.com/anthonypburns)<br />[💻](https://github.com/snipe/snipe-it/commits?author=anthonypburns "Code") | [<img src="https://avatars2.githubusercontent.com/u/1972329?v=4" width="110px;"/><br /><sub>Alexander Chibrikin</sub>](http://phpprofi.ru/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alek13 "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\LicenseSeat;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\License;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class CheckinLicensesFromAllUsers extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:checkin-from-all {--license_id=} {--notify}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Checks in licenses from all users';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$license_id = $this->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');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\LicenseSeat;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use App\Models\License;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class CheckoutLicenseToAllUsers extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:checkout-to-all {--license_id=} {--notify}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
$license_id = $this->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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,16 @@ class LdapSync extends Command
|
||||
|
||||
// Grab subsets based on location-specific DNs, and overwrite location for these users.
|
||||
foreach ($ldap_ou_locations as $ldap_loc) {
|
||||
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]);
|
||||
try {
|
||||
$location_users = Ldap::findLdapUsers($ldap_loc["ldap_ou"]);
|
||||
} catch (\Exception $e) { // FIXME: this is stolen from line 77 or so above
|
||||
if ($this->option('json_summary')) {
|
||||
$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);
|
||||
return [];
|
||||
}
|
||||
$usernames = array();
|
||||
for ($i = 0; $i < $location_users["count"]; $i++) {
|
||||
|
||||
@@ -187,8 +196,33 @@ class LdapSync extends Command
|
||||
|
||||
// Sync activated state for Active Directory.
|
||||
if ( array_key_exists('useraccountcontrol', $results[$i]) ) {
|
||||
/* The following is _probably_ the correct logic, but we can't use it because
|
||||
some users may have been dependent upon the previous behavior, and this
|
||||
could cause additional access to be available to users they don't want
|
||||
to allow to log in.
|
||||
|
||||
$useraccountcontrol = $results[$i]['useraccountcontrol'][0];
|
||||
if(
|
||||
// based on MS docs at: https://support.microsoft.com/en-us/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties
|
||||
($useraccountcontrol & 0x200) && // is a NORMAL_ACCOUNT
|
||||
!($useraccountcontrol & 0x02) && // *and* _not_ ACCOUNTDISABLE
|
||||
!($useraccountcontrol & 0x10) // *and* _not_ LOCKOUT
|
||||
) {
|
||||
$user->activated = 1;
|
||||
} else {
|
||||
$user->activated = 0;
|
||||
} */
|
||||
$enabled_accounts = [
|
||||
'512', '544', '66048', '66080', '262656', '262688', '328192', '328224', '4260352'
|
||||
'512', // 0x200 NORMAL_ACCOUNT
|
||||
'544', // 0x220 NORMAL_ACCOUNT, PASSWD_NOTREQD
|
||||
'66048', // 0x10200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD
|
||||
'66080', // 0x10220 NORMAL_ACCOUNT, PASSWD_NOTREQD, DONT_EXPIRE_PASSWORD
|
||||
'262656', // 0x40200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED
|
||||
'262688', // 0x40220 NORMAL_ACCOUNT, PASSWD_NOTREQD, SMARTCARD_REQUIRED
|
||||
'328192', // 0x50200 NORMAL_ACCOUNT, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
|
||||
'328224', // 0x50220 NORMAL_ACCOUNT, PASSWD_NOT_REQD, SMARTCARD_REQUIRED, DONT_EXPIRE_PASSWORD
|
||||
'4260352',// 0x410200 NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD, DONT_REQ_PREAUTH
|
||||
'1049088',// 0x100200 NORMAL_ACCOUNT, NOT_DELEGATED
|
||||
];
|
||||
$user->activated = ( in_array($results[$i]['useraccountcontrol'][0], $enabled_accounts) ) ? 1 : 0;
|
||||
}
|
||||
@@ -239,7 +273,7 @@ class LdapSync extends Command
|
||||
}
|
||||
}
|
||||
} else if ($this->option('json_summary')) {
|
||||
$json_summary = [ "error" => false, "error_message" => "", "summary" => $summary ];
|
||||
$json_summary = [ "error" => false, "error_message" => "", "summary" => $summary ]; // hardcoding the error to false and the error_message to blank seems a bit weird
|
||||
$this->info(json_encode($json_summary));
|
||||
} else {
|
||||
return $summary;
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
|
||||
|
||||
class MergeUsersByUsername extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:merge-users';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This command allows you to merge the history of users. It looks for users without an email address as their username and merges them into the version that does have an email username.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// Get the list of users who have an email address as their username
|
||||
$users = User::where('username', 'LIKE', '%@%')->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();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -453,6 +453,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);
|
||||
|
||||
// Update custom fields in the database.
|
||||
// Validation for these fields is handled through the AssetRequest form request
|
||||
@@ -646,11 +647,12 @@ class AssetsController extends Controller
|
||||
$asset_name = request('name', null);
|
||||
|
||||
// Set the location ID to the RTD location id if there is one
|
||||
if ($asset->rtd_location_id!='') {
|
||||
$asset->location_id = $target->rtd_location_id;
|
||||
}
|
||||
|
||||
// Wait, why are we doing this? This overrides the stuff we set further up, which makes no sense.
|
||||
// TODO: Follow up here. WTF. Commented out for now.
|
||||
|
||||
// if ((isset($target->rtd_location_id)) && ($asset->rtd_location_id!='')) {
|
||||
// $asset->location_id = $target->rtd_location_id;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\User;
|
||||
use App\Http\Transformers\ConsumablesTransformer;
|
||||
use App\Helpers\Helper;
|
||||
|
||||
@@ -157,7 +158,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] [<snipe@snipe.net>]
|
||||
@@ -196,4 +197,55 @@ class ConsumablesController extends Controller
|
||||
$data = array('total' => $consumableCount, 'rows' => $rows);
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checkout a consumable
|
||||
*
|
||||
* @author [A. Gutierrez] [<andres@baller.tv>]
|
||||
* @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'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,14 @@ class ImportController extends Controller
|
||||
{
|
||||
$this->authorize('import');
|
||||
// Run a backup immediately before processing
|
||||
Artisan::call('backup:run');
|
||||
|
||||
if ($request->has('run-backup')) {
|
||||
\Log::debug('Backup manually requested via importer');
|
||||
Artisan::call('backup:run');
|
||||
} else {
|
||||
\Log::debug('NO BACKUP requested via importer');
|
||||
}
|
||||
|
||||
$errors = $request->import(Import::find($import_id));
|
||||
$redirectTo = "hardware.index";
|
||||
switch ($request->get('import-type')) {
|
||||
|
||||
@@ -209,7 +209,7 @@ class StatuslabelsController extends Controller
|
||||
{
|
||||
$this->authorize('view', Statuslabel::class);
|
||||
$this->authorize('index', Asset::class);
|
||||
$assets = Asset::where('status_id','=',$id);
|
||||
$assets = Asset::where('status_id','=',$id)->with('assignedTo');
|
||||
|
||||
$allowed_columns = [
|
||||
'id',
|
||||
|
||||
@@ -76,6 +76,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'));
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ class AssetsController extends Controller
|
||||
$asset->supplier_id = request('supplier_id', 0);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
$asset->rtd_location_id = request('rtd_location_id', null);
|
||||
|
||||
|
||||
if ($asset->assigned_to=='') {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
|
||||
@@ -303,8 +303,8 @@ class LoginController extends Controller
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
$request->session()->forget('2fa_authed');
|
||||
|
||||
$request->session()->regenerate(true);
|
||||
Auth::logout();
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
@@ -194,4 +194,44 @@ class CustomFieldsetsController extends Controller
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field in a fieldset to required
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0]
|
||||
*/
|
||||
public function makeFieldRequired($fieldset_id, $field_id)
|
||||
{
|
||||
|
||||
$this->authorize('update', CustomFieldset::class);
|
||||
$field = CustomField::findOrFail($field_id);
|
||||
$fieldset = CustomFieldset::findOrFail($fieldset_id);
|
||||
$fields[$field->id] = ['required' => 1];
|
||||
$fieldset->fields()->syncWithoutDetaching($fields);
|
||||
|
||||
return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id])
|
||||
->with("success", trans('Field successfully set to required'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the field in a fieldset to optional
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0]
|
||||
*/
|
||||
public function makeFieldOptional($fieldset_id, $field_id)
|
||||
{
|
||||
$this->authorize('update', CustomFieldset::class);
|
||||
$field = CustomField::findOrFail($field_id);
|
||||
$fieldset = CustomFieldset::findOrFail($fieldset_id);
|
||||
$fields[$field->id] = ['required' => 0];
|
||||
$fieldset->fields()->syncWithoutDetaching($fields);
|
||||
|
||||
return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id])
|
||||
->with("success", trans('Field successfully set to optional'));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -246,17 +246,23 @@ class LicensesController extends Controller
|
||||
*/
|
||||
public function getCheckout($licenceId)
|
||||
{
|
||||
|
||||
// Check that the license is valid
|
||||
if ($license = License::where('id',$licenceId)->first()) {
|
||||
|
||||
$this->authorize('checkout', $license);
|
||||
|
||||
// If the license is valid, check that there is an available seat
|
||||
if ($license->getAvailSeatsCountAttribute() < 1) {
|
||||
return redirect()->route('licenses.index')->with('error', 'There are no available seats for this license');
|
||||
}
|
||||
return view('licenses/checkout', compact('license'));
|
||||
}
|
||||
|
||||
$this->authorize('checkout', $license);
|
||||
return view('licenses/checkout', compact('license'));
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.does_not_exist'));
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class ReportsController extends Controller
|
||||
|
||||
$depreciations = Depreciation::get();
|
||||
// Grab all the assets
|
||||
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'location', 'assetlog', 'company', 'model.category', 'model.depreciation')
|
||||
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'location', 'company', 'model.category', 'model.depreciation')
|
||||
->orderBy('created_at', 'DESC')->get();
|
||||
|
||||
return view('reports/depreciation', compact('assets'))->with('depreciations',$depreciations);
|
||||
|
||||
@@ -240,6 +240,12 @@ class UsersController extends Controller
|
||||
if ($user->id == $request->input('manager_id')) {
|
||||
return redirect()->back()->withInput()->with('error', 'You cannot be your own manager.');
|
||||
}
|
||||
|
||||
// If the user isn't a superuser, don't let them edit their own permissions
|
||||
if ((!Auth::user()->isSuperUser()) && ($user->id == Auth::user()->id)) {
|
||||
return redirect()->back()->withInput()->with('error', 'You cannot edit your own permissions. Please contact an administrator.');
|
||||
}
|
||||
|
||||
$this->authorize('update', $user);
|
||||
// Figure out of this user was an admin before this edit
|
||||
$orig_permissions_array = $user->decodePermissions();
|
||||
@@ -429,6 +435,10 @@ class UsersController extends Controller
|
||||
if ($request->filled('department_id')) {
|
||||
$update_array['department_id'] = $request->input('department_id');
|
||||
}
|
||||
if ($request->filled('city')) {
|
||||
$update_array['city'] = $request->input('city');
|
||||
}
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$update_array['company_id'] = $request->input('company_id');
|
||||
}
|
||||
|
||||
+2
-5
@@ -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,
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class ContentSecurityPolicyHeader
|
||||
{
|
||||
/**
|
||||
* Handle the given request and get the response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
if ((config('app.debug')=='true') || (config('app.enable_csp')!='true')) {
|
||||
$response = $next($request);
|
||||
return $response;
|
||||
}
|
||||
|
||||
$policy[] = "default-src 'self'";
|
||||
$policy[] = "style-src 'self' 'unsafe-inline' oss.maxcdn.com";
|
||||
$policy[] = "script-src 'self' 'unsafe-inline' 'unsafe-eval' cdnjs.cloudflare.com";
|
||||
$policy[] = "connect-src 'self'";
|
||||
$policy[] = "object-src 'none'";
|
||||
$policy[] = "font-src 'self' data:";
|
||||
$policy[] = "img-src 'self' data: gravatar.com";
|
||||
$policy = join(';', $policy);
|
||||
|
||||
$response = $next($request);
|
||||
$response->headers->set('Content-Security-Policy', $policy);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class FrameGuard
|
||||
{
|
||||
/**
|
||||
* Handle the given request and get the response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
if (config('app.allow_iframing') == false) {
|
||||
$response->headers->set('X-Frame-Options', 'SAMEORIGIN', false);
|
||||
}
|
||||
return $response;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class NosniffGuard
|
||||
{
|
||||
/**
|
||||
* Handle the given request and get the response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
$response->headers->set('X-Content-Type-Options', 'nosniff', false);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class ReferrerPolicyHeader
|
||||
{
|
||||
/**
|
||||
* Handle the given request and get the response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$response = $next($request);
|
||||
$response->headers->set('Referrer-Policy', config('app.referrer_policy'));
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class SecurityHeaders
|
||||
{
|
||||
/**
|
||||
* Handle an incoming request.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return mixed
|
||||
*/
|
||||
|
||||
// See https://securityheaders.com/
|
||||
private $unwantedHeaderList = [
|
||||
'X-Powered-By',
|
||||
'Server',
|
||||
];
|
||||
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
|
||||
class XssProtectHeader
|
||||
{
|
||||
/**
|
||||
* Handle the given request and get the response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure $next
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
$mode = '1;mode=block';
|
||||
$response = $next($request);
|
||||
$response->headers->set('X-XSS-Protection', $mode);
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class AssetRequest extends Request
|
||||
if ($this->request->get('model_id') != '') {
|
||||
$model = AssetModel::find($this->request->get('model_id'));
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
if (($model) && (isset($model->fieldset)) && ($model->fieldset)) {
|
||||
$rules += $model->fieldset->validation_rules();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -47,6 +47,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;
|
||||
|
||||
\Log::debug('UserImporter.php Activated: '.$this->findCsvMatch($row, 'activated'));
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
| licensed to email | license_email | License |
|
||||
| licensed to name | license_name | License |
|
||||
| maintained | maintained | License |
|
||||
| manager_id | | User |
|
||||
| manager_id | | User |
|
||||
| manufacturer | manufacturer | All |
|
||||
| model name | asset_model | Asset |
|
||||
| model number | model_number | Asset |
|
||||
@@ -34,4 +34,8 @@
|
||||
| User Related Fields | assigned_to | Asset |
|
||||
| name | | |
|
||||
| username | | |
|
||||
| address | address | User |
|
||||
| city | city | User |
|
||||
| state | state | User |
|
||||
| country | country | User |
|
||||
|
||||
|
||||
@@ -226,10 +226,10 @@ class Asset extends Depreciable
|
||||
if ($location != null) {
|
||||
$this->location_id = $location;
|
||||
} else {
|
||||
if($target->location) {
|
||||
if (isset($target->location)) {
|
||||
$this->location_id = $target->location->id;
|
||||
}
|
||||
if($target instanceof Location) {
|
||||
if ($target instanceof Location) {
|
||||
$this->location_id = $target->id;
|
||||
}
|
||||
}
|
||||
@@ -878,7 +878,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();
|
||||
}
|
||||
|
||||
@@ -128,9 +128,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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -265,13 +265,13 @@ class Ldap extends Model
|
||||
$search_results = ldap_search($ldapconn, $base_dn, '('.$filter.')');
|
||||
|
||||
if (!$search_results) {
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn));
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work.
|
||||
}
|
||||
|
||||
// Get results from page
|
||||
$results = ldap_get_entries($ldapconn, $search_results);
|
||||
if (!$results) {
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn));
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_get_entries').ldap_error($ldapconn)); // FIXME this is never called in any routed context - only from the Artisan command. So this redirect will never work.
|
||||
}
|
||||
|
||||
// Add results to result set
|
||||
@@ -286,7 +286,7 @@ class Ldap extends Model
|
||||
// Clean up after search
|
||||
$result_set['count'] = $global_count;
|
||||
$results = $result_set;
|
||||
ldap_control_paged_result($ldapconn, 0);
|
||||
@ldap_control_paged_result($ldapconn, 0);
|
||||
|
||||
return $results;
|
||||
|
||||
|
||||
+26
-5
@@ -41,13 +41,20 @@ trait Loggable
|
||||
$settings = Setting::getSettings();
|
||||
$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');
|
||||
throw new \Exception('All checkout logs require a target.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($target->id)) {
|
||||
throw new \Exception('That target seems invalid (no target ID available).');
|
||||
return;
|
||||
}
|
||||
|
||||
$log->target_type = get_class($target);
|
||||
$log->target_id = $target->id;
|
||||
|
||||
@@ -138,7 +145,11 @@ trait Loggable
|
||||
|
||||
$log->location_id = null;
|
||||
$log->note = $note;
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
||||
if (Auth::user()) {
|
||||
$log->user_id = Auth::user()->id;
|
||||
}
|
||||
|
||||
$log->logaction('checkin from');
|
||||
|
||||
$params = [
|
||||
@@ -154,14 +165,24 @@ trait Loggable
|
||||
$checkinClass = null;
|
||||
|
||||
if (method_exists($target, 'notify')) {
|
||||
$target->notify(new static::$checkinClass($params));
|
||||
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!='')) {
|
||||
$recipient->notify(new static::$checkinClass($params));
|
||||
try {
|
||||
$recipient->notify(new static::$checkinClass($params));
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $log;
|
||||
|
||||
+13
-1
@@ -237,7 +237,7 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -379,6 +379,18 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
|
||||
} 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;
|
||||
|
||||
@@ -76,10 +76,18 @@ class CheckinLicenseNotification 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',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -268,8 +268,11 @@ class AssetPresenter extends Presenter
|
||||
"searchable" => true,
|
||||
"sortable" => true,
|
||||
"switchable" => true,
|
||||
"title" => ($field->field_encrypted=='1') ?'<i class="fa fa-lock"></i> '.$field->name : $field->name,
|
||||
"formatter" => "customFieldsFormatter"
|
||||
"title" => $field->name,
|
||||
"formatter"=> 'customFieldsFormatter',
|
||||
"escape" => true,
|
||||
"class" => ($field->field_encrypted=='1') ? 'css-padlock' : '',
|
||||
"visible" => true,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
@@ -171,21 +171,22 @@ class UserPresenter extends Presenter
|
||||
"formatter" => "usersLinkObjFormatter"
|
||||
],
|
||||
[
|
||||
"field" => "assets_count",
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
"switchable" => true,
|
||||
"title" => ' <span class="hidden-md hidden-lg">Assets</span>'
|
||||
.'<span class="hidden-xs"><i class="fa fa-barcode fa-lg"></i></span>',
|
||||
"visible" => true,
|
||||
'field' => 'assets_count',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'escape' => true,
|
||||
'class' => 'css-barcode',
|
||||
'title' => 'Assets',
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
"field" => "licenses_count",
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
"switchable" => true,
|
||||
"title" => ' <span class="hidden-md hidden-lg">Licenses</span>'
|
||||
.'<span class="hidden-xs"><i class="fa fa-floppy-o fa-lg"></i></span>',
|
||||
'class' => 'css-license',
|
||||
"title" => 'License',
|
||||
"visible" => true,
|
||||
],
|
||||
[
|
||||
@@ -193,8 +194,8 @@ class UserPresenter extends Presenter
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
"switchable" => true,
|
||||
"title" => ' <span class="hidden-md hidden-lg">Consumables</span>'
|
||||
.'<span class="hidden-xs"><i class="fa fa-tint fa-lg"></i></span>',
|
||||
'class' => 'css-consumable',
|
||||
"title" => 'Consumables',
|
||||
"visible" => true,
|
||||
],
|
||||
[
|
||||
@@ -202,8 +203,8 @@ class UserPresenter extends Presenter
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
"switchable" => true,
|
||||
"title" => ' <span class="hidden-md hidden-lg">Accessories</span>'
|
||||
.'<span class="hidden-xs"><i class="fa fa-keyboard-o fa-lg"></i></span>',
|
||||
'class' => 'css-accessory',
|
||||
"title" => 'Accessories',
|
||||
"visible" => true,
|
||||
],
|
||||
[
|
||||
@@ -323,9 +324,14 @@ class UserPresenter extends Presenter
|
||||
return config('app.url').'/uploads/avatars/'.$this->avatar;
|
||||
}
|
||||
|
||||
if ((Setting::getSettings()->load_remote=='1') && ($this->email!='')) {
|
||||
$gravatar = md5(strtolower(trim($this->email)));
|
||||
return "//gravatar.com/avatar/".$gravatar;
|
||||
if (Setting::getSettings()->load_remote=='1') {
|
||||
if ($this->model->gravatar!='') {
|
||||
$gravatar = md5(strtolower(trim($this->model->gravatar)));
|
||||
return "//gravatar.com/avatar/".$gravatar;
|
||||
} elseif ($this->email!='') {
|
||||
$gravatar = md5(strtolower(trim($this->email)));
|
||||
return "//gravatar.com/avatar/".$gravatar;
|
||||
}
|
||||
}
|
||||
|
||||
// Set a fun, gender-neutral default icon
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
"laravel/tinker": "^1.0",
|
||||
"laravelcollective/html": "^5.5",
|
||||
"league/csv": "^9.2",
|
||||
"maknz/slack": "^1.7",
|
||||
"alek13/slack": "^1.7",
|
||||
"neitanod/forceutf8": "^2.0",
|
||||
"patchwork/utf8": "^1.3",
|
||||
"phpdocumentor/reflection-docblock": "^4.0",
|
||||
|
||||
Generated
+642
-245
File diff suppressed because it is too large
Load Diff
+23
-9
@@ -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
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v4.9.2',
|
||||
'full_app_version' => 'v4.9.2 - build 4352-gec723a3da',
|
||||
'build_version' => '4352',
|
||||
'app_version' => 'v4.9.5',
|
||||
'full_app_version' => 'v4.9.5 - build 4482-g5b68a321a',
|
||||
'build_version' => '4482',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'gec723a3da',
|
||||
'full_hash' => 'v4.9.2-9-gec723a3da',
|
||||
'hash_version' => 'g5b68a321a',
|
||||
'full_hash' => 'v4.9.5-44-g5b68a321a',
|
||||
'branch' => 'master',
|
||||
);
|
||||
);
|
||||
|
||||
+601
-6
File diff suppressed because one or more lines are too long
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
.skin-contrast .main-header .navbar{background-color:#001f3f}.skin-contrast .main-header .navbar .nav>li>a{color:#fff}.skin-contrast .main-header .navbar .nav .open>a,.skin-contrast .main-header .navbar .nav .open>a:focus,.skin-contrast .main-header .navbar .nav .open>a:hover,.skin-contrast .main-header .navbar .nav>.active>a,.skin-contrast .main-header .navbar .nav>li>a:active,.skin-contrast .main-header .navbar .nav>li>a:focus,.skin-contrast .main-header .navbar .nav>li>a:hover,.skin-contrast .main-header .navbar .sidebar-toggle:hover{background:rgba(0,0,0,.1);color:#f6f6f6}.skin-contrast .main-header .navbar .sidebar-toggle{color:#fff}.skin-contrast .main-header .navbar .sidebar-toggle:hover{background-color:#001226}@media (max-width:767px){.skin-contrast .main-header .navbar .dropdown-menu li.divider{background-color:hsla(0,0%,100%,.1)}.skin-contrast .main-header .navbar .dropdown-menu li a{color:#fff}.skin-contrast .main-header .navbar .dropdown-menu li a:hover{background:#001226}}.skin-contrast .main-header li.user-header{background-color:#001f3f}.skin-contrast .content-header{background:transparent}.skin-contrast .left-side,.skin-contrast .main-sidebar,.skin-contrast .wrapper{background-color:#222d32}.skin-contrast .user-panel>.info,.skin-contrast .user-panel>.info>a{color:#fff}.skin-contrast .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-contrast .sidebar-menu>li>a{border-left:3px solid transparent}.skin-contrast .sidebar-menu>li.active>a,.skin-contrast .sidebar-menu>li:hover>a{color:#fff;background:#1e282c;border-left-color:#001f3f}.skin-contrast .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-contrast .sidebar a{color:#b8c7ce}.skin-contrast .sidebar a:hover{text-decoration:none}.skin-contrast .treeview-menu>li>a{color:#8aa4af}.skin-contrast .treeview-menu>li.active>a,.skin-contrast .treeview-menu>li>a:hover{color:#fff}.skin-contrast .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px}.skin-contrast .sidebar-form .btn,.skin-contrast .sidebar-form input[type=text]{-webkit-box-shadow:none;box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-contrast .sidebar-form input[type=text]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-contrast .sidebar-form input[type=text]:focus,.skin-contrast .sidebar-form input[type=text]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-contrast .sidebar-form input[type=text]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-contrast .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-contrast.layout-top-nav .main-header>.logo .logo-variant{background-color:none}.btn.btn-primary,.btn .btn-primary:link,.btn:hover.btn-primary,.btn:hover .btn-primary:link{background-color:#00060c;border-color:#000;color:#fff}.btn:hovera.btn-primary:hover,.btna.btn-primary:hover{background-color:#000;border-color:#000;color:#fff}.btn.btn-white:link,.btn:hover.btn-white:link{background-color:#00060c;color:#fff}.btn.btn-white:hover,.btn:hover.btn-white:hover{background-color:#000;color:#fff}a,a:hover{color:#001f3f}a:hover{text-decoration:underline}a:visited{color:#001f3f}a.btn:hover{color:#fff;text-decoration:underline}a.btn:visited{color:#fff}.text-primary{color:#000}.skin-contrast .treeview-menu>li>a{color:#fff}.bg-teal{background-color:#1b6a6a!important}.bg-orange{background-color:#995400!important}.bg-purple{background-color:#3a3767!important}.bg-maroon{background-color:#7d1038!important}.pagination>li>a{color:#00060c!important}.pagination>.active>a{background-color:#001f3f;color:#fff!important}btn-success{background-color:#000d07}input::-webkit-input-placeholder{color:#37383c!important}input::-moz-placeholder{color:#37383c!important}input::-ms-input-placeholder{color:#37383c!important}.select2-default,.select2-selection__placeholder{color:#37383c!important}.callout.callout-info{background-color:#003351!important}.fixed-table-container tbody .selected td{background-color:#fff8af}
|
||||
.skin-contrast .main-header .navbar{background-color:#001f3f}.skin-contrast .main-header .navbar .nav>li>a{color:#fff}.skin-contrast .main-header .navbar .nav .open>a,.skin-contrast .main-header .navbar .nav .open>a:focus,.skin-contrast .main-header .navbar .nav .open>a:hover,.skin-contrast .main-header .navbar .nav>.active>a,.skin-contrast .main-header .navbar .nav>li>a:active,.skin-contrast .main-header .navbar .nav>li>a:focus,.skin-contrast .main-header .navbar .nav>li>a:hover,.skin-contrast .main-header .navbar .sidebar-toggle:hover{background:rgba(0,0,0,.1);color:#f6f6f6}.skin-contrast .main-header .navbar .sidebar-toggle{color:#fff}.skin-contrast .main-header .navbar .sidebar-toggle:hover{background-color:#001226}@media (max-width:767px){.skin-contrast .main-header .navbar .dropdown-menu li.divider{background-color:hsla(0,0%,100%,.1)}.skin-contrast .main-header .navbar .dropdown-menu li a{color:#fff}.skin-contrast .main-header .navbar .dropdown-menu li a:hover{background:#001226}}.skin-contrast .main-header li.user-header{background-color:#001f3f}.skin-contrast .content-header{background:transparent}.skin-contrast .left-side,.skin-contrast .main-sidebar,.skin-contrast .wrapper{background-color:#222d32}.skin-contrast .user-panel>.info,.skin-contrast .user-panel>.info>a{color:#fff}.skin-contrast .sidebar-menu>li.header{color:#4b646f;background:#1a2226}.skin-contrast .sidebar-menu>li>a{border-left:3px solid transparent}.skin-contrast .sidebar-menu>li.active>a,.skin-contrast .sidebar-menu>li:hover>a{color:#fff;background:#1e282c;border-left-color:#001f3f}.skin-contrast .sidebar-menu>li>.treeview-menu{margin:0 1px;background:#2c3b41}.skin-contrast .sidebar a{color:#b8c7ce}.skin-contrast .sidebar a:hover{text-decoration:none}.skin-contrast .treeview-menu>li>a{color:#8aa4af}.skin-contrast .treeview-menu>li.active>a,.skin-contrast .treeview-menu>li>a:hover{color:#fff}.skin-contrast .sidebar-form{border-radius:3px;border:1px solid #374850;margin:10px}.skin-contrast .sidebar-form .btn,.skin-contrast .sidebar-form input[type=text]{-webkit-box-shadow:none;box-shadow:none;background-color:#374850;border:1px solid transparent;height:35px;-webkit-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.skin-contrast .sidebar-form input[type=text]{color:#666;border-top-left-radius:2px;border-top-right-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:2px}.skin-contrast .sidebar-form input[type=text]:focus,.skin-contrast .sidebar-form input[type=text]:focus+.input-group-btn .btn{background-color:#fff;color:#666}.skin-contrast .sidebar-form input[type=text]:focus+.input-group-btn .btn{border-left-color:#fff}.skin-contrast .sidebar-form .btn{color:#999;border-top-left-radius:0;border-top-right-radius:2px;border-bottom-right-radius:2px;border-bottom-left-radius:0}.skin-contrast.layout-top-nav .main-header>.logo .logo-variant{background-color:none}.btn.btn-primary,.btn .btn-primary:link,.btn:hover.btn-primary,.btn:hover .btn-primary:link{background-color:#00060c;border-color:#000;color:#fff}.btn:hovera.btn-primary:hover,.btna.btn-primary:hover{background-color:#000;border-color:#000;color:#fff}.btn.btn-white:link,.btn:hover.btn-white:link{background-color:#00060c;color:#fff}.btn.btn-white:hover,.btn:hover.btn-white:hover{background-color:#000;color:#fff}a,a:hover{color:#001f3f}a:hover{text-decoration:underline}a:visited{color:#001f3f}a.btn:hover{color:#fff;text-decoration:underline}a.btn:visited{color:#fff}.text-primary{color:#000}.skin-contrast .treeview-menu>li>a{color:#fff}.bg-teal{background-color:#1b6a6a!important}.bg-orange{background-color:#995400!important}.bg-purple{background-color:#3a3767!important}.bg-maroon{background-color:#7d1038!important}.pagination>li>a{color:#00060c!important}.pagination>.active>a{background-color:#001f3f;color:#fff!important}btn-success{background-color:#000d07}input::-webkit-input-placeholder{color:#b5bbc8!important}input::-moz-placeholder{color:#b5bbc8!important}input::-ms-input-placeholder{color:#b5bbc8!important}.select2-default,.select2-selection__placeholder{color:#37383c!important}.callout.callout-info{background-color:#003351!important}.fixed-table-container tbody .selected td{background-color:#fff8af}
|
||||
/*# sourceMappingURL=skin-contrast.css.map*/
|
||||
File diff suppressed because one or more lines are too long
+9841
-27
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+27
-27
File diff suppressed because one or more lines are too long
+11
-11
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"/js/build/vue.js": "/js/build/vue.js?id=684d1ab5c98c5b1b9d3c",
|
||||
"/js/build/vue.js": "/js/build/vue.js?id=aff26ce7202625817ca1",
|
||||
"/css/AdminLTE.css": "/css/AdminLTE.css?id=56b8066cfbc70df10545",
|
||||
"/css/app.css": "/css/app.css?id=407edb63cc6b6dc62405",
|
||||
"/css/overrides.css": "/css/overrides.css?id=014ba62bc420467fd405",
|
||||
"/css/overrides.css": "/css/overrides.css?id=d1fe6296eb548247a5ad",
|
||||
"/css/skins/skin-blue.css": "/css/skins/skin-blue.css?id=c28283a1d468e2337428",
|
||||
"/css/skins/skin-red.css": "/css/skins/skin-red.css?id=079dd6c501fa9ea60a98",
|
||||
"/css/skins/skin-contrast.css": "/css/skins/skin-contrast.css?id=47303dc15032d3ecb343",
|
||||
"/css/skins/skin-contrast.css": "/css/skins/skin-contrast.css?id=62e14190151e9efc9995",
|
||||
"/css/skins/skin-green.css": "/css/skins/skin-green.css?id=2c53f7ed585fcad563b2",
|
||||
"/css/skins/skin-green-dark.css": "/css/skins/skin-green-dark.css?id=cb34691dbbb72cae7f5f",
|
||||
"/css/skins/skin-black.css": "/css/skins/skin-black.css?id=1dfec89b8640b69dc0fc",
|
||||
@@ -18,13 +18,13 @@
|
||||
"/css/skins/skin-blue-dark.css": "/css/skins/skin-blue-dark.css?id=d25c77d9c6f4cfe2efd4",
|
||||
"/css/skins/skin-orange-dark.css": "/css/skins/skin-orange-dark.css?id=abc219c1fed59cecb860",
|
||||
"/css/skins/skin-orange.css": "/css/skins/skin-orange.css?id=59664dbd286988d2a438",
|
||||
"/js/build/vue.js.map": "/js/build/vue.js.map?id=8fafb985154034fd882a",
|
||||
"/js/build/vue.js.map": "/js/build/vue.js.map?id=41a870ef3b9b5c6688ca",
|
||||
"/css/AdminLTE.css.map": "/css/AdminLTE.css.map?id=5a2d6f3c59191ce716e2",
|
||||
"/css/app.css.map": "/css/app.css.map?id=96b5c985e860716e6a16",
|
||||
"/css/overrides.css.map": "/css/overrides.css.map?id=fe0a3186bd85efc442ca",
|
||||
"/css/overrides.css.map": "/css/overrides.css.map?id=f3e3cf42859eb4a28a7b",
|
||||
"/css/skins/skin-blue.css.map": "/css/skins/skin-blue.css.map?id=129b9523e6ffd5683230",
|
||||
"/css/skins/skin-red.css.map": "/css/skins/skin-red.css.map?id=292dfa49bf2b6f23fa59",
|
||||
"/css/skins/skin-contrast.css.map": "/css/skins/skin-contrast.css.map?id=141c0891e3ed15673d22",
|
||||
"/css/skins/skin-contrast.css.map": "/css/skins/skin-contrast.css.map?id=bf37f812f0b6a109b5ce",
|
||||
"/css/skins/skin-green.css.map": "/css/skins/skin-green.css.map?id=50461604ff9b1934d580",
|
||||
"/css/skins/skin-green-dark.css.map": "/css/skins/skin-green-dark.css.map?id=988cf7da13d22c56bd8c",
|
||||
"/css/skins/skin-black.css.map": "/css/skins/skin-black.css.map?id=ad0bf20283280a01b34f",
|
||||
@@ -37,8 +37,8 @@
|
||||
"/css/skins/skin-blue-dark.css.map": "/css/skins/skin-blue-dark.css.map?id=32784cb5d02773eb0e69",
|
||||
"/css/skins/skin-orange-dark.css.map": "/css/skins/skin-orange-dark.css.map?id=68b998638217fd08ef29",
|
||||
"/css/skins/skin-orange.css.map": "/css/skins/skin-orange.css.map?id=f90fda3cc0a48c048a9e",
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=41fe3b2990d453da1997",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=8ec0e00558ab4b60acb8",
|
||||
"/css/build/all.css": "/css/build/all.css?id=41fe3b2990d453da1997",
|
||||
"/js/build/all.js": "/js/build/all.js?id=8ec0e00558ab4b60acb8"
|
||||
}
|
||||
"/css/dist/all.css": "/css/dist/all.css?id=0491555899142b86167d",
|
||||
"/js/dist/all.js": "/js/dist/all.js?id=5ac062af7b26fb838213",
|
||||
"/css/build/all.css": "/css/build/all.css?id=0491555899142b86167d",
|
||||
"/js/build/all.js": "/js/build/all.js?id=5ac062af7b26fb838213"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
<style>
|
||||
tr {
|
||||
padding-left:30px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div v-show="processDetail">
|
||||
|
||||
@@ -11,30 +5,38 @@ tr {
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-8" style="padding-top: 30px; margin: 0 auto;">
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="import-type">Import Type:</label>
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="import-type">Import Type:</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<select2 :options="options.importTypes" v-model="options.importType" required>
|
||||
<option disabled value="0"></option>
|
||||
</select2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<select2 :options="options.importTypes" v-model="options.importType" required>
|
||||
<option disabled value="0"></option>
|
||||
</select2>
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="import-update">Update Existing Values?:</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<input type="checkbox" class="minimal" name="import-update" v-model="options.update">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="import-update">Update Existing Values?:</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<input type="checkbox" name="import-update" v-model="options.update">
|
||||
</div>
|
||||
</div>
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="send-welcome">Send Welcome Email for new Users?</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<input type="checkbox" name="send-welcome" v-model="options.send_welcome">
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="send-welcome">Send Welcome Email for new Users?</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<input type="checkbox" class="minimal" name="send-welcome" v-model="options.send_welcome">
|
||||
</div>
|
||||
</div>
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<label for="run-backup">Backup before importing?</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<input type="checkbox" class="minimal" name="run-backup" v-model="options.run_backup">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert col-md-8 col-md-offset-2" style="text-align:left"
|
||||
@@ -43,53 +45,53 @@ tr {
|
||||
{{ this.statusText }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-8" style="padding-top: 30px;">
|
||||
<div class="col-md-4 text-right"><h4>Header Field</h4></div>
|
||||
<div class="col-md-4"><h4>Import Field</h4></div>
|
||||
<div class="col-md-4"><h4>Sample Value</h4></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-8" style="padding-top: 30px;">
|
||||
<div class="col-md-4 text-right"><h4>Header Field</h4></div>
|
||||
<div class="col-md-4"><h4>Import Field</h4></div>
|
||||
<div class="col-md-4"><h4>Sample Value</h4></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template v-for="(header, index) in file.header_row">
|
||||
<div class="row">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-4 text-right">
|
||||
<label :for="header" class="control-label">{{ header }}</label>
|
||||
</div>
|
||||
<div class="col-md-4 form-group">
|
||||
<div required>
|
||||
<select2 :options="columns" v-model="columnMappings[header]">
|
||||
<option value="0">Do Not Import</option>
|
||||
</select2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<p class="form-control-static">{{ activeFile.first_row[index] }}</p>
|
||||
</div>
|
||||
<template v-for="(header, index) in file.header_row">
|
||||
<div class="row">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-8">
|
||||
<div class="col-md-4 text-right">
|
||||
<label :for="header" class="control-label">{{ header }}</label>
|
||||
</div>
|
||||
<div class="col-md-4 form-group">
|
||||
<div required>
|
||||
<select2 :options="columns" v-model="columnMappings[header]">
|
||||
<option value="0">Do Not Import</option>
|
||||
</select2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-2 text-right" style="padding-top: 20px;">
|
||||
<button type="button" class="btn btn-sm btn-default" @click="processDetail = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary" @click="postSave">Import</button>
|
||||
<br><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="alert col-md-8 col-md-offset-2" style="padding-top: 20px;"
|
||||
:class="alertClass"
|
||||
v-if="statusText">
|
||||
{{ this.statusText }}
|
||||
<div class="col-md-4">
|
||||
<p class="form-control-static">{{ activeFile.first_row[index] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-md-offset-2 text-right" style="padding-top: 20px;">
|
||||
<button type="button" class="btn btn-sm btn-default" @click="processDetail = false">Cancel</button>
|
||||
<button type="submit" class="btn btn-sm btn-primary" @click="postSave">Import</button>
|
||||
<br><br>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="alert col-md-8 col-md-offset-2" style="padding-top: 20px;"
|
||||
:class="alertClass"
|
||||
v-if="statusText">
|
||||
{{ this.statusText }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@@ -167,6 +169,10 @@ tr {
|
||||
{id: 'manager_first_name', text: 'Manager First Name' },
|
||||
{id: 'manager_last_name', text: 'Manager Last Name' },
|
||||
{id: 'activated', text: 'Activated' },
|
||||
{id: 'address', text: 'Address' },
|
||||
{id: 'city', text: 'City' },
|
||||
{id: 'state', text: 'State' },
|
||||
{id: 'country', text: 'Country' },
|
||||
|
||||
],
|
||||
customFields: this.customFields,
|
||||
@@ -192,14 +198,14 @@ tr {
|
||||
switch(this.options.importType) {
|
||||
case 'asset':
|
||||
return this.columnOptions.general
|
||||
.concat(this.columnOptions.assets)
|
||||
.concat(this.columnOptions.customFields)
|
||||
.sort(sorter);
|
||||
.concat(this.columnOptions.assets)
|
||||
.concat(this.columnOptions.customFields)
|
||||
.sort(sorter);
|
||||
|
||||
case 'consumable':
|
||||
return this.columnOptions.general
|
||||
.concat(this.columnOptions.consumables)
|
||||
.sort(sorter);
|
||||
.concat(this.columnOptions.consumables)
|
||||
.sort(sorter);
|
||||
case 'license':
|
||||
return this.columnOptions.general.concat(this.columnOptions.licenses).sort(sorter);
|
||||
case 'user':
|
||||
@@ -237,6 +243,7 @@ tr {
|
||||
'import-update': this.options.update,
|
||||
'send-welcome': this.options.send_welcome,
|
||||
'import-type': this.options.importType,
|
||||
'run-backup': this.options.run_backup,
|
||||
'column-mappings': this.columnMappings
|
||||
}).then( ({body}) => {
|
||||
// Success
|
||||
@@ -289,4 +296,4 @@ tr {
|
||||
select2: require('../select2.vue')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
@@ -83,7 +83,7 @@
|
||||
<div class="modal-header">
|
||||
<button type="button " class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h2 class="modal-title">
|
||||
<h4 class="modal-title">
|
||||
Create Client
|
||||
</h4>
|
||||
</div>
|
||||
@@ -151,7 +151,7 @@
|
||||
<div class="modal-header">
|
||||
<button type="button " class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h2 class="modal-title">
|
||||
<h4 class="modal-title">
|
||||
Edit Client
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<div class="modal-header">
|
||||
<button type="button " class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h2 class="modal-title">
|
||||
<h4 class="modal-title">
|
||||
Create Token
|
||||
</h4>
|
||||
</div>
|
||||
@@ -134,7 +134,7 @@
|
||||
<div class="modal-header">
|
||||
<button type="button " class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
|
||||
<h2 class="modal-title">
|
||||
<h4 class="modal-title">
|
||||
Personal Access Token
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
@@ -224,7 +224,7 @@ $(document).ready(function () {
|
||||
var answer = {
|
||||
results: data.items,
|
||||
pagination: {
|
||||
more: "true" //(params.page < data.page_count)
|
||||
more: data.pagination.more
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ $(function () {
|
||||
var answer = {
|
||||
results: data.items,
|
||||
pagination: {
|
||||
more: "true" //(params.page < data.page_count)
|
||||
more: data.pagination.more
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -465,3 +465,72 @@ h4 {
|
||||
border-top: 1px solid #dddddd;
|
||||
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";
|
||||
}
|
||||
@@ -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',
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -88,6 +88,11 @@
|
||||
'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)',
|
||||
'firstnamelastinitial' => 'First Name Last Initial (janes@example.com)',
|
||||
'first' => 'First',
|
||||
'first_name' => 'First Name',
|
||||
'first_name_format' => 'First Name (jane@example.com)',
|
||||
'files' => 'Files',
|
||||
|
||||
@@ -469,7 +469,10 @@ Form::macro('username_format', function ($name = "username_format", $selected =
|
||||
'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 = '<select name="'.$name.'" class="'.$class.'" style="width: 100%" aria-label="'.$name.'">';
|
||||
|
||||
@@ -276,7 +276,7 @@ View Assets for {{ $user->present()->fullName() }}
|
||||
}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-switchable="true" data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"><span class="sr-only">Icon</span></th>
|
||||
<th data-switchable="true" data-visible="true" data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">Icon</th>
|
||||
<th data-switchable="true" data-visible="true" class="col-sm-3" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
|
||||
<th data-switchable="true" data-visible="true" class="col-sm-3" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
||||
<th data-switchable="true" data-visible="true" class="col-sm-3" data-field="action_type">{{ trans('general.action') }}</th>
|
||||
|
||||
@@ -56,7 +56,19 @@
|
||||
<td>{{$field->format}}</td>
|
||||
<td>{{$field->element}}</td>
|
||||
<td>{{ $field->field_encrypted=='1' ? trans('general.yes') : trans('general.no') }}</td>
|
||||
<td>{{$field->pivot->required ? "REQUIRED" : "OPTIONAL"}}</td>
|
||||
<td>
|
||||
@if ($field->pivot->required)
|
||||
<a href="{{ route('fields.optional', [$custom_fieldset->id, $field->id]) }}">
|
||||
<i class="fa fa-check text-success" aria-hidden="true"></i>
|
||||
<span class="sr-only">Required - click to make optional</span>
|
||||
</a>
|
||||
@else
|
||||
<a href="{{ route('fields.required', [$custom_fieldset->id, $field->id]) }}">
|
||||
<i class="fa fa-times text-danger" aria-hidden="true"></i>
|
||||
<span class="sr-only">Optional - click to make required</span>
|
||||
</a>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
@can('update', $custom_fieldset)
|
||||
<a href="{{ route('fields.disassociate', [$field,$custom_fieldset->id]) }}" class="btn btn-sm btn-danger">Remove</a>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
'createText' => trans('admin/groups/titles.create') ,
|
||||
'updateText' => trans('admin/groups/titles.update'),
|
||||
'item' => $group,
|
||||
'formAction' => ($group !== null && $group->id !== null) ? route('groups.index', ['group' => $group->id]) : route('groups.store'),
|
||||
'formAction' => ($group !== null && $group->id !== null) ? route('groups.update', ['group' => $group->id]) : route('groups.store'),
|
||||
|
||||
])
|
||||
@section('content')
|
||||
|
||||
@@ -156,15 +156,17 @@
|
||||
$("#assigned_user").show();
|
||||
|
||||
$("#selected_status_status").removeClass('text-danger');
|
||||
$("#selected_status_status").removeClass('text-warning');
|
||||
$("#selected_status_status").addClass('text-success');
|
||||
$("#selected_status_status").html('<i class="fa fa-check"></i> That status is deployable. This asset can be checked out.');
|
||||
|
||||
|
||||
} else {
|
||||
$("#assignto_selector").hide();
|
||||
$("#selected_status_status").removeClass('text-danger');
|
||||
$("#selected_status_status").removeClass('text-success');
|
||||
$("#selected_status_status").addClass('text-danger');
|
||||
$("#selected_status_status").html('<i class="fa fa-times"></i> That asset status is not deployable. This asset cannot be checked out. ');
|
||||
$("#selected_status_status").addClass('text-warning');
|
||||
$("#selected_status_status").html('<i class="fa fa-warning"></i> That asset status is not deployable. This asset cannot be checked out. ');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,175 +1,167 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Labels</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<title>Labels</title>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php
|
||||
$settings->labels_width = $settings->labels_width - $settings->labels_display_sgutter;
|
||||
$settings->labels_height = $settings->labels_height - $settings->labels_display_bgutter;
|
||||
// Leave space on bottom for 1D barcode if necessary
|
||||
$qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->alt_barcode!='') ? $settings->labels_height - .3 : $settings->labels_height - .3;
|
||||
// Leave space on left for QR code if necessary
|
||||
$qr_txt_size = ($settings->qr_code=='1' ? $settings->labels_width - $qr_size - .1: $settings->labels_width);
|
||||
?>
|
||||
<?php
|
||||
$settings->labels_width = $settings->labels_width - $settings->labels_display_sgutter;
|
||||
$settings->labels_height = $settings->labels_height - $settings->labels_display_bgutter;
|
||||
// Leave space on bottom for 1D barcode if necessary
|
||||
$qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->alt_barcode!='') ? $settings->labels_height - .3 : $settings->labels_height - .3;
|
||||
?>
|
||||
|
||||
<style>
|
||||
<style>
|
||||
body {
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
width: {{ $settings->labels_pagewidth }}in;
|
||||
height: {{ $settings->labels_pageheight }}in;
|
||||
margin: {{ $settings->labels_pmargin_top }}in {{ $settings->labels_pmargin_right }}in {{ $settings->labels_pmargin_bottom }}in {{ $settings->labels_pmargin_left }}in;
|
||||
font-size: {{ $settings->labels_fontsize }}pt;
|
||||
}
|
||||
.label {
|
||||
width: {{ $settings->labels_width }}in;
|
||||
height: {{ $settings->labels_height }}in;
|
||||
padding: 0in;
|
||||
margin-right: {{ $settings->labels_display_sgutter }}in; /* the gutter */
|
||||
margin-bottom: {{ $settings->labels_display_bgutter }}in;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
}
|
||||
.page-break {
|
||||
page-break-after:always;
|
||||
}
|
||||
div.qr_img {
|
||||
width: {{ $qr_size }}in;
|
||||
height: {{ $qr_size }}in;
|
||||
|
||||
body {
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
width: {{ $settings->labels_pagewidth }}in;
|
||||
height: {{ $settings->labels_pageheight }}in;
|
||||
margin: {{ $settings->labels_pmargin_top }}in {{ $settings->labels_pmargin_right }}in {{ $settings->labels_pmargin_bottom }}in {{ $settings->labels_pmargin_left }}in;
|
||||
font-size: {{ $settings->labels_fontsize }}pt;
|
||||
}
|
||||
float: left;
|
||||
display: inline-flex;
|
||||
padding-right: .15in;
|
||||
}
|
||||
img.qr_img {
|
||||
|
||||
.label {
|
||||
width: {{ $settings->labels_width }}in;
|
||||
height: {{ $settings->labels_height }}in;
|
||||
padding: 0in;
|
||||
margin-right: {{ $settings->labels_display_sgutter }}in; /* the gutter */
|
||||
margin-bottom: {{ $settings->labels_display_bgutter }}in;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
}
|
||||
width: 120.79%;
|
||||
height: 120.79%;
|
||||
margin-top: -6.9%;
|
||||
margin-left: -6.9%;
|
||||
padding-bottom: .04in;
|
||||
}
|
||||
img.barcode {
|
||||
display:block;
|
||||
|
||||
.page-break {
|
||||
page-break-after:always;
|
||||
}
|
||||
padding-top: .11in;
|
||||
width: 100%;
|
||||
}
|
||||
.qr_text {
|
||||
width: {{ $settings->labels_width }}in;
|
||||
height: {{ $settings->labels_height }}in;
|
||||
padding-top: {{$settings->labels_display_bgutter}}in;
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
font-size: {{$settings->labels_fontsize}};
|
||||
padding-right: .01in;
|
||||
overflow: hidden !important;
|
||||
display: inline;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
div.barcode_container {
|
||||
|
||||
div.qr_img {
|
||||
width: {{ $qr_size }}in;
|
||||
height: {{ $qr_size }}in;
|
||||
float: left;
|
||||
display: inline-block;
|
||||
padding-right: .04in;
|
||||
}
|
||||
img.qr_img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
img.barcode {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.qr_text {
|
||||
width: {{ $qr_txt_size }}in;
|
||||
height: {{ $qr_size }}in;
|
||||
padding-top: .10in;
|
||||
font-family: arial, helvetica, sans-serif;
|
||||
padding-right: .01in;
|
||||
overflow: hidden !important;
|
||||
display: inline-block;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
div.barcode_container {
|
||||
float: left;
|
||||
width: 100%;
|
||||
display: inline;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.next-padding {
|
||||
margin: {{ $settings->labels_pmargin_top }}in {{ $settings->labels_pmargin_right }}in {{ $settings->labels_pmargin_bottom }}in {{ $settings->labels_pmargin_left }}in;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media print {
|
||||
.noprint {
|
||||
display: none !important;
|
||||
width: 100%;
|
||||
display: inline;
|
||||
overflow: hidden;
|
||||
}
|
||||
.next-padding {
|
||||
margin: {{ $settings->labels_pmargin_top }}in {{ $settings->labels_pmargin_right }}in {{ $settings->labels_pmargin_bottom }}in {{ $settings->labels_pmargin_left }}in;
|
||||
font-size: 0;
|
||||
margin: {{ $settings->labels_pmargin_top }}in {{ $settings->labels_pmargin_right }}in {{ $settings->labels_pmargin_bottom }}in {{ $settings->labels_pmargin_left }}in;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen {
|
||||
.label {
|
||||
outline: .02in black solid; /* outline doesn't occupy space like border does */
|
||||
@media print {
|
||||
.noprint {
|
||||
display: none !important;
|
||||
}
|
||||
.next-padding {
|
||||
margin: {{ $settings->labels_pmargin_top }}in {{ $settings->labels_pmargin_right }}in {{ $settings->labels_pmargin_bottom }}in {{ $settings->labels_pmargin_left }}in;
|
||||
font-size: 0;
|
||||
}
|
||||
}
|
||||
.noprint {
|
||||
font-size: 13px;
|
||||
padding-bottom: 15px;
|
||||
@media screen {
|
||||
.label {
|
||||
outline: .02in black solid; /* outline doesn't occupy space like border does */
|
||||
}
|
||||
.noprint {
|
||||
font-size: 13px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if ($snipeSettings->custom_css)
|
||||
{{ $snipeSettings->show_custom_css() }}
|
||||
@endif
|
||||
|
||||
</style>
|
||||
@if ($snipeSettings->custom_css)
|
||||
{{ $snipeSettings->show_custom_css() }}
|
||||
@endif
|
||||
</style>
|
||||
|
||||
@foreach ($assets as $asset)
|
||||
<?php $count++; ?>
|
||||
<div class="label">
|
||||
<?php $count++; ?>
|
||||
<div class="label">
|
||||
|
||||
@if ($settings->qr_code=='1')
|
||||
<div class="qr_img">
|
||||
<img src="./{{ $asset->id }}/qr_code" class="qr_img">
|
||||
</div>
|
||||
@endif
|
||||
@if ($settings->qr_code=='1')
|
||||
<div class="qr_img">
|
||||
<img src="./{{ $asset->id }}/qr_code" class="qr_img">
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="qr_text">
|
||||
@if ($settings->qr_text!='')
|
||||
<div class="pull-left">
|
||||
<strong>{{ $settings->qr_text }}</strong>
|
||||
<br>
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_company_name=='1') && ($asset->company))
|
||||
<div class="pull-left">
|
||||
C: {{ $asset->company->name }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_name=='1') && ($asset->name!=''))
|
||||
<div class="pull-left">
|
||||
N: {{ $asset->name }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_tag=='1') && ($asset->asset_tag!=''))
|
||||
<div class="pull-left">
|
||||
T: {{ $asset->asset_tag }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_serial=='1') && ($asset->serial!=''))
|
||||
<div class="pull-left">
|
||||
S: {{ $asset->serial }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_model=='1') && ($asset->model->name!=''))
|
||||
<div class="pull-left">
|
||||
M: {{ $asset->model->name }} {{ $asset->model->model_number }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="qr_text">
|
||||
@if ($settings->qr_text!='')
|
||||
<div class="pull-left">
|
||||
<strong>{{ $settings->qr_text }}</strong>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
@if ((($settings->alt_barcode_enabled=='1') && $settings->alt_barcode!=''))
|
||||
<div class="barcode_container">
|
||||
<img src="./{{ $asset->id }}/barcode" class="barcode">
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_company_name=='1') && ($asset->company))
|
||||
<div class="pull-left">
|
||||
C: {{ $asset->company->name }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_name=='1') && ($asset->name!=''))
|
||||
<div class="pull-left">
|
||||
N: {{ $asset->name }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_tag=='1') && ($asset->asset_tag!=''))
|
||||
<div class="pull-left">
|
||||
T: {{ $asset->asset_tag }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_serial=='1') && ($asset->serial!=''))
|
||||
<div class="pull-left">
|
||||
S: {{ $asset->serial }}
|
||||
</div>
|
||||
@endif
|
||||
@if (($settings->labels_display_model=='1') && ($asset->model->name!=''))
|
||||
<div class="pull-left">
|
||||
M: {{ $asset->model->name }} {{ $asset->model->model_number }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@if ((($settings->alt_barcode_enabled=='1') && $settings->alt_barcode!=''))
|
||||
<div class="barcode_container">
|
||||
<img src="./{{ $asset->id }}/barcode" class="barcode">
|
||||
</div>
|
||||
@if ($count % $settings->labels_per_page == 0)
|
||||
<div class="page-break"></div>
|
||||
<div class="next-padding"> </div>
|
||||
@endif
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@if ($count % $settings->labels_per_page == 0)
|
||||
<div class="page-break"></div>
|
||||
<div class="next-padding"> </div>
|
||||
@endif
|
||||
|
||||
@endforeach
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@@ -995,7 +995,7 @@
|
||||
data-cookie-id-table="assetHistory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="icon" data-visible="true" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"><span class="sr-only">Icon</span></th>
|
||||
<th data-visible="true" style="width: 40px;" class="hidden-xs">Icon</th>
|
||||
<th class="col-sm-2" data-visible="true" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
|
||||
<th class="col-sm-1" data-visible="true" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
||||
<th class="col-sm-1" data-visible="true" data-field="action_type">{{ trans('general.action') }}</th>
|
||||
@@ -1039,7 +1039,7 @@
|
||||
data-cookie-id-table="assetFileHistory">
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-visible="true" data-field="icon"><span class="sr-only">Icon</span></th>
|
||||
<th data-visible="true" data-field="icon">Icon</th>
|
||||
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="notes">{{ trans('general.notes') }}</th>
|
||||
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="image">{{ trans('general.image') }}</th>
|
||||
<th class="col-md-2" data-searchable="true" data-visible="true" data-field="filename">{{ trans('general.file_name') }}</th>
|
||||
|
||||
@@ -810,7 +810,7 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h2 class="modal-title" id="myModalLabel">&nbps;</h4>
|
||||
<h4 class="modal-title" id="myModalLabel"> </h4>
|
||||
</div>
|
||||
<div class="modal-body"></div>
|
||||
<div class="modal-footer">
|
||||
@@ -829,6 +829,7 @@
|
||||
|
||||
|
||||
<script src="{{ url(mix('js/dist/all.js')) }}" nonce="{{ csrf_token() }}"></script>
|
||||
<script src="/js/pGenerator.jquery.js"></script>
|
||||
|
||||
@section('moar_scripts')
|
||||
@show
|
||||
|
||||
@@ -326,9 +326,9 @@
|
||||
|
||||
<table
|
||||
data-columns="{{ \App\Presenters\LicensePresenter::dataTableLayoutSeats() }}"
|
||||
data-cookie-id-table="seatsTable-{{ $license->id }}"
|
||||
data-id-table="seatsTable-{{ $license->id }}"
|
||||
id="seatsTable-{{$license->id}}"
|
||||
data-cookie-id-table="seatsTable"
|
||||
data-id-table="seatsTable"
|
||||
id="seatsTable"
|
||||
data-pagination="true"
|
||||
data-search="false"
|
||||
data-side-pagination="server"
|
||||
@@ -375,7 +375,7 @@
|
||||
}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-visible="true" aria-hidden="true"><span class="sr-only">Icon</span></th>
|
||||
<th data-visible="true" aria-hidden="true">Icon</th>
|
||||
<th class="col-md-4" data-field="file_name" data-visible="true" data-sortable="true" data-switchable="true">{{ trans('general.file_name') }}</th>
|
||||
<th class="col-md-4" data-field="notes" data-visible="true" data-sortable="true" data-switchable="true">{{ trans('general.notes') }}</th>
|
||||
<th class="col-md-2" data-field="created_at" data-visible="true" data-sortable="true" data-switchable="true">{{ trans('general.created_at') }}</th>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-manufacturer_id">{{ trans('general.manufacturer') }}:
|
||||
</label></div>
|
||||
<div class="col-md-8 col-xs-12 required">
|
||||
<select class="js-data-ajax" data-endpoint="manufacturers" name="manufacturer_id" style="width: 100%" id="modal-manufactuer_id" />
|
||||
<select class="js-data-ajax" data-endpoint="manufacturers" name="manufacturer_id" style="width: 100%" id="modal-manufactuer_id"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-category_id">{{ trans('general.category') }}:
|
||||
</label></div>
|
||||
<div class="col-md-8 col-xs-12 required">
|
||||
<select class="js-data-ajax" data-endpoint="categories/asset" name="category_id" style="width: 100%" id="modal-category_id" />
|
||||
<select class="js-data-ajax" data-endpoint="categories/asset" name="category_id" style="width: 100%" id="modal-category_id"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{{-- See snipeit_modals.js for what powers this --}}
|
||||
<script src="/js/pGenerator.jquery.js"></script>
|
||||
|
||||
|
||||
<script nonce="{{ csrf_token() }}">
|
||||
$(document).ready(function () {
|
||||
|
||||
$('#genPassword').pGenerator({
|
||||
window.setTimeout(function () {
|
||||
$('#modal-genPassword').pGenerator({
|
||||
'bind': 'click',
|
||||
'passwordElement': '#modal-password',
|
||||
'displayElement': '#generated-password',
|
||||
'displayElement': '#modal-generated-password',
|
||||
'passwordLength': 16,
|
||||
'uppercase': true,
|
||||
'lowercase': true,
|
||||
@@ -17,13 +17,14 @@
|
||||
$('#modal-password_confirmation').val($('#modal-password').val());
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 1000);
|
||||
</script>
|
||||
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
<h2 class="modal-title">{{ trans('admin/users/table.createuser') }}</h4>
|
||||
<h2 class="modal-title">{{ trans('admin/users/table.createuser') }}</h2>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{{ route('api.users.store') }}" onsubmit="return false">
|
||||
@@ -47,14 +48,14 @@
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-password">{{ trans('admin/users/table.password') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='password' name="password" id='modal-password' class="form-control">
|
||||
<a href="#" class="left" id="genPassword">Generate</a>
|
||||
<a href="#" class="left" id="modal-genPassword">Generate</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-form-row">
|
||||
<div class="col-md-4 col-xs-12"><label for="modal-password_confirmation">{{ trans('admin/users/table.password_confirm') }}:</label></div>
|
||||
<div class="col-md-8 col-xs-12 required"><input type='password' name="password_confirmation" id='modal-password_confirmation' class="form-control">
|
||||
<div id="generated-password"></div>
|
||||
<div id="modal-generated-password"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<label class="col-md-3 control-label" for="image">{{ trans('general.image_upload') }}</label>
|
||||
<div class="col-md-9">
|
||||
|
||||
<input type="file" id="image" name="image" aria-label="image">
|
||||
<input type="file" id="image" name="image" aria-label="image" class="sr-only">
|
||||
|
||||
<label class="btn btn-default" aria-hidden="true">
|
||||
{{ trans('button.select_file') }}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"><span class="sr-only">Icon</span></th>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">Icon</th>
|
||||
<th class="col-sm-3" data-searchable="false" data-sortable="true" data-field="created_at" data-formatter="dateDisplayFormatter">{{ trans('general.date') }}</th>
|
||||
<th class="col-sm-2" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
||||
<th class="col-sm-2" data-field="action_type">{{ trans('general.action') }}</th>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="company" data-sortable="false" data-visible="false">{{ trans('admin/companies/table.title') }}</th>
|
||||
<th data-field="company" data-sortable="false" data-visible="false" data-formatter="companiesLinkObjFormatter">{{ trans('admin/companies/table.title') }}</th>
|
||||
<th data-sortable="true" data-field="id" data-visible="false">{{ trans('general.id') }}</th>
|
||||
<th data-sortable="false" data-field="asset_name" data-formatter="assetNameLinkFormatter">{{ trans('admin/asset_maintenances/table.asset_name') }}</th>
|
||||
<th data-sortable="false" data-field="supplier" data-formatter="suppliersLinkObjFormatter">{{ trans('general.supplier') }}</th>
|
||||
|
||||
@@ -55,6 +55,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- City -->
|
||||
<div class="form-group{{ $errors->has('city') ? ' has-error' : '' }}">
|
||||
<label class="col-md-3 control-label" for="city">{{ trans('general.city') }}</label>
|
||||
<div class="col-md-4">
|
||||
<input class="form-control" type="text" name="city" id="city" aria-label="city" />
|
||||
{!! $errors->first('city', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- activated -->
|
||||
<div class="form-group">
|
||||
<div class="col-sm-3 control-label">
|
||||
|
||||
@@ -610,7 +610,6 @@
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
<script src="{{ asset('js/pGenerator.jquery.js') }}"></script>
|
||||
|
||||
<script nonce="{{ csrf_token() }}">
|
||||
$(document).ready(function() {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
@stop
|
||||
|
||||
@section('header_right')
|
||||
|
||||
@can('create', \App\Models\User::class)
|
||||
@if ($snipeSettings->ldap_enabled == 1)
|
||||
<a href="{{ route('ldap/user') }}" class="btn btn-default pull-right"><span class="fa fa-sitemap"></span> LDAP Sync</a>
|
||||
@@ -74,7 +75,7 @@
|
||||
id="usersTable"
|
||||
class="table table-striped snipe-table"
|
||||
data-url="{{ route('api.users.index',
|
||||
array('deleted'=> (Input::get('status')=='deleted') ? 'true' : 'false','company_id'=>e(Input::get('company_id')))) }}"
|
||||
array('deleted'=> (request('status')=='deleted') ? 'true' : 'false','company_id' => e(request('company_id')))) }}"
|
||||
data-export-options='{
|
||||
"fileName": "export-users-{{ date('Y-m-d') }}",
|
||||
"ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"]
|
||||
@@ -91,6 +92,8 @@
|
||||
@stop
|
||||
|
||||
@section('moar_scripts')
|
||||
|
||||
|
||||
@include ('partials.bootstrap-table')
|
||||
|
||||
|
||||
|
||||
@@ -142,11 +142,31 @@
|
||||
<td class="text-nowrap">{{ trans('admin/users/table.name') }}</td>
|
||||
<td>{{ $user->present()->fullName() }}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="text-nowrap">{{ trans('admin/users/table.username') }}</td>
|
||||
<td>{{ $user->username }}</td>
|
||||
</tr>
|
||||
@if (($user->address) || ($user->city) || ($user->state) || ($user->country))
|
||||
<tr>
|
||||
<td class="text-nowrap">{{ trans('general.address') }}</td>
|
||||
<td>
|
||||
@if ($user->address)
|
||||
{{ $user->address }} <br>
|
||||
@endif
|
||||
@if ($user->city)
|
||||
{{ $user->city }}
|
||||
@endif
|
||||
@if ($user->state)
|
||||
{{ $user->state }}
|
||||
@endif
|
||||
@if ($user->country)
|
||||
{{ $user->country }}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@endif
|
||||
<tr>
|
||||
<td class="text-nowrap">{{ trans('general.groups') }}</td>
|
||||
<td>
|
||||
@@ -244,6 +264,13 @@
|
||||
<td class="text-nowrap">{{ trans('general.login_enabled') }}</td>
|
||||
<td>{{ ($user->activated=='1') ? trans('general.yes') : trans('general.no') }}</td>
|
||||
</tr>
|
||||
@if ($user->ldap_import!='1')
|
||||
<tr>
|
||||
<td class="text-nowrap">LDAP</td>
|
||||
<td>{{ trans('general.yes') }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
|
||||
@if ($user->activated=='1')
|
||||
<tr>
|
||||
@@ -278,6 +305,13 @@
|
||||
|
||||
@endif
|
||||
|
||||
@if ($user->notes)
|
||||
<tr>
|
||||
<td class="text-nowrap">{{ trans('admin/users/table.notes') }}</td>
|
||||
<td>{{ $user->notes }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
|
||||
</table>
|
||||
</div>
|
||||
@@ -290,7 +324,7 @@
|
||||
<a href="{{ route('users.edit', $user->id) }}" style="width: 100%;" class="btn btn-sm btn-primary hidden-print">{{ trans('admin/users/general.edit') }}</a>
|
||||
</div>
|
||||
@endcan
|
||||
|
||||
|
||||
@can('create', $user)
|
||||
<div class="col-md-12" style="padding-top: 5px;">
|
||||
<a href="{{ route('clone/user', $user->id) }}" style="width: 100%;" class="btn btn-sm btn-primary hidden-print">{{ trans('admin/users/general.clone') }}</a>
|
||||
@@ -522,7 +556,7 @@
|
||||
}'>
|
||||
<thead>
|
||||
<tr>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter"><span class="sr-only">Icon</span></th>
|
||||
<th data-field="icon" style="width: 40px;" class="hidden-xs" data-formatter="iconFormatter">Icon</th>
|
||||
<th class="col-sm-3" data-field="created_at" data-formatter="dateDisplayFormatter" data-sortable="true">{{ trans('general.date') }}</th>
|
||||
<th class="col-sm-2" data-field="admin" data-formatter="usersLinkObjFormatter">{{ trans('general.admin') }}</th>
|
||||
<th class="col-sm-2" data-field="action_type">{{ trans('general.action') }}</th>
|
||||
|
||||
+16
-7
@@ -189,7 +189,6 @@ Route::group(['prefix' => 'v1','namespace' => 'Api', 'middleware' => 'api'], fun
|
||||
|
||||
|
||||
/*--- Consumables API ---*/
|
||||
|
||||
Route::resource('consumables', 'ConsumablesController',
|
||||
[
|
||||
'names' =>
|
||||
@@ -204,12 +203,22 @@ Route::group(['prefix' => 'v1','namespace' => 'Api', 'middleware' => 'api'], fun
|
||||
'parameters' => ['consumable' => 'consumable_id']
|
||||
]
|
||||
); // 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 ---*/
|
||||
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
|
||||
Route::group([ 'prefix' => 'fields','middleware' => ['auth'] ], function () {
|
||||
|
||||
Route::get('required/{fieldset_id}/{field_id}',
|
||||
['uses' => 'CustomFieldsetsController@makeFieldRequired',
|
||||
'as' => 'fields.required']
|
||||
);
|
||||
|
||||
Route::get('optional/{fieldset_id}/{field_id}',
|
||||
['uses' => 'CustomFieldsetsController@makeFieldOptional',
|
||||
'as' => 'fields.optional']
|
||||
);
|
||||
|
||||
Route::get('{field_id}/fieldset/{fieldset_id}/disassociate',
|
||||
['uses' => 'CustomFieldsController@deleteFieldFromFieldset',
|
||||
'as' => 'fields.disassociate']
|
||||
|
||||
+1
-1
@@ -422,7 +422,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)
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ class GroupsCest
|
||||
$I->wantTo("Test Validation Fails with short name");
|
||||
$I->amOnPage(route('groups.create'));
|
||||
$I->seeResponseCodeIs(200);
|
||||
$I->fillField('name', 't2');
|
||||
$I->fillField('name', 't');
|
||||
$I->click('Save');
|
||||
$I->seeElement('.alert-danger');
|
||||
$I->see('The name must be at least 3 characters', '.alert-msg');
|
||||
|
||||
+29
-2
@@ -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('firstname_lastname', $fullname);
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
@@ -86,6 +86,33 @@ class UserTest extends BaseTest
|
||||
$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('firstinitial.lastname', $fullname);
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
public function lastNameUnderscoreFirstInitial()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'allanovnaromanovaoshostakova_n';
|
||||
$user = User::generateFormattedNameFromFullName('lastname_firstinitial', $fullname);
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
public function firstNameLastName()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'nataliaallanovnaromanovaoshostakova';
|
||||
$user = User::generateFormattedNameFromFullName('firstnamelastname', $fullname);
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
public function firstNameLastInitial()
|
||||
{
|
||||
$fullname = "Natalia Allanovna Romanova-O'Shostakova";
|
||||
$expected_username = 'nataliaa';
|
||||
$user = User::generateFormattedNameFromFullName('firstnamelastinitial', $fullname);
|
||||
$this->assertEquals($expected_username, $user['username']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user