Merge branch 'develop' into develop
This commit is contained in:
commit
c2c009a018
693 changed files with 6136 additions and 3136 deletions
|
@ -2783,6 +2783,60 @@
|
|||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "lukasfehling",
|
||||
"name": "Lukas Fehling",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/56871540?v=4",
|
||||
"profile": "https://github.com/lukasfehling",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "fernando-almeida",
|
||||
"name": "Fernando Almeida",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1975990?v=4",
|
||||
"profile": "https://github.com/fernando-almeida",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "akemidx",
|
||||
"name": "akemidx",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/116301219?v=4",
|
||||
"profile": "https://github.com/akemidx",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "oguzbilgic",
|
||||
"name": "Oguz Bilgic",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/144778?v=4",
|
||||
"profile": "http://oguz.site",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "scoo73r",
|
||||
"name": "Scooter Crawford",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/9262438?v=4",
|
||||
"profile": "https://github.com/scoo73r",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "subdriven",
|
||||
"name": "subdriven",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/5957345?v=4",
|
||||
"profile": "https://github.com/subdriven",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -174,3 +174,9 @@ REPORT_TIME_LIMIT=12000
|
|||
REQUIRE_SAML=false
|
||||
API_THROTTLE_PER_MINUTE=120
|
||||
CSV_ESCAPE_FORMULAS=true
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: SCIM
|
||||
# --------------------------------------------
|
||||
SCIM_TRACE=false
|
||||
SCIM_STANDARDS_COMPLIANCE=false
|
2
.github/workflows/SA-codeql.yml
vendored
2
.github/workflows/SA-codeql.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
|||
language: [ 'javascript' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
|
2
.github/workflows/codacy-analysis.yml
vendored
2
.github/workflows/codacy-analysis.yml
vendored
|
@ -32,7 +32,7 @@ jobs:
|
|||
steps:
|
||||
# Checkout the repository to the GitHub Actions runner
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||
- name: Run Codacy Analysis CLI
|
||||
|
|
2
.github/workflows/docker-alpine.yml
vendored
2
.github/workflows/docker-alpine.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
|||
steps:
|
||||
# https://github.com/actions/checkout
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
|
|
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
|||
steps:
|
||||
# https://github.com/actions/checkout
|
||||
- name: Checkout codebase
|
||||
uses: actions/checkout@v3.1.0
|
||||
uses: actions/checkout@v3.3.0
|
||||
|
||||
# https://github.com/docker/setup-buildx-action
|
||||
- name: Setup Docker Buildx
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
 [](https://crowdin.com/project/snipe-it) [](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://discord.gg/yZFtShAcKk) [](https://huntr.dev)
|
||||
[](#contributors) [](https://discord.gg/yZFtShAcKk) [](https://huntr.dev)
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
|
||||
|
@ -60,6 +60,7 @@ Since the release of the JSON REST API, several third-party developers have been
|
|||
- [InQRy -unmaintained-](https://github.com/Microsoft/InQRy) by [@Microsoft](https://github.com/Microsoft)
|
||||
- [SnipeitPS](https://github.com/snazy2000/SnipeitPS) by [@snazy2000](https://github.com/snazy2000) - Powershell API Wrapper for Snipe-it
|
||||
- [jamf2snipe](https://github.com/grokability/jamf2snipe) - Python script to sync assets between a JAMFPro instance and a Snipe-IT instance
|
||||
- [jamf-snipe-rename](https://macblog.org/jamf-snipe-rename/) - Python script to rename computers in Jamf from Snipe-IT
|
||||
- [Marksman](https://github.com/Scope-IT/marksman) - A Windows agent for Snipe-IT
|
||||
- [Snipe-IT plugin for Jira Service Desk](https://marketplace.atlassian.com/apps/1220964/snipe-it-for-jira)
|
||||
- [Python 3 CSV importer](https://github.com/gastamper/snipeit-csvimporter) - allows importing assets into Snipe-IT based on Item Name rather than Asset Tag.
|
||||
|
@ -138,7 +139,8 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
|||
| [<img src="https://avatars.githubusercontent.com/u/38761237?v=4" width="110px;"/><br /><sub>Alex Janes</sub>](https://adagiohealth.org)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adagioajanes "Code") | [<img src="https://avatars.githubusercontent.com/u/32387849?v=4" width="110px;"/><br /><sub>Nuraeil</sub>](https://github.com/nuraeil)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nuraeil "Code") | [<img src="https://avatars.githubusercontent.com/u/48162670?v=4" width="110px;"/><br /><sub>TenOfTens</sub>](https://github.com/TenOfTens)<br />[💻](https://github.com/snipe/snipe-it/commits?author=TenOfTens "Code") | [<img src="https://avatars.githubusercontent.com/u/9415391?v=4" width="110px;"/><br /><sub>waffle</sub>](https://ditisjens.be/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=insert-waffle "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") | [<img src="https://avatars.githubusercontent.com/u/3839381?v=4" width="110px;"/><br /><sub>Achmad Fienan Rahardianto</sub>](https://github.com/veenone)<br />[💻](https://github.com/snipe/snipe-it/commits?author=veenone "Code") | [<img src="https://avatars.githubusercontent.com/u/19945501?v=4" width="110px;"/><br /><sub>Yevhenii Huzii</sub>](https://github.com/QveenSi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=QveenSi "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/97299851?v=4" width="110px;"/><br /><sub>Christian Weirich</sub>](https://github.com/chrisweirich)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chrisweirich "Code") | [<img src="https://avatars.githubusercontent.com/u/1294403?v=4" width="110px;"/><br /><sub>denzfarid</sub>](https://github.com/denzfarid)<br /> | [<img src="https://avatars.githubusercontent.com/u/94018771?v=4" width="110px;"/><br /><sub>ntbutler-nbcs</sub>](https://github.com/ntbutler-nbcs)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ntbutler-nbcs "Code") | [<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="110px;"/><br /><sub>Naveen</sub>](https://naveensrinivasan.dev)<br />[💻](https://github.com/snipe/snipe-it/commits?author=naveensrinivasan "Code") | [<img src="https://avatars.githubusercontent.com/u/55674383?v=4" width="110px;"/><br /><sub>Mike Roquemore</sub>](https://github.com/mikeroq)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikeroq "Code") | [<img src="https://avatars.githubusercontent.com/u/7991086?v=4" width="110px;"/><br /><sub>Daniel Reeder</sub>](https://github.com/reederda)<br />[🌍](#translation-reederda "Translation") [🌍](#translation-reederda "Translation") [💻](https://github.com/snipe/snipe-it/commits?author=reederda "Code") | [<img src="https://avatars.githubusercontent.com/u/109422491?v=4" width="110px;"/><br /><sub>vickyjaura183</sub>](https://github.com/vickyjaura183)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vickyjaura183 "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/32363424?v=4" width="110px;"/><br /><sub>Peace</sub>](https://github.com/julian-piehl)<br />[💻](https://github.com/snipe/snipe-it/commits?author=julian-piehl "Code") | [<img src="https://avatars.githubusercontent.com/u/231528?v=4" width="110px;"/><br /><sub>Kyle Gordon</sub>](https://github.com/kylegordon)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kylegordon "Code") | [<img src="https://avatars.githubusercontent.com/u/53009155?v=4" width="110px;"/><br /><sub>Katharina Drexel</sub>](http://www.bfh.ch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sunflowerbofh "Code") | [<img src="https://avatars.githubusercontent.com/u/1931963?v=4" width="110px;"/><br /><sub>David Sferruzza</sub>](https://david.sferruzza.fr/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=dsferruzza "Code") | [<img src="https://avatars.githubusercontent.com/u/19511639?v=4" width="110px;"/><br /><sub>Rick Nelson</sub>](https://github.com/rnelsonee)<br />[💻](https://github.com/snipe/snipe-it/commits?author=rnelsonee "Code") | [<img src="https://avatars.githubusercontent.com/u/94169344?v=4" width="110px;"/><br /><sub>BasO12</sub>](https://github.com/BasO12)<br />[💻](https://github.com/snipe/snipe-it/commits?author=BasO12 "Code") | [<img src="https://avatars.githubusercontent.com/u/111710123?v=4" width="110px;"/><br /><sub>Vautia</sub>](https://github.com/Vautia)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Vautia "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") | [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/28321?v=4" width="110px;"/><br /><sub>Chris Hartjes</sub>](http://www.littlehart.net/atthekeyboard)<br />[💻](https://github.com/snipe/snipe-it/commits?author=chartjes "Code") | [<img src="https://avatars.githubusercontent.com/u/2404584?v=4" width="110px;"/><br /><sub>geo-chen</sub>](https://github.com/geo-chen)<br />[💻](https://github.com/snipe/snipe-it/commits?author=geo-chen "Code") | [<img src="https://avatars.githubusercontent.com/u/6006620?v=4" width="110px;"/><br /><sub>Phan Nguyen</sub>](https://github.com/nh314)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nh314 "Code") | [<img src="https://avatars.githubusercontent.com/u/115993812?v=4" width="110px;"/><br /><sub>Iisakki Jaakkola</sub>](https://github.com/StarlessNights)<br />[💻](https://github.com/snipe/snipe-it/commits?author=StarlessNights "Code") | [<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="110px;"/><br /><sub>Ikko Ashimine</sub>](https://bandism.net/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=eltociear "Code") | [<img src="https://avatars.githubusercontent.com/u/56871540?v=4" width="110px;"/><br /><sub>Lukas Fehling</sub>](https://github.com/lukasfehling)<br />[💻](https://github.com/snipe/snipe-it/commits?author=lukasfehling "Code") | [<img src="https://avatars.githubusercontent.com/u/1975990?v=4" width="110px;"/><br /><sub>Fernando Almeida</sub>](https://github.com/fernando-almeida)<br />[💻](https://github.com/snipe/snipe-it/commits?author=fernando-almeida "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/116301219?v=4" width="110px;"/><br /><sub>akemidx</sub>](https://github.com/akemidx)<br />[💻](https://github.com/snipe/snipe-it/commits?author=akemidx "Code") | [<img src="https://avatars.githubusercontent.com/u/144778?v=4" width="110px;"/><br /><sub>Oguz Bilgic</sub>](http://oguz.site)<br />[💻](https://github.com/snipe/snipe-it/commits?author=oguzbilgic "Code") | [<img src="https://avatars.githubusercontent.com/u/9262438?v=4" width="110px;"/><br /><sub>Scooter Crawford</sub>](https://github.com/scoo73r)<br />[💻](https://github.com/snipe/snipe-it/commits?author=scoo73r "Code") | [<img src="https://avatars.githubusercontent.com/u/5957345?v=4" width="110px;"/><br /><sub>subdriven</sub>](https://github.com/subdriven)<br />[💻](https://github.com/snipe/snipe-it/commits?author=subdriven "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
|
4
app.json
4
app.json
|
@ -148,7 +148,7 @@
|
|||
"image": "heroku/php",
|
||||
"addons": [
|
||||
"cleardb:ignite",
|
||||
"heroku-redis:hobby-dev",
|
||||
"heroku-redis:mini",
|
||||
"papertrail:choklad"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class CheckoutLicenseToAllUsers extends Command
|
|||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Command description';
|
||||
protected $description = 'Checks out licenses to all users';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Department;
|
||||
use App\Models\Group;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Ldap;
|
||||
|
@ -57,6 +58,7 @@ class LdapSync extends Command
|
|||
$ldap_result_country = Setting::getSettings()->ldap_country;
|
||||
$ldap_result_dept = Setting::getSettings()->ldap_dept;
|
||||
$ldap_result_manager = Setting::getSettings()->ldap_manager;
|
||||
$ldap_default_group = Setting::getSettings()->ldap_default_group;
|
||||
|
||||
try {
|
||||
$ldapconn = Ldap::connectToLdap();
|
||||
|
@ -177,6 +179,16 @@ class LdapSync extends Command
|
|||
|
||||
$manager_cache = [];
|
||||
|
||||
if($ldap_default_group != null) {
|
||||
|
||||
$default = Group::find($ldap_default_group);
|
||||
if (!$default) {
|
||||
$ldap_default_group = null; // un-set the default group if that group doesn't exist
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
for ($i = 0; $i < $results['count']; $i++) {
|
||||
$item = [];
|
||||
$item['username'] = isset($results[$i][$ldap_result_username][0]) ? $results[$i][$ldap_result_username][0] : '';
|
||||
|
@ -192,6 +204,7 @@ class LdapSync extends Command
|
|||
$item['department'] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : '';
|
||||
$item['manager'] = isset($results[$i][$ldap_result_manager][0]) ? $results[$i][$ldap_result_manager][0] : '';
|
||||
|
||||
|
||||
$department = Department::firstOrCreate([
|
||||
'name' => $item['department'],
|
||||
]);
|
||||
|
@ -326,6 +339,10 @@ class LdapSync extends Command
|
|||
if ($user->save()) {
|
||||
$item['note'] = $item['createorupdate'];
|
||||
$item['status'] = 'success';
|
||||
if ( $item['createorupdate'] === 'created' && $ldap_default_group) {
|
||||
$user->groups()->attach($ldap_default_group);
|
||||
}
|
||||
|
||||
} else {
|
||||
foreach ($user->getErrors()->getMessages() as $key => $err) {
|
||||
$errors .= $err[0];
|
||||
|
|
|
@ -214,7 +214,7 @@ class RestoreFromBackup extends Command
|
|||
$env_vars['MYSQL_PWD'] = config('database.connections.mysql.password');
|
||||
// TODO notes: we are stealing the dump_binary_path (which *probably* also has your copy of the mysql binary in it. But it might not, so we might need to extend this)
|
||||
// we unilaterally prepend a slash to the `mysql` command. This might mean your path could look like /blah/blah/blah//mysql - which should be fine. But maybe in some environments it isn't?
|
||||
$mysql_binary = config('database.connections.mysql.dump.dump_binary_path').'/mysql';
|
||||
$mysql_binary = config('database.connections.mysql.dump.dump_binary_path').\DIRECTORY_SEPARATOR.'mysql'.(\DIRECTORY_SEPARATOR == '\\' ? ".exe" : "");
|
||||
if( ! file_exists($mysql_binary) ) {
|
||||
return $this->error("mysql tool at: '$mysql_binary' does not exist, cannot restore. Please edit DB_DUMP_PATH in your .env to point to a directory that contains the mysqldump and mysql binary");
|
||||
}
|
||||
|
|
|
@ -39,33 +39,39 @@ class SyncAssetCounters extends Command
|
|||
public function handle()
|
||||
{
|
||||
$start = microtime(true);
|
||||
|
||||
// We need the whole count of all assets in order to set up the progress bar
|
||||
$assets_count = Asset::withTrashed()->count();
|
||||
$bar = $this->output->createProgressBar($assets_count);
|
||||
|
||||
$assets = Asset::withCount('checkins as checkins_count', 'checkouts as checkouts_count', 'userRequests as user_requests_count')
|
||||
->withTrashed()->get();
|
||||
->withTrashed()->chunk(100, function ($assets) use ($bar) {
|
||||
|
||||
if ($assets) {
|
||||
if ($assets->count() > 0) {
|
||||
$bar = $this->output->createProgressBar($assets->count());
|
||||
if ($assets->count() > 0) {
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
$asset->checkin_counter = (int) $asset->checkins_count;
|
||||
$asset->checkout_counter = (int) $asset->checkouts_count;
|
||||
$asset->requests_counter = (int) $asset->user_requests_count;
|
||||
$asset->unsetEventDispatcher();
|
||||
$asset->save();
|
||||
$output['info'][] = 'Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests';
|
||||
$bar->advance();
|
||||
}
|
||||
$bar->finish();
|
||||
foreach ($assets as $asset) {
|
||||
|
||||
foreach ($output['info'] as $key => $output_text) {
|
||||
$this->info($output_text);
|
||||
}
|
||||
$asset->checkin_counter = (int) $asset->checkins_count;
|
||||
$asset->checkout_counter = (int) $asset->checkouts_count;
|
||||
$asset->requests_counter = (int) $asset->user_requests_count;
|
||||
$asset->unsetEventDispatcher();
|
||||
$asset->save();
|
||||
$bar->advance();
|
||||
|
||||
\Log::debug('Asset: '.$asset->id.' has '.$asset->checkin_counter.' checkins, '.$asset->checkout_counter.' checkouts, and '.$asset->requests_counter.' requests');
|
||||
|
||||
}
|
||||
|
||||
$time_elapsed_secs = microtime(true) - $start;
|
||||
$this->info('Sync executed in '.$time_elapsed_secs.' seconds');
|
||||
} else {
|
||||
$this->info('No assets to sync');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$bar->finish();
|
||||
$time_elapsed_secs = microtime(true) - $start;
|
||||
$this->info("\nSync of ".$assets_count.' assets executed in '.$time_elapsed_secs.' seconds');
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ use App\Models\Statuslabel;
|
|||
use Crypt;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Image;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class Helper
|
||||
{
|
||||
|
@ -1125,6 +1126,26 @@ class Helper
|
|||
|
||||
return $settings;
|
||||
}
|
||||
public static function AgeFormat($date) {
|
||||
$year = Carbon::parse($date)
|
||||
->diff(now())->y;
|
||||
$month = Carbon::parse($date)
|
||||
->diff(now())->m;
|
||||
$days = Carbon::parse($date)
|
||||
->diff(now())->d;
|
||||
$age='';
|
||||
if ($year) {
|
||||
$age .= $year.'y ';
|
||||
}
|
||||
if ($month) {
|
||||
$age .= $month.'m ';
|
||||
}
|
||||
if ($days) {
|
||||
$age .= $days.'d';
|
||||
}
|
||||
|
||||
return $age;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conversion between units of measurement
|
||||
|
@ -1164,5 +1185,4 @@ class Helper
|
|||
default: throw new \InvalidArgumentException('Unit: \''.$unit.'\' is not supported');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
186
app/Http/Controllers/Accessories/AccessoriesFilesController.php
Normal file
186
app/Http/Controllers/Accessories/AccessoriesFilesController.php
Normal file
|
@ -0,0 +1,186 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Accessories;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AssetFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Accessory;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Accessory\HttpFoundation\JsonResponse;
|
||||
use enshrined\svgSanitize\Sanitizer;
|
||||
|
||||
class AccessoriesFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a accessory.
|
||||
*
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param AssetFileRequest $request
|
||||
* @param int $accessoryId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store(AssetFileRequest $request, $accessoryId = null)
|
||||
{
|
||||
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('accessories.show', ['accessory'=>$accessoryId])->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
|
||||
$accessory = Accessory::find($accessoryId);
|
||||
|
||||
if (isset($accessory->id)) {
|
||||
$this->authorize('accessories.files', $accessory);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/accessories')) {
|
||||
Storage::makeDirectory('private_uploads/accessories', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
$file_name = 'accessory-'.$accessory->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
||||
|
||||
|
||||
// Check for SVG and sanitize it
|
||||
if ($extension == 'svg') {
|
||||
\Log::debug('This is an SVG');
|
||||
\Log::debug($file_name);
|
||||
|
||||
$sanitizer = new Sanitizer();
|
||||
$dirtySVG = file_get_contents($file->getRealPath());
|
||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||
|
||||
try {
|
||||
Storage::put('private_uploads/accessories/'.$file_name, $cleanSVG);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Upload no workie :( ');
|
||||
\Log::debug($e);
|
||||
}
|
||||
|
||||
} else {
|
||||
Storage::put('private_uploads/accessories/'.$file_name, file_get_contents($file));
|
||||
}
|
||||
|
||||
//Log the upload to the log
|
||||
$accessory->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('accessories.show', $accessory->id)->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.show', $accessory->id)->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('accessories.index')
|
||||
->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected accessory file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $accessoryId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($accessoryId = null, $fileId = null)
|
||||
{
|
||||
$accessory = Accessory::find($accessoryId);
|
||||
|
||||
// the asset is valid
|
||||
if (isset($accessory->id)) {
|
||||
$this->authorize('update', $accessory);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('accessories/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('accessories/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the licence management page
|
||||
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $accessoryId
|
||||
* @param int $fileId
|
||||
* @return \Symfony\Accessory\HttpFoundation\Response
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($accessoryId = null, $fileId = null, $download = true)
|
||||
{
|
||||
|
||||
\Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||
$accessory = Accessory::find($accessoryId);
|
||||
|
||||
|
||||
|
||||
// the accessory is valid
|
||||
if (isset($accessory->id)) {
|
||||
$this->authorize('view', $accessory);
|
||||
$this->authorize('accessories.files', $accessory);
|
||||
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/accessories/'.$log->filename;
|
||||
|
||||
if (Storage::missing($file)) {
|
||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||
\Log::debug('URL should be '.Storage::url($file));
|
||||
|
||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||
->header('Content-Type', 'text/plain');
|
||||
} else {
|
||||
|
||||
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
|
||||
// won't work, as they're not accessible via the web
|
||||
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
|
||||
return StorageHelper::downloader($file);
|
||||
} else {
|
||||
if ($download != 'true') {
|
||||
\Log::debug('display the file');
|
||||
if ($contents = file_get_contents(Storage::url($file))) { // TODO - this will fail on private S3 files or large public ones
|
||||
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
|
||||
}
|
||||
|
||||
return JsonResponse::create(['error' => 'Failed validation: '], 500);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader($file);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('accessories.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
|
||||
}
|
||||
}
|
|
@ -100,6 +100,7 @@ class AssetsController extends Controller
|
|||
'checkout_counter',
|
||||
'checkin_counter',
|
||||
'requests_counter',
|
||||
'byod',
|
||||
];
|
||||
|
||||
$filter = [];
|
||||
|
@ -120,7 +121,6 @@ class AssetsController extends Controller
|
|||
|
||||
if ($filter_non_deprecable_assets) {
|
||||
$non_deprecable_models = AssetModel::select('id')->whereNotNull('depreciation_id')->get();
|
||||
|
||||
$assets->InModelList($non_deprecable_models->toArray());
|
||||
}
|
||||
|
||||
|
@ -141,6 +141,14 @@ class AssetsController extends Controller
|
|||
$assets->where('assets.status_id', '=', $request->input('status_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('asset_tag')) {
|
||||
$assets->where('assets.asset_tag', '=', $request->input('asset_tag'));
|
||||
}
|
||||
|
||||
if ($request->filled('serial')) {
|
||||
$assets->where('assets.serial', '=', $request->input('serial'));
|
||||
}
|
||||
|
||||
if ($request->input('requestable') == 'true') {
|
||||
$assets->where('assets.requestable', '=', '1');
|
||||
}
|
||||
|
@ -182,6 +190,10 @@ class AssetsController extends Controller
|
|||
$assets->ByDepreciationId($request->input('depreciation_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('byod')) {
|
||||
$assets->where('assets.byod', '=', $request->input('byod'));
|
||||
}
|
||||
|
||||
$request->filled('order_number') ? $assets = $assets->where('assets.order_number', '=', e($request->get('order_number'))) : '';
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
|
@ -259,6 +271,11 @@ class AssetsController extends Controller
|
|||
// more sad, horrible workarounds for laravel bugs when doing full text searches
|
||||
$assets->where('assets.assigned_to', '>', '0');
|
||||
break;
|
||||
case 'byod':
|
||||
// This is kind of redundant, since we already check for byod=1 above, but this keeps the
|
||||
// sidebar nav links a little less chaotic
|
||||
$assets->where('assets.byod', '=', '1');
|
||||
break;
|
||||
default:
|
||||
|
||||
if ((! $request->filled('status_id')) && ($settings->show_archived_in_list != '1')) {
|
||||
|
@ -357,19 +374,38 @@ class AssetsController extends Controller
|
|||
/**
|
||||
* Returns JSON with information about an asset (by tag) for detail view.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param string $tag
|
||||
* @since [v4.2.1]
|
||||
* @return JsonResponse
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function showByTag(Request $request, $tag)
|
||||
{
|
||||
if ($asset = Asset::with('assetstatus')->with('assignedTo')->where('asset_tag', $tag)->first()) {
|
||||
$this->authorize('view', $asset);
|
||||
$this->authorize('index', Asset::class);
|
||||
$assets = Asset::where('asset_tag', $tag)->with('assetstatus')->with('assignedTo');
|
||||
|
||||
return (new AssetsTransformer)->transformAsset($asset, $request);
|
||||
// Check if they've passed ?deleted=true
|
||||
if ($request->input('deleted', 'false') == 'true') {
|
||||
$assets = $assets->withTrashed();
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
|
||||
|
||||
if (($assets = $assets->get()) && ($assets->count()) > 0) {
|
||||
|
||||
// If there is exactly one result and the deleted parameter is not passed, we should pull the first (and only)
|
||||
// asset from the returned collection, since transformAsset() expects an Asset object, NOT a collection
|
||||
if (($assets->count() == 1) && ($request->input('deleted') != 'true')) {
|
||||
return (new AssetsTransformer)->transformAsset($assets->first());
|
||||
|
||||
// If there is more than one result OR if the endpoint is requesting deleted items (even if there is only one
|
||||
// match, return the normal collection transformed.
|
||||
} else {
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// If there are 0 results, return the "no such asset" response
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
||||
|
||||
}
|
||||
|
||||
|
@ -379,29 +415,25 @@ class AssetsController extends Controller
|
|||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param string $serial
|
||||
* @since [v4.2.1]
|
||||
* @return JsonResponse
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function showBySerial(Request $request, $serial)
|
||||
{
|
||||
$this->authorize('index', Asset::class);
|
||||
if ($assets = Asset::with('assetstatus')->with('assignedTo')
|
||||
->withTrashed()->where('serial', $serial)->get()) {
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
|
||||
$assets = Asset::where('serial', $serial)->with('assetstatus')->with('assignedTo');
|
||||
|
||||
$assets = Asset::with('assetstatus')->with('assignedTo');
|
||||
|
||||
if ($request->input('deleted', 'false') === 'true') {
|
||||
// Check if they've passed ?deleted=true
|
||||
if ($request->input('deleted', 'false') == 'true') {
|
||||
$assets = $assets->withTrashed();
|
||||
}
|
||||
|
||||
$assets = $assets->where('serial', $serial)->get();
|
||||
if ($assets) {
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
|
||||
} else {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Asset not found'), 200);
|
||||
}
|
||||
|
||||
if (($assets = $assets->get()) && ($assets->count()) > 0) {
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count());
|
||||
}
|
||||
|
||||
// If there are 0 results, return the "no such asset" response
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,6 +10,7 @@ use App\Models\Category;
|
|||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class CategoriesController extends Controller
|
||||
{
|
||||
|
@ -107,7 +108,7 @@ class CategoriesController extends Controller
|
|||
public function show($id)
|
||||
{
|
||||
$this->authorize('view', Category::class);
|
||||
$category = Category::findOrFail($id);
|
||||
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
||||
return (new CategoriesTransformer)->transformCategory($category);
|
||||
|
||||
}
|
||||
|
@ -126,8 +127,14 @@ class CategoriesController extends Controller
|
|||
{
|
||||
$this->authorize('update', Category::class);
|
||||
$category = Category::findOrFail($id);
|
||||
|
||||
// Don't allow the user to change the category_type once it's been created
|
||||
if (($request->filled('category_type')) && ($category->category_type != $request->input('category_type'))) {
|
||||
return response()->json(
|
||||
Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.update.cannot_change_category_type'))
|
||||
);
|
||||
}
|
||||
$category->fill($request->all());
|
||||
$category->category_type = strtolower($request->input('category_type'));
|
||||
$category = $request->handleImages($category);
|
||||
|
||||
if ($category->save()) {
|
||||
|
@ -148,7 +155,7 @@ class CategoriesController extends Controller
|
|||
public function destroy($id)
|
||||
{
|
||||
$this->authorize('delete', Category::class);
|
||||
$category = Category::findOrFail($id);
|
||||
$category = Category::withCount('assets as assets_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count')->findOrFail($id);
|
||||
|
||||
if (! $category->isDeletable()) {
|
||||
return response()->json(
|
||||
|
|
|
@ -228,6 +228,7 @@ class ConsumablesController extends Controller
|
|||
|
||||
foreach ($consumable->consumableAssignments as $consumable_assignment) {
|
||||
$rows[] = [
|
||||
'avatar' => ($consumable_assignment->user) ? e($consumable_assignment->user->present()->gravatar) : '',
|
||||
'name' => ($consumable_assignment->user) ? $consumable_assignment->user->present()->nameUrl() : 'Deleted User',
|
||||
'created_at' => Helper::getFormattedDateObject($consumable_assignment->created_at, 'datetime'),
|
||||
'note' => ($consumable_assignment->note) ? e($consumable_assignment->note) : null,
|
||||
|
|
|
@ -96,7 +96,7 @@ class CustomFieldsController extends Controller
|
|||
$data = $request->all();
|
||||
$regex_format = null;
|
||||
|
||||
if (str_contains($data['format'], 'regex:')) {
|
||||
if ((array_key_exists('format', $data)) && (str_contains($data['format'], 'regex:'))) {
|
||||
$regex_format = $data['format'];
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ class ImportController extends Controller
|
|||
$this->authorize('import');
|
||||
|
||||
// Run a backup immediately before processing
|
||||
if ($request->has('run-backup')) {
|
||||
if ($request->get('run-backup')) {
|
||||
\Log::debug('Backup manually requested via importer');
|
||||
Artisan::call('backup:run');
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@ use App\Models\Asset;
|
|||
use App\Models\Company;
|
||||
use App\Models\License;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CurrentInventory;
|
||||
use Auth;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
|
@ -148,6 +149,14 @@ class UsersController extends Controller
|
|||
$users = $users->where('remote', '=', $request->input('remote'));
|
||||
}
|
||||
|
||||
if ($request->filled('two_factor_enrolled')) {
|
||||
$users = $users->where('two_factor_enrolled', '=', $request->input('two_factor_enrolled'));
|
||||
}
|
||||
|
||||
if ($request->filled('two_factor_optin')) {
|
||||
$users = $users->where('two_factor_optin', '=', $request->input('two_factor_optin'));
|
||||
}
|
||||
|
||||
if ($request->filled('start_date')) {
|
||||
$users = $users->where('users.start_date', '=', $request->input('start_date'));
|
||||
}
|
||||
|
@ -156,7 +165,6 @@ class UsersController extends Controller
|
|||
$users = $users->where('users.end_date', '=', $request->input('end_date'));
|
||||
}
|
||||
|
||||
|
||||
if ($request->filled('assets_count')) {
|
||||
$users->has('assets', '=', $request->input('assets_count'));
|
||||
}
|
||||
|
@ -207,11 +215,39 @@ class UsersController extends Controller
|
|||
default:
|
||||
$allowed_columns =
|
||||
[
|
||||
'last_name', 'first_name', 'email', 'jobtitle', 'username', 'employee_num',
|
||||
'assets', 'accessories', 'consumables', 'licenses', 'groups', 'activated', 'created_at',
|
||||
'two_factor_enrolled', 'two_factor_optin', 'last_login', 'assets_count', 'licenses_count',
|
||||
'consumables_count', 'accessories_count', 'phone', 'address', 'city', 'state',
|
||||
'country', 'zip', 'id', 'ldap_import', 'remote', 'start_date', 'end_date',
|
||||
'last_name',
|
||||
'first_name',
|
||||
'email',
|
||||
'jobtitle',
|
||||
'username',
|
||||
'employee_num',
|
||||
'assets',
|
||||
'accessories',
|
||||
'consumables',
|
||||
'licenses',
|
||||
'groups',
|
||||
'activated',
|
||||
'created_at',
|
||||
'two_factor_enrolled',
|
||||
'two_factor_optin',
|
||||
'last_login',
|
||||
'assets_count',
|
||||
'licenses_count',
|
||||
'consumables_count',
|
||||
'accessories_count',
|
||||
'phone',
|
||||
'address',
|
||||
'city',
|
||||
'state',
|
||||
'country',
|
||||
'zip',
|
||||
'id',
|
||||
'ldap_import',
|
||||
'two_factor_optin',
|
||||
'two_factor_enrolled',
|
||||
'remote',
|
||||
'start_date',
|
||||
'end_date',
|
||||
];
|
||||
|
||||
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
|
||||
|
@ -490,6 +526,26 @@ class UsersController extends Controller
|
|||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify a specific user via email with all of their assigned assets.
|
||||
*
|
||||
* @author [Lukas Fehling] [<lukas.fehling@adabay.rocks>]
|
||||
* @since [v6.0.13]
|
||||
* @param Request $request
|
||||
* @param $id
|
||||
* @return string JSON
|
||||
*/
|
||||
public function emailAssetList(Request $request, $id)
|
||||
{
|
||||
$user = User::findOrFail($id);
|
||||
|
||||
if (empty($user->email)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.inventorynotification.error')));
|
||||
}
|
||||
|
||||
return response()->Helper::formatStandardApiResponse('success', null, trans('admin/users/message.inventorynotification.success'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of consumables assigned to a user.
|
||||
|
|
|
@ -62,7 +62,7 @@ class AssetModelsFilesController extends Controller
|
|||
$model->logUpload($file_name, e($request->get('notes')));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('success', trans('admin/hardware/message.upload.success'));
|
||||
return redirect()->back()->with('success', trans('general.file_upload_success'));
|
||||
}
|
||||
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.upload.nofiles'));
|
||||
|
|
|
@ -147,6 +147,7 @@ class AssetsController extends Controller
|
|||
$asset->supplier_id = request('supplier_id', null);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
$asset->rtd_location_id = request('rtd_location_id', null);
|
||||
$asset->byod = request('byod', 0);
|
||||
|
||||
if (! empty($settings->audit_interval)) {
|
||||
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||
|
@ -319,6 +320,7 @@ class AssetsController extends Controller
|
|||
// If the box isn't checked, it's not in the request at all.
|
||||
$asset->requestable = $request->filled('requestable');
|
||||
$asset->rtd_location_id = $request->input('rtd_location_id', null);
|
||||
$asset->byod = $request->input('byod', 0);
|
||||
|
||||
if ($asset->assigned_to == '') {
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
|
|
|
@ -135,9 +135,7 @@ class LoginController extends Controller
|
|||
} else {
|
||||
|
||||
// Better logging
|
||||
if (!$saml->isEnabled()) {
|
||||
\Log::debug("SAML page requested, but SAML does not seem to enabled.");
|
||||
} else {
|
||||
if (empty($samlData)) {
|
||||
\Log::debug("SAML page requested, but samlData seems empty.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ class ResetPasswordController extends Controller
|
|||
public function __construct()
|
||||
{
|
||||
$this->middleware('guest');
|
||||
$this->middleware('throttle:10,1');
|
||||
}
|
||||
|
||||
protected function rules()
|
||||
|
@ -116,7 +117,7 @@ class ResetPasswordController extends Controller
|
|||
}
|
||||
|
||||
\Log::debug('Password reset for '.$user->username.' FAILED - this user exists but the token is not valid');
|
||||
return redirect()->back()->withInput($request->only('email'))->with('error', trans('passwords.token'));
|
||||
return redirect()->back()->withInput($request->only('email'))->with('success', trans('passwords.reset'));
|
||||
|
||||
}
|
||||
|
||||
|
|
180
app/Http/Controllers/Components/ComponentsFilesController.php
Normal file
180
app/Http/Controllers/Components/ComponentsFilesController.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Components;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AssetFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Component;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use enshrined\svgSanitize\Sanitizer;
|
||||
|
||||
class ComponentsFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a component.
|
||||
*
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param AssetFileRequest $request
|
||||
* @param int $componentId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store(AssetFileRequest $request, $componentId = null)
|
||||
{
|
||||
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('components.show', ['component'=>$componentId])->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
$component = Component::find($componentId);
|
||||
|
||||
if (isset($component->id)) {
|
||||
$this->authorize('update', $component);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/components')) {
|
||||
Storage::makeDirectory('private_uploads/components', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
$file_name = 'component-'.$component->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
||||
|
||||
|
||||
// Check for SVG and sanitize it
|
||||
if ($extension == 'svg') {
|
||||
\Log::debug('This is an SVG');
|
||||
\Log::debug($file_name);
|
||||
|
||||
$sanitizer = new Sanitizer();
|
||||
$dirtySVG = file_get_contents($file->getRealPath());
|
||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||
|
||||
try {
|
||||
Storage::put('private_uploads/components/'.$file_name, $cleanSVG);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Upload no workie :( ');
|
||||
\Log::debug($e);
|
||||
}
|
||||
|
||||
} else {
|
||||
Storage::put('private_uploads/components/'.$file_name, file_get_contents($file));
|
||||
}
|
||||
|
||||
//Log the upload to the log
|
||||
$component->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('components.show', $component->id)->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('components.show', $component->id)->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('components.index')
|
||||
->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected component file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $componentId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($componentId = null, $fileId = null)
|
||||
{
|
||||
$component = Component::find($componentId);
|
||||
|
||||
// the asset is valid
|
||||
if (isset($component->id)) {
|
||||
$this->authorize('update', $component);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('components/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('components/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the licence management page
|
||||
return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $componentId
|
||||
* @param int $fileId
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($componentId = null, $fileId = null, $download = true)
|
||||
{
|
||||
\Log::debug('Private filesystem is: '.config('filesystems.default'));
|
||||
$component = Component::find($componentId);
|
||||
|
||||
// the component is valid
|
||||
if (isset($component->id)) {
|
||||
$this->authorize('view', $component);
|
||||
$this->authorize('components.files', $component);
|
||||
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/components/'.$log->filename;
|
||||
|
||||
if (Storage::missing($file)) {
|
||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||
\Log::debug('URL should be '.Storage::url($file));
|
||||
|
||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||
->header('Content-Type', 'text/plain');
|
||||
} else {
|
||||
|
||||
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
|
||||
return StorageHelper::downloader($file);
|
||||
} else {
|
||||
if ($download != 'true') {
|
||||
\Log::debug('display the file');
|
||||
if ($contents = file_get_contents(Storage::url($file))) { // TODO - this will fail on private S3 files or large public ones
|
||||
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
|
||||
}
|
||||
|
||||
return JsonResponse::create(['error' => 'Failed validation: '], 500);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader($file);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('components.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
|
||||
}
|
||||
}
|
180
app/Http/Controllers/Consumables/ConsumablesFilesController.php
Normal file
180
app/Http/Controllers/Consumables/ConsumablesFilesController.php
Normal file
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Consumables;
|
||||
|
||||
use App\Helpers\StorageHelper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\AssetFileRequest;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Consumable;
|
||||
use Illuminate\Support\Facades\Response;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
||||
use enshrined\svgSanitize\Sanitizer;
|
||||
|
||||
class ConsumablesFilesController extends Controller
|
||||
{
|
||||
/**
|
||||
* Validates and stores files associated with a consumable.
|
||||
*
|
||||
* @todo Switch to using the AssetFileRequest form request validator.
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param AssetFileRequest $request
|
||||
* @param int $consumableId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function store(AssetFileRequest $request, $consumableId = null)
|
||||
{
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('consumables.show', ['consumable'=>$consumableId])->with('error', trans('general.feature_disabled'));
|
||||
}
|
||||
|
||||
$consumable = Consumable::find($consumableId);
|
||||
|
||||
if (isset($consumable->id)) {
|
||||
$this->authorize('update', $consumable);
|
||||
|
||||
if ($request->hasFile('file')) {
|
||||
if (! Storage::exists('private_uploads/consumables')) {
|
||||
Storage::makeDirectory('private_uploads/consumables', 775);
|
||||
}
|
||||
|
||||
foreach ($request->file('file') as $file) {
|
||||
|
||||
$extension = $file->getClientOriginalExtension();
|
||||
$file_name = 'consumable-'.$consumable->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
||||
|
||||
|
||||
// Check for SVG and sanitize it
|
||||
if ($extension == 'svg') {
|
||||
\Log::debug('This is an SVG');
|
||||
\Log::debug($file_name);
|
||||
|
||||
$sanitizer = new Sanitizer();
|
||||
$dirtySVG = file_get_contents($file->getRealPath());
|
||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||
|
||||
try {
|
||||
Storage::put('private_uploads/consumables/'.$file_name, $cleanSVG);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug('Upload no workie :( ');
|
||||
\Log::debug($e);
|
||||
}
|
||||
|
||||
} else {
|
||||
Storage::put('private_uploads/consumables/'.$file_name, file_get_contents($file));
|
||||
}
|
||||
|
||||
//Log the upload to the log
|
||||
$consumable->logUpload($file_name, e($request->input('notes')));
|
||||
}
|
||||
|
||||
|
||||
return redirect()->route('consumables.show', $consumable->id)->with('success', trans('general.file_upload_success'));
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('consumables.show', $consumable->id)->with('error', trans('general.no_files_uploaded'));
|
||||
}
|
||||
// Prepare the error message
|
||||
return redirect()->route('consumables.index')
|
||||
->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the selected consumable file.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.0]
|
||||
* @param int $consumableId
|
||||
* @param int $fileId
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function destroy($consumableId = null, $fileId = null)
|
||||
{
|
||||
$consumable = Consumable::find($consumableId);
|
||||
|
||||
// the asset is valid
|
||||
if (isset($consumable->id)) {
|
||||
$this->authorize('update', $consumable);
|
||||
$log = Actionlog::find($fileId);
|
||||
|
||||
// Remove the file if one exists
|
||||
if (Storage::exists('consumables/'.$log->filename)) {
|
||||
try {
|
||||
Storage::delete('consumables/'.$log->filename);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
}
|
||||
}
|
||||
|
||||
$log->delete();
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', trans('admin/hardware/message.deletefile.success'));
|
||||
}
|
||||
|
||||
// Redirect to the licence management page
|
||||
return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the selected file to be viewed.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v1.4]
|
||||
* @param int $consumableId
|
||||
* @param int $fileId
|
||||
* @return \Symfony\Consumable\HttpFoundation\Response
|
||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||
*/
|
||||
public function show($consumableId = null, $fileId = null, $download = true)
|
||||
{
|
||||
$consumable = Consumable::find($consumableId);
|
||||
|
||||
// the consumable is valid
|
||||
if (isset($consumable->id)) {
|
||||
$this->authorize('view', $consumable);
|
||||
$this->authorize('consumables.files', $consumable);
|
||||
|
||||
if (! $log = Actionlog::find($fileId)) {
|
||||
return response('No matching record for that asset/file', 500)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
|
||||
$file = 'private_uploads/consumables/'.$log->filename;
|
||||
|
||||
if (Storage::missing($file)) {
|
||||
\Log::debug('FILE DOES NOT EXISTS for '.$file);
|
||||
\Log::debug('URL should be '.Storage::url($file));
|
||||
|
||||
return response('File '.$file.' ('.Storage::url($file).') not found on server', 404)
|
||||
->header('Content-Type', 'text/plain');
|
||||
} else {
|
||||
|
||||
// We have to override the URL stuff here, since local defaults in Laravel's Flysystem
|
||||
// won't work, as they're not accessible via the web
|
||||
if (config('filesystems.default') == 'local') { // TODO - is there any way to fix this at the StorageHelper layer?
|
||||
return StorageHelper::downloader($file);
|
||||
} else {
|
||||
if ($download != 'true') {
|
||||
\Log::debug('display the file');
|
||||
if ($contents = file_get_contents(Storage::url($file))) { // TODO - this will fail on private S3 files or large public ones
|
||||
return Response::make(Storage::url($file)->header('Content-Type', mime_content_type($file)));
|
||||
}
|
||||
|
||||
return JsonResponse::create(['error' => 'Failed validation: '], 500);
|
||||
}
|
||||
|
||||
return StorageHelper::downloader($file);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return redirect()->route('consumables.index')->with('error', trans('general.file_does_not_exist', ['id' => $fileId]));
|
||||
}
|
||||
}
|
|
@ -86,14 +86,24 @@ class CustomFieldsController extends Controller
|
|||
{
|
||||
$this->authorize('create', CustomField::class);
|
||||
|
||||
$show_in_email = $request->get("show_in_email", 0);
|
||||
$display_in_user_view = $request->get("display_in_user_view", 0);
|
||||
|
||||
// Override the display settings if the field is encrypted
|
||||
if ($request->get("field_encrypted") == '1') {
|
||||
$show_in_email = '0';
|
||||
$display_in_user_view = '0';
|
||||
}
|
||||
|
||||
$field = new CustomField([
|
||||
"name" => trim($request->get("name")),
|
||||
"element" => $request->get("element"),
|
||||
"help_text" => $request->get("help_text"),
|
||||
"field_values" => $request->get("field_values"),
|
||||
"field_encrypted" => $request->get("field_encrypted", 0),
|
||||
"show_in_email" => $request->get("show_in_email", 0),
|
||||
"show_in_email" => $show_in_email,
|
||||
"is_unique" => $request->get("is_unique", 0),
|
||||
"display_in_user_view" => $display_in_user_view,
|
||||
"user_id" => Auth::id()
|
||||
]);
|
||||
|
||||
|
@ -221,13 +231,24 @@ class CustomFieldsController extends Controller
|
|||
|
||||
$this->authorize('update', $field);
|
||||
|
||||
|
||||
$show_in_email = $request->get("show_in_email", 0);
|
||||
$display_in_user_view = $request->get("display_in_user_view", 0);
|
||||
|
||||
// Override the display settings if the field is encrypted
|
||||
if ($request->get("field_encrypted") == '1') {
|
||||
$show_in_email = '0';
|
||||
$display_in_user_view = '0';
|
||||
}
|
||||
|
||||
$field->name = trim(e($request->get("name")));
|
||||
$field->element = e($request->get("element"));
|
||||
$field->field_values = e($request->get("field_values"));
|
||||
$field->user_id = Auth::id();
|
||||
$field->help_text = $request->get("help_text");
|
||||
$field->show_in_email = $request->get("show_in_email", 0);
|
||||
$field->show_in_email = $show_in_email;
|
||||
$field->is_unique = $request->get("is_unique", 0);
|
||||
$field->display_in_user_view = $display_in_user_view;
|
||||
|
||||
if ($request->get('format') == 'CUSTOM REGEX') {
|
||||
$field->format = e($request->get('custom_format'));
|
||||
|
|
|
@ -34,7 +34,7 @@ class DashboardController extends Controller
|
|||
$counts['license'] = \App\Models\License::assetcount();
|
||||
$counts['consumable'] = \App\Models\Consumable::count();
|
||||
$counts['component'] = \App\Models\Component::count();
|
||||
$counts['user'] = \App\Models\User::count();
|
||||
$counts['user'] = \App\Models\Company::scopeCompanyables(Auth::user())->count();
|
||||
$counts['grand_total'] = $counts['asset'] + $counts['accessory'] + $counts['license'] + $counts['consumable'];
|
||||
|
||||
if ((! file_exists(storage_path().'/oauth-private.key')) || (! file_exists(storage_path().'/oauth-public.key'))) {
|
||||
|
|
|
@ -763,7 +763,7 @@ class ReportsController extends Controller
|
|||
if ($request->filled('username')) {
|
||||
// Only works if we're checked out to a user, not anything else.
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = ($asset->assignedTo) ? $asset->assignedTo->username : '';
|
||||
$row[] = ($asset->assignedto) ? $asset->assignedto->username : '';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
@ -772,7 +772,7 @@ class ReportsController extends Controller
|
|||
if ($request->filled('employee_num')) {
|
||||
// Only works if we're checked out to a user, not anything else.
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = ($asset->assignedTo) ? $asset->assignedTo->employee_num : '';
|
||||
$row[] = ($asset->assignedto) ? $asset->assignedto->employee_num : '';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
@ -780,7 +780,7 @@ class ReportsController extends Controller
|
|||
|
||||
if ($request->filled('manager')) {
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = (($asset->assignedTo) && ($asset->assignedTo->manager)) ? $asset->assignedTo->manager->present()->fullName : '';
|
||||
$row[] = (($asset->assignedto) && ($asset->assignedto->manager)) ? $asset->assignedto->manager->present()->fullName : '';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
@ -788,7 +788,7 @@ class ReportsController extends Controller
|
|||
|
||||
if ($request->filled('department')) {
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = (($asset->assignedTo) && ($asset->assignedTo->department)) ? $asset->assignedTo->department->name : '';
|
||||
$row[] = (($asset->assignedto) && ($asset->assignedto->department)) ? $asset->assignedto->department->name : '';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
@ -796,7 +796,7 @@ class ReportsController extends Controller
|
|||
|
||||
if ($request->filled('title')) {
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = ($asset->assignedTo) ? $asset->assignedTo->jobtitle : '';
|
||||
$row[] = ($asset->assignedto) ? $asset->assignedto->jobtitle : '';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
@ -1110,13 +1110,19 @@ class ReportsController extends Controller
|
|||
$rows[] = implode(',', $header);
|
||||
|
||||
foreach ($assetsForReport as $item) {
|
||||
$row = [ ];
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->model->category->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
|
||||
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
|
||||
$rows[] = implode(',', $row);
|
||||
|
||||
if ($item['assetItem'] != null){
|
||||
|
||||
$row = [ ];
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->model->category->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->model->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->name));
|
||||
$row[] = str_replace(',', '', e($item['assetItem']->asset_tag));
|
||||
$row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user')));
|
||||
$rows[] = implode(',', $row);
|
||||
} else {
|
||||
// Log the error maybe?
|
||||
}
|
||||
}
|
||||
|
||||
// spit out a csv
|
||||
|
|
|
@ -7,6 +7,7 @@ use App\Helpers\StorageHelper;
|
|||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\SettingsSamlRequest;
|
||||
use App\Http\Requests\SetupUserRequest;
|
||||
use App\Models\Group;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Asset;
|
||||
use App\Models\User;
|
||||
|
@ -919,6 +920,8 @@ class SettingsController extends Controller
|
|||
public function getLdapSettings()
|
||||
{
|
||||
$setting = Setting::getSettings();
|
||||
$groups = Group::pluck('name', 'id');
|
||||
|
||||
|
||||
/**
|
||||
* This validator is only temporary (famous last words.) - @snipe
|
||||
|
@ -937,7 +940,7 @@ class SettingsController extends Controller
|
|||
|
||||
|
||||
|
||||
return view('settings.ldap', compact('setting'))->withErrors($validator);
|
||||
return view('settings.ldap', compact('setting', 'groups'))->withErrors($validator);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -964,6 +967,7 @@ class SettingsController extends Controller
|
|||
$setting->ldap_pword = Crypt::encrypt($request->input('ldap_pword'));
|
||||
}
|
||||
$setting->ldap_basedn = $request->input('ldap_basedn');
|
||||
$setting->ldap_default_group = $request->input('ldap_default_group');
|
||||
$setting->ldap_filter = $request->input('ldap_filter');
|
||||
$setting->ldap_username_field = $request->input('ldap_username_field');
|
||||
$setting->ldap_lname_field = $request->input('ldap_lname_field');
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Models\AssetModel;
|
|||
use App\Models\Company;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Models\CustomField;
|
||||
use App\Notifications\RequestAssetCancelation;
|
||||
use App\Notifications\RequestAssetNotification;
|
||||
use Illuminate\Http\Request;
|
||||
|
@ -29,23 +30,41 @@ class ViewAssetsController extends Controller
|
|||
public function getIndex()
|
||||
{
|
||||
$user = User::with(
|
||||
'assets',
|
||||
'assets.model',
|
||||
'assets.model.fieldset.fields',
|
||||
'consumables',
|
||||
'accessories',
|
||||
'licenses',
|
||||
'userloc',
|
||||
'userlog'
|
||||
)->withTrashed()->find(Auth::user()->id);
|
||||
)->find(Auth::user()->id);
|
||||
|
||||
$userlog = $user->userlog->load('item', 'user', 'target');
|
||||
$field_array = array();
|
||||
|
||||
// Loop through all the custom fields that are applied to any model the user has assigned
|
||||
foreach ($user->assets as $asset) {
|
||||
|
||||
// Make sure the model has a custom fieldset before trying to loop through the associated fields
|
||||
if ($asset->model->fieldset) {
|
||||
|
||||
foreach ($asset->model->fieldset->fields as $field) {
|
||||
// check and make sure they're allowed to see the value of the custom field
|
||||
if ($field->display_in_user_view == '1') {
|
||||
$field_array[$field->db_column] = $field->name;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Since some models may re-use the same fieldsets/fields, let's make the array unique so we don't repeat columns
|
||||
array_unique($field_array);
|
||||
|
||||
if (isset($user->id)) {
|
||||
return view('account/view-assets', compact('user', 'userlog'))
|
||||
return view('account/view-assets', compact('user', 'field_array' ))
|
||||
->with('settings', Setting::getSettings());
|
||||
} else {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
|
||||
}
|
||||
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')
|
||||
->with('error', trans('admin/users/message.user_not_found', $user->id));
|
||||
|
|
|
@ -52,6 +52,13 @@ class AssetCountForSidebar
|
|||
\Log::debug($e);
|
||||
}
|
||||
|
||||
try {
|
||||
$total_byod_sidebar = Asset::where('byod', '=', '1')->count();
|
||||
view()->share('total_byod_sidebar', $total_byod_sidebar);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ class ImageUploadRequest extends Request
|
|||
}
|
||||
|
||||
// Remove Current image if exists
|
||||
if (Storage::disk('public')->exists($path.'/'.$item->{$use_db_field})) {
|
||||
if (($item->{$use_db_field}!='') && (Storage::disk('public')->exists($path.'/'.$item->{$use_db_field}))) {
|
||||
\Log::debug('A file already exists that we are replacing - we should delete the old one.');
|
||||
try {
|
||||
Storage::disk('public')->delete($path.'/'.$item->{$use_db_field});
|
||||
|
|
|
@ -49,7 +49,7 @@ class ItemImportRequest extends FormRequest
|
|||
$errorMessage = null;
|
||||
|
||||
if (is_null($fieldValue)) {
|
||||
$errorMessage = trans('validation.import_field_empty');
|
||||
$errorMessage = trans('validation.import_field_empty', ['fieldname' => $field]);
|
||||
$this->errorCallback($import, $field, $errorMessage);
|
||||
|
||||
return $this->errors;
|
||||
|
|
|
@ -85,6 +85,7 @@ class ActionlogsTransformer
|
|||
'id' => (int) $actionlog->item->id,
|
||||
'name' => ($actionlog->itemType()=='user') ? e($actionlog->item->getFullNameAttribute()) : e($actionlog->item->getDisplayNameAttribute()),
|
||||
'type' => e($actionlog->itemType()),
|
||||
'serial' =>e($actionlog->item->serial) ? e($actionlog->item->serial) : null
|
||||
] : null,
|
||||
'location' => ($actionlog->location) ? [
|
||||
'id' => (int) $actionlog->location->id,
|
||||
|
|
|
@ -22,6 +22,22 @@ class AssetModelsTransformer
|
|||
|
||||
public function transformAssetModel(AssetModel $assetmodel)
|
||||
{
|
||||
|
||||
$default_field_values = array();
|
||||
|
||||
// Reach into the custom fields and models_custom_fields pivot table to find the default values for this model
|
||||
if ($assetmodel->fieldset) {
|
||||
foreach($assetmodel->fieldset->fields AS $field) {
|
||||
$default_field_values[] = [
|
||||
'name' => e($field->name),
|
||||
'db_column_name' => e($field->db_column_name()),
|
||||
'default_value' => ($field->defaultValue($assetmodel->id)) ? e($field->defaultValue($assetmodel->id)) : null,
|
||||
'format' => e($field->format),
|
||||
'required' => ($field->pivot->required == '1') ? true : false,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$array = [
|
||||
'id' => (int) $assetmodel->id,
|
||||
'name' => e($assetmodel->name),
|
||||
|
@ -44,6 +60,7 @@ class AssetModelsTransformer
|
|||
'id' => (int) $assetmodel->fieldset->id,
|
||||
'name'=> e($assetmodel->fieldset->name),
|
||||
] : null,
|
||||
'default_fieldset_values' => $default_field_values,
|
||||
'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None',
|
||||
'requestable' => ($assetmodel->requestable == '1') ? true : false,
|
||||
'notes' => e($assetmodel->notes),
|
||||
|
|
|
@ -8,6 +8,7 @@ use App\Models\Setting;
|
|||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
|
||||
class AssetsTransformer
|
||||
{
|
||||
public function transformAssets(Collection $assets, $total)
|
||||
|
@ -34,6 +35,8 @@ class AssetsTransformer
|
|||
'id' => (int) $asset->model->id,
|
||||
'name'=> e($asset->model->name),
|
||||
] : null,
|
||||
'byod' => ($asset->byod ? true : false),
|
||||
|
||||
'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null,
|
||||
'eol' => ($asset->purchase_date != '') ? Helper::getFormattedDateObject($asset->present()->eol_date(), 'date') : null,
|
||||
'status_label' => ($asset->assetstatus) ? [
|
||||
|
@ -80,6 +83,7 @@ class AssetsTransformer
|
|||
'next_audit_date' => Helper::getFormattedDateObject($asset->next_audit_date, 'date'),
|
||||
'deleted_at' => Helper::getFormattedDateObject($asset->deleted_at, 'datetime'),
|
||||
'purchase_date' => Helper::getFormattedDateObject($asset->purchase_date, 'date'),
|
||||
'age' => $asset->purchase_date ? Helper::AgeFormat($asset->purchase_date) : '',
|
||||
'last_checkout' => Helper::getFormattedDateObject($asset->last_checkout, 'datetime'),
|
||||
'expected_checkin' => Helper::getFormattedDateObject($asset->expected_checkin, 'date'),
|
||||
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
|
||||
|
@ -131,7 +135,7 @@ class AssetsTransformer
|
|||
$array['custom_fields'] = $fields_array;
|
||||
}
|
||||
} else {
|
||||
$array['custom_fields'] = [];
|
||||
$array['custom_fields'] = new \stdClass; // HACK to force generation of empty object instead of empty list
|
||||
}
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
|
@ -185,6 +189,7 @@ class AssetsTransformer
|
|||
'name' => e($asset->assigned->getFullNameAttribute()),
|
||||
'first_name'=> e($asset->assigned->first_name),
|
||||
'last_name'=> ($asset->assigned->last_name) ? e($asset->assigned->last_name) : null,
|
||||
'email'=> ($asset->assigned->email) ? e($asset->assigned->email) : null,
|
||||
'employee_number' => ($asset->assigned->employee_num) ? e($asset->assigned->employee_num) : null,
|
||||
'type' => 'user',
|
||||
] : null;
|
||||
|
|
|
@ -22,6 +22,26 @@ class CategoriesTransformer
|
|||
|
||||
public function transformCategory(Category $category = null)
|
||||
{
|
||||
|
||||
// We only ever use item_count for categories in this transformer, so it makes sense to keep it
|
||||
// simple and do this switch here.
|
||||
switch ($category->category_type) {
|
||||
case 'asset':
|
||||
$category->item_count = $category->assets_count;
|
||||
break;
|
||||
case 'accessory':
|
||||
$category->item_count = $category->accessories_count;
|
||||
break;
|
||||
case 'consumable':
|
||||
$category->item_count = $category->consumables_count;
|
||||
break;
|
||||
case 'component':
|
||||
$category->item_count = $category->components_count;
|
||||
break;
|
||||
default:
|
||||
$category->item_count = 0;
|
||||
}
|
||||
|
||||
if ($category) {
|
||||
$array = [
|
||||
'id' => (int) $category->id,
|
||||
|
@ -33,7 +53,7 @@ class CategoriesTransformer
|
|||
'eula' => ($category->getEula()),
|
||||
'checkin_email' => ($category->checkin_email == '1'),
|
||||
'require_acceptance' => ($category->require_acceptance == '1'),
|
||||
'item_count' => (int) $category->itemCount(),
|
||||
'item_count' => (int) $category->item_count,
|
||||
'assets_count' => (int) $category->assets_count,
|
||||
'accessories_count' => (int) $category->accessories_count,
|
||||
'consumables_count' => (int) $category->consumables_count,
|
||||
|
|
|
@ -47,6 +47,7 @@ class CustomFieldsTransformer
|
|||
'field_values_array' => ($field->field_values) ? explode("\r\n", e($field->field_values)) : null,
|
||||
'type' => e($field->element),
|
||||
'required' => (($field->pivot) && ($field->pivot->required=='1')) ? true : false,
|
||||
'display_in_user_view' => ($field->display_in_user_view =='1') ? true : false,
|
||||
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
|
||||
];
|
||||
|
|
|
@ -56,8 +56,8 @@ class UsersTransformer
|
|||
'permissions' => $user->decodePermissions(),
|
||||
'activated' => ($user->activated == '1') ? true : false,
|
||||
'ldap_import' => ($user->ldap_import == '1') ? true : false,
|
||||
'two_factor_activated' => ($user->two_factor_active()) ? true : false,
|
||||
'two_factor_enrolled' => ($user->two_factor_active_and_enrolled()) ? true : false,
|
||||
'two_factor_optin' => ($user->two_factor_active()) ? true : false,
|
||||
'assets_count' => (int) $user->assets_count,
|
||||
'licenses_count' => (int) $user->licenses_count,
|
||||
'accessories_count' => (int) $user->accessories_count,
|
||||
|
|
|
@ -77,6 +77,7 @@ abstract class Importer
|
|||
'manager_first_name' => 'manager first name',
|
||||
'manager_last_name' => 'manager last name',
|
||||
'min_amt' => 'minimum quantity',
|
||||
'remote' => 'remote',
|
||||
];
|
||||
/**
|
||||
* Map of item fields->csv names
|
||||
|
@ -288,6 +289,7 @@ abstract class Importer
|
|||
'department_id' => '',
|
||||
'username' => $this->findCsvMatch($row, 'username'),
|
||||
'activated' => $this->fetchHumanBoolean($this->findCsvMatch($row, 'activated')),
|
||||
'remote' => $this->fetchHumanBoolean(($this->findCsvMatch($row, 'remote'))),
|
||||
];
|
||||
|
||||
// Maybe we're lucky and the user already exists.
|
||||
|
|
|
@ -57,6 +57,7 @@ class UserImporter extends ItemImporter
|
|||
$this->item['employee_num'] = $this->findCsvMatch($row, 'employee_num');
|
||||
$this->item['department_id'] = $this->createOrFetchDepartment($this->findCsvMatch($row, 'department'));
|
||||
$this->item['manager_id'] = $this->fetchManager($this->findCsvMatch($row, 'manager_first_name'), $this->findCsvMatch($row, 'manager_last_name'));
|
||||
$this->item['remote'] =($this->fetchHumanBoolean($this->findCsvMatch($row, 'remote')) ==1 ) ? '1' : 0;
|
||||
|
||||
$user_department = $this->findCsvMatch($row, 'department');
|
||||
if ($this->shouldUpdateField($user_department)) {
|
||||
|
|
|
@ -101,6 +101,23 @@ class Accessory extends SnipeModel
|
|||
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the accessories -> action logs -> uploads relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.1.13]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function uploads()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
|
||||
->where('item_type', '=', self::class)
|
||||
->where('action_type', '=', 'uploaded')
|
||||
->whereNotNull('filename')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the accessory -> supplier relationship
|
||||
*
|
||||
|
|
|
@ -95,6 +95,7 @@ class Asset extends Depreciable
|
|||
'location_id' => 'integer',
|
||||
'rtd_company_id' => 'integer',
|
||||
'supplier_id' => 'integer',
|
||||
'byod' => 'boolean',
|
||||
];
|
||||
|
||||
protected $rules = [
|
||||
|
@ -106,7 +107,6 @@ class Asset extends Depreciable
|
|||
'physical' => 'numeric|max:1|nullable',
|
||||
'checkout_date' => 'date|max:10|min:10|nullable',
|
||||
'checkin_date' => 'date|max:10|min:10|nullable',
|
||||
'supplier_id' => 'exists:suppliers,id|numeric|nullable',
|
||||
'location_id' => 'exists:locations,id|nullable',
|
||||
'rtd_location_id' => 'exists:locations,id|nullable',
|
||||
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
|
||||
|
@ -144,6 +144,7 @@ class Asset extends Depreciable
|
|||
'requestable',
|
||||
'last_checkout',
|
||||
'expected_checkin',
|
||||
'byod',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
|
@ -315,14 +316,10 @@ class Asset extends Depreciable
|
|||
}
|
||||
|
||||
$this->last_checkout = $checkout_at;
|
||||
$this->name = $name;
|
||||
|
||||
$this->assignedTo()->associate($target);
|
||||
|
||||
|
||||
if ($name != null) {
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
if ($location != null) {
|
||||
$this->location_id = $location;
|
||||
} else {
|
||||
|
|
|
@ -10,6 +10,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||
use Illuminate\Support\Facades\Gate;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use App\Helpers\Helper;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
/**
|
||||
* Model for Categories. Categories are a higher-level group
|
||||
|
@ -97,6 +98,7 @@ class Category extends SnipeModel
|
|||
*/
|
||||
public function isDeletable()
|
||||
{
|
||||
|
||||
return Gate::allows('delete', $this)
|
||||
&& ($this->itemCount() == 0);
|
||||
}
|
||||
|
@ -150,7 +152,10 @@ class Category extends SnipeModel
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the number of items in the category
|
||||
* Get the number of items in the category. This should NEVER be used in
|
||||
* a collection of categories, as you'll end up with an n+1 query problem.
|
||||
*
|
||||
* It should only be used in a single category context.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v2.0]
|
||||
|
@ -158,6 +163,11 @@ class Category extends SnipeModel
|
|||
*/
|
||||
public function itemCount()
|
||||
{
|
||||
|
||||
if (isset($this->{Str::plural($this->category_type).'_count'})) {
|
||||
return $this->{Str::plural($this->category_type).'_count'};
|
||||
}
|
||||
|
||||
switch ($this->category_type) {
|
||||
case 'asset':
|
||||
return $this->assets()->count();
|
||||
|
@ -169,9 +179,10 @@ class Category extends SnipeModel
|
|||
return $this->consumables()->count();
|
||||
case 'license':
|
||||
return $this->licenses()->count();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return '0';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,7 @@ class CheckoutAcceptance extends Model
|
|||
{
|
||||
// At this point the endpoint is the same for everything.
|
||||
// In the future this may want to be adapted for individual notifications.
|
||||
return config('mail.reply_to.address');
|
||||
return (config('mail.reply_to.address')) ? config('mail.reply_to.address') : '' ;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -73,6 +73,10 @@ final class Company extends SnipeModel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scoping table queries, determining if a logged in user is part of a company, and only allows
|
||||
* that user to see items associated with that company
|
||||
*/
|
||||
private static function scopeCompanyablesDirectly($query, $column = 'company_id', $table_name = null)
|
||||
{
|
||||
if (Auth::user()) {
|
||||
|
@ -127,6 +131,11 @@ final class Company extends SnipeModel
|
|||
return false;
|
||||
} elseif (! static::isFullMultipleCompanySupportEnabled()) {
|
||||
return true;
|
||||
} elseif (!$companyable instanceof Company && !\Schema::hasColumn($companyable->getModel()->getTable(), 'company_id')) {
|
||||
// This is primary for the gate:allows-check in location->isDeletable()
|
||||
// Locations don't have a company_id so without this it isn't possible to delete locations with FullMultipleCompanySupport enabled
|
||||
// because this function is called by SnipePermissionsPolicy->before()
|
||||
return true;
|
||||
} else {
|
||||
if (Auth::user()) {
|
||||
$current_user_company_id = Auth::user()->company_id;
|
||||
|
|
|
@ -88,6 +88,24 @@ class Component extends SnipeModel
|
|||
'location' => ['name'],
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the components -> action logs -> uploads relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.1.13]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function uploads()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
|
||||
->where('item_type', '=', self::class)
|
||||
->where('action_type', '=', 'uploaded')
|
||||
->whereNotNull('filename')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the component -> location relationship
|
||||
*
|
||||
|
|
|
@ -96,6 +96,24 @@ class Consumable extends SnipeModel
|
|||
'manufacturer' => ['name'],
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the components -> action logs -> uploads relationship
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v6.1.13]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function uploads()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Actionlog::class, 'item_id')
|
||||
->where('item_type', '=', self::class)
|
||||
->where('action_type', '=', 'uploaded')
|
||||
->whereNotNull('filename')
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the attribute of whether or not the consumable is requestable
|
||||
*
|
||||
|
|
|
@ -48,7 +48,11 @@ class CustomField extends Model
|
|||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $rules = [];
|
||||
protected $rules = [
|
||||
'name' => 'required|unique:custom_fields',
|
||||
'element' => 'required|in:text,listbox,textarea,checkbox,radio',
|
||||
'field_encrypted' => 'nullable|boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
@ -64,6 +68,7 @@ class CustomField extends Model
|
|||
'help_text',
|
||||
'show_in_email',
|
||||
'is_unique',
|
||||
'display_in_user_view',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -356,15 +361,9 @@ class CustomField extends Model
|
|||
public function validationRules($regex_format = null)
|
||||
{
|
||||
return [
|
||||
'name' => 'required|unique:custom_fields',
|
||||
'element' => [
|
||||
'required',
|
||||
Rule::in(['text', 'listbox', 'textarea', 'checkbox', 'radio']),
|
||||
],
|
||||
'format' => [
|
||||
Rule::in(array_merge(array_keys(self::PREDEFINED_FORMATS), self::PREDEFINED_FORMATS, [$regex_format])),
|
||||
],
|
||||
'field_encrypted' => 'nullable|boolean',
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class Department extends SnipeModel
|
|||
];
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|max:255',
|
||||
'name' => 'required|max:255|is_unique_department',
|
||||
'location_id' => 'numeric|nullable',
|
||||
'company_id' => 'numeric|nullable',
|
||||
'manager_id' => 'numeric|nullable',
|
||||
|
|
|
@ -123,12 +123,20 @@ class License extends Depreciable
|
|||
static::created(function ($license) {
|
||||
$newSeatCount = $license->getAttributes()['seats'];
|
||||
|
||||
return static::adjustSeatCount($license, $oldSeatCount = 0, $newSeatCount);
|
||||
return static::adjustSeatCount($license, 0, $newSeatCount);
|
||||
});
|
||||
// However, we listen for updating to be able to prevent the edit if we cannot delete enough seats.
|
||||
static::updating(function ($license) {
|
||||
$newSeatCount = $license->getAttributes()['seats'];
|
||||
$oldSeatCount = isset($license->getOriginal()['seats']) ? $license->getOriginal()['seats'] : 0;
|
||||
//$oldSeatCount = isset($license->getOriginal()['seats']) ? $license->getOriginal()['seats'] : 0;
|
||||
/*
|
||||
That previous method *did* mostly work, but if you ever managed to get your $license->seats value out of whack
|
||||
with your actual count of license_seats *records*, you would never manage to get back 'into whack'.
|
||||
The below method actually grabs a count of existing license_seats records, so it will be more accurate.
|
||||
This means that if your license_seats are out of whack, you can change the quantity and hit 'save' and it
|
||||
will manage to 'true up' and make your counts line up correctly.
|
||||
*/
|
||||
$oldSeatCount = $license->license_seats_count;
|
||||
|
||||
return static::adjustSeatCount($license, $oldSeatCount, $newSeatCount);
|
||||
});
|
||||
|
|
|
@ -21,11 +21,10 @@ class Setting extends Model
|
|||
use Notifiable, ValidatingTrait;
|
||||
|
||||
/**
|
||||
* The app settings cache key name.
|
||||
*
|
||||
* @var string
|
||||
* The cache property so that multiple invocations of this will only load the Settings record from disk only once
|
||||
* @var self
|
||||
*/
|
||||
const APP_SETTINGS_KEY = 'snipeit_app_settings';
|
||||
public static ?self $_cache = null;
|
||||
|
||||
/**
|
||||
* The setup check cache key name.
|
||||
|
@ -98,14 +97,15 @@ class Setting extends Model
|
|||
*/
|
||||
public static function getSettings(): ?self
|
||||
{
|
||||
return Cache::rememberForever(self::APP_SETTINGS_KEY, function () {
|
||||
if (!self::$_cache) {
|
||||
// Need for setup as no tables exist
|
||||
try {
|
||||
return self::first();
|
||||
self::$_cache = self::first();
|
||||
} catch (\Throwable $th) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
return self::$_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,8 +41,10 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
|||
}
|
||||
);
|
||||
|
||||
$config['validations'][$core.'externalId'] = 'string'; // not required, but supported mostly just for Okta
|
||||
$mappings['externalId'] = AttributeMapping::eloquent('scim_externalid');
|
||||
// externalId support
|
||||
$config['validations'][$core.'externalId'] = 'string|nullable'; // not required, but supported mostly just for Okta
|
||||
// note that the mapping is *not* namespaced like the other $mappings
|
||||
$config['mapping']['externalId'] = AttributeMapping::eloquent('scim_externalid');
|
||||
|
||||
$config['validations'][$core.'emails'] = 'nullable|array'; // emails are not required in Snipe-IT...
|
||||
$config['validations'][$core.'emails.*.value'] = 'email'; // ...(had to remove the recommended 'required' here)
|
||||
|
|
|
@ -61,6 +61,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
'remote',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'scim_externalid'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
@ -337,6 +338,24 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
return $this->belongsToMany(\App\Models\License::class, 'license_seats', 'assigned_to', 'license_id')->withPivot('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes a count of all items assigned
|
||||
*
|
||||
* @author J. Vinsmoke
|
||||
* @since [v6.1]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
Public function allAssignedCount() {
|
||||
$assetsCount = $this->assets()->count();
|
||||
$licensesCount = $this->licenses()->count();
|
||||
$accessoriesCount = $this->accessories()->count();
|
||||
$consumablesCount = $this->consumables()->count();
|
||||
|
||||
$totalCount = $assetsCount + $licensesCount + $accessoriesCount + $consumablesCount;
|
||||
|
||||
return (int) $totalCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Establishes the user -> actionlogs relationship
|
||||
*
|
||||
|
@ -567,6 +586,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
if ((Setting::getSettings()->two_factor_enabled == '1') && ($this->two_factor_optin == '1')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the 2FA is required for everyone so is implicitly active
|
||||
elseif (Setting::getSettings()->two_factor_enabled == '2') {
|
||||
return true;
|
||||
|
@ -575,18 +595,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin user who created this user
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.0.5]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function createdBy()
|
||||
{
|
||||
return $this->belongsTo(\App\Models\User::class, 'created_by')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether two-factor authorization is required and the user has activated it
|
||||
* and enrolled a device
|
||||
|
@ -615,6 +623,19 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the admin user who created this user
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v6.0.5]
|
||||
* @return \Illuminate\Database\Eloquent\Relations\Relation
|
||||
*/
|
||||
public function createdBy()
|
||||
{
|
||||
return $this->belongsTo(\App\Models\User::class, 'created_by')->withTrashed();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function decodePermissions()
|
||||
{
|
||||
|
|
|
@ -19,11 +19,11 @@ class WelcomeNotification extends Notification
|
|||
*/
|
||||
public function __construct(array $content)
|
||||
{
|
||||
$this->_data['email'] = $content['email'];
|
||||
$this->_data['first_name'] = $content['first_name'];
|
||||
$this->_data['last_name'] = $content['last_name'];
|
||||
$this->_data['username'] = $content['username'];
|
||||
$this->_data['password'] = $content['password'];
|
||||
$this->_data['email'] = htmlspecialchars_decode($content['email']);
|
||||
$this->_data['first_name'] = htmlspecialchars_decode($content['first_name']);
|
||||
$this->_data['last_name'] = htmlspecialchars_decode($content['last_name']);
|
||||
$this->_data['username'] = htmlspecialchars_decode($content['username']);
|
||||
$this->_data['password'] = htmlspecialchars_decode($content['password']);
|
||||
$this->_data['url'] = url('/');
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@ class SettingObserver
|
|||
*/
|
||||
public function saved(Setting $setting)
|
||||
{
|
||||
Cache::forget(Setting::APP_SETTINGS_KEY);
|
||||
Cache::forget(Setting::SETUP_CHECK_KEY);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ class AssetModelPresenter extends Presenter
|
|||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.category'),
|
||||
'visible' => false,
|
||||
'visible' => true,
|
||||
'formatter' => 'categoriesLinkObjFormatter',
|
||||
],
|
||||
[
|
||||
|
|
|
@ -140,6 +140,12 @@ class AssetPresenter extends Presenter
|
|||
'visible' => false,
|
||||
'title' => trans('general.purchase_date'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'age',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.age'),
|
||||
], [
|
||||
'field' => 'purchase_cost',
|
||||
'searchable' => true,
|
||||
|
@ -244,6 +250,14 @@ class AssetPresenter extends Presenter
|
|||
'visible' => false,
|
||||
'title' => trans('general.next_audit_date'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'byod',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.byod'),
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
@ -70,47 +70,33 @@ class CategoryPresenter extends Presenter
|
|||
'visible' => true,
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
], [
|
||||
'field' => 'actions',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => false,
|
||||
'title' => trans('table.actions'),
|
||||
],[
|
||||
"field" => "use_default_eula",
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
"title" => trans('admin/categories/general.use_default_eula_column'),
|
||||
'visible' => true,
|
||||
"formatter" => 'trueFalseFormatter',
|
||||
],[
|
||||
"field" => "checkin_email",
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
"class" => 'css-envelope',
|
||||
"title" => 'Send Email',
|
||||
"visible" => true,
|
||||
"formatter" => 'trueFalseFormatter',
|
||||
],[
|
||||
"field" => "require_acceptance",
|
||||
"searchable" => false,
|
||||
"sortable" => true,
|
||||
'formatter' => 'categoriesActionsFormatter',
|
||||
],
|
||||
[
|
||||
], [
|
||||
'field' => 'created_at',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.created_at'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
],
|
||||
[
|
||||
], [
|
||||
'field' => 'updated_at',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.updated_at'),
|
||||
'formatter' => 'dateDisplayFormatter',
|
||||
], [
|
||||
'field' => 'actions',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'switchable' => false,
|
||||
'title' => trans('table.actions'),
|
||||
'formatter' => 'categoriesActionsFormatter',
|
||||
],
|
||||
];
|
||||
|
||||
|
|
|
@ -268,9 +268,9 @@ class UserPresenter extends Presenter
|
|||
'formatter' => 'trueFalseFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'two_factor_activated',
|
||||
'field' => 'two_factor_optin',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/users/general.two_factor_active'),
|
||||
'visible' => false,
|
||||
|
|
|
@ -114,6 +114,24 @@ class AuthServiceProvider extends ServiceProvider
|
|||
}
|
||||
});
|
||||
|
||||
Gate::define('accessories.files', function ($user) {
|
||||
if ($user->hasAccess('accessories.files')) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Gate::define('components.files', function ($user) {
|
||||
if ($user->hasAccess('components.files')) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Gate::define('consumables.files', function ($user) {
|
||||
if ($user->hasAccess('consumables.files')) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
// Can the user import CSVs?
|
||||
Gate::define('import', function ($user) {
|
||||
if ($user->hasAccess('import')) {
|
||||
|
@ -159,6 +177,10 @@ class AuthServiceProvider extends ServiceProvider
|
|||
return $user->hasAccess('self.checkout_assets');
|
||||
});
|
||||
|
||||
Gate::define('self.view_purchase_cost', function ($user) {
|
||||
return $user->hasAccess('self.view_purchase_cost');
|
||||
});
|
||||
|
||||
// This is largely used to determine whether to display the gear icon sidenav
|
||||
// in the left-side navigation
|
||||
Gate::define('backend.interact', function ($user) {
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Models\Department;
|
||||
use DB;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Validator;
|
||||
|
||||
/**
|
||||
|
@ -213,6 +215,23 @@ class ValidationServiceProvider extends ServiceProvider
|
|||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
Validator::extend('is_unique_department', function ($attribute, $value, $parameters, $validator) {
|
||||
$data = $validator->getData();
|
||||
if ((array_key_exists('location_id', $data) && $data['location_id'] != null) && (array_key_exists('company_id', $data) && $data['company_id'] != null)) {
|
||||
$count = Department::where('name', $data['name'])
|
||||
->where('location_id', $data['location_id'])
|
||||
->where('company_id', $data['company_id'])
|
||||
->whereNotNull('company_id')
|
||||
->whereNotNull('location_id')
|
||||
->count('name');
|
||||
|
||||
return $count < 1;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
16
composer.lock
generated
16
composer.lock
generated
|
@ -78,19 +78,19 @@
|
|||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/grokability/laravel-scim-server.git",
|
||||
"reference": "9e7a8fd51a7380bc18ca1f01256574d75a2c6b49"
|
||||
"reference": "2c7ecc450eee59234e059ec2e7724b2d8f3a8369"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/grokability/laravel-scim-server/zipball/9e7a8fd51a7380bc18ca1f01256574d75a2c6b49",
|
||||
"reference": "9e7a8fd51a7380bc18ca1f01256574d75a2c6b49",
|
||||
"url": "https://api.github.com/repos/grokability/laravel-scim-server/zipball/2c7ecc450eee59234e059ec2e7724b2d8f3a8369",
|
||||
"reference": "2c7ecc450eee59234e059ec2e7724b2d8f3a8369",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/console": "^6.0|^7.0|^8.0",
|
||||
"illuminate/database": "^6.0|^7.0|^8.0",
|
||||
"illuminate/support": "^6.0|^7.0|^8.0",
|
||||
"php": "^7.4|^8.0",
|
||||
"illuminate/console": "^6.0|^7.0|^8.0|^9.0",
|
||||
"illuminate/database": "^6.0|^7.0|^8.0|^9.0",
|
||||
"illuminate/support": "^6.0|^7.0|^8.0|^9.0",
|
||||
"php": "^7.0|^8.0",
|
||||
"tmilos/scim-filter-parser": "^1.3",
|
||||
"tmilos/scim-schema": "^0.1.0"
|
||||
},
|
||||
|
@ -133,7 +133,7 @@
|
|||
"support": {
|
||||
"source": "https://github.com/grokability/laravel-scim-server/tree/master"
|
||||
},
|
||||
"time": "2022-10-06T00:42:37+00:00"
|
||||
"time": "2022-11-22T20:26:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "asm89/stack-cors",
|
||||
|
|
|
@ -4,7 +4,7 @@ use Monolog\Handler\NullHandler;
|
|||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Handler\SyslogUdpHandler;
|
||||
|
||||
return [
|
||||
$config = [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
|
@ -35,6 +35,8 @@ return [
|
|||
*/
|
||||
|
||||
'channels' => [
|
||||
// This will get overwritten to 'single' AND 'rollbar' in the code at the bottom of this file
|
||||
// if a ROLLBAR_TOKEN is given in the .env file
|
||||
'stack' => [
|
||||
'driver' => 'stack',
|
||||
'channels' => ['single'],
|
||||
|
@ -104,7 +106,23 @@ return [
|
|||
'scimtrace' => [
|
||||
'driver' => 'single',
|
||||
'path' => storage_path('logs/scim.log')
|
||||
]
|
||||
],
|
||||
|
||||
'rollbar' => [
|
||||
'driver' => 'monolog',
|
||||
'handler' => \Rollbar\Laravel\MonologHandler::class,
|
||||
'access_token' => env('ROLLBAR_TOKEN'),
|
||||
'level' => env('ROLLBAR_LEVEL', 'error'),
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
|
||||
// Only add rollbar if the .env has a rollbar token
|
||||
if ((env('APP_ENV')=='production') && (env('ROLLBAR_TOKEN'))) {
|
||||
$config['channels']['stack']['channels'] = ['single', 'rollbar'];
|
||||
}
|
||||
|
||||
|
||||
return $config;
|
|
@ -145,6 +145,13 @@ return [
|
|||
'note' => '',
|
||||
'display' => true,
|
||||
],
|
||||
[
|
||||
'permission' => 'accessories.files',
|
||||
'label' => 'View and Modify Accessory Files',
|
||||
'note' => '',
|
||||
'display' => true,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
'Consumables' => [
|
||||
|
@ -178,6 +185,12 @@ return [
|
|||
'note' => '',
|
||||
'display' => true,
|
||||
],
|
||||
[
|
||||
'permission' => 'consumables.files',
|
||||
'label' => 'View and Modify Consumable Files',
|
||||
'note' => '',
|
||||
'display' => true,
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
|
@ -264,6 +277,12 @@ return [
|
|||
'note' => '',
|
||||
'display' => true,
|
||||
],
|
||||
[
|
||||
'permission' => 'components.files',
|
||||
'label' => 'View and Modify Component Files',
|
||||
'note' => '',
|
||||
'display' => true,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
|
@ -626,6 +645,13 @@ return [
|
|||
'display' => true,
|
||||
],
|
||||
|
||||
[
|
||||
'permission' => 'self.view_purchase_cost',
|
||||
'label' => 'View Purchase-Cost Column',
|
||||
'note' => 'This user can see the purchase cost column of items assigned to them.',
|
||||
'display' => true,
|
||||
],
|
||||
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
"trace" => env("SCIM_TRACE",false),
|
||||
// below, if we ever get 'sure' that we can change this default to 'true' we should
|
||||
"omit_main_schema_in_return" => env('SCIM_STANDARDS_COMPLIANCE', false),
|
||||
"publish_routes" => false,
|
||||
"trace" => env("SCIM_TRACE",false)
|
||||
];
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<?php
|
||||
return array (
|
||||
'app_version' => 'v6.0.12',
|
||||
'full_app_version' => 'v6.0.12 - build 8876-gbc4c6abe0',
|
||||
'build_version' => '8876',
|
||||
'app_version' => 'v6.0.14',
|
||||
'full_app_version' => 'v6.0.14 - build 9161-g799c9c910',
|
||||
'build_version' => '9161',
|
||||
'prerelease_version' => '',
|
||||
'hash_version' => 'gbc4c6abe0',
|
||||
'full_hash' => 'v6.0.12-50-gbc4c6abe0',
|
||||
'branch' => 'develop',
|
||||
'hash_version' => 'g799c9c910',
|
||||
'full_hash' => 'v6.0.14-117-g799c9c910',
|
||||
'branch' => 'master',
|
||||
);
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddsLdapDefaultGroupToSettingsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->integer('ldap_default_group')
|
||||
->after('ldap_basedn')->default(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->dropColumn('ldap_default_group');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddDisplayToUserInCustomFields extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('custom_fields', function (Blueprint $table) {
|
||||
$table->boolean('display_in_user_view')->nullable()->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('custom_fields', function (Blueprint $table) {
|
||||
$table->dropColumn('display_in_user_view');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class FixNullableMigrationForSettings extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->string('ldap_default_group')->nullable()->default(null)->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
// nothing to do here - this is a hotfix
|
||||
}
|
||||
}
|
34
database/migrations/2023_01_18_122534_add_byod_to_assets.php
Normal file
34
database/migrations/2023_01_18_122534_add_byod_to_assets.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddByodToAssets extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
$table->boolean('byod')->nullable()->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
if (Schema::hasColumn('assets', 'byod')) {
|
||||
$table->dropColumn('byod');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
360
package-lock.json
generated
360
package-lock.json
generated
|
@ -1329,9 +1329,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@fortawesome/fontawesome-free": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.0.tgz",
|
||||
"integrity": "sha512-CNR7qRIfCwWHNN7FnKUniva94edPdyQzil/zCwk3v6k4R6rR2Fr8i4s3PM7n/lyfPA6Zfko9z5WDzFxG9SW1uQ=="
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.1.tgz",
|
||||
"integrity": "sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A=="
|
||||
},
|
||||
"@jridgewell/gen-mapping": {
|
||||
"version": "0.1.1",
|
||||
|
@ -3588,9 +3588,9 @@
|
|||
}
|
||||
},
|
||||
"camelcase": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
|
||||
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
|
||||
"integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
|
||||
},
|
||||
"caniuse-api": {
|
||||
"version": "3.0.0",
|
||||
|
@ -4244,75 +4244,60 @@
|
|||
}
|
||||
},
|
||||
"css-loader": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
|
||||
"integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz",
|
||||
"integrity": "sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==",
|
||||
"requires": {
|
||||
"camelcase": "^5.3.1",
|
||||
"camelcase": "^6.0.0",
|
||||
"cssesc": "^3.0.0",
|
||||
"icss-utils": "^4.1.1",
|
||||
"loader-utils": "^1.2.3",
|
||||
"normalize-path": "^3.0.0",
|
||||
"loader-utils": "^2.0.0",
|
||||
"postcss": "^7.0.32",
|
||||
"postcss-modules-extract-imports": "^2.0.0",
|
||||
"postcss-modules-local-by-default": "^3.0.2",
|
||||
"postcss-modules-local-by-default": "^3.0.3",
|
||||
"postcss-modules-scope": "^2.2.0",
|
||||
"postcss-modules-values": "^3.0.0",
|
||||
"postcss-value-parser": "^4.1.0",
|
||||
"schema-utils": "^2.7.0",
|
||||
"semver": "^6.3.0"
|
||||
"schema-utils": "^2.7.1",
|
||||
"semver": "^7.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"loader-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
"integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "7.0.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
|
||||
"integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"picocolors": "^0.2.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "7.3.8",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
|
||||
"integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
|
||||
"requires": {
|
||||
"lru-cache": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -4936,7 +4921,8 @@
|
|||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
},
|
||||
"escodegen": {
|
||||
"version": "1.14.3",
|
||||
|
@ -15028,7 +15014,8 @@
|
|||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"has-symbols": {
|
||||
"version": "1.0.1",
|
||||
|
@ -15350,56 +15337,24 @@
|
|||
"postcss": "^7.0.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "7.0.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
|
||||
"integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"picocolors": "^0.2.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -15867,8 +15822,7 @@
|
|||
"json5": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA=="
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "6.1.0",
|
||||
|
@ -16453,7 +16407,6 @@
|
|||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"yallist": "^4.0.0"
|
||||
}
|
||||
|
@ -17011,7 +16964,8 @@
|
|||
"normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU="
|
||||
"integrity": "sha1-Dc1p/yOhybEf0JeDFmRKA4ghamU=",
|
||||
"dev": true
|
||||
},
|
||||
"normalize-range": {
|
||||
"version": "0.1.2",
|
||||
|
@ -17691,56 +17645,24 @@
|
|||
"postcss": "^7.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "7.0.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
|
||||
"integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"picocolors": "^0.2.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -17755,56 +17677,24 @@
|
|||
"postcss-value-parser": "^4.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "7.0.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
|
||||
"integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"picocolors": "^0.2.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -17817,56 +17707,24 @@
|
|||
"postcss-selector-parser": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "7.0.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
|
||||
"integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"picocolors": "^0.2.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -17879,56 +17737,24 @@
|
|||
"postcss": "^7.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"picocolors": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
|
||||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.36",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
|
||||
"integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
|
||||
"version": "7.0.39",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
|
||||
"integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
"picocolors": "^0.2.1",
|
||||
"source-map": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -18714,7 +18540,8 @@
|
|||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
},
|
||||
"send": {
|
||||
"version": "0.18.0",
|
||||
|
@ -20418,8 +20245,7 @@
|
|||
"yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"yaml": {
|
||||
"version": "1.10.2",
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
"vue-template-compiler": "2.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.2.0",
|
||||
"@fortawesome/fontawesome-free": "^6.2.1",
|
||||
"acorn": "^8.8.0",
|
||||
"acorn-import-assertions": "^1.8.0",
|
||||
"admin-lte": "^2.4.18",
|
||||
|
@ -37,7 +37,7 @@
|
|||
"bootstrap-less": "^3.3.8",
|
||||
"bootstrap-table": "1.20.2",
|
||||
"chart.js": "^2.9.4",
|
||||
"css-loader": "^3.6.0",
|
||||
"css-loader": "^4.0.0",
|
||||
"ekko-lightbox": "^5.1.1",
|
||||
"icheck": "^1.0.2",
|
||||
"imagemin": "^8.0.1",
|
||||
|
@ -48,7 +48,7 @@
|
|||
"jquery.iframe-transport": "^1.0.0",
|
||||
"jspdf-autotable": "^3.5.24",
|
||||
"less": "^4.1.2",
|
||||
"less-loader": "^5.0.0",
|
||||
"less-loader": "^5.0",
|
||||
"list.js": "^1.5.0",
|
||||
"papaparse": "^4.3.3",
|
||||
"select2": "4.0.13",
|
||||
|
|
|
@ -968,4 +968,9 @@ th.css-accessory > .th-inner::before {
|
|||
margin-top: 51px;
|
||||
}
|
||||
}
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
|
|
@ -601,4 +601,9 @@ th.css-accessory > .th-inner::before {
|
|||
margin-top: 51px;
|
||||
}
|
||||
}
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
|
10
public/css/dist/all.css
vendored
10
public/css/dist/all.css
vendored
|
@ -23830,6 +23830,11 @@ th.css-accessory > .th-inner::before {
|
|||
margin-top: 51px;
|
||||
}
|
||||
}
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.select2-container {
|
||||
|
@ -24917,4 +24922,9 @@ th.css-accessory > .th-inner::before {
|
|||
margin-top: 51px;
|
||||
}
|
||||
}
|
||||
.ellipsis {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
|
3
public/css/dist/skins/skin-black-dark.css
vendored
3
public/css/dist/skins/skin-black-dark.css
vendored
|
@ -217,6 +217,9 @@ a:visited {
|
|||
.navbar-nav > li > a:link {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.modal-content {
|
||||
background-color: var(--back-main);
|
||||
color: var(--text-main);
|
||||
|
|
|
@ -217,6 +217,9 @@ a:visited {
|
|||
.navbar-nav > li > a:link {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.modal-content {
|
||||
background-color: var(--back-main);
|
||||
color: var(--text-main);
|
||||
|
|
3
public/css/dist/skins/skin-black.css
vendored
3
public/css/dist/skins/skin-black.css
vendored
|
@ -199,6 +199,9 @@ a.btn-danger:visited {
|
|||
.btn-danger.btn-sm.disabled {
|
||||
color: #FFF;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.sidebar-toggle-mobile {
|
||||
color: #FFF !important;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-black.min.css
vendored
3
public/css/dist/skins/skin-black.min.css
vendored
|
@ -199,6 +199,9 @@ a.btn-danger:visited {
|
|||
.btn-danger.btn-sm.disabled {
|
||||
color: #FFF;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.sidebar-toggle-mobile {
|
||||
color: #FFF !important;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-blue-dark.css
vendored
3
public/css/dist/skins/skin-blue-dark.css
vendored
|
@ -212,6 +212,9 @@ a:visited {
|
|||
.navbar-nav > li > a:link {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.modal-content {
|
||||
background-color: var(--back-main);
|
||||
color: var(--text-main);
|
||||
|
|
3
public/css/dist/skins/skin-blue-dark.min.css
vendored
3
public/css/dist/skins/skin-blue-dark.min.css
vendored
|
@ -212,6 +212,9 @@ a:visited {
|
|||
.navbar-nav > li > a:link {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.modal-content {
|
||||
background-color: var(--back-main);
|
||||
color: var(--text-main);
|
||||
|
|
5
public/css/dist/skins/skin-blue.css
vendored
5
public/css/dist/skins/skin-blue.css
vendored
|
@ -123,7 +123,7 @@
|
|||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.skin-blue.layout-top-nav .main-header > .logo .logo-variant {
|
||||
background-color: none;
|
||||
background-color: unset;
|
||||
}
|
||||
.btn.btn-primary,
|
||||
btn-sm.btn-primary,
|
||||
|
@ -218,6 +218,9 @@ a:hover {
|
|||
.text-primary {
|
||||
color: #23536f;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.fixed-table-container tbody .selected td {
|
||||
background-color: #fff8af;
|
||||
}
|
||||
|
|
5
public/css/dist/skins/skin-blue.min.css
vendored
5
public/css/dist/skins/skin-blue.min.css
vendored
|
@ -123,7 +123,7 @@
|
|||
border-bottom-left-radius: 0;
|
||||
}
|
||||
.skin-blue.layout-top-nav .main-header > .logo .logo-variant {
|
||||
background-color: none;
|
||||
background-color: unset;
|
||||
}
|
||||
.btn.btn-primary,
|
||||
btn-sm.btn-primary,
|
||||
|
@ -218,6 +218,9 @@ a:hover {
|
|||
.text-primary {
|
||||
color: #23536f;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.fixed-table-container tbody .selected td {
|
||||
background-color: #fff8af;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-green-dark.css
vendored
3
public/css/dist/skins/skin-green-dark.css
vendored
|
@ -205,6 +205,9 @@ a:visited {
|
|||
.bootstrap-table .fixed-table-container .table thead th .sortable {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.thead,
|
||||
.navbar-nav > li > a:link {
|
||||
color: var(--nav-link);
|
||||
|
|
|
@ -205,6 +205,9 @@ a:visited {
|
|||
.bootstrap-table .fixed-table-container .table thead th .sortable {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.thead,
|
||||
.navbar-nav > li > a:link {
|
||||
color: var(--nav-link);
|
||||
|
|
3
public/css/dist/skins/skin-green.css
vendored
3
public/css/dist/skins/skin-green.css
vendored
|
@ -195,6 +195,9 @@ a:visited {
|
|||
.text-primary {
|
||||
color: #004023;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.fixed-table-container tbody .selected td {
|
||||
background-color: #fff8af;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-green.min.css
vendored
3
public/css/dist/skins/skin-green.min.css
vendored
|
@ -195,6 +195,9 @@ a:visited {
|
|||
.text-primary {
|
||||
color: #004023;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.fixed-table-container tbody .selected td {
|
||||
background-color: #fff8af;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-orange-dark.css
vendored
3
public/css/dist/skins/skin-orange-dark.css
vendored
|
@ -196,6 +196,9 @@ li.dropdown-item-marker {
|
|||
background: linear-gradient(to bottom, var(--header) 0%, var(--header) 100%);
|
||||
border-color: var(--header);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.bootstrap-table .fixed-table-container .table thead th .sortable {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
|
|
|
@ -196,6 +196,9 @@ li.dropdown-item-marker {
|
|||
background: linear-gradient(to bottom, var(--header) 0%, var(--header) 100%);
|
||||
border-color: var(--header);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.bootstrap-table .fixed-table-container .table thead th .sortable {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-orange.css
vendored
3
public/css/dist/skins/skin-orange.css
vendored
|
@ -190,6 +190,9 @@ a.btn-warning:visited,
|
|||
a.btn-danger:visited {
|
||||
color: #FFF;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.fixed-table-container tbody .selected td {
|
||||
background-color: #fff8af;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-orange.min.css
vendored
3
public/css/dist/skins/skin-orange.min.css
vendored
|
@ -190,6 +190,9 @@ a.btn-warning:visited,
|
|||
a.btn-danger:visited {
|
||||
color: #FFF;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.fixed-table-container tbody .selected td {
|
||||
background-color: #fff8af;
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-purple-dark.css
vendored
3
public/css/dist/skins/skin-purple-dark.css
vendored
|
@ -223,6 +223,9 @@ a:visited {
|
|||
a:link {
|
||||
color: var(--link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.btn-primary.hover {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
|
|
|
@ -223,6 +223,9 @@ a:visited {
|
|||
a:link {
|
||||
color: var(--link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.btn-primary.hover {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-purple.css
vendored
3
public/css/dist/skins/skin-purple.css
vendored
|
@ -196,6 +196,9 @@ a.btn-danger:visited {
|
|||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #605ca8;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.search-highlight,
|
||||
.search-highlight:hover {
|
||||
background-color: #e9d15b;
|
||||
|
|
3
public/css/dist/skins/skin-purple.min.css
vendored
3
public/css/dist/skins/skin-purple.min.css
vendored
|
@ -196,6 +196,9 @@ a.btn-danger:visited {
|
|||
.select2-container--default .select2-selection--multiple .select2-selection__choice {
|
||||
background-color: #605ca8;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.search-highlight,
|
||||
.search-highlight:hover {
|
||||
background-color: #e9d15b;
|
||||
|
|
3
public/css/dist/skins/skin-red-dark.css
vendored
3
public/css/dist/skins/skin-red-dark.css
vendored
|
@ -226,6 +226,9 @@ a:visited {
|
|||
a:hover {
|
||||
color: var(--hover-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.btn-primary.hover {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-red-dark.min.css
vendored
3
public/css/dist/skins/skin-red-dark.min.css
vendored
|
@ -226,6 +226,9 @@ a:visited {
|
|||
a:hover {
|
||||
color: var(--hover-link);
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
.btn-primary.hover {
|
||||
color: var(--nav-link);
|
||||
}
|
||||
|
|
3
public/css/dist/skins/skin-red.css
vendored
3
public/css/dist/skins/skin-red.css
vendored
|
@ -207,4 +207,7 @@ a.btn-danger:visited {
|
|||
.search-highlight:hover {
|
||||
background-color: #e9d15b;
|
||||
}
|
||||
.far fa-life-ring {
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue