Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 172942878b | |||
| 46279c5f3d | |||
| 731dc29bf5 | |||
| 530a76881e | |||
| 257a501d70 | |||
| e047d5516c |
@@ -2585,49 +2585,6 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "QveenSi",
|
||||
"name": "Yevhenii Huzii",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19945501?v=4",
|
||||
"profile": "https://github.com/QveenSi",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "veenone",
|
||||
"name": "Achmad Fienan Rahardianto",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/3839381?v=4",
|
||||
"profile": "https://github.com/veenone",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "QveenSi",
|
||||
"name": "Yevhenii Huzii",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/19945501?v=4",
|
||||
"profile": "https://github.com/QveenSi",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "chrisweirich",
|
||||
"name": "Christian Weirich",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/97299851?v=4",
|
||||
"profile": "https://github.com/chrisweirich",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "denzfarid",
|
||||
"name": "denzfarid",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/1294403?v=4",
|
||||
"profile": "https://github.com/denzfarid",
|
||||
"contributions": []
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -138,13 +138,6 @@ PRIVATE_AWS_BUCKET=null
|
||||
PRIVATE_AWS_URL=null
|
||||
PRIVATE_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: AWS Settings
|
||||
# --------------------------------------------
|
||||
AWS_ACCESS_KEY_ID=null
|
||||
AWS_SECRET_ACCESS_KEY=null
|
||||
AWS_DEFAULT_REGION=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: LOGIN THROTTLING
|
||||
# --------------------------------------------
|
||||
|
||||
+1
-8
@@ -134,13 +134,6 @@ PRIVATE_AWS_BUCKET=null
|
||||
PRIVATE_AWS_URL=null
|
||||
PRIVATE_AWS_BUCKET_ROOT=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: AWS Settings
|
||||
# --------------------------------------------
|
||||
AWS_ACCESS_KEY_ID=null
|
||||
AWS_SECRET_ACCESS_KEY=null
|
||||
AWS_DEFAULT_REGION=null
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: LOGIN THROTTLING
|
||||
# --------------------------------------------
|
||||
@@ -164,4 +157,4 @@ IMPORT_TIME_LIMIT=600
|
||||
IMPORT_MEMORY_LIMIT=500M
|
||||
REPORT_TIME_LIMIT=12000
|
||||
REQUIRE_SAML=false
|
||||
API_THROTTLE_PER_MINUTE=120
|
||||
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ IMAGE_LIB=gd
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# OPTIONAL: AWS SETTINGS
|
||||
# OPTIONAL: AWS S3 SETTINGS
|
||||
# --------------------------------------------
|
||||
AWS_SECRET_ACCESS_KEY=null
|
||||
AWS_ACCESS_KEY_ID=null
|
||||
|
||||
@@ -1,27 +1,42 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
title: "[Feature Request]: "
|
||||
labels: ["feature request"]
|
||||
assignees:
|
||||
- snipe
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. The more information you can provide about your use-case, the more liklely we are to consider your feature.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
body:
|
||||
- type: input
|
||||
attributes:
|
||||
label: Snipe-IT Version
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: server_operatingSystem
|
||||
attributes:
|
||||
label: Operating System
|
||||
description: 'e.g. Ubuntu, Windows'
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Web Server
|
||||
description: 'e.g. Apache, IIS'
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: PHP Version
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Additional context Add any other context or screenshots about the feature request here.
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# This workflow checks out code, performs a CodeQL analysis (for JavaScript) and integrates the results
|
||||
# with the GitHub Advanced Security code scanning feature.
|
||||
# More information: https://codeql.github.com/
|
||||
name: CodeQL Security Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
# schedule:
|
||||
# - cron: '15 17 * * 1'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: CodeQL Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -19,8 +19,6 @@ on:
|
||||
|
||||
jobs:
|
||||
codacy-security-scan:
|
||||
# Ensure schedule job never runs on forked repos. It's only executed for 'snipe/snipe-it'
|
||||
if: (github.repository == 'snipe/snipe-it') || ((github.repository != 'snipe/snipe-it') && (github.event_name != 'schedule'))
|
||||
name: Codacy Security Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
@@ -23,7 +23,6 @@ php7.4-xml \
|
||||
php7.4-mbstring \
|
||||
php7.4-zip \
|
||||
php7.4-bcmath \
|
||||
php7.4-redis \
|
||||
patch \
|
||||
curl \
|
||||
wget \
|
||||
@@ -42,7 +41,6 @@ libmcrypt-dev \
|
||||
php7.4-dev \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
dnsutils \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ RUN apk add --no-cache \
|
||||
php7-xmlwriter \
|
||||
php7-xmlreader \
|
||||
php7-sodium \
|
||||
php7-redis \
|
||||
curl \
|
||||
wget \
|
||||
vim \
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
 [](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
|
||||
|
||||
This is a FOSS project for asset management in IT Operations. Knowing who has which laptop, when it was purchased in order to depreciate it correctly, handling software licenses, etc.
|
||||
|
||||
It is built on [Laravel 8](http://laravel.com).
|
||||
It is built on [Laravel 6](http://laravel.com).
|
||||
|
||||
Snipe-IT is actively developed and we [release quite frequently](https://github.com/snipe/snipe-it/releases). ([Check out the live demo here](https://snipeitapp.com/demo/).)
|
||||
|
||||
@@ -131,8 +131,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<img src="https://avatars.githubusercontent.com/u/1975640?v=4" width="110px;"/><br /><sub>Evan Taylor</sub>](https://github.com/Delta5)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Delta5 "Code") | [<img src="https://avatars.githubusercontent.com/u/8735148?v=4" width="110px;"/><br /><sub>Petri Asikainen</sub>](https://github.com/PetriAsi)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PetriAsi "Code") | [<img src="https://avatars.githubusercontent.com/u/11424540?v=4" width="110px;"/><br /><sub>derdeagle</sub>](https://github.com/derdeagle)<br />[💻](https://github.com/snipe/snipe-it/commits?author=derdeagle "Code") | [<img src="https://avatars.githubusercontent.com/u/176950?v=4" width="110px;"/><br /><sub>Mike Frysinger</sub>](https://wh0rd.org/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=vapier "Code") | [<img src="https://avatars.githubusercontent.com/u/22044358?v=4" width="110px;"/><br /><sub>ALPHA</sub>](https://github.com/AL4AL)<br />[💻](https://github.com/snipe/snipe-it/commits?author=AL4AL "Code") | [<img src="https://avatars.githubusercontent.com/u/1042587?v=4" width="110px;"/><br /><sub>FliegenKLATSCH</sub>](https://www.ifern.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=FliegenKLATSCH "Code") | [<img src="https://avatars.githubusercontent.com/u/442138?v=4" width="110px;"/><br /><sub>Jeremy Price</sub>](https://github.com/jerm)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jerm "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/84392209?v=4" width="110px;"/><br /><sub>Toreg87</sub>](https://github.com/Toreg87)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Toreg87 "Code") | [<img src="https://avatars.githubusercontent.com/u/67638596?v=4" width="110px;"/><br /><sub>Matthew Nickson</sub>](https://github.com/Computroniks)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Computroniks "Code") | [<img src="https://avatars.githubusercontent.com/u/1646397?v=4" width="110px;"/><br /><sub>Jethro Nederhof</sub>](https://jethron.id.au)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jethron "Code") | [<img src="https://avatars.githubusercontent.com/u/23289826?v=4" width="110px;"/><br /><sub>Oskar Stenberg</sub>](https://github.com/01ste02)<br />[💻](https://github.com/snipe/snipe-it/commits?author=01ste02 "Code") | [<img src="https://avatars.githubusercontent.com/u/82208283?v=4" width="110px;"/><br /><sub>Robert-Azelis</sub>](https://github.com/Robert-Azelis)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Robert-Azelis "Code") | [<img src="https://avatars.githubusercontent.com/u/60648387?v=4" width="110px;"/><br /><sub>Alexander William Smith</sub>](https://github.com/alwism)<br />[💻](https://github.com/snipe/snipe-it/commits?author=alwism "Code") | [<img src="https://avatars.githubusercontent.com/u/24418301?v=4" width="110px;"/><br /><sub>LEITWERK AG</sub>](https://www.leitwerk.de/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leitwerk-ag "Code") |
|
||||
| [<img src="https://avatars.githubusercontent.com/u/1911435?v=4" width="110px;"/><br /><sub>Adam</sub>](http://www.aboutcher.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=adamboutcher "Code") | [<img src="https://avatars.githubusercontent.com/u/16104273?v=4" width="110px;"/><br /><sub>Ian</sub>](https://snksrv.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sneak-it "Code") | [<img src="https://avatars.githubusercontent.com/u/4023909?v=4" width="110px;"/><br /><sub>Shao Yu-Lung (Allen)</sub>](http://blog.bestlong.idv.tw/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=bestlong "Code") | [<img src="https://avatars.githubusercontent.com/u/76475453?v=4" width="110px;"/><br /><sub>Haxatron</sub>](https://github.com/Haxatron)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Haxatron "Code") | [<img src="https://avatars.githubusercontent.com/u/88776392?v=4" width="110px;"/><br /><sub>PlaneNuts</sub>](https://github.com/PlaneNuts)<br />[💻](https://github.com/snipe/snipe-it/commits?author=PlaneNuts "Code") | [<img src="https://avatars.githubusercontent.com/u/3842948?v=4" width="110px;"/><br /><sub>Bradley Coudriet</sub>](http://bjcpgd.cias.rit.edu)<br />[💻](https://github.com/snipe/snipe-it/commits?author=exula "Code") | [<img src="https://avatars.githubusercontent.com/u/21966173?v=4" width="110px;"/><br /><sub>Dalton Durst</sub>](https://daltondur.st)<br />[💻](https://github.com/snipe/snipe-it/commits?author=UniversalSuperBox "Code") |
|
||||
| [<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/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") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class KillAllSessions extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:global-logout {--force : Skip the danger prompt; assuming you enter "y"} ';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This command will destroy all web sessions on disk and will force a re-login for all users.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
if (!$this->option('force') && !$this->confirm("****************************************************\nTHIS WILL FORCE A LOGIN FOR ALL LOGGED IN USERS.\n\nAre you SURE you wish to continue? ")) {
|
||||
return $this->error("Session loss not confirmed");
|
||||
}
|
||||
|
||||
$session_files = glob(storage_path("framework/sessions/*"));
|
||||
|
||||
$count = 0;
|
||||
foreach ($session_files as $file) {
|
||||
|
||||
if (is_file($file))
|
||||
unlink($file);
|
||||
$count++;
|
||||
}
|
||||
\DB::table('users')->update(['remember_token' => null]);
|
||||
|
||||
$this->info($count. ' sessions cleared!');
|
||||
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,6 @@ class LdapSync extends Command
|
||||
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
|
||||
$ldap_result_country = Setting::getSettings()->ldap_country;
|
||||
$ldap_result_dept = Setting::getSettings()->ldap_dept;
|
||||
$ldap_result_manager = Setting::getSettings()->ldap_manager;
|
||||
|
||||
try {
|
||||
$ldapconn = Ldap::connectToLdap();
|
||||
@@ -185,12 +184,12 @@ class LdapSync extends Command
|
||||
$item['jobtitle'] = isset($results[$i][$ldap_result_jobtitle][0]) ? $results[$i][$ldap_result_jobtitle][0] : '';
|
||||
$item['country'] = isset($results[$i][$ldap_result_country][0]) ? $results[$i][$ldap_result_country][0] : '';
|
||||
$item['department'] = isset($results[$i][$ldap_result_dept][0]) ? $results[$i][$ldap_result_dept][0] : '';
|
||||
$item['manager'] = isset($results[$i][$ldap_result_manager][0]) ? $results[$i][$ldap_result_manager][0] : '';
|
||||
|
||||
$department = Department::firstOrCreate([
|
||||
'name' => $item['department'],
|
||||
]);
|
||||
|
||||
|
||||
$user = User::where('username', $item['username'])->first();
|
||||
if ($user) {
|
||||
// Updating an existing user.
|
||||
@@ -213,17 +212,6 @@ class LdapSync extends Command
|
||||
$user->country = $item['country'];
|
||||
$user->department_id = $department->id;
|
||||
|
||||
if($item['manager'] != null) {
|
||||
//Captures only the Canonical Name
|
||||
$item['manager'] = ltrim($item['manager'], "CN=");
|
||||
$item['manager'] = substr($item['manager'],0, strpos($item['manager'], ','));
|
||||
$ldap_manager = User::where('username', $item['manager'])->first();
|
||||
if ( $ldap_manager && isset($ldap_manager->id) ) {
|
||||
$user->manager_id = $ldap_manager->id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Sync activated state for Active Directory.
|
||||
if (array_key_exists('useraccountcontrol', $results[$i])) {
|
||||
/* The following is _probably_ the correct logic, but we can't use it because
|
||||
|
||||
@@ -1,503 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use App\Models\Setting;
|
||||
use Exception;
|
||||
use Crypt;
|
||||
|
||||
/**
|
||||
* Check if a given ip is in a network
|
||||
* @param string $ip IP to check in IPV4 format eg. 127.0.0.1
|
||||
* @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed
|
||||
* @return boolean true if the ip is in this range / false if not.
|
||||
*/
|
||||
function ip_in_range( $ip, $range ) {
|
||||
if ( strpos( $range, '/' ) == false ) {
|
||||
$range .= '/32';
|
||||
}
|
||||
// $range is in IP/CIDR format eg 127.0.0.1/24
|
||||
list( $range, $netmask ) = explode( '/', $range, 2 );
|
||||
$range_decimal = ip2long( $range );
|
||||
$ip_decimal = ip2long( $ip );
|
||||
$wildcard_decimal = pow( 2, ( 32 - $netmask ) ) - 1;
|
||||
$netmask_decimal = ~ $wildcard_decimal;
|
||||
return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) );
|
||||
}
|
||||
// NOTE - this function was shamelessly stolen from this gist: https://gist.github.com/tott/7684443
|
||||
|
||||
class LdapTroubleshooter extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'ldap:troubleshoot
|
||||
{--ldap-search : Output an ldapsearch command-line for testing your LDAP config}
|
||||
{--force : Skip the interactive yes/no prompt for confirmation}
|
||||
{--debug : Include debugging output (verbose)}
|
||||
{--trace : Include extremely verbose LDAP trace output}
|
||||
{--timeout=15 : Timeout for LDAP Bind operations}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Runs a series of non-destructive LDAP commands to help try and determine correct LDAP settings for your environment.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output something *only* if debug is enabled
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function debugout($string)
|
||||
{
|
||||
if($this->option('debug')) {
|
||||
$this->line($string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
if($this->option('trace')) {
|
||||
ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);
|
||||
}
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
$this->settings = $settings;
|
||||
if($this->option('ldap-search')) {
|
||||
if(!$this->option('force')) {
|
||||
$confirmation = $this->confirm('WARNING: This command will display your LDAP password on your terminal. Are you sure this is ok?');
|
||||
if(!$confirmation) {
|
||||
$this->error('ABORTING');
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
$output = [];
|
||||
if($settings->ldap_server_cert_ignore) {
|
||||
$this->line("# Ignoring server certificate validity");
|
||||
$output[] = "LDAPTLS_REQCERT=never";
|
||||
}
|
||||
if($settings->ldap_client_tls_cert && $settings->ldap_client_tls_key) {
|
||||
$this->line("# Adding LDAP Client Certificate and Key");
|
||||
$output[] = "LDAPTLS_CERT=storage/ldap_client_tls.cert";
|
||||
$output[] = "LDAPTLS_KEY=storage/ldap_client_tls.key";
|
||||
}
|
||||
$output[] = "ldapsearch";
|
||||
$output[] = $settings->ldap_server;
|
||||
$output[] = "-x";
|
||||
$output[] = "-b ".escapeshellarg($settings->ldap_basedn);
|
||||
$output[] = "-D ".escapeshellarg($settings->ldap_uname);
|
||||
$output[] = "-w ".escapeshellarg(\Crypt::Decrypt($settings->ldap_pword));
|
||||
if(substr($settings->ldap_filter,0,1) == "(" ) {
|
||||
$output[] = escapeshellarg($settings->ldap_filter);
|
||||
} else {
|
||||
$output[] = escapeshellarg("(".$settings->ldap_filter.")");
|
||||
}
|
||||
if($settings->ldap_tls) {
|
||||
$this->line("# adding STARTTLS option");
|
||||
$output[] = "-Z";
|
||||
}
|
||||
$output[] = "-v";
|
||||
$this->line("\n");
|
||||
$this->line(implode(" \\\n",$output));
|
||||
exit(0);
|
||||
}
|
||||
if(!$this->option('force')) {
|
||||
$confirmation = $this->confirm('WARNING: This command will make several attempts to connect to your LDAP server. Are you sure this is ok?');
|
||||
if(!$confirmation) {
|
||||
$this->error('ABORTING');
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
//$this->line(print_r($settings,true));
|
||||
$this->info("STAGE 1: Checking settings");
|
||||
if(!$settings->ldap_enabled) {
|
||||
$this->error("WARNING: Snipe-IT's LDAP setting is not turned on. (That may be OK if you're still trying to figure out settings)");
|
||||
}
|
||||
|
||||
$ldap_conn = false;
|
||||
try {
|
||||
$ldap_conn = ldap_connect($settings->ldap_server);
|
||||
} catch (Exception $e) {
|
||||
$this->error("WARNING: Exception caught when executing 'ldap_connect()' - ".$e->getMessage().". We will try to guess.");
|
||||
}
|
||||
|
||||
if(!$ldap_conn) {
|
||||
$this->error("WARNING: LDAP Server setting of: ".$settings->ldap_server." cannot be parsed. We will try to guess.");
|
||||
//exit(-1);
|
||||
}
|
||||
//since we never use $ldap_conn again, we don't have to ldap_unbind() it (it's not even connected, tbh - that only happens at bind-time)
|
||||
|
||||
$parsed = parse_url($settings->ldap_server);
|
||||
|
||||
if(@$parsed['scheme'] != 'ldap' && @$parsed['scheme'] != 'ldaps') {
|
||||
$this->error("WARNING: LDAP URL Scheme of '".@$parsed['scheme']."' is probably incorrect; should usually be ldap or ldaps");
|
||||
}
|
||||
|
||||
if(!@$parsed['host']) {
|
||||
$this->error("ERROR: Cannot determine hostname or IP from ldap URL: ".$settings->ldap_server.". ABORTING.");
|
||||
exit(-1);
|
||||
} else {
|
||||
$this->info("Determined LDAP hostname to be: ".$parsed['host']);
|
||||
}
|
||||
|
||||
$this->info("Performing DNS lookup of: ".$parsed['host']);
|
||||
$ips = dns_get_record($parsed['host']);
|
||||
$raw_ips = [];
|
||||
|
||||
//$this->info("Host IP is: ".print_r($ips,true));
|
||||
|
||||
if(!$ips || count($ips) == 0) {
|
||||
$this->error("ERROR: DNS lookup of host: ".$parsed['host']." has failed. ABORTING.");
|
||||
exit(-1);
|
||||
}
|
||||
$this->debugout("IP's? ".print_r($ips,true));
|
||||
foreach($ips as $ip) {
|
||||
if(!isset($ip['ip'])) {
|
||||
continue;
|
||||
}
|
||||
$raw_ips[]=$ip['ip'];
|
||||
if($ip['ip'] == "127.0.0.1") {
|
||||
$this->error("WARNING: Using the localhost IP as the LDAP server. This is usually wrong");
|
||||
}
|
||||
if(ip_in_range($ip['ip'],'10.0.0.0/8') || ip_in_range($ip['ip'],'192.168.0.0/16') || ip_in_range($ip['ip'], '172.16.0.0/12')) {
|
||||
$this->error("WARNING: Using an RFC1918 Private address for LDAP server. This may be correct, but it can be a problem if your Snipe-IT instance is not hosted on your private network");
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("STAGE 2: Checking basic network connectivity");
|
||||
$ports = [389,636];
|
||||
if(@$parsed['port'] && !in_array($parsed['port'],$ports)) {
|
||||
$ports[] = $parsed['port'];
|
||||
}
|
||||
|
||||
$open_ports=[];
|
||||
foreach($ports as $port ) {
|
||||
$errno = 0;
|
||||
$errstr = '';
|
||||
$timeout = 30.0;
|
||||
$result = '';
|
||||
$this->info("Attempting to connect to port: ".$port." - may take up to $timeout seconds");
|
||||
try {
|
||||
$result = fsockopen($parsed['host'], $port, $errno, $errstr, 30.0);
|
||||
} catch(Exception $e) {
|
||||
$this->error("Exception: ".$e->getMessage());
|
||||
}
|
||||
if($result) {
|
||||
$this->info("Success!");
|
||||
$open_ports[] = $port;
|
||||
} else {
|
||||
$this->error("WARNING: Cannot connect to port: $port - $errstr ($errno)");
|
||||
}
|
||||
}
|
||||
|
||||
if(count($open_ports) == 0) {
|
||||
$this->error("ERROR - no open ports. ABORTING.");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
$this->info("STAGE 3: Determine encryption algorithm, if any");
|
||||
|
||||
$ldap_urls = [];
|
||||
$pretty_ldap_urls = [];
|
||||
foreach($open_ports as $port) {
|
||||
$this->line("Trying TLS first for port $port");
|
||||
$ldap_url = "ldaps://".$parsed['host'].":$port";
|
||||
if($this->test_anonymous_bind($ldap_url)) {
|
||||
$this->info("Anonymous bind succesful to $ldap_url!");
|
||||
$ldap_urls[] = [ $ldap_url, true, false ];
|
||||
$pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ];
|
||||
continue; // TODO - lots of copypasta in these if(test_anonymous_bind()) routines...
|
||||
} else {
|
||||
$this->error("WARNING: Failed to bind to $ldap_url - trying without certificate checks.");
|
||||
}
|
||||
|
||||
if($this->test_anonymous_bind($ldap_url, false)) {
|
||||
$this->info("Anonymous bind succesful to $ldap_url with certifcate-checks disabled");
|
||||
$ldap_urls[] = [ $ldap_url, false, false ];
|
||||
$pretty_ldap_urls[] = [ $ldap_url, "no", "no" ];
|
||||
continue;
|
||||
} else {
|
||||
$this->error("WARNING: Failed to bind to $ldap_url with certificate checks disabled. Trying unencrypted with STARTTLS");
|
||||
}
|
||||
|
||||
$ldap_url = "ldap://".$parsed['host'].":$port";
|
||||
if($this->test_anonymous_bind($ldap_url, true, true)) {
|
||||
$this->info("Plain connection to $ldap_url with STARTTLS succesful!");
|
||||
$ldap_urls[] = [ $ldap_url, true, true ];
|
||||
$pretty_ldap_urls[] = [ $ldap_url, "YES", "YES" ];
|
||||
continue;
|
||||
} else {
|
||||
$this->error("WARNING: Failed to bind to $ldap_url with STARTTLS enabled. Trying without STARTTLS");
|
||||
}
|
||||
|
||||
if($this->test_anonymous_bind($ldap_url)) {
|
||||
$this->info("Plain connection to $ldap_url succesful!");
|
||||
$ldap_urls[] = [ $ldap_url, true, false ];
|
||||
$pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ];
|
||||
continue;
|
||||
} else {
|
||||
$this->error("WARNING: Failed to bind to $ldap_url. Giving up on port $port");
|
||||
}
|
||||
}
|
||||
|
||||
$this->debugout(print_r($ldap_urls,true));
|
||||
|
||||
if(count($ldap_urls) > 0 ) {
|
||||
$this->info("Found working LDAP URL's: ");
|
||||
foreach($ldap_urls as $ldap_url) { // TODO maybe do this as a $this->table() instead?
|
||||
$this->info("LDAP URL: ".$ldap_url[0]);
|
||||
$this->info($ldap_url[0]. ($ldap_url[1] ? " certificate checks enabled" : " certificate checks disabled"). ($ldap_url[2] ? " STARTTLS Enabled ": " STARTTLS Disabled"));
|
||||
}
|
||||
$this->table(["URL", "Cert Checks Enabled?", "STARTTLS Enabled?"],$pretty_ldap_urls);
|
||||
} else {
|
||||
$this->error("ERROR - no valid LDAP URL's available - ABORTING");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$this->info("STAGE 4: Test Administrative Bind for LDAP Sync");
|
||||
foreach($ldap_urls AS $ldap_url) {
|
||||
$this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $settings->ldap_uname, Crypt::decrypt($settings->ldap_pword));
|
||||
}
|
||||
|
||||
$this->info("STAGE 5: Test BaseDN");
|
||||
//grab all LDAP_ constants and fill up a reversed array mapping from weird LDAP dotted-strings to (Constant Name)
|
||||
$all_defined_constants = get_defined_constants();
|
||||
$ldap_constants = [];
|
||||
foreach($all_defined_constants AS $key => $val) {
|
||||
if(starts_with($key,"LDAP_") && is_string($val)) {
|
||||
$ldap_constants[$val] = $key; // INVERT the meaning here!
|
||||
}
|
||||
}
|
||||
$this->debugout("LDAP constants are: ".print_r($ldap_constants,true));
|
||||
|
||||
// recursive function that 'cleans' the returned array from ldap_get_entries which are formatted awfully
|
||||
$cleaner = function ($array) {
|
||||
$cleaned = [];
|
||||
for($i = 0; $i < $array['count']; $i++) {
|
||||
$row = $array[$i];
|
||||
$clean_row = [];
|
||||
foreach($row AS $key => $val ) {
|
||||
$this->debugout("Key is: ".$key);
|
||||
if($key == "count" || is_int($key) || $key == "dn") {
|
||||
$this->debugout(" and we're gonna skip it\n");
|
||||
continue;
|
||||
}
|
||||
$this->debugout(" And that seems fine.\n");
|
||||
if(array_key_exists('count',$val)) {
|
||||
if($val['count'] == 1) {
|
||||
$clean_row[$key] = $val[0];
|
||||
} else {
|
||||
unset($val['count']); //these counts are annoying
|
||||
$elements = [];
|
||||
foreach($val as $entry) {
|
||||
if(isset($ldap_constants[$entry])) {
|
||||
$elements[] = $ldap_constants[$entry];
|
||||
} else {
|
||||
$elements[] = $entry;
|
||||
}
|
||||
}
|
||||
$clean_row[$key] = $elements;
|
||||
}
|
||||
} else {
|
||||
$clean_row[$key] = $val;
|
||||
}
|
||||
}
|
||||
$cleaned[$i] = $clean_row;
|
||||
}
|
||||
return $cleaned;
|
||||
};
|
||||
|
||||
foreach($ldap_urls AS $ldap_url) {
|
||||
if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,Crypt::decrypt($settings->ldap_pword))) {
|
||||
$this->info("Success getting informational bind!");
|
||||
} else {
|
||||
$this->error("Unable to get information from bind.");
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("STAGE 6: Test LDAP Login to Snipe-IT");
|
||||
foreach($ldap_urls AS $ldap_url) {
|
||||
$this->info("Starting auth to ".$ldap_url[0]);
|
||||
while(true) {
|
||||
$with_tls = $ldap_url[1] ? "with": "without";
|
||||
$with_startssl = $ldap_url[2] ? "using": "not using";
|
||||
if(!$this->confirm('Do you wish to try to authenticate to this directory: '.$ldap_url[0]." $with_tls TLS and $with_startssl STARTSSL?")) {
|
||||
break;
|
||||
}
|
||||
$username = $this->ask("Username");
|
||||
$password = $this->secret("Password");
|
||||
$this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results?
|
||||
}
|
||||
}
|
||||
|
||||
$this->info("LDAP TROUBLESHOOTING COMPLETE!");
|
||||
}
|
||||
|
||||
public function connect_to_ldap($ldap_url, $check_cert, $start_tls)
|
||||
{
|
||||
$lconn = ldap_connect($ldap_url);
|
||||
ldap_set_option($lconn, LDAP_OPT_PROTOCOL_VERSION, 3); // should we 'test' different protocol versions here? Does anyone even use anything other than LDAPv3?
|
||||
// no - it's formally deprecated: https://tools.ietf.org/html/rfc3494
|
||||
if(!$check_cert) {
|
||||
putenv('LDAPTLS_REQCERT=never'); // This is horrible; is this *really* the only way to do it?
|
||||
} else {
|
||||
putenv('LDAPTLS_REQCERT'); // have to very explicitly and manually *UN* set the env var here to ensure it works
|
||||
}
|
||||
if($this->settings->ldap_client_tls_cert && $this->settings->ldap_client_tls_key) {
|
||||
// client-side TLS certificate support for LDAP (Google Secure LDAP)
|
||||
putenv('LDAPTLS_CERT=storage/ldap_client_tls.cert');
|
||||
putenv('LDAPTLS_KEY=storage/ldap_client_tls.key');
|
||||
}
|
||||
if($start_tls) {
|
||||
if(!ldap_start_tls($lconn)) {
|
||||
$this->error("WARNING: Unable to start TLS");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!$lconn) {
|
||||
$this->error("WARNING: Failed to generate connection string - using: ".$ldap_url);
|
||||
return false;
|
||||
}
|
||||
$net = ldap_set_option($lconn, LDAP_OPT_NETWORK_TIMEOUT, $this->option('timeout'));
|
||||
$time = ldap_set_option($lconn, LDAP_OPT_TIMELIMIT, $this->option('timeout'));
|
||||
if(!$net || !$time) {
|
||||
$this->error("Unable to set timeouts!");
|
||||
}
|
||||
return $lconn;
|
||||
}
|
||||
|
||||
public function test_anonymous_bind($ldap_url, $check_cert = true, $start_tls = false)
|
||||
{
|
||||
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert , $start_tls) {
|
||||
try {
|
||||
$lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
|
||||
$this->info("gonna try to bind now, this can take a while if we mess it up");
|
||||
$bind_results = ldap_bind($lconn);
|
||||
$this->info("Bind results are: ".$bind_results." which translate into boolean: ".(bool)$bind_results);
|
||||
return (bool)$bind_results;
|
||||
} catch (Exception $e) {
|
||||
$this->error("WARNING: Exception caught during bind - ".$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_authed_bind($ldap_url, $check_cert, $start_tls, $username, $password)
|
||||
{
|
||||
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password) {
|
||||
try {
|
||||
$lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
|
||||
$bind_results = ldap_bind($lconn, $username, $password);
|
||||
if(!$bind_results) {
|
||||
$this->error("WARNING: Failed to bind to $ldap_url as $username");
|
||||
return false;
|
||||
} else {
|
||||
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
|
||||
return (bool)$lconn;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_informational_bind($ldap_url, $check_cert, $start_tls, $username, $password)
|
||||
{
|
||||
return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert, $start_tls, $username, $password) {
|
||||
try { // TODO - copypasta'ed from test_authed_bind
|
||||
$conn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls);
|
||||
$bind_results = ldap_bind($conn, $username, $password);
|
||||
if(!$bind_results) {
|
||||
$this->error("WARNING: Failed to bind to $ldap_url as $username");
|
||||
return false;
|
||||
}
|
||||
$this->info("SUCCESS - Able to bind to $ldap_url as $username");
|
||||
$result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/);
|
||||
$results = ldap_get_entries($conn, $result);
|
||||
$cleaned_results = $cleaner($results);
|
||||
$this->line(print_r($cleaned_results,true));
|
||||
//okay, great - now how do we display those results? I have no idea.
|
||||
// I don't see why this throws an Exception for Google LDAP, but I guess we ought to try and catch it?
|
||||
$this->comment("I guess we're trying to do the ldap search here, but sometimes it takes too long?");
|
||||
$search_results = ldap_search($conn, $settings->base_dn, $settings->filter);
|
||||
$this->info("Printing first 10 results: ");
|
||||
for($i=0;$i<10;$i++) {
|
||||
$this->info($search_results[$i]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage());
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/***********************************************
|
||||
*
|
||||
* This function executes $function - which is expected to be some kind of executable function -
|
||||
* with a timeout set. It respects the timeout by forking execution and setting a strict timer
|
||||
* for which to get back a SIGUSR1 or SIGUSR2 signal from the forked process.
|
||||
*
|
||||
***********************************************/
|
||||
private function timed_boolean_execute($function)
|
||||
{
|
||||
if(!(function_exists('pcntl_sigtimedwait') && function_exists('posix_getpid') && function_exists('pcntl_fork') && function_exists('posix_kill') && function_exists('pcntl_wifsignaled'))) {
|
||||
// POSIX functions needed for forking aren't present, just run the function inline (ignoring timeout)
|
||||
$this->info('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected');
|
||||
return $function();
|
||||
} else {
|
||||
$parent_pid = posix_getpid();
|
||||
$pid = pcntl_fork();
|
||||
switch($pid) {
|
||||
case 0:
|
||||
//we're the 'child'
|
||||
if($function()) {
|
||||
//SUCCESS = SIGUSR1
|
||||
posix_kill($parent_pid, SIGUSR1);
|
||||
} else {
|
||||
//FAILURE = SIGUSR2
|
||||
posix_kill($parent_pid, SIGUSR2);
|
||||
}
|
||||
exit();
|
||||
break; //yes I know we don't need it.
|
||||
case -1:
|
||||
//couldn't fork
|
||||
$this->error("COULD NOT FORK - assuming failure");
|
||||
return false;
|
||||
break; //I still know that we don't need it
|
||||
default:
|
||||
//we remain the 'parent', $pid is the PID of the forked process.
|
||||
$siginfo = [];
|
||||
$exit_status = pcntl_sigtimedwait ([SIGUSR1, SIGUSR2], $siginfo, $this->option('timeout'));
|
||||
if ($exit_status == SIGUSR1) {
|
||||
return true;
|
||||
} else {
|
||||
posix_kill($pid, SIGKILL); //make sure we don't have processes hanging around that might try and send signals during later executions, confusing us
|
||||
return false;
|
||||
}
|
||||
break; //Yeah I get it already, shush.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -41,20 +41,10 @@ class MergeUsersByUsername extends Command
|
||||
{
|
||||
// Get the list of users who have an email address as their username
|
||||
$users = User::where('username', 'LIKE', '%@%')->whereNull('deleted_at')->get();
|
||||
$this->info($users->count().' total non-deleted users whose usernames contain a @ symbol.');
|
||||
|
||||
|
||||
foreach ($users as $user) {
|
||||
$parts = explode('@', trim($user->username));
|
||||
$this->info('Checking against username '.trim($parts[0]).'.');
|
||||
|
||||
|
||||
$bad_users = User::where('username', '=', trim($parts[0]))
|
||||
->whereNull('deleted_at')
|
||||
->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')
|
||||
->get();
|
||||
|
||||
|
||||
$parts = explode('@', $user->username);
|
||||
$bad_users = User::where('username', '=', $parts[0])->whereNull('deleted_at')->with('assets', 'manager', 'userlog', 'licenses', 'consumables', 'accessories', 'managedLocations')->get();
|
||||
|
||||
foreach ($bad_users as $bad_user) {
|
||||
$this->info($bad_user->username.' ('.$bad_user->id.') will be merged into '.$user->username.' ('.$user->id.') ');
|
||||
|
||||
@@ -46,31 +46,30 @@ class MoveUploadsToNewDisk extends Command
|
||||
}
|
||||
$delete_local = $this->argument('delete_local');
|
||||
|
||||
$public_uploads['accessories'] = glob('public/uploads/accessories'."/*.*");
|
||||
$public_uploads['assets'] = glob('public/uploads/assets'."/*.*");
|
||||
$public_uploads['avatars'] = glob('public/uploads/avatars'."/*.*");
|
||||
$public_uploads['categories'] = glob('public/uploads/categories'."/*.*");
|
||||
$public_uploads['companies'] = glob('public/uploads/companies'."/*.*");
|
||||
$public_uploads['components'] = glob('public/uploads/components'."/*.*");
|
||||
$public_uploads['consumables'] = glob('public/uploads/consumables'."/*.*");
|
||||
$public_uploads['departments'] = glob('public/uploads/departments'."/*.*");
|
||||
$public_uploads['locations'] = glob('public/uploads/locations'."/*.*");
|
||||
$public_uploads['manufacturers'] = glob('public/uploads/manufacturers'."/*.*");
|
||||
$public_uploads['suppliers'] = glob('public/uploads/suppliers'."/*.*");
|
||||
$public_uploads['assetmodels'] = glob('public/uploads/models'."/*.*");
|
||||
|
||||
$public_uploads['accessories'] = glob('public/accessories'.'/*.*');
|
||||
$public_uploads['assets'] = glob('public/assets'.'/*.*');
|
||||
$public_uploads['avatars'] = glob('public/avatars'.'/*.*');
|
||||
$public_uploads['categories'] = glob('public/categories'.'/*.*');
|
||||
$public_uploads['companies'] = glob('public/companies'.'/*.*');
|
||||
$public_uploads['components'] = glob('public/components'.'/*.*');
|
||||
$public_uploads['consumables'] = glob('public/consumables'.'/*.*');
|
||||
$public_uploads['departments'] = glob('public/departments'.'/*.*');
|
||||
$public_uploads['locations'] = glob('public/locations'.'/*.*');
|
||||
$public_uploads['manufacturers'] = glob('public/manufacturers'.'/*.*');
|
||||
$public_uploads['suppliers'] = glob('public/suppliers'.'/*.*');
|
||||
$public_uploads['assetmodels'] = glob('public/models'.'/*.*');
|
||||
|
||||
// iterate files
|
||||
foreach ($public_uploads as $public_type => $public_upload) {
|
||||
$type_count = 0;
|
||||
$this->info('- There are ' . count($public_upload) . ' PUBLIC ' . $public_type . ' files.');
|
||||
$this->info('- There are '.count($public_upload).' PUBLIC '.$public_type.' files.');
|
||||
|
||||
for ($i = 0; $i < count($public_upload); $i++) {
|
||||
$type_count++;
|
||||
$filename = basename($public_upload[$i]);
|
||||
|
||||
try {
|
||||
Storage::disk('public')->put('uploads/'.$public_type.'/'.$filename, file_get_contents($public_upload[$i]));
|
||||
try {
|
||||
Storage::disk('public')->put('uploads/'.public_type.'/'.$filename, file_get_contents($public_upload[$i]));
|
||||
$new_url = Storage::disk('public')->url('uploads/'.$public_type.'/'.$filename, $filename);
|
||||
$this->info($type_count.'. PUBLIC: '.$filename.' was copied to '.$new_url);
|
||||
} catch (\Exception $e) {
|
||||
@@ -80,87 +79,83 @@ class MoveUploadsToNewDisk extends Command
|
||||
}
|
||||
}
|
||||
|
||||
$logos = glob("public/uploads/setting*.*");
|
||||
$this->info("- There are ".count($logos).' files that might be logos.');
|
||||
$logos = glob('public/uploads/setting*.*');
|
||||
$this->info('- There are '.count($logos).' files that might be logos.');
|
||||
$type_count = 0;
|
||||
|
||||
foreach ($logos as $logo) {
|
||||
$this->info($logo);
|
||||
$type_count++;
|
||||
$filename = basename($logo);
|
||||
Storage::disk('public')->put('uploads/' . $filename, file_get_contents($logo));
|
||||
$this->info($type_count . '. LOGO: ' . $filename . ' was copied to ' . env('PUBLIC_AWS_URL') . '/uploads/' . $filename);
|
||||
Storage::disk('public')->put('uploads/'.$filename, file_get_contents($logo));
|
||||
$this->info($type_count.'. LOGO: '.$filename.' was copied to '.env('PUBLIC_AWS_URL').'/uploads/'.$filename);
|
||||
}
|
||||
|
||||
$private_uploads['assets'] = glob('storage/private_uploads/assets'."/*.*");
|
||||
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'."/*.*");
|
||||
$private_uploads['audits'] = glob('storage/private_uploads/audits'."/*.*");
|
||||
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'."/*.*");
|
||||
$private_uploads['imports'] = glob('storage/private_uploads/imports'."/*.*");
|
||||
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'."/*.*");
|
||||
$private_uploads['users'] = glob('storage/private_uploads/users'."/*.*");
|
||||
$private_uploads['backups'] = glob('storage/private_uploads/backups'."/*.*");
|
||||
|
||||
$private_uploads['assets'] = glob('storage/private_uploads/assets'.'/*.*');
|
||||
$private_uploads['signatures'] = glob('storage/private_uploads/signatures'.'/*.*');
|
||||
$private_uploads['audits'] = glob('storage/private_uploads/audits'.'/*.*');
|
||||
$private_uploads['assetmodels'] = glob('storage/private_uploads/assetmodels'.'/*.*');
|
||||
$private_uploads['imports'] = glob('storage/private_uploads/imports'.'/*.*');
|
||||
$private_uploads['licenses'] = glob('storage/private_uploads/licenses'.'/*.*');
|
||||
$private_uploads['users'] = glob('storage/private_uploads/users'.'/*.*');
|
||||
$private_uploads['backups'] = glob('storage/private_uploads/users'.'/*.*');
|
||||
|
||||
foreach ($private_uploads as $private_type => $private_upload) {
|
||||
{
|
||||
$this->info('- There are ' . count($private_upload) . ' PRIVATE ' . $private_type . ' files.');
|
||||
$this->info('- There are '.count($private_upload).' PRIVATE '.$private_type.' files.');
|
||||
|
||||
$type_count = 0;
|
||||
for ($x = 0; $x < count($private_upload); $x++) {
|
||||
$type_count++;
|
||||
$filename = basename($private_upload[$x]);
|
||||
$type_count = 0;
|
||||
for ($x = 0; $x < count($private_upload); $x++) {
|
||||
$type_count++;
|
||||
$filename = basename($private_upload[$x]);
|
||||
|
||||
try {
|
||||
Storage::put($private_type . '/' . $filename, file_get_contents($private_upload[$i]));
|
||||
$new_url = Storage::url($private_type . '/' . $filename, $filename);
|
||||
$this->info($type_count . '. PRIVATE: ' . $filename . ' was copied to ' . $new_url);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
$this->error($e);
|
||||
}
|
||||
try {
|
||||
Storage::put($private_type.'/'.$filename, file_get_contents($private_upload[$i]));
|
||||
$new_url = Storage::url($private_type.'/'.$filename, $filename);
|
||||
$this->info($type_count.'. PRIVATE: '.$filename.' was copied to '.$new_url);
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
$this->error($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($delete_local == 'true') {
|
||||
$public_delete_count = 0;
|
||||
$private_delete_count = 0;
|
||||
|
||||
if ($delete_local == 'true') {
|
||||
$public_delete_count = 0;
|
||||
$private_delete_count = 0;
|
||||
$this->info("\n\n");
|
||||
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
||||
$this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n");
|
||||
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
||||
|
||||
$this->info("\n\n");
|
||||
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
||||
$this->warn("\nTHIS WILL DELETE ALL OF YOUR LOCAL UPLOADED FILES. \n\nThis cannot be undone, so you should take a backup of your system before you proceed.\n");
|
||||
$this->error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!! WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!');
|
||||
|
||||
if ($this->confirm('Do you wish to continue?')) {
|
||||
foreach ($public_uploads as $public_type => $public_upload) {
|
||||
for ($i = 0; $i < count($public_upload); $i++) {
|
||||
$filename = $public_upload[$i];
|
||||
try {
|
||||
unlink($filename);
|
||||
$public_delete_count++;
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
$this->error($e);
|
||||
}
|
||||
if ($this->confirm('Do you wish to continue?')) {
|
||||
foreach ($public_uploads as $public_type => $public_upload) {
|
||||
for ($i = 0; $i < count($public_upload); $i++) {
|
||||
$filename = $public_upload[$i];
|
||||
try {
|
||||
unlink($filename);
|
||||
$public_delete_count++;
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
$this->error($e);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($private_uploads as $private_type => $private_upload) {
|
||||
for ($i = 0; $i < count($private_upload); $i++) {
|
||||
$filename = $private_upload[$i];
|
||||
try {
|
||||
unlink($filename);
|
||||
$private_delete_count++;
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
$this->error($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($public_delete_count . ' PUBLIC local files and ' . $private_delete_count . ' PRIVATE local files were deleted from your filesystem.');
|
||||
}
|
||||
|
||||
foreach ($private_uploads as $private_type => $private_upload) {
|
||||
for ($i = 0; $i < count($private_upload); $i++) {
|
||||
$filename = $private_upload[$i];
|
||||
try {
|
||||
unlink($filename);
|
||||
$private_delete_count++;
|
||||
} catch (\Exception $e) {
|
||||
\Log::debug($e);
|
||||
$this->error($e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->info($public_delete_count.' PUBLIC local files and '.$private_delete_count.' PRIVATE local files were deleted from your filesystem.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ class RegenerateAssetTags extends Command
|
||||
}
|
||||
|
||||
foreach ($total_assets as $asset) {
|
||||
|
||||
$start_tag++;
|
||||
$output['info'][] = 'Asset tag:'.$asset->asset_tag;
|
||||
$asset->asset_tag = $settings->auto_increment_prefix.$settings->auto_increment_prefix.$start_tag;
|
||||
|
||||
@@ -72,15 +72,8 @@ class RegenerateAssetTags extends Command
|
||||
|
||||
// Use forceSave here to override model level validation
|
||||
$asset->forceSave();
|
||||
$start_tag++;
|
||||
if ($bar) {
|
||||
$bar->advance();
|
||||
}
|
||||
}
|
||||
|
||||
$settings->next_auto_tag_base = Asset::zerofill($start_tag, $settings->zerofill_count);
|
||||
$settings->save();
|
||||
|
||||
$bar->finish();
|
||||
$this->info("\n");
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ class ResetDemoSettings extends Command
|
||||
$settings->auto_increment_assets = 1;
|
||||
$settings->logo = 'snipe-logo.png';
|
||||
$settings->alert_email = 'service@snipe-it.io';
|
||||
$settings->login_note = 'Use `admin` / `password` to login to the demo.';
|
||||
$settings->header_color = null;
|
||||
$settings->barcode_type = 'QRCODE';
|
||||
$settings->default_currency = 'USD';
|
||||
|
||||
@@ -13,8 +13,8 @@ class RestoreFromBackup extends Command
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:restore
|
||||
{--force : Skip the danger prompt; assuming you enter "y"}
|
||||
{filename : The zip file to be migrated}
|
||||
{--force : Skip the danger prompt; assuming you hit "y"}
|
||||
{filename : The full path of the .zip file to be migrated}
|
||||
{--no-progress : Don\'t show a progress bar}';
|
||||
|
||||
/**
|
||||
@@ -82,7 +82,6 @@ class RestoreFromBackup extends Command
|
||||
return $this->error('Could not access file: '.$filename.' - '.array_key_exists($errcode, $errors) ? $errors[$errcode] : " Unknown reason: $errcode");
|
||||
}
|
||||
|
||||
|
||||
$private_dirs = [
|
||||
'storage/private_uploads/assets', // these are asset _files_, not the pictures.
|
||||
'storage/private_uploads/audits',
|
||||
@@ -227,9 +226,6 @@ class RestoreFromBackup extends Command
|
||||
return $this->error('Unable to invoke mysql via CLI');
|
||||
}
|
||||
|
||||
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
||||
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
||||
|
||||
// $this->info("Stdout says? ".fgets($pipes[1])); //FIXME: I think we might need to set non-blocking mode to use this properly?
|
||||
// $this->info("Stderr says? ".fgets($pipes[2])); //FIXME: ditto, same.
|
||||
// should we read stdout?
|
||||
@@ -249,28 +245,19 @@ class RestoreFromBackup extends Command
|
||||
return false;
|
||||
}
|
||||
$bytes_read = 0;
|
||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
$bytes_written = fwrite($pipes[0], $buffer);
|
||||
if ($bytes_written === false) {
|
||||
$stdout = fgets($pipes[1]);
|
||||
$this->info($stdout);
|
||||
$stderr = fgets($pipes[2]);
|
||||
$this->info($stderr);
|
||||
|
||||
try {
|
||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
||||
$bytes_read += strlen($buffer);
|
||||
// \Log::debug("Buffer is: '$buffer'");
|
||||
$bytes_written = fwrite($pipes[0], $buffer);
|
||||
|
||||
if ($bytes_written === false) {
|
||||
throw new Exception("Unable to write to pipe");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
\Log::error("Error during restore!!!! ".$e->getMessage());
|
||||
$err_out = fgets($pipes[1]);
|
||||
$err_err = fgets($pipes[2]);
|
||||
\Log::error("Error OUTPUT: ".$err_out);
|
||||
$this->info($err_out);
|
||||
\Log::error("Error ERROR : ".$err_err);
|
||||
$this->error($err_err);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!feof($sql_contents) || $bytes_read == 0) {
|
||||
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class Handler extends ExceptionHandler
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
if ($this->shouldReport($exception)) {
|
||||
\Log::error($exception);
|
||||
Log::error($exception);
|
||||
return parent::report($exception);
|
||||
}
|
||||
}
|
||||
@@ -84,12 +84,10 @@ class Handler extends ExceptionHandler
|
||||
switch ($e->getStatusCode()) {
|
||||
case '404':
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode . ' endpoint not found'), 404);
|
||||
case '429':
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Too many requests'), 429);
|
||||
case '405':
|
||||
case '405':
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Method not allowed'), 405);
|
||||
default:
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), $statusCode);
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statusCode), 405);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+13
-79
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use App\Models\Accessory;
|
||||
use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
@@ -841,16 +842,6 @@ class Helper
|
||||
return preg_replace('/\s+/u', '_', trim($string));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array (or null) of the the raw and formatted date object for easy use in
|
||||
* the API and the bootstrap table listings.
|
||||
*
|
||||
* @param $date
|
||||
* @param $type
|
||||
* @param $array
|
||||
* @return array|string|null
|
||||
*/
|
||||
|
||||
public static function getFormattedDateObject($date, $type = 'datetime', $array = true)
|
||||
{
|
||||
if ($date == '') {
|
||||
@@ -858,42 +849,21 @@ class Helper
|
||||
}
|
||||
|
||||
$settings = Setting::getSettings();
|
||||
$tmp_date = new \Carbon($date);
|
||||
|
||||
/**
|
||||
* Wrap this in a try/catch so that if Carbon crashes, for example if the $date value
|
||||
* isn't actually valid, we don't crash out completely.
|
||||
*
|
||||
* While this *shouldn't* typically happen since we validate dates before entering them
|
||||
* into the database (and we use date/datetime fields for native fields in the system),
|
||||
* it is a possible scenario that a custom field could be created as an "ANY" field, data gets
|
||||
* added, and then the custom field format gets edited later. If someone put bad data in the
|
||||
* database before then - or if they manually edited the field's value - it will crash.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
try {
|
||||
$tmp_date = new \Carbon($date);
|
||||
|
||||
if ($type == 'datetime') {
|
||||
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format.' '.$settings->time_display_format);
|
||||
} else {
|
||||
$dt['date'] = $tmp_date->format('Y-m-d');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format);
|
||||
}
|
||||
|
||||
if ($array == 'true') {
|
||||
return $dt;
|
||||
}
|
||||
|
||||
return $dt['formatted'];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::warning($e);
|
||||
return $date.' (Invalid '.$type.' value.)';
|
||||
if ($type == 'datetime') {
|
||||
$dt['datetime'] = $tmp_date->format('Y-m-d H:i:s');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format.' '.$settings->time_display_format);
|
||||
} else {
|
||||
$dt['date'] = $tmp_date->format('Y-m-d');
|
||||
$dt['formatted'] = $tmp_date->format($settings->date_display_format);
|
||||
}
|
||||
|
||||
if ($array == 'true') {
|
||||
return $dt;
|
||||
}
|
||||
|
||||
return $dt['formatted'];
|
||||
}
|
||||
|
||||
// Nicked from Drupal :)
|
||||
@@ -1089,40 +1059,4 @@ class Helper
|
||||
|
||||
return $file_name;
|
||||
}
|
||||
|
||||
public static function formatFilesizeUnits($bytes)
|
||||
{
|
||||
if ($bytes >= 1073741824)
|
||||
{
|
||||
$bytes = number_format($bytes / 1073741824, 2) . ' GB';
|
||||
}
|
||||
elseif ($bytes >= 1048576)
|
||||
{
|
||||
$bytes = number_format($bytes / 1048576, 2) . ' MB';
|
||||
}
|
||||
elseif ($bytes >= 1024)
|
||||
{
|
||||
$bytes = number_format($bytes / 1024, 2) . ' KB';
|
||||
}
|
||||
elseif ($bytes > 1)
|
||||
{
|
||||
$bytes = $bytes . ' bytes';
|
||||
}
|
||||
elseif ($bytes == 1)
|
||||
{
|
||||
$bytes = $bytes . ' byte';
|
||||
}
|
||||
else
|
||||
{
|
||||
$bytes = '0 bytes';
|
||||
}
|
||||
|
||||
return $bytes;
|
||||
}
|
||||
public static function SettingUrls(){
|
||||
$settings=['#','fields.index', 'statuslabels.index', 'models.index', 'categories.index', 'manufacturers.index', 'suppliers.index', 'departments.index', 'locations.index', 'companies.index', 'depreciations.index'];
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Models\Accessory;
|
||||
use App\Models\Company;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Redirect;
|
||||
|
||||
/** This controller handles all actions related to Accessories for
|
||||
@@ -80,8 +79,6 @@ class AccessoriesController extends Controller
|
||||
$accessory->qty = request('qty');
|
||||
$accessory->user_id = Auth::user()->id;
|
||||
$accessory->supplier_id = request('supplier_id');
|
||||
$accessory->notes = request('notes');
|
||||
|
||||
|
||||
$accessory = $request->handleImages($accessory);
|
||||
|
||||
@@ -131,17 +128,6 @@ class AccessoriesController extends Controller
|
||||
return redirect()->route('accessories.index')->with('error', trans('admin/accessories/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$min = $accessory->numCheckedOut();
|
||||
$validator = Validator::make($request->all(), [
|
||||
"qty" => "required|numeric|min:$min"
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$this->authorize($accessory);
|
||||
|
||||
// Update the accessory data
|
||||
@@ -157,7 +143,6 @@ class AccessoriesController extends Controller
|
||||
$accessory->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
|
||||
$accessory->qty = request('qty');
|
||||
$accessory->supplier_id = request('supplier_id');
|
||||
$accessory->notes = request('notes');
|
||||
|
||||
$accessory = $request->handleImages($accessory);
|
||||
|
||||
|
||||
@@ -7,22 +7,13 @@ use App\Events\CheckoutDeclined;
|
||||
use App\Events\ItemAccepted;
|
||||
use App\Events\ItemDeclined;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Models\Company;
|
||||
use App\Models\Contracts\Acceptable;
|
||||
use App\Models\User;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Accessory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Http\Controllers\SettingsController;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class AcceptanceController extends Controller
|
||||
{
|
||||
@@ -48,7 +39,6 @@ class AcceptanceController extends Controller
|
||||
{
|
||||
$acceptance = CheckoutAcceptance::find($id);
|
||||
|
||||
|
||||
if (is_null($acceptance)) {
|
||||
return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
@@ -106,92 +96,29 @@ class AcceptanceController extends Controller
|
||||
Storage::makeDirectory('private_uploads/signatures', 775);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for the eula-pdfs directory
|
||||
*/
|
||||
if (! Storage::exists('private_uploads/eula-pdfs')) {
|
||||
Storage::makeDirectory('private_uploads/eula-pdfs', 775);
|
||||
$sig_filename = '';
|
||||
if ($request->filled('signature_output')) {
|
||||
$sig_filename = 'siglog-'.Str::uuid().'-'.date('Y-m-d-his').'.png';
|
||||
$data_uri = e($request->input('signature_output'));
|
||||
$encoded_image = explode(',', $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
|
||||
}
|
||||
|
||||
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
|
||||
$display_model = '';
|
||||
$pdf_view_route = '';
|
||||
$pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
|
||||
$sig_filename='';
|
||||
|
||||
|
||||
if ($request->input('asset_acceptance') == 'accepted') {
|
||||
$acceptance->accept($sig_filename);
|
||||
|
||||
// The item was accepted, check for a signature
|
||||
if ($request->filled('signature_output')) {
|
||||
$sig_filename = 'siglog-'.Str::uuid().'-'.date('Y-m-d-his').'.png';
|
||||
$data_uri = $request->input('signature_output');
|
||||
$encoded_image = explode(',', $data_uri);
|
||||
$decoded_image = base64_decode($encoded_image[1]);
|
||||
Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
|
||||
}
|
||||
|
||||
|
||||
// this is horrible
|
||||
if ($acceptance->checkoutable_type == 'App\Models\Asset') {
|
||||
$pdf_view_route ='account.accept.accept-asset-eula';
|
||||
$asset_model = AssetModel::find($item->model_id);
|
||||
$display_model = $asset_model->name;
|
||||
$assigned_to = User::find($item->assigned_to)->present()->fullName;
|
||||
|
||||
} elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') {
|
||||
$pdf_view_route ='account.accept.accept-accessory-eula';
|
||||
$accessory = Accessory::find($item->id);
|
||||
$display_model = $accessory->name;
|
||||
$assigned_to = User::find($item->assignedTo);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather the data for the PDF. We fire this whether there is a signature required or not,
|
||||
* since we want the moment-in-time proof of what the EULA was when they accepted it.
|
||||
*/
|
||||
$branding_settings = SettingsController::getPDFBranding();
|
||||
|
||||
if (is_null($branding_settings->logo)){
|
||||
$path_logo = "";
|
||||
} else {
|
||||
$path_logo = public_path() . '/uploads/' . $branding_settings->logo;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'item_tag' => $item->asset_tag,
|
||||
'item_model' => $display_model,
|
||||
'item_serial' => $item->serial,
|
||||
'eula' => $item->getEula(),
|
||||
'check_out_date' => Carbon::parse($acceptance->created_at)->format($branding_settings->date_display_format),
|
||||
'accepted_date' => Carbon::parse($acceptance->accepted_at)->format($branding_settings->date_display_format),
|
||||
'assigned_to' => $assigned_to,
|
||||
'company_name' => $branding_settings->site_name,
|
||||
'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null,
|
||||
'logo' => $path_logo,
|
||||
'date_settings' => $branding_settings->date_display_format,
|
||||
];
|
||||
|
||||
if ($pdf_view_route!='') {
|
||||
\Log::debug($pdf_filename.' is the filename, and the route was specified.');
|
||||
$pdf = Pdf::loadView($pdf_view_route, $data);
|
||||
Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output());
|
||||
}
|
||||
|
||||
$acceptance->accept($sig_filename, $item->getEula(), $pdf_filename);
|
||||
event(new CheckoutAccepted($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.accepted');
|
||||
|
||||
} else {
|
||||
$acceptance->decline($sig_filename);
|
||||
|
||||
event(new CheckoutDeclined($acceptance));
|
||||
|
||||
$return_msg = trans('admin/users/message.declined');
|
||||
}
|
||||
|
||||
|
||||
return redirect()->to('account/accept')->with('success', $return_msg);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,34 +3,17 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Actionlog;
|
||||
use Response;
|
||||
|
||||
class ActionlogController extends Controller
|
||||
{
|
||||
public function displaySig($filename)
|
||||
{
|
||||
// PHP doesn't let you handle file not found errors well with
|
||||
// file_get_contents, so we set the error reporting for just this class
|
||||
error_reporting(0);
|
||||
|
||||
$this->authorize('view', \App\Models\Asset::class);
|
||||
$file = config('app.private_uploads').'/signatures/'.$filename;
|
||||
$filetype = Helper::checkUploadIsImage($file);
|
||||
$contents = file_get_contents($file);
|
||||
|
||||
$contents = file_get_contents($file, false, stream_context_create(['http' => ['ignore_errors' => true]]));
|
||||
if ($contents === false) {
|
||||
\Log::warn('File '.$file.' not found');
|
||||
return false;
|
||||
} else {
|
||||
return Response::make($contents)->header('Content-Type', $filetype);
|
||||
}
|
||||
|
||||
}
|
||||
public function getStoredEula($filename){
|
||||
$this->authorize('view', \App\Models\Asset::class);
|
||||
$file = config('app.private_uploads').'/eula-pdfs/'.$filename;
|
||||
|
||||
return Response::download($file);
|
||||
return Response::make($contents)->header('Content-Type', $filetype);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@ class AccessoriesController extends Controller
|
||||
'notes',
|
||||
'created_at',
|
||||
'min_amt',
|
||||
'company_id',
|
||||
'notes',
|
||||
'company_id'
|
||||
];
|
||||
|
||||
|
||||
@@ -71,10 +70,6 @@ class AccessoriesController extends Controller
|
||||
$accessories->where('location_id','=',$request->input('location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('notes')) {
|
||||
$accessories->where('notes','=',$request->input('notes'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($accessories) && ($request->get('offset') > $accessories->count())) ? $accessories->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -102,7 +102,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// create a new model instance
|
||||
$assetMaintenance = new AssetMaintenance();
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
@@ -154,7 +154,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function update(Request $request, $assetMaintenanceId = null)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
|
||||
@@ -218,7 +218,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function destroy($assetMaintenanceId)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
|
||||
|
||||
@@ -70,10 +70,6 @@ class AssetModelsController extends Controller
|
||||
$assetmodels->onlyTrashed();
|
||||
}
|
||||
|
||||
if ($request->filled('category_id')) {
|
||||
$assetmodels = $assetmodels->where('models.category_id', '=', $request->input('category_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$assetmodels->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class AssetsController extends Controller
|
||||
*/
|
||||
public function index(Request $request, $audit = null)
|
||||
{
|
||||
|
||||
\Log::debug(Route::currentRouteName());
|
||||
$filter_non_deprecable_assets = false;
|
||||
|
||||
/**
|
||||
@@ -345,7 +345,6 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Here we're just determining which Transformer (via $transformer) to use based on the
|
||||
* variables we set earlier on in this method - we default to AssetsTransformer.
|
||||
@@ -522,7 +521,7 @@ class AssetsController extends Controller
|
||||
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost')); // this is the API's store method, so I don't know that I want to do this? Confusing. FIXME (or not?!)
|
||||
$asset->purchase_date = $request->get('purchase_date', null);
|
||||
$asset->assigned_to = $request->get('assigned_to', null);
|
||||
$asset->supplier_id = $request->get('supplier_id');
|
||||
$asset->supplier_id = $request->get('supplier_id', 0);
|
||||
$asset->requestable = $request->get('requestable', 0);
|
||||
$asset->rtd_location_id = $request->get('rtd_location_id', null);
|
||||
$asset->location_id = $request->get('rtd_location_id', null);
|
||||
@@ -714,33 +713,23 @@ class AssetsController extends Controller
|
||||
* @since [v5.1.18]
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function restore(Request $request, $assetId = null)
|
||||
public function restore($assetId = null)
|
||||
{
|
||||
// Get asset information
|
||||
$asset = Asset::withTrashed()->find($assetId);
|
||||
$this->authorize('delete', $asset);
|
||||
|
||||
if (isset($asset->id)) {
|
||||
// Restore the asset
|
||||
Asset::withTrashed()->where('id', $assetId)->restore();
|
||||
|
||||
if ($asset->deleted_at=='') {
|
||||
$message = 'Asset was not deleted. No data was changed.';
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item_type = Asset::class;
|
||||
$logaction->item_id = $asset->id;
|
||||
$logaction->created_at = date("Y-m-d H:i:s");
|
||||
$logaction->user_id = Auth::user()->id;
|
||||
$logaction->logaction('restored');
|
||||
|
||||
} else {
|
||||
|
||||
$message = trans('admin/hardware/message.restore.success');
|
||||
// Restore the asset
|
||||
Asset::withTrashed()->where('id', $assetId)->restore();
|
||||
|
||||
$logaction = new Actionlog();
|
||||
$logaction->item_type = Asset::class;
|
||||
$logaction->item_id = $asset->id;
|
||||
$logaction->created_at = date("Y-m-d H:i:s");
|
||||
$logaction->user_id = Auth::user()->id;
|
||||
$logaction->logaction('restored');
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', (new AssetsTransformer)->transformAsset($asset, $request), $message));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/hardware/message.restore.success')));
|
||||
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/hardware/message.does_not_exist')), 200);
|
||||
@@ -797,9 +786,6 @@ class AssetsController extends Controller
|
||||
$error_payload['target_type'] = 'user';
|
||||
}
|
||||
|
||||
if ($request->filled('status_id')) {
|
||||
$asset->status_id = $request->get('status_id');
|
||||
}
|
||||
|
||||
|
||||
if (! isset($target)) {
|
||||
|
||||
@@ -40,7 +40,6 @@ class ComponentsController extends Controller
|
||||
'purchase_cost',
|
||||
'qty',
|
||||
'image',
|
||||
'notes',
|
||||
];
|
||||
|
||||
|
||||
@@ -63,10 +62,6 @@ class ComponentsController extends Controller
|
||||
$components->where('location_id', '=', $request->input('location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('notes')) {
|
||||
$components->where('notes','=',$request->input('notes'));
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($components) && ($request->get('offset') > $components->count())) ? $components->count() : $request->get('offset', 0);
|
||||
|
||||
@@ -42,7 +42,6 @@ class ConsumablesController extends Controller
|
||||
'item_no',
|
||||
'qty',
|
||||
'image',
|
||||
'notes',
|
||||
];
|
||||
|
||||
|
||||
@@ -75,10 +74,6 @@ class ConsumablesController extends Controller
|
||||
$consumables->where('location_id','=',$request->input('location_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('notes')) {
|
||||
$consumables->where('notes','=',$request->input('notes'));
|
||||
}
|
||||
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
|
||||
@@ -134,14 +134,7 @@ class ImportController extends Controller
|
||||
\Log::debug('NO BACKUP requested via importer');
|
||||
}
|
||||
|
||||
$import = Import::find($import_id);
|
||||
|
||||
if(is_null($import)){
|
||||
$error[0][0] = trans("validation.exists", ["attribute" => "file"]);
|
||||
return response()->json(Helper::formatStandardApiResponse('import-errors', null, $error), 500);
|
||||
}
|
||||
|
||||
$errors = $request->import($import);
|
||||
$errors = $request->import(Import::find($import_id));
|
||||
$redirectTo = 'hardware.index';
|
||||
switch ($request->get('import-type')) {
|
||||
case 'asset':
|
||||
|
||||
@@ -116,20 +116,16 @@ class LicenseSeatsController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success')));
|
||||
}
|
||||
|
||||
// the logging functions expect only one "target". if both asset and user are present in the request,
|
||||
// we simply let assets take precedence over users...
|
||||
if ($licenseSeat->isDirty('assigned_to')) {
|
||||
$target = $is_checkin ? $oldUser : User::find($licenseSeat->assigned_to);
|
||||
}
|
||||
if ($licenseSeat->isDirty('asset_id')) {
|
||||
$target = $is_checkin ? $oldAsset : Asset::find($licenseSeat->asset_id);
|
||||
}
|
||||
|
||||
if (is_null($target)){
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Target not found'));
|
||||
}
|
||||
|
||||
if ($licenseSeat->save()) {
|
||||
// the logging functions expect only one "target". if both asset and user are present in the request,
|
||||
// we simply let assets take precedence over users...
|
||||
$changes = $licenseSeat->getChanges();
|
||||
if (array_key_exists('assigned_to', $changes)) {
|
||||
$target = $is_checkin ? $oldUser : User::find($changes['assigned_to']);
|
||||
}
|
||||
if (array_key_exists('asset_id', $changes)) {
|
||||
$target = $is_checkin ? $oldAsset : Asset::find($changes['asset_id']);
|
||||
}
|
||||
|
||||
if ($is_checkin) {
|
||||
$licenseSeat->logCheckin($target, $request->input('note'));
|
||||
|
||||
@@ -26,8 +26,7 @@ class LicensesController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', License::class);
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier','category')->withCount('freeSeats as free_seats_count'));
|
||||
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'manufacturer', 'supplier', 'category')->withCount('freeSeats as free_seats_count'));
|
||||
|
||||
if ($request->filled('company_id')) {
|
||||
$licenses->where('company_id', '=', $request->input('company_id'));
|
||||
@@ -149,10 +148,9 @@ class LicensesController extends Controller
|
||||
}
|
||||
|
||||
$total = $licenses->count();
|
||||
|
||||
$licenses = $licenses->skip($offset)->take($limit)->get();
|
||||
return (new LicensesTransformer)->transformLicenses($licenses, $total);
|
||||
|
||||
return (new LicensesTransformer)->transformLicenses($licenses, $total);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,11 +29,11 @@ class ProfileController extends Controller
|
||||
// Make sure the asset and request still exist
|
||||
if ($checkoutRequest && $checkoutRequest->itemRequested()) {
|
||||
$results['rows'][] = [
|
||||
'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()),
|
||||
'name' => e($checkoutRequest->itemRequested()->present()->name()),
|
||||
'type' => e($checkoutRequest->itemType()),
|
||||
'qty' => (int) $checkoutRequest->quantity,
|
||||
'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null,
|
||||
'image' => $checkoutRequest->itemRequested()->present()->getImageUrl(),
|
||||
'name' => $checkoutRequest->itemRequested()->present()->name(),
|
||||
'type' => $checkoutRequest->itemType(),
|
||||
'qty' => $checkoutRequest->quantity,
|
||||
'location' => ($checkoutRequest->location()) ? $checkoutRequest->location()->name : null,
|
||||
'expected_checkin' => Helper::getFormattedDateObject($checkoutRequest->itemRequested()->expected_checkin, 'datetime'),
|
||||
'request_date' => Helper::getFormattedDateObject($checkoutRequest->created_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -18,7 +18,6 @@ use Illuminate\Support\Facades\Notification;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use App\Http\Requests\SlackSettingsRequest;
|
||||
use App\Http\Transformers\LoginAttemptsTransformer;
|
||||
|
||||
|
||||
class SettingsController extends Controller
|
||||
|
||||
@@ -30,20 +30,6 @@ class StatuslabelsController extends Controller
|
||||
$statuslabels = $statuslabels->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
|
||||
// if a status_type is passed, filter by that
|
||||
if ($request->filled('status_type')) {
|
||||
if (strtolower($request->input('status_type')) == 'pending') {
|
||||
$statuslabels = $statuslabels->Pending();
|
||||
} elseif (strtolower($request->input('status_type')) == 'archived') {
|
||||
$statuslabels = $statuslabels->Archived();
|
||||
} elseif (strtolower($request->input('status_type')) == 'deployable') {
|
||||
$statuslabels = $statuslabels->Deployable();
|
||||
} elseif (strtolower($request->input('status_type')) == 'undeployable') {
|
||||
$statuslabels = $statuslabels->Undeployable();
|
||||
}
|
||||
}
|
||||
|
||||
// Set the offset to the API call's offset, unless the offset is higher than the actual count of items in which
|
||||
// case we override with the actual count, so we should return 0 items.
|
||||
$offset = (($statuslabels) && ($request->get('offset') > $statuslabels->count())) ? $statuslabels->count() : $request->get('offset', 0);
|
||||
@@ -94,8 +80,8 @@ class StatuslabelsController extends Controller
|
||||
if ($statuslabel->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.create.success')));
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statuslabel->getErrors()));
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $statuslabel->getErrors()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +100,6 @@ class StatuslabelsController extends Controller
|
||||
return (new StatuslabelsTransformer)->transformStatuslabel($statuslabel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
@@ -131,7 +116,6 @@ class StatuslabelsController extends Controller
|
||||
|
||||
$request->except('deployable', 'pending', 'archived');
|
||||
|
||||
|
||||
if (! $request->filled('type')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Status label type is required.'));
|
||||
}
|
||||
@@ -177,8 +161,6 @@ class StatuslabelsController extends Controller
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/statuslabels/message.assoc_assets')));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Show a count of assets by status label for pie chart
|
||||
*
|
||||
|
||||
@@ -7,7 +7,6 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\SaveUserRequest;
|
||||
use App\Http\Transformers\AccessoriesTransformer;
|
||||
use App\Http\Transformers\AssetsTransformer;
|
||||
use App\Http\Transformers\ConsumablesTransformer;
|
||||
use App\Http\Transformers\LicensesTransformer;
|
||||
use App\Http\Transformers\SelectlistTransformer;
|
||||
use App\Http\Transformers\UsersTransformer;
|
||||
@@ -63,7 +62,6 @@ class UsersController extends Controller
|
||||
'users.updated_at',
|
||||
'users.username',
|
||||
'users.zip',
|
||||
'users.remote',
|
||||
'users.ldap_import',
|
||||
|
||||
])->with('manager', 'groups', 'userloc', 'company', 'department', 'assets', 'licenses', 'accessories', 'consumables')
|
||||
@@ -133,30 +131,6 @@ class UsersController extends Controller
|
||||
$users = $users->where('users.manager_id','=',$request->input('manager_id'));
|
||||
}
|
||||
|
||||
if ($request->filled('ldap_import')) {
|
||||
$users = $users->where('ldap_import', '=', $request->input('ldap_import'));
|
||||
}
|
||||
|
||||
if ($request->filled('remote')) {
|
||||
$users = $users->where('remote', '=', $request->input('remote'));
|
||||
}
|
||||
|
||||
if ($request->filled('assets_count')) {
|
||||
$users->has('assets', '=', $request->input('assets_count'));
|
||||
}
|
||||
|
||||
if ($request->filled('consumables_count')) {
|
||||
$users->has('consumables', '=', $request->input('consumables_count'));
|
||||
}
|
||||
|
||||
if ($request->filled('licenses_count')) {
|
||||
$users->has('licenses', '=', $request->input('licenses_count'));
|
||||
}
|
||||
|
||||
if ($request->filled('accessories_count')) {
|
||||
$users->has('accessories', '=', $request->input('accessories_count'));
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$users = $users->TextSearch($request->input('search'));
|
||||
}
|
||||
@@ -192,7 +166,7 @@ class UsersController extends Controller
|
||||
'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',
|
||||
'country', 'zip', 'id', 'ldap_import',
|
||||
];
|
||||
|
||||
$sort = in_array($request->get('sort'), $allowed_columns) ? $request->get('sort') : 'first_name';
|
||||
@@ -471,24 +445,6 @@ class UsersController extends Controller
|
||||
return (new AssetsTransformer)->transformAssets($assets, $assets->count(), $request);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of consumables assigned to a user.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @param $userId
|
||||
* @return string JSON
|
||||
*/
|
||||
public function consumables(Request $request, $id)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$this->authorize('view', Consumable::class);
|
||||
$user = User::findOrFail($id);
|
||||
$consumables = $user->consumables;
|
||||
return (new ConsumablesTransformer)->transformConsumables($consumables, $consumables->count(), $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of accessories assigned to a user.
|
||||
*
|
||||
@@ -519,14 +475,10 @@ class UsersController extends Controller
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$this->authorize('view', License::class);
|
||||
|
||||
if ($user = User::where('id', $id)->withTrashed()->first()) {
|
||||
$licenses = $user->licenses()->get();
|
||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.user_not_found', compact('id'))));
|
||||
$user = User::where('id', $id)->withTrashed()->first();
|
||||
$licenses = $user->licenses()->get();
|
||||
|
||||
return (new LicensesTransformer())->transformLicenses($licenses, $licenses->count());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -65,7 +65,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
$asset = null;
|
||||
|
||||
if ($asset = Asset::find(request('asset_id'))) {
|
||||
@@ -96,7 +96,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// create a new model instance
|
||||
$assetMaintenance = new AssetMaintenance();
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
@@ -148,7 +148,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function edit($assetMaintenanceId = null)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||
// Redirect to the improvement management page
|
||||
@@ -199,7 +199,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function update(Request $request, $assetMaintenanceId = null)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||
// Redirect to the asset maintenance management page
|
||||
@@ -267,7 +267,7 @@ class AssetMaintenancesController extends Controller
|
||||
*/
|
||||
public function destroy($assetMaintenanceId)
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
$this->authorize('edit', Asset::class);
|
||||
// Check if the asset maintenance exists
|
||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||
// Redirect to the asset maintenance management page
|
||||
|
||||
@@ -98,22 +98,17 @@ class AssetCheckinController extends Controller
|
||||
}
|
||||
|
||||
$asset->location_id = $asset->rtd_location_id;
|
||||
\Log::debug('After Location ID: '.$asset->location_id);
|
||||
\Log::debug('After RTD Location ID: '.$asset->rtd_location_id);
|
||||
|
||||
if ($request->filled('location_id')) {
|
||||
\Log::debug('NEW Location ID: '.$request->get('location_id'));
|
||||
$asset->location_id = e($request->get('location_id'));
|
||||
}
|
||||
|
||||
$checkin_at = date('Y-m-d H:i:s');
|
||||
if (($request->filled('checkin_at')) && ($request->get('checkin_at') != date('Y-m-d'))) {
|
||||
$checkin_at = $request->get('checkin_at');
|
||||
}
|
||||
|
||||
if(!empty($asset->licenseseats->all())){
|
||||
foreach ($asset->licenseseats as $seat){
|
||||
$seat->assigned_to = null;
|
||||
$seat->save();
|
||||
}
|
||||
$checkin_at = date('Y-m-d');
|
||||
if ($request->filled('checkin_at')) {
|
||||
$checkin_at = $request->input('checkin_at');
|
||||
}
|
||||
|
||||
// Get all pending Acceptances for this asset and delete them
|
||||
|
||||
@@ -80,15 +80,6 @@ class AssetCheckoutController extends Controller
|
||||
$asset->status_id = $request->get('status_id');
|
||||
}
|
||||
|
||||
if(!empty($asset->licenseseats->all())){
|
||||
if(request('checkout_to_type') == 'user') {
|
||||
foreach ($asset->licenseseats as $seat){
|
||||
$seat->assigned_to = $target->id;
|
||||
$seat->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset->checkOut($target, $admin, $checkout_at, $expected_checkin, e($request->get('note')), $request->get('name'))) {
|
||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.checkout.success'));
|
||||
}
|
||||
|
||||
@@ -137,12 +137,12 @@ class AssetsController extends Controller
|
||||
$asset->archived = '0';
|
||||
$asset->physical = '1';
|
||||
$asset->depreciate = '0';
|
||||
$asset->status_id = request('status_id');
|
||||
$asset->status_id = request('status_id', 0);
|
||||
$asset->warranty_months = request('warranty_months', null);
|
||||
$asset->purchase_cost = Helper::ParseCurrency($request->get('purchase_cost'));
|
||||
$asset->purchase_date = request('purchase_date', null);
|
||||
$asset->assigned_to = request('assigned_to', null);
|
||||
$asset->supplier_id = request('supplier_id', null);
|
||||
$asset->supplier_id = request('supplier_id', 0);
|
||||
$asset->requestable = request('requestable', 0);
|
||||
$asset->rtd_location_id = request('rtd_location_id', null);
|
||||
|
||||
@@ -168,9 +168,9 @@ class AssetsController extends Controller
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(implode(', ', $request->input($field->convertUnicodeDbSlug())));
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e(implode(', ', $request->input($field->convertUnicodeDbSlug()))));
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -235,7 +235,6 @@ class AssetsController extends Controller
|
||||
->with('statuslabel_types', Helper::statusTypeList());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a view that presents information about an asset for detail view.
|
||||
*
|
||||
@@ -310,7 +309,6 @@ class AssetsController extends Controller
|
||||
$asset->location_id = $request->input('rtd_location_id', null);
|
||||
}
|
||||
|
||||
|
||||
if ($request->filled('image_delete')) {
|
||||
try {
|
||||
unlink(public_path().'/uploads/assets/'.$asset->image);
|
||||
@@ -344,9 +342,9 @@ class AssetsController extends Controller
|
||||
if ($field->field_encrypted == '1') {
|
||||
if (Gate::allows('admin')) {
|
||||
if (is_array($request->input($field->convertUnicodeDbSlug()))) {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(implode(', ', $request->input($field->convertUnicodeDbSlug())));
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e(implode(', ', $request->input($field->convertUnicodeDbSlug()))));
|
||||
} else {
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt($request->input($field->convertUnicodeDbSlug()));
|
||||
$asset->{$field->convertUnicodeDbSlug()} = \Crypt::encrypt(e($request->input($field->convertUnicodeDbSlug())));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -403,24 +401,6 @@ class AssetsController extends Controller
|
||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.delete.success'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the assets table by serial, and redirects if it finds one
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @return Redirect
|
||||
*/
|
||||
public function getAssetBySerial(Request $request)
|
||||
{
|
||||
$topsearch = ($request->get('topsearch')=="true");
|
||||
|
||||
if (!$asset = Asset::where('serial', '=', $request->get('serial'))->first()) {
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||
}
|
||||
$this->authorize('view', $asset);
|
||||
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the assets table by asset tag, and redirects if it finds one
|
||||
*
|
||||
@@ -440,7 +420,6 @@ class AssetsController extends Controller
|
||||
return redirect()->route('hardware.show', $asset->id)->with('topsearch', $topsearch);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a QR code for the asset
|
||||
*
|
||||
@@ -813,7 +792,6 @@ class AssetsController extends Controller
|
||||
return view('hardware/audit-overdue');
|
||||
}
|
||||
|
||||
|
||||
public function auditStore(Request $request, $id)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
@@ -844,7 +822,6 @@ class AssetsController extends Controller
|
||||
$asset->location_id = $request->input('location_id');
|
||||
}
|
||||
|
||||
|
||||
if ($asset->save()) {
|
||||
$file_name = '';
|
||||
// Upload an image, if attached
|
||||
@@ -861,13 +838,12 @@ class AssetsController extends Controller
|
||||
|
||||
|
||||
$asset->logAudit($request->input('note'), $request->input('location_id'), $file_name);
|
||||
return redirect()->route('assets.audit.due')->with('success', trans('admin/hardware/message.audit.success'));
|
||||
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.audit.success'));
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequestedIndex($user_id = null)
|
||||
{
|
||||
$this->authorize('index', Asset::class);
|
||||
$requestedItems = CheckoutRequest::with('user', 'requestedItem')->whereNull('canceled_at')->with('user', 'requestedItem');
|
||||
|
||||
if ($user_id) {
|
||||
|
||||
@@ -2,16 +2,21 @@
|
||||
|
||||
namespace App\Http\Controllers\Assets;
|
||||
|
||||
use App\Events\CheckoutableCheckedIn;
|
||||
use App\Models\Actionlog;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\CheckInOutRequest;
|
||||
use App\Models\CheckoutAcceptance;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
use App\Http\Requests\AssetCheckinRequest;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
|
||||
|
||||
class BulkAssetsController extends Controller
|
||||
{
|
||||
@@ -31,17 +36,9 @@ class BulkAssetsController extends Controller
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
if (! $request->filled('ids')) {
|
||||
return redirect()->back()->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||
|
||||
return redirect()->back()->with('error', 'No assets selected');
|
||||
}
|
||||
|
||||
// Figure out where we need to send the user after the update is complete, and store that in the session
|
||||
$bulk_back_url = request()->headers->get('referer');
|
||||
session(['bulk_back_url' => $bulk_back_url]);
|
||||
|
||||
\Log::debug('Back to url: '.$bulk_back_url);
|
||||
|
||||
|
||||
|
||||
$asset_ids = array_values(array_unique($request->input('ids')));
|
||||
|
||||
@@ -58,8 +55,14 @@ class BulkAssetsController extends Controller
|
||||
$assets->each(function ($asset) {
|
||||
$this->authorize('delete', $asset);
|
||||
});
|
||||
|
||||
return view('hardware/bulk-delete')->with('assets', $assets);
|
||||
|
||||
case 'checkin':
|
||||
$assets = Asset::with('assignedTo', 'location')->find($asset_ids);
|
||||
$assets->each(function ($asset) {
|
||||
$this->authorize('checkin', $asset);
|
||||
});
|
||||
return view('hardware/bulk-checkin')->with('assets', $assets);
|
||||
case 'edit':
|
||||
return view('hardware/bulk')
|
||||
->with('assets', $asset_ids)
|
||||
@@ -82,15 +85,10 @@ class BulkAssetsController extends Controller
|
||||
{
|
||||
$this->authorize('update', Asset::class);
|
||||
|
||||
// Get the back url from the session and then destroy the session
|
||||
$bulk_back_url = route('hardware.index');
|
||||
if ($request->session()->has('bulk_back_url')) {
|
||||
$bulk_back_url = $request->session()->pull('bulk_back_url');
|
||||
}
|
||||
|
||||
\Log::debug($request->input('ids'));
|
||||
|
||||
if (! $request->filled('ids') || count($request->input('ids')) <= 0) {
|
||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.update.no_assets_selected'));
|
||||
return redirect()->route('hardware.index')->with('warning', trans('No assets selected, so nothing was updated.'));
|
||||
}
|
||||
|
||||
$assets = array_keys($request->input('ids'));
|
||||
@@ -161,13 +159,11 @@ class BulkAssetsController extends Controller
|
||||
->update($this->update_array);
|
||||
} // endforeach
|
||||
|
||||
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.update.success'));
|
||||
|
||||
|
||||
return redirect()->route('hardware.index')->with('success', trans('admin/hardware/message.update.success'));
|
||||
// no values given, nothing to update
|
||||
}
|
||||
|
||||
// no values given, nothing to update
|
||||
return redirect($bulk_back_url)->with('warning', trans('admin/hardware/message.update.nothing_updated'));
|
||||
return redirect()->route('hardware.index')->with('warning', trans('admin/hardware/message.update.nothing_updated'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,11 +200,6 @@ class BulkAssetsController extends Controller
|
||||
{
|
||||
$this->authorize('delete', Asset::class);
|
||||
|
||||
$bulk_back_url = route('hardware.index');
|
||||
if ($request->session()->has('bulk_back_url')) {
|
||||
$bulk_back_url = $request->session()->pull('bulk_back_url');
|
||||
}
|
||||
|
||||
if ($request->filled('ids')) {
|
||||
$assets = Asset::find($request->get('ids'));
|
||||
foreach ($assets as $asset) {
|
||||
@@ -220,13 +211,15 @@ class BulkAssetsController extends Controller
|
||||
->update($update_array);
|
||||
} // endforeach
|
||||
|
||||
return redirect($bulk_back_url)->with('success', trans('admin/hardware/message.delete.success'));
|
||||
return redirect()->to('hardware')->with('success', trans('admin/hardware/message.delete.success'));
|
||||
// no values given, nothing to update
|
||||
}
|
||||
|
||||
return redirect($bulk_back_url)->with('error', trans('admin/hardware/message.delete.nothing_updated'));
|
||||
return redirect()->to('hardware')->with('info', trans('admin/hardware/message.delete.nothing_updated'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Show Bulk Checkout Page
|
||||
* @return View View to checkout multiple assets
|
||||
@@ -234,8 +227,6 @@ class BulkAssetsController extends Controller
|
||||
public function showCheckout()
|
||||
{
|
||||
$this->authorize('checkout', Asset::class);
|
||||
// Filter out assets that are not deployable.
|
||||
|
||||
return view('hardware/bulk-checkout');
|
||||
}
|
||||
|
||||
@@ -245,9 +236,6 @@ class BulkAssetsController extends Controller
|
||||
*/
|
||||
public function storeCheckout(Request $request)
|
||||
{
|
||||
|
||||
$this->authorize('checkout', Asset::class);
|
||||
|
||||
try {
|
||||
$admin = Auth::user();
|
||||
|
||||
@@ -306,4 +294,55 @@ class BulkAssetsController extends Controller
|
||||
return redirect()->to('hardware/bulk-checkout')->with('error', $e->getErrors());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show Bulk Checkout Page
|
||||
* @return View View to checkout multiple assets
|
||||
*/
|
||||
public function showCheckin(Request $request)
|
||||
{
|
||||
$this->authorize('checkin', Asset::class);
|
||||
$assets = Asset::find($request->input('ids'));
|
||||
return view('hardware/bulk-checkin')->with($assets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Multiple Checkout Request
|
||||
* @return View
|
||||
*/
|
||||
public function storeCheckin(AssetCheckinRequest $request)
|
||||
{
|
||||
$this->authorize('checkin', Asset::class);
|
||||
|
||||
|
||||
if (! is_array($request->get('ids'))) {
|
||||
return redirect()->route('hardware')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected'));
|
||||
}
|
||||
|
||||
$asset_ids = array_filter($request->get('ids'));
|
||||
|
||||
DB::transaction(function () use ($asset_ids, $request) {
|
||||
foreach ($asset_ids as $asset_id) {
|
||||
$asset = Asset::findOrFail($asset_id);
|
||||
$this->authorize('checkin', $asset);
|
||||
event(new CheckoutableCheckedIn($asset, '', Auth::user(), $request->input('note')));
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Get all pending Acceptances for this asset and delete them
|
||||
$assets = Asset::find($request->input('ids'));
|
||||
$acceptances = CheckoutAcceptance::pending()->whereHasMorph('checkoutable',
|
||||
[Asset::class],
|
||||
function (Builder $query) use ($asset) {
|
||||
$query->where('id', $asset->id);
|
||||
})->get();
|
||||
$acceptances->map(function($acceptance) {
|
||||
$acceptance->delete();
|
||||
});
|
||||
|
||||
return redirect()->to('hardware');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -68,21 +68,17 @@ class LoginController extends Controller
|
||||
return redirect()->intended('/');
|
||||
}
|
||||
|
||||
if (!$request->session()->has('loggedout')) {
|
||||
// If the environment is set to ALWAYS require SAML, go straight to the SAML route.
|
||||
// We don't need to check other settings, as this should override those.
|
||||
if (config('app.require_saml')) {
|
||||
return redirect()->route('saml.login');
|
||||
}
|
||||
//If the environment is set to ALWAYS require SAML, go straight to the SAML route.
|
||||
//We don't need to check other settings, as this should override those.
|
||||
if(config('app.require_saml')) {
|
||||
return redirect()->route('saml.login');
|
||||
}
|
||||
|
||||
|
||||
if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == '1' && ! ($request->has('nosaml') || $request->session()->has('error'))) {
|
||||
return redirect()->route('saml.login');
|
||||
}
|
||||
if ($this->saml->isEnabled() && Setting::getSettings()->saml_forcelogin == '1' && ! ($request->has('nosaml') || $request->session()->has('error'))) {
|
||||
return redirect()->route('saml.login');
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->login_common_disabled == '1') {
|
||||
\Log::debug('login_common_disabled is set to 1 - return a 403');
|
||||
return view('errors.403');
|
||||
}
|
||||
|
||||
@@ -106,13 +102,11 @@ class LoginController extends Controller
|
||||
{
|
||||
$saml = $this->saml;
|
||||
$samlData = $request->session()->get('saml_login');
|
||||
|
||||
if ($saml->isEnabled() && ! empty($samlData)) {
|
||||
|
||||
try {
|
||||
Log::debug('Attempting to log user in by SAML authentication.');
|
||||
$user = $saml->samlLogin($samlData);
|
||||
|
||||
if (!is_null($user)) {
|
||||
if (! is_null($user)) {
|
||||
Auth::login($user);
|
||||
} else {
|
||||
$username = $saml->getUsername();
|
||||
@@ -125,26 +119,11 @@ class LoginController extends Controller
|
||||
$user->last_login = \Carbon::now();
|
||||
$user->save();
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::warning('There was an error authenticating the SAML user: '.$e->getMessage());
|
||||
throw new \Exception($e->getMessage());
|
||||
}
|
||||
|
||||
// Fallthrough with better logging
|
||||
} else {
|
||||
|
||||
// Better logging
|
||||
if (!$saml->isEnabled()) {
|
||||
\Log::warning("SAML page requested, but SAML does not seem to enabled.");
|
||||
} else {
|
||||
\Log::warning("SAML page requested, but samlData seems empty.");
|
||||
}
|
||||
}
|
||||
|
||||
\Log::warning("Something else went wrong while trying to login as SAML user");
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +161,7 @@ class LoginController extends Controller
|
||||
Log::debug("Local user ".$request->input('username')." does not exist");
|
||||
Log::debug("Creating local user ".$request->input('username'));
|
||||
|
||||
if ($user = Ldap::createUserFromLdap($ldap_user, $request->input('password'))) {
|
||||
if ($user = Ldap::createUserFromLdap($ldap_user)) { //this handles passwords on its own
|
||||
Log::debug("Local user created.");
|
||||
} else {
|
||||
Log::debug("Could not create local user.");
|
||||
@@ -256,15 +235,12 @@ class LoginController extends Controller
|
||||
*/
|
||||
public function login(Request $request)
|
||||
{
|
||||
|
||||
//If the environment is set to ALWAYS require SAML, return access denied
|
||||
if (config('app.require_saml')) {
|
||||
\Log::debug('require SAML is enabled in the .env - return a 403');
|
||||
if(config('app.require_saml')) {
|
||||
return view('errors.403');
|
||||
}
|
||||
|
||||
if (Setting::getSettings()->login_common_disabled == '1') {
|
||||
\Log::debug('login_common_disabled is set to 1 - return a 403');
|
||||
return view('errors.403');
|
||||
}
|
||||
|
||||
@@ -355,6 +331,7 @@ class LoginController extends Controller
|
||||
|
||||
$secret = Google2FA::generateSecretKey();
|
||||
$user->two_factor_secret = $secret;
|
||||
$user->save();
|
||||
|
||||
$barcode = new Barcode();
|
||||
$barcode_obj =
|
||||
@@ -372,8 +349,6 @@ class LoginController extends Controller
|
||||
[-2, -2, -2, -2]
|
||||
);
|
||||
|
||||
$user->save(); // make sure to save *AFTER* displaying the barcode, or else we might save a two_factor_secret that we never actually displayed to the user if the barcode fails
|
||||
|
||||
return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj);
|
||||
}
|
||||
|
||||
@@ -418,7 +393,7 @@ class LoginController extends Controller
|
||||
return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required'));
|
||||
}
|
||||
|
||||
if (! $request->has('two_factor_secret')) { // TODO this seems almost the same as above?
|
||||
if (! $request->has('two_factor_secret')) {
|
||||
return redirect()->route('two-factor')->with('error', 'Two-factor code is required.');
|
||||
}
|
||||
|
||||
@@ -446,17 +421,10 @@ class LoginController extends Controller
|
||||
*/
|
||||
public function logout(Request $request)
|
||||
{
|
||||
// Logout is only allowed with a http POST but we need to allow GET for SAML SLO
|
||||
$settings = Setting::getSettings();
|
||||
$saml = $this->saml;
|
||||
$samlLogout = $request->session()->get('saml_logout');
|
||||
$sloRedirectUrl = null;
|
||||
$sloRequestUrl = null;
|
||||
|
||||
// Only allow GET if we are doing SAML SLO otherwise abort with 405
|
||||
if ($request->isMethod('GET') && !$samlLogout) {
|
||||
abort(405);
|
||||
}
|
||||
|
||||
if ($saml->isEnabled()) {
|
||||
$auth = $saml->getAuth();
|
||||
@@ -473,6 +441,8 @@ class LoginController extends Controller
|
||||
return redirect()->away($sloRequestUrl);
|
||||
}
|
||||
|
||||
$request->session()->regenerate(true);
|
||||
|
||||
$request->session()->regenerate(true);
|
||||
Auth::logout();
|
||||
|
||||
@@ -503,7 +473,6 @@ class LoginController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
public function username()
|
||||
{
|
||||
return 'username';
|
||||
@@ -530,7 +499,6 @@ class LoginController extends Controller
|
||||
->withErrors([$this->username() => $message]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override the lockout time and duration
|
||||
*
|
||||
|
||||
@@ -51,7 +51,6 @@ class SamlController extends Controller
|
||||
$metadata = $this->saml->getSPMetadata();
|
||||
|
||||
if (empty($metadata)) {
|
||||
\Log::debug('SAML metadata is empty - return a 403');
|
||||
return response()->view('errors.403', [], 403);
|
||||
}
|
||||
|
||||
@@ -142,6 +141,6 @@ class SamlController extends Controller
|
||||
return view('errors.403');
|
||||
}
|
||||
|
||||
return redirect()->route('logout')->with(['saml_logout' => true,'saml_slo_redirect_url' => $sloUrl]);
|
||||
return redirect()->route('logout')->with('saml_slo_redirect_url', $sloUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ class ComponentsController extends Controller
|
||||
$component->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost', null));
|
||||
$component->qty = $request->input('qty');
|
||||
$component->user_id = Auth::id();
|
||||
$component->notes = $request->input('notes');
|
||||
|
||||
$component = $request->handleImages($component);
|
||||
|
||||
@@ -129,7 +128,7 @@ class ComponentsController extends Controller
|
||||
if (is_null($component = Component::find($componentId))) {
|
||||
return redirect()->route('components.index')->with('error', trans('admin/components/message.does_not_exist'));
|
||||
}
|
||||
$min = $component->numCheckedOut();
|
||||
$min = $component->numCHeckedOut();
|
||||
$validator = Validator::make($request->all(), [
|
||||
'qty' => "required|numeric|min:$min",
|
||||
]);
|
||||
@@ -153,7 +152,6 @@ class ComponentsController extends Controller
|
||||
$component->purchase_date = $request->input('purchase_date');
|
||||
$component->purchase_cost = Helper::ParseCurrency(request('purchase_cost'));
|
||||
$component->qty = $request->input('qty');
|
||||
$component->notes = $request->input('notes');
|
||||
|
||||
$component = $request->handleImages($component);
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ use App\Models\Company;
|
||||
use App\Models\Consumable;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Consumables for
|
||||
@@ -79,8 +78,6 @@ class ConsumablesController extends Controller
|
||||
$consumable->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
|
||||
$consumable->qty = $request->input('qty');
|
||||
$consumable->user_id = Auth::id();
|
||||
$consumable->notes = $request->input('notes');
|
||||
|
||||
|
||||
$consumable = $request->handleImages($consumable);
|
||||
|
||||
@@ -129,17 +126,6 @@ class ConsumablesController extends Controller
|
||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.does_not_exist'));
|
||||
}
|
||||
|
||||
$min = $consumable->numCheckedOut();
|
||||
$validator = Validator::make($request->all(), [
|
||||
"qty" => "required|numeric|min:$min"
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
$this->authorize($consumable);
|
||||
|
||||
$consumable->name = $request->input('name');
|
||||
@@ -154,7 +140,6 @@ class ConsumablesController extends Controller
|
||||
$consumable->purchase_date = $request->input('purchase_date');
|
||||
$consumable->purchase_cost = Helper::ParseCurrency($request->input('purchase_cost'));
|
||||
$consumable->qty = Helper::ParseFloat($request->input('qty'));
|
||||
$consumable->notes = $request->input('notes');
|
||||
|
||||
$consumable = $request->handleImages($consumable);
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class CustomFieldsetsController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
$results = $set->fields()->attach($request->input('field_id'), ['required' => ($request->input('required') == 'on'), 'order' => (int)$request->input('order', 1)]);
|
||||
$results = $set->fields()->attach($request->input('field_id'), ['required' => ($request->input('required') == 'on'), 'order' => $request->input('order', 1)]);
|
||||
|
||||
return redirect()->route('fieldsets.show', [$id])->with('success', trans('admin/custom_fields/message.field.create.assoc_success'));
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Kits;
|
||||
use App\Http\Controllers\CheckInOutRequest;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\PredefinedKit;
|
||||
use App\Models\Asset;
|
||||
use App\Models\PredefinedLicence;
|
||||
use App\Models\PredefinedModel;
|
||||
use App\Models\User;
|
||||
|
||||
@@ -134,7 +134,6 @@ class LicensesController extends Controller
|
||||
->with('maintained_list', $maintained_list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates and stores the license form data submitted from the edit
|
||||
* license form.
|
||||
|
||||
@@ -211,35 +211,23 @@ class LocationsController extends Controller
|
||||
|
||||
public function print_assigned($id)
|
||||
{
|
||||
$location = Location::where('id', $id)->first();
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
|
||||
|
||||
if ($location = Location::where('id', $id)->first()) {
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get();
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
|
||||
}
|
||||
|
||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||
|
||||
|
||||
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
}
|
||||
|
||||
public function print_all_assigned($id)
|
||||
{
|
||||
if ($location = Location::where('id', $id)->first()) {
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
|
||||
}
|
||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||
|
||||
|
||||
$location = Location::where('id', $id)->first();
|
||||
$parent = Location::where('id', $location->parent_id)->first();
|
||||
$manager = User::where('id', $location->manager_id)->first();
|
||||
$users = User::where('location_id', $id)->with('company', 'department', 'location')->get();
|
||||
$assets = Asset::where('location_id', $id)->with('model', 'model.category')->get();
|
||||
|
||||
return view('locations/print')->with('assets', $assets)->with('users', $users)->with('location', $location)->with('parent', $parent)->with('manager', $manager);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,18 +275,13 @@ class ReportsController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
if($actionlog->item){
|
||||
$item_name = e($actionlog->item->getDisplayNameAttribute());
|
||||
} else {
|
||||
$item_name = '';
|
||||
}
|
||||
|
||||
$row = [
|
||||
$actionlog->created_at,
|
||||
($actionlog->user) ? e($actionlog->user->getFullNameAttribute()) : '',
|
||||
$actionlog->present()->actionType(),
|
||||
e($actionlog->itemType()),
|
||||
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
|
||||
($actionlog->itemType() == 'user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
|
||||
$target_name,
|
||||
($actionlog->note) ? e($actionlog->note) : '',
|
||||
$actionlog->log_meta,
|
||||
@@ -938,17 +933,12 @@ class ReportsController extends Controller
|
||||
/**
|
||||
* Get all assets with pending checkout acceptances
|
||||
*/
|
||||
if($showDeleted) {
|
||||
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->withTrashed()->with(['assignedTo' , 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
} else {
|
||||
$acceptances = CheckoutAcceptance::pending()->where('checkoutable_type', 'App\Models\Asset')->with(['assignedTo' => function ($query) {
|
||||
$query->withTrashed();
|
||||
}, 'checkoutable.assignedTo', 'checkoutable.model'])->get();
|
||||
}
|
||||
|
||||
$acceptances = CheckoutAcceptance::pending()->with('assignedTo')->get();
|
||||
|
||||
$assetsForReport = $acceptances
|
||||
->filter(function ($acceptance) {
|
||||
return $acceptance->checkoutable_type == 'App\Models\Asset';
|
||||
->filter(function($acceptance) {
|
||||
return $acceptance->checkoutable_type == 'App\Models\Asset' && !is_null($acceptance->assignedTo);
|
||||
})
|
||||
->map(function($acceptance) {
|
||||
return ['assetItem' => $acceptance->checkoutable, 'acceptance' => $acceptance];
|
||||
|
||||
@@ -942,11 +942,10 @@ class SettingsController extends Controller
|
||||
$setting->ldap_lname_field = $request->input('ldap_lname_field');
|
||||
$setting->ldap_fname_field = $request->input('ldap_fname_field');
|
||||
$setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query');
|
||||
$setting->ldap_version = $request->input('ldap_version', 3);
|
||||
$setting->ldap_version = $request->input('ldap_version');
|
||||
$setting->ldap_active_flag = $request->input('ldap_active_flag');
|
||||
$setting->ldap_emp_num = $request->input('ldap_emp_num');
|
||||
$setting->ldap_email = $request->input('ldap_email');
|
||||
$setting->ldap_manager = $request->input('ldap_manager');
|
||||
$setting->ad_domain = $request->input('ad_domain');
|
||||
$setting->is_ad = $request->input('is_ad', '0');
|
||||
$setting->ad_append_domain = $request->input('ad_append_domain', '0');
|
||||
@@ -1026,12 +1025,6 @@ class SettingsController extends Controller
|
||||
|
||||
return redirect()->back()->withInput()->withErrors($setting->getErrors());
|
||||
}
|
||||
public static function getPDFBranding()
|
||||
{
|
||||
$pdf_branding= Setting::getSettings();
|
||||
|
||||
return $pdf_branding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the listing of backups.
|
||||
@@ -1044,7 +1037,7 @@ class SettingsController extends Controller
|
||||
*/
|
||||
public function getBackups()
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
$path = 'app/backups';
|
||||
$backup_files = Storage::files($path);
|
||||
$files_raw = [];
|
||||
@@ -1061,7 +1054,7 @@ class SettingsController extends Controller
|
||||
'filename' => basename($backup_files[$f]),
|
||||
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
||||
'modified_value' => $file_timestamp,
|
||||
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
||||
'modified_display' => Helper::getFormattedDateObject($file_timestamp, $type = 'datetime', false),
|
||||
|
||||
];
|
||||
}
|
||||
@@ -1234,11 +1227,7 @@ class SettingsController extends Controller
|
||||
// TODO: run a backup
|
||||
|
||||
|
||||
Artisan::call('db:wipe', [
|
||||
'--force' => true,
|
||||
]);
|
||||
|
||||
\Log::debug('Attempting to restore from: '. storage_path($path).'/'.$filename);
|
||||
Artisan::call('db:wipe');
|
||||
|
||||
// run the restore command
|
||||
Artisan::call('snipeit:restore',
|
||||
@@ -1250,26 +1239,19 @@ class SettingsController extends Controller
|
||||
|
||||
// If it's greater than 300, it probably worked
|
||||
$output = Artisan::output();
|
||||
|
||||
if (strlen($output) > 300) {
|
||||
$find_user = DB::table('users')->where('first_name', $user->first_name)->where('last_name', $user->last_name)->exists();
|
||||
|
||||
if (!$find_user){
|
||||
if(!$find_user){
|
||||
\Log::warning('Attempting to restore user: ' . $user->first_name . ' ' . $user->last_name);
|
||||
$new_user = $user->replicate();
|
||||
$new_user->push();
|
||||
}
|
||||
|
||||
|
||||
\Log::debug('Logging all users out..');
|
||||
Artisan::call('snipeit:global-logout', ['--force' => true]);
|
||||
|
||||
/* run migrations */
|
||||
\Log::debug('Migrating database...');
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
$migrate_output = Artisan::output();
|
||||
\Log::debug($migrate_output);
|
||||
|
||||
$session_files = glob(storage_path("framework/sessions/*"));
|
||||
foreach ($session_files as $file) {
|
||||
if (is_file($file))
|
||||
unlink($file);
|
||||
}
|
||||
DB::table('users')->update(['remember_token' => null]);
|
||||
\Auth::logout();
|
||||
|
||||
|
||||
@@ -46,13 +46,13 @@ class BulkUsersController extends Controller
|
||||
foreach ($users as $user) {
|
||||
if (($user->activated == '1') && ($user->email != '')) {
|
||||
$credentials = ['email' => $user->email];
|
||||
Password::sendResetLink($credentials/* , function (Message $message) {
|
||||
$message->subject($this->getEmailSubject()); // TODO - I'm not sure if we still need this, but this second parameter is no longer accepted in later Laravel versions.
|
||||
} */ ); // TODO - so hopefully this doesn't give us generic password reset messages? But it at least _works_
|
||||
Password::sendResetLink($credentials, function (Message $message) {
|
||||
$message->subject($this->getEmailSubject());
|
||||
});
|
||||
}
|
||||
}
|
||||
return redirect()->back()->with('success', trans('admin/users/message.password_resets_sent'));
|
||||
|
||||
return redirect()->back()->with('success', trans('admin/users/message.password_resets_sent'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,11 +90,7 @@ class BulkUsersController extends Controller
|
||||
->conditionallyAddItem('department_id')
|
||||
->conditionallyAddItem('company_id')
|
||||
->conditionallyAddItem('locale')
|
||||
->conditionallyAddItem('remote')
|
||||
->conditionallyAddItem('ldap_import')
|
||||
->conditionallyAddItem('activated');
|
||||
|
||||
|
||||
// If the manager_id is one of the users being updated, generate a warning.
|
||||
if (array_search($request->input('manager_id'), $user_raw_array)) {
|
||||
$manager_conflict = true;
|
||||
@@ -105,16 +101,11 @@ class BulkUsersController extends Controller
|
||||
if (! $manager_conflict) {
|
||||
$this->conditionallyAddItem('manager_id');
|
||||
}
|
||||
|
||||
// Save the updated info
|
||||
User::whereIn('id', $user_raw_array)
|
||||
->where('id', '!=', Auth::id())->update($this->update_array);
|
||||
|
||||
if (array_key_exists('location_id', $this->update_array)){
|
||||
Asset::where('assigned_type', User::class)
|
||||
->whereIn('assigned_to', $user_raw_array)
|
||||
->update(['location_id' => $this->update_array['location_id']]);
|
||||
}
|
||||
|
||||
// Only sync groups if groups were selected
|
||||
if ($request->filled('groups')) {
|
||||
foreach ($users as $user) {
|
||||
@@ -180,7 +171,6 @@ class BulkUsersController extends Controller
|
||||
$accessories = DB::table('accessories_users')->whereIn('assigned_to', $user_raw_array)->get();
|
||||
$licenses = DB::table('license_seats')->whereIn('assigned_to', $user_raw_array)->get();
|
||||
|
||||
|
||||
$this->logItemCheckinAndDelete($assets, Asset::class);
|
||||
$this->logItemCheckinAndDelete($accessories, Accessory::class);
|
||||
$this->logItemCheckinAndDelete($licenses, LicenseSeat::class);
|
||||
@@ -191,7 +181,6 @@ class BulkUsersController extends Controller
|
||||
'assigned_type' => null,
|
||||
]);
|
||||
|
||||
|
||||
LicenseSeat::whereIn('id', $licenses->pluck('id'))->update(['assigned_to' => null]);
|
||||
|
||||
foreach ($users as $user) {
|
||||
|
||||
@@ -93,8 +93,8 @@ class UsersController extends Controller
|
||||
$this->authorize('create', User::class);
|
||||
$user = new User;
|
||||
//Username, email, and password need to be handled specially because the need to respect config values on an edit.
|
||||
$user->email = trim($request->input('email'));
|
||||
$user->username = trim($request->input('username'));
|
||||
$user->email = e($request->input('email'));
|
||||
$user->username = e($request->input('username'));
|
||||
if ($request->filled('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
@@ -115,7 +115,6 @@ class UsersController extends Controller
|
||||
$user->state = $request->input('state', null);
|
||||
$user->country = $request->input('country', null);
|
||||
$user->zip = $request->input('zip', null);
|
||||
$user->remote = $request->input('remote', 0);
|
||||
|
||||
// Strip out the superuser permission if the user isn't a superadmin
|
||||
$permissions_array = $request->input('permission');
|
||||
@@ -180,6 +179,7 @@ class UsersController extends Controller
|
||||
if ($user = User::find($id)) {
|
||||
$this->authorize('update', $user);
|
||||
$permissions = config('permissions');
|
||||
|
||||
$groups = Group::pluck('name', 'id');
|
||||
|
||||
$userGroups = $user->groups()->pluck('name', 'id');
|
||||
@@ -190,7 +190,9 @@ class UsersController extends Controller
|
||||
return view('users/edit', compact('user', 'groups', 'userGroups', 'permissions', 'userPermissions'))->with('item', $user);
|
||||
}
|
||||
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.user_not_found', compact('id')));
|
||||
$error = trans('admin/users/message.user_not_found', compact('id'));
|
||||
|
||||
return redirect()->route('users.index')->with('error', $error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,9 +245,9 @@ class UsersController extends Controller
|
||||
|
||||
// Update the user
|
||||
if ($request->filled('username')) {
|
||||
$user->username = trim($request->input('username'));
|
||||
$user->username = $request->input('username');
|
||||
}
|
||||
$user->email = trim($request->input('email'));
|
||||
$user->email = $request->input('email');
|
||||
$user->first_name = $request->input('first_name');
|
||||
$user->last_name = $request->input('last_name');
|
||||
$user->two_factor_optin = $request->input('two_factor_optin') ?: 0;
|
||||
@@ -265,7 +267,6 @@ class UsersController extends Controller
|
||||
$user->country = $request->input('country', null);
|
||||
$user->activated = $request->input('activated', 0);
|
||||
$user->zip = $request->input('zip', null);
|
||||
$user->remote = $request->input('remote', 0);
|
||||
|
||||
// Update the location of any assets checked out to this user
|
||||
Asset::where('assigned_type', User::class)
|
||||
@@ -622,11 +623,12 @@ class UsersController extends Controller
|
||||
public function sendPasswordReset($id)
|
||||
{
|
||||
if (($user = User::find($id)) && ($user->activated == '1') && ($user->email != '') && ($user->ldap_import == '0')) {
|
||||
$credentials = ['email' => trim($user->email)];
|
||||
$credentials = ['email' => $user->email];
|
||||
|
||||
try {
|
||||
|
||||
Password::sendResetLink($credentials);
|
||||
\Password::sendResetLink($credentials, function (Message $message) use ($user) {
|
||||
$message->subject($this->getEmailSubject());
|
||||
});
|
||||
|
||||
return redirect()->back()->with('success', trans('admin/users/message.password_reset_sent', ['email' => $user->email]));
|
||||
} catch (\Exception $e) {
|
||||
|
||||
+1
-1
@@ -39,13 +39,13 @@ class Kernel extends HttpKernel
|
||||
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
|
||||
\App\Http\Middleware\VerifyCsrfToken::class,
|
||||
\App\Http\Middleware\CheckLocale::class,
|
||||
\App\Http\Middleware\CheckUserIsActivated::class,
|
||||
\App\Http\Middleware\CheckForTwoFactor::class,
|
||||
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
|
||||
\App\Http\Middleware\AssetCountForSidebar::class,
|
||||
],
|
||||
|
||||
'api' => [
|
||||
'throttle:120,1',
|
||||
'auth:api',
|
||||
],
|
||||
];
|
||||
|
||||
+7
-10
@@ -4,9 +4,8 @@ namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Auth;
|
||||
|
||||
class CheckUserIsActivated
|
||||
class Authenticate
|
||||
{
|
||||
/**
|
||||
* The Guard implementation.
|
||||
@@ -35,16 +34,14 @@ class CheckUserIsActivated
|
||||
*/
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
|
||||
// If there is a user AND the user is NOT activated, send them to the login page
|
||||
// This prevents people who still have active sessions logged in and their status gets toggled
|
||||
// to inactive (aka unable to login)
|
||||
if (($request->user()) && (!$request->user()->isActivated())) {
|
||||
Auth::logout();
|
||||
return redirect()->guest('login');
|
||||
if ($this->auth->guest()) {
|
||||
if ($request->ajax()) {
|
||||
return response('Unauthorized.', 401);
|
||||
} else {
|
||||
return redirect()->guest('login');
|
||||
}
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,7 @@ class CheckForTwoFactor
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
// Skip the logic if the user is on the two factor pages or the setup pages
|
||||
|
||||
// TODO - what we have below only works because our ROUTE uri's look _exactly_ like the route *names*.
|
||||
// The problem is that, in the new(-ish) Laravel routing system, the route-name doesn't match if the route _verb_ is wrong.
|
||||
// so we can have a blade that POST's to a route('two-factor') - but that route *name* is only matched when the method is GET
|
||||
// because we attached the name to the GET, not to the POST (as route names *SHOULD* be unique in Laravel)
|
||||
// there has got to be a better way to do this, but this is the best I could come up with for now.
|
||||
if (in_array($request->route()->getName(), self::IGNORE_ROUTES) || in_array($request->route()->uri(), self::IGNORE_ROUTES)) {
|
||||
if (in_array($request->route()->getName(), self::IGNORE_ROUTES)) {
|
||||
return $next($request);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,15 +42,30 @@ class SecurityHeaders
|
||||
// - https://github.com/w3c/webappsec-feature-policy/issues/189
|
||||
|
||||
$feature_policy[] = "accelerometer 'none'";
|
||||
$feature_policy[] = "ambient-light-sensor 'none'";
|
||||
$feature_policy[] = "animations 'none'";
|
||||
$feature_policy[] = "autoplay 'none'";
|
||||
$feature_policy[] = "battery 'none'";
|
||||
$feature_policy[] = "camera 'none'";
|
||||
$feature_policy[] = "display-capture 'none'";
|
||||
$feature_policy[] = "document-domain 'none'";
|
||||
$feature_policy[] = "encrypted-media 'none'";
|
||||
$feature_policy[] = "fullscreen 'none'";
|
||||
$feature_policy[] = "geolocation 'none'";
|
||||
$feature_policy[] = "gyroscope 'none'";
|
||||
$feature_policy[] = "legacy-image-formats 'none'";
|
||||
$feature_policy[] = "magnetometer 'none'";
|
||||
$feature_policy[] = "microphone 'none'";
|
||||
$feature_policy[] = "midi 'none'";
|
||||
$feature_policy[] = "oversized-images 'none'";
|
||||
$feature_policy[] = "payment 'none'";
|
||||
$feature_policy[] = "picture-in-picture 'none'";
|
||||
$feature_policy[] = "publickey-credentials 'none'";
|
||||
$feature_policy[] = "sync-xhr 'none'";
|
||||
$feature_policy[] = "unsized-media 'none'";
|
||||
$feature_policy[] = "usb 'none'";
|
||||
$feature_policy[] = "vibrate 'none'";
|
||||
$feature_policy[] = "wake-lock 'none'";
|
||||
$feature_policy[] = "xr-spatial-tracking 'none'";
|
||||
|
||||
$feature_policy = implode(';', $feature_policy);
|
||||
|
||||
@@ -25,7 +25,6 @@ class AssetCheckoutRequest extends Request
|
||||
'assigned_user' => 'required_without_all:assigned_asset,assigned_location',
|
||||
'assigned_asset' => 'required_without_all:assigned_user,assigned_location',
|
||||
'assigned_location' => 'required_without_all:assigned_user,assigned_asset',
|
||||
'status_id' => 'exists:status_labels,id,deployable,1',
|
||||
'checkout_to_type' => 'required|in:asset,location,user',
|
||||
];
|
||||
|
||||
|
||||
@@ -60,8 +60,8 @@ class ItemImportRequest extends FormRequest
|
||||
}
|
||||
$importer->setCallbacks([$this, 'log'], [$this, 'progress'], [$this, 'errorCallback'])
|
||||
->setUserId(Auth::id())
|
||||
->setUpdating($this->get('import-update'))
|
||||
->setShouldNotify($this->get('send-welcome'))
|
||||
->setUpdating($this->has('import-update'))
|
||||
->setShouldNotify($this->has('send-welcome'))
|
||||
->setUsernameFormat('firstname.lastname')
|
||||
->setFieldMappings($fieldMappings);
|
||||
$importer->import();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
@@ -8,82 +9,82 @@ use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class ActionlogsTransformer
|
||||
{
|
||||
|
||||
public function transformActionlogs (Collection $actionlogs, $total)
|
||||
public function transformActionlogs(Collection $actionlogs, $total)
|
||||
{
|
||||
$array = array();
|
||||
$array = [];
|
||||
$settings = Setting::getSettings();
|
||||
foreach ($actionlogs as $actionlog) {
|
||||
$array[] = self::transformActionlog($actionlog, $settings);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
private function clean_field($value)
|
||||
{
|
||||
// This object stuff is weird, and is used to make up for the fact that
|
||||
// older data can get strangely formatted if an asset existed,
|
||||
// then a new custom field is added, and the asset is saved again.
|
||||
// It can result in funnily-formatted strings like:
|
||||
//
|
||||
// {"_snipeit_right_sized_fault_tolerant_localareanetwo_1":
|
||||
// {"old":null,"new":{"value":"1579490695972","_snipeit_new_field_2":2,"_snipeit_new_field_3":"Monday, 20 January 2020 2:24:55 PM"}}
|
||||
// so we have to walk down that next level
|
||||
if(is_object($value) && isset($value->value)) {
|
||||
return $this->clean_field($value->value);
|
||||
}
|
||||
return is_scalar($value) || is_null($value) ? e($value) : e(json_encode($value));
|
||||
}
|
||||
|
||||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||
public function transformActionlog(Actionlog $actionlog, $settings = null)
|
||||
{
|
||||
$icon = $actionlog->present()->icon();
|
||||
if ($actionlog->filename!='') {
|
||||
$icon = e(\App\Helpers\Helper::filetype_icon($actionlog->filename));
|
||||
if ($actionlog->filename != '') {
|
||||
$icon = e(Helper::filetype_icon($actionlog->filename));
|
||||
}
|
||||
|
||||
// This is necessary since we can't escape special characters within a JSON object
|
||||
if (($actionlog->log_meta) && ($actionlog->log_meta!='')) {
|
||||
if (($actionlog->log_meta) && ($actionlog->log_meta != '')) {
|
||||
$meta_array = json_decode($actionlog->log_meta);
|
||||
|
||||
if ($meta_array) {
|
||||
foreach ($meta_array as $fieldname => $fieldata) {
|
||||
$clean_meta[$fieldname]['old'] = $this->clean_field($fieldata->old);
|
||||
$clean_meta[$fieldname]['new'] = $this->clean_field($fieldata->new);
|
||||
}
|
||||
foreach ($meta_array as $key => $value) {
|
||||
foreach ($value as $meta_key => $meta_value) {
|
||||
if (is_array($meta_value)) {
|
||||
foreach ($meta_value as $meta_value_key => $meta_value_value) {
|
||||
if (is_scalar($meta_value_value)) {
|
||||
$clean_meta[$key][$meta_value_key] = e($meta_value_value);
|
||||
} else {
|
||||
$clean_meta[$key][$meta_value_key] = 'invalid scalar: '.print_r($meta_value_value, true);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
// This object stuff is weird, and is used to make up for the fact that
|
||||
// older data can get strangely formatted if an asset existed,
|
||||
// then a new custom field is added, and the asset is saved again.
|
||||
// It can result in funnily-formatted strings like:
|
||||
//
|
||||
// {"_snipeit_right_sized_fault_tolerant_localareanetwo_1":
|
||||
// {"old":null,"new":{"value":"1579490695972","_snipeit_new_field_2":2,"_snipeit_new_field_3":"Monday, 20 January 2020 2:24:55 PM"}}
|
||||
// so we have to walk down that next level
|
||||
|
||||
$file_url = '';
|
||||
if($actionlog->filename!='') {
|
||||
if ($actionlog->present()->actionType() == 'accepted') {
|
||||
$file_url = route('log.storedeula.download', ['filename' => $actionlog->filename]);
|
||||
} else {
|
||||
if ($actionlog->itemType() == 'asset') {
|
||||
$file_url = route('show/assetfile', ['assetId' => $actionlog->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'license') {
|
||||
$file_url = route('show.licensefile', ['licenseId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
} elseif ($actionlog->itemType() == 'user') {
|
||||
$file_url = route('show/userfile', ['userId' => $actionlog->item->id, 'fileId' => $actionlog->id]);
|
||||
if (is_object($meta_value)) {
|
||||
foreach ($meta_value as $meta_value_key => $meta_value_value) {
|
||||
if ($meta_value_key == 'value') {
|
||||
$clean_meta[$key]['old'] = null;
|
||||
$clean_meta[$key]['new'] = e($meta_value->value);
|
||||
} else {
|
||||
$clean_meta[$meta_value_key]['old'] = null;
|
||||
$clean_meta[$meta_value_key]['new'] = e($meta_value_value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$clean_meta[$key][$meta_key] = e($meta_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$array = [
|
||||
$array = [
|
||||
'id' => (int) $actionlog->id,
|
||||
'icon' => $icon,
|
||||
'file' => ($actionlog->filename!='')
|
||||
?
|
||||
'file' => ($actionlog->filename != '') ?
|
||||
[
|
||||
'url' => $file_url,
|
||||
'url' => route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]),
|
||||
'filename' => $actionlog->filename,
|
||||
'inlineable' => (bool) Helper::show_file_inline($actionlog->filename),
|
||||
] : null,
|
||||
|
||||
'item' => ($actionlog->item) ? [
|
||||
'id' => (int) $actionlog->item->id,
|
||||
'name' => ($actionlog->itemType()=='user') ? e($actionlog->item->getFullNameAttribute()) : e($actionlog->item->getDisplayNameAttribute()),
|
||||
'name' => ($actionlog->itemType() == 'user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
|
||||
'type' => e($actionlog->itemType()),
|
||||
] : null,
|
||||
'location' => ($actionlog->location) ? [
|
||||
@@ -92,18 +93,18 @@ class ActionlogsTransformer
|
||||
] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'),
|
||||
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(null, $actionlog->item), 'date'): null,
|
||||
'next_audit_date' => ($actionlog->itemType() == 'asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(null, $actionlog->item), 'date') : null,
|
||||
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
|
||||
'action_type' => $actionlog->present()->actionType(),
|
||||
'admin' => ($actionlog->user) ? [
|
||||
'id' => (int) $actionlog->user->id,
|
||||
'name' => e($actionlog->user->getFullNameAttribute()),
|
||||
'first_name'=> e($actionlog->user->first_name),
|
||||
'last_name'=> e($actionlog->user->last_name)
|
||||
'last_name'=> e($actionlog->user->last_name),
|
||||
] : null,
|
||||
'target' => ($actionlog->target) ? [
|
||||
'id' => (int) $actionlog->target->id,
|
||||
'name' => ($actionlog->targetType()=='user') ? e($actionlog->target->getFullNameAttribute()) : e($actionlog->target->getDisplayNameAttribute()),
|
||||
'name' => ($actionlog->targetType() == 'user') ? e($actionlog->target->getFullNameAttribute()) : e($actionlog->target->getDisplayNameAttribute()),
|
||||
'type' => e($actionlog->targetType()),
|
||||
] : null,
|
||||
|
||||
@@ -111,25 +112,19 @@ class ActionlogsTransformer
|
||||
'signature_file' => ($actionlog->accept_signature) ? route('log.signature.view', ['filename' => $actionlog->accept_signature ]) : null,
|
||||
'log_meta' => ((isset($clean_meta)) && (is_array($clean_meta))) ? $clean_meta: null,
|
||||
'action_date' => ($actionlog->action_date) ? Helper::getFormattedDateObject($actionlog->action_date, 'datetime'): Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
||||
];
|
||||
//\Log::info("Clean Meta is: ".print_r($clean_meta,true));
|
||||
|
||||
//dd($array);
|
||||
];
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function transformCheckedoutActionlog (Collection $accessories_users, $total)
|
||||
public function transformCheckedoutActionlog(Collection $accessories_users, $total)
|
||||
{
|
||||
|
||||
$array = array();
|
||||
$array = [];
|
||||
foreach ($accessories_users as $user) {
|
||||
$array[] = (new UsersTransformer)->transformUser($user);
|
||||
}
|
||||
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ namespace App\Http\Transformers;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Setting;
|
||||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
@@ -22,9 +21,6 @@ class AssetsTransformer
|
||||
|
||||
public function transformAsset(Asset $asset)
|
||||
{
|
||||
// This uses the getSettings() method so we're pulling from the cache versus querying the settings on single asset
|
||||
$setting = Setting::getSettings();
|
||||
|
||||
$array = [
|
||||
'id' => (int) $asset->id,
|
||||
'name' => e($asset->name),
|
||||
@@ -69,8 +65,6 @@ class AssetsTransformer
|
||||
'name'=> e($asset->defaultLoc->name),
|
||||
] : null,
|
||||
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
|
||||
'qr' => ($setting->qr_code=='1') ? config('app.url').'/uploads/barcodes/qr-'.str_slug($asset->asset_tag).'-'.str_slug($asset->id).'.png' : null,
|
||||
'alt_barcode' => ($setting->alt_barcode_enabled=='1') ? config('app.url').'/uploads/barcodes/'.str_slug($setting->alt_barcode).'-'.str_slug($asset->asset_tag).'.png' : null,
|
||||
'assigned_to' => $this->transformAssignedTo($asset),
|
||||
'warranty_months' => ($asset->warranty_months > 0) ? e($asset->warranty_months.' '.trans('admin/hardware/form.months')) : null,
|
||||
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
|
||||
@@ -98,36 +92,21 @@ class AssetsTransformer
|
||||
$decrypted = Helper::gracefulDecrypt($field, $asset->{$field->convertUnicodeDbSlug()});
|
||||
$value = (Gate::allows('superadmin')) ? $decrypted : strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
|
||||
if ($field->format == 'DATE'){
|
||||
if (Gate::allows('superadmin')){
|
||||
$value = Helper::getFormattedDateObject($value)['formatted'];
|
||||
} else {
|
||||
$value = strtoupper(trans('admin/custom_fields/general.encrypted'));
|
||||
}
|
||||
}
|
||||
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->convertUnicodeDbSlug()),
|
||||
'value' => e($value),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
|
||||
];
|
||||
|
||||
} else {
|
||||
$value = $asset->{$field->convertUnicodeDbSlug()};
|
||||
|
||||
if ($field->format == 'DATE'){
|
||||
$value = Helper::getFormattedDateObject($value)['formatted'];
|
||||
}
|
||||
$fields_array[$field->name] = [
|
||||
'field' => e($field->convertUnicodeDbSlug()),
|
||||
'value' => e($value),
|
||||
'value' => e($asset->{$field->convertUnicodeDbSlug()}),
|
||||
'field_format' => $field->format,
|
||||
'element' => $field->element,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
$array['custom_fields'] = $fields_array;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -45,7 +45,6 @@ class ComponentsTransformer
|
||||
'id' => (int) $component->company->id,
|
||||
'name' => e($component->company->name),
|
||||
] : null,
|
||||
'notes' => ($component->notes) ? e($component->notes) : null,
|
||||
'created_at' => Helper::getFormattedDateObject($component->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($component->updated_at, 'datetime'),
|
||||
'user_can_checkout' => ($component->numRemaining() > 0) ? 1 : 0,
|
||||
|
||||
@@ -38,7 +38,6 @@ class ConsumablesTransformer
|
||||
'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost),
|
||||
'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'),
|
||||
'qty' => (int) $consumable->qty,
|
||||
'notes' => ($consumable->notes) ? e($consumable->notes) : null,
|
||||
'created_at' => Helper::getFormattedDateObject($consumable->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($consumable->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -46,7 +46,7 @@ class CustomFieldsTransformer
|
||||
'field_values' => ($field->field_values) ? e($field->field_values) : null,
|
||||
'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,
|
||||
'required' => $field->pivot ? $field->pivot->required : false,
|
||||
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -98,7 +98,7 @@ class DepreciationReportTransformer
|
||||
'purchase_cost' => Helper::formatCurrencyOutput($asset->purchase_cost),
|
||||
'book_value' => Helper::formatCurrencyOutput($depreciated_value),
|
||||
'monthly_depreciation' => $monthly_depreciation,
|
||||
'checked_out_to' => ($checkout_target) ? e($checkout_target) : null,
|
||||
'checked_out_to' => $checkout_target,
|
||||
'diff' => Helper::formatCurrencyOutput($diff),
|
||||
'number_of_months' => ($asset->model && $asset->model->depreciation) ? e($asset->model->depreciation->months) : null,
|
||||
'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? e($asset->model->depreciation->name) : null,
|
||||
|
||||
@@ -28,7 +28,6 @@ class UsersTransformer
|
||||
'first_name' => e($user->first_name),
|
||||
'last_name' => e($user->last_name),
|
||||
'username' => e($user->username),
|
||||
'remote' => ($user->remote == '1') ? true : false,
|
||||
'locale' => ($user->locale) ? e($user->locale) : null,
|
||||
'employee_num' => e($user->employee_num),
|
||||
'manager' => ($user->manager) ? [
|
||||
|
||||
@@ -39,7 +39,6 @@ class AssetImporter extends ItemImporter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$this->createAssetIfNotExists($row);
|
||||
}
|
||||
|
||||
@@ -97,12 +96,10 @@ class AssetImporter extends ItemImporter
|
||||
$item['rtd_location_id'] = $this->item['location_id'];
|
||||
}
|
||||
|
||||
$item['last_audit_date'] = null;
|
||||
if (isset($this->item['last_audit_date'])) {
|
||||
$item['last_audit_date'] = $this->item['last_audit_date'];
|
||||
}
|
||||
|
||||
$item['next_audit_date'] = null;
|
||||
if (isset($this->item['next_audit_date'])) {
|
||||
$item['next_audit_date'] = $this->item['next_audit_date'];
|
||||
}
|
||||
@@ -130,7 +127,7 @@ class AssetImporter extends ItemImporter
|
||||
//-- user_id is a property of the abstract class Importer, which this class inherits from and it's setted by
|
||||
//-- the class that needs to use it (command importer or GUI importer inside the project).
|
||||
if (isset($target)) {
|
||||
$asset->fresh()->checkOut($target, $this->user_id, date('Y-m-d H:i:s'));
|
||||
$asset->fresh()->checkOut($target, $this->user_id);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
@@ -35,7 +35,7 @@ class LicenseImporter extends ItemImporter
|
||||
->first();
|
||||
if ($license) {
|
||||
if (! $this->updating) {
|
||||
$this->log('A matching License '.$this->item['name'].' with serial '.$this->item['serial'].' already exists');
|
||||
$this->log('A matching License '.$this->item['name'].'with serial '.$this->item['serial'].' already exists');
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -47,22 +47,14 @@ class LicenseImporter extends ItemImporter
|
||||
$license = new License;
|
||||
}
|
||||
$asset_tag = $this->item['asset_tag'] = $this->findCsvMatch($row, 'asset_tag'); // used for checkout out to an asset.
|
||||
|
||||
$this->item["expiration_date"] = null;
|
||||
if ($this->findCsvMatch($row, "expiration_date")!='') {
|
||||
$this->item["expiration_date"] = date("Y-m-d 00:00:01", strtotime($this->findCsvMatch($row, "expiration_date")));
|
||||
}
|
||||
$this->item['expiration_date'] = $this->findCsvMatch($row, 'expiration_date');
|
||||
$this->item['license_email'] = $this->findCsvMatch($row, 'license_email');
|
||||
$this->item['license_name'] = $this->findCsvMatch($row, 'license_name');
|
||||
$this->item['maintained'] = $this->findCsvMatch($row, 'maintained');
|
||||
$this->item['purchase_order'] = $this->findCsvMatch($row, 'purchase_order');
|
||||
$this->item['reassignable'] = $this->findCsvMatch($row, 'reassignable');
|
||||
$this->item['seats'] = $this->findCsvMatch($row, 'seats');
|
||||
|
||||
$this->item["termination_date"] = null;
|
||||
if ($this->findCsvMatch($row, "termination_date")!='') {
|
||||
$this->item["termination_date"] = date("Y-m-d 00:00:01", strtotime($this->findCsvMatch($row, "termination_date")));
|
||||
}
|
||||
$this->item['termination_date'] = $this->findCsvMatch($row, 'termination_date');
|
||||
|
||||
if ($editingLicense) {
|
||||
$license->update($this->sanitizeItemForUpdating($license));
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Importer;
|
||||
|
||||
use App\Models\Department;
|
||||
use App\Models\Setting;
|
||||
use App\Models\User;
|
||||
use App\Notifications\WelcomeNotification;
|
||||
|
||||
@@ -61,13 +60,6 @@ class UserImporter extends ItemImporter
|
||||
if ($this->shouldUpdateField($user_department)) {
|
||||
$this->item['department_id'] = $this->createOrFetchDepartment($user_department);
|
||||
}
|
||||
|
||||
if (is_null($this->item['username']) || $this->item['username'] == "") {
|
||||
$user_full_name = $this->item['first_name'] . ' ' . $this->item['last_name'];
|
||||
$user_formatted_array = User::generateFormattedNameFromFullName($user_full_name, Setting::getSettings()->username_format);
|
||||
$this->item['username'] = $user_formatted_array['username'];
|
||||
}
|
||||
|
||||
$user = User::where('username', $this->item['username'])->first();
|
||||
if ($user) {
|
||||
if (! $this->updating) {
|
||||
|
||||
@@ -24,13 +24,10 @@ use Illuminate\Support\Facades\Notification;
|
||||
class CheckoutableListener
|
||||
{
|
||||
/**
|
||||
* Notify the user about the checked out checkoutable and add a record to the
|
||||
* checkout_requests table.
|
||||
* Notify the user about the checked out checkoutable
|
||||
*/
|
||||
public function onCheckedOut($event)
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
@@ -61,12 +58,14 @@ class CheckoutableListener
|
||||
*/
|
||||
public function onCheckedIn($event)
|
||||
{
|
||||
\Log::debug('onCheckedIn in the Checkoutable listener fired');
|
||||
\Log::debug('checkin fired');
|
||||
|
||||
/**
|
||||
* When the item wasn't checked out to a user, we can't send notifications
|
||||
*/
|
||||
if (! $event->checkedOutTo instanceof User) {
|
||||
\Log::debug('checked out to not a user');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,14 +81,16 @@ class CheckoutableListener
|
||||
$acceptance->delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Use default locale
|
||||
\Log::debug('checked out to a user');
|
||||
if (! $event->checkedOutTo->locale) {
|
||||
\Log::debug('Use default settings locale');
|
||||
Notification::locale(Setting::getSettings()->locale)->send(
|
||||
$this->getNotifiables($event),
|
||||
$this->getCheckinNotification($event)
|
||||
);
|
||||
} else {
|
||||
\Log::debug('Use user locale? I do not think this works as expected yet');
|
||||
// \Log::debug(print_r($this->getNotifiables($event), true));
|
||||
Notification::send(
|
||||
$this->getNotifiables($event),
|
||||
$this->getCheckinNotification($event)
|
||||
@@ -150,6 +151,10 @@ class CheckoutableListener
|
||||
private function getCheckinNotification($event)
|
||||
{
|
||||
|
||||
// $model = get_class($event->checkoutable);
|
||||
|
||||
|
||||
|
||||
$notificationClass = null;
|
||||
|
||||
switch (get_class($event->checkoutable)) {
|
||||
|
||||
@@ -22,44 +22,23 @@ use App\Models\LicenseSeat;
|
||||
|
||||
class LogListener
|
||||
{
|
||||
/**
|
||||
* These onBlah methods are used by the subscribe() method further down in this file.
|
||||
* This one creates an action_logs entry for the checkin
|
||||
* @param CheckoutableCheckedIn $event
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
public function onCheckoutableCheckedIn(CheckoutableCheckedIn $event)
|
||||
{
|
||||
$event->checkoutable->logCheckin($event->checkedOutTo, $event->note, $event->action_date);
|
||||
}
|
||||
|
||||
/**
|
||||
* These onBlah methods are used by the subscribe() method further down in this file.
|
||||
* This one creates an action_logs entry for the checkout
|
||||
*
|
||||
* @param CheckoutableCheckedOut $event
|
||||
* @return void
|
||||
*
|
||||
*/
|
||||
public function onCheckoutableCheckedOut(CheckoutableCheckedOut $event)
|
||||
{
|
||||
$event->checkoutable->logCheckout($event->note, $event->checkedOutTo, $event->checkoutable->last_checkout);
|
||||
}
|
||||
|
||||
/**
|
||||
* These onBlah methods are used by the subscribe() method further down in this file.
|
||||
* This creates the entry in the action_logs table for the accept/decline action
|
||||
*/
|
||||
public function onCheckoutAccepted(CheckoutAccepted $event)
|
||||
{
|
||||
|
||||
\Log::error('event passed to the onCheckoutAccepted listener:');
|
||||
$logaction = new Actionlog();
|
||||
|
||||
$logaction->item()->associate($event->acceptance->checkoutable);
|
||||
$logaction->target()->associate($event->acceptance->assignedTo);
|
||||
$logaction->accept_signature = $event->acceptance->signature_filename;
|
||||
$logaction->filename = $event->acceptance->stored_eula_file;
|
||||
$logaction->action_type = 'accepted';
|
||||
|
||||
// TODO: log the actual license seat that was checked out
|
||||
@@ -67,7 +46,6 @@ class LogListener
|
||||
$logaction->item()->associate($event->acceptance->checkoutable->license);
|
||||
}
|
||||
|
||||
\Log::debug('New onCheckoutAccepted Listener fired. logaction: '.print_r($logaction, true));
|
||||
$logaction->save();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class Accessory extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'model_number', 'order_number', 'purchase_date', 'notes'];
|
||||
protected $searchableAttributes = ['name', 'model_number', 'order_number', 'purchase_date'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
@@ -61,10 +61,9 @@ class Accessory extends SnipeModel
|
||||
'category_id' => 'required|integer|exists:categories,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'min_amt' => 'integer|min:0|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
'purchase_cost' => 'numeric|nullable',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Whether the model should inject it's identifier to the unique
|
||||
* validation rules before attempting validation. If this property
|
||||
@@ -95,7 +94,6 @@ class Accessory extends SnipeModel
|
||||
'qty',
|
||||
'min_amt',
|
||||
'requestable',
|
||||
'notes',
|
||||
];
|
||||
|
||||
|
||||
@@ -112,7 +110,6 @@ class Accessory extends SnipeModel
|
||||
return $this->belongsTo(\App\Models\Supplier::class, 'supplier_id');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the requestable attribute on the accessory
|
||||
*
|
||||
@@ -223,8 +220,8 @@ class Accessory extends SnipeModel
|
||||
if ($this->image) {
|
||||
return Storage::disk('public')->url(app('accessories_upload_path').$this->image);
|
||||
}
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,21 +307,6 @@ class Accessory extends SnipeModel
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many items within an accessory are checked out
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0]
|
||||
* @return int
|
||||
*/
|
||||
public function numCheckedOut()
|
||||
{
|
||||
$checkedout = 0;
|
||||
$checkedout = $this->users->count();
|
||||
|
||||
return $checkedout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many items of an accessory remain
|
||||
*
|
||||
|
||||
@@ -25,7 +25,7 @@ class Actionlog extends SnipeModel
|
||||
|
||||
protected $table = 'action_logs';
|
||||
public $timestamps = true;
|
||||
protected $fillable = ['created_at', 'item_type', 'user_id', 'item_id', 'action_type', 'note', 'target_id', 'target_type', 'stored_eula'];
|
||||
protected $fillable = ['created_at', 'item_type', 'user_id', 'item_id', 'action_type', 'note', 'target_id', 'target_type'];
|
||||
|
||||
use Searchable;
|
||||
|
||||
@@ -34,7 +34,7 @@ class Actionlog extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['action_type', 'note', 'log_meta','user_id'];
|
||||
protected $searchableAttributes = ['action_type', 'note', 'log_meta'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
@@ -43,7 +43,6 @@ class Actionlog extends SnipeModel
|
||||
*/
|
||||
protected $searchableRelations = [
|
||||
'company' => ['name'],
|
||||
'user' => ['first_name','last_name','username'],
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -70,7 +69,6 @@ class Actionlog extends SnipeModel
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the actionlog -> item relationship
|
||||
*
|
||||
@@ -127,7 +125,6 @@ class Actionlog extends SnipeModel
|
||||
return camel_case(class_basename($this->target_type));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the actionlog -> uploads relationship
|
||||
*
|
||||
@@ -191,7 +188,6 @@ class Actionlog extends SnipeModel
|
||||
return $this->belongsTo(\App\Models\Location::class, 'location_id')->withTrashed();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the file exists, and if it does, force a download
|
||||
*
|
||||
|
||||
+2
-19
@@ -111,7 +111,7 @@ class Asset extends Depreciable
|
||||
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
|
||||
'status' => 'integer',
|
||||
'serial' => 'unique_serial|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
'purchase_cost' => 'numeric|nullable',
|
||||
'next_audit_date' => 'date|nullable',
|
||||
'last_audit_date' => 'date|nullable',
|
||||
'supplier_id' => 'exists:suppliers,id|nullable',
|
||||
@@ -195,25 +195,10 @@ class Asset extends Depreciable
|
||||
$model = AssetModel::find($this->model_id);
|
||||
|
||||
if (($model) && ($model->fieldset)) {
|
||||
|
||||
foreach ($model->fieldset->fields as $field){
|
||||
if($field->format == 'BOOLEAN'){
|
||||
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
|
||||
$this->rules += $model->fieldset->validation_rules();
|
||||
|
||||
foreach ($this->model->fieldset->fields as $field){
|
||||
if($field->format == 'BOOLEAN'){
|
||||
$this->{$field->db_column} = filter_var($this->{$field->db_column}, FILTER_VALIDATE_BOOLEAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return parent::save($params);
|
||||
}
|
||||
|
||||
@@ -1187,9 +1172,7 @@ class Asset extends Depreciable
|
||||
|
||||
public function scopeRequestableAssets($query)
|
||||
{
|
||||
$table = $query->getModel()->getTable();
|
||||
|
||||
return Company::scopeCompanyables($query->where($table.'.requestable', '=', 1))
|
||||
return Company::scopeCompanyables($query->where('requestable', '=', 1))
|
||||
->whereHas('assetstatus', function ($query) {
|
||||
$query->where(function ($query) {
|
||||
$query->where('deployable', '=', 1)
|
||||
|
||||
@@ -57,24 +57,20 @@ class CheckoutAcceptance extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a record to the checkout_acceptance table ONLY.
|
||||
* Do not add stuff here that doesn't have a corresponding column in the
|
||||
* checkout_acceptances table or you'll get an error.
|
||||
* Accept the checkout acceptance
|
||||
*
|
||||
* @param string $signature_filename
|
||||
*/
|
||||
public function accept($signature_filename, $eula = null, $filename = null)
|
||||
public function accept($signature_filename)
|
||||
{
|
||||
$this->accepted_at = now();
|
||||
$this->signature_filename = $signature_filename;
|
||||
$this->stored_eula = $eula;
|
||||
$this->stored_eula_file = $filename;
|
||||
$this->save();
|
||||
|
||||
/**
|
||||
* Update state for the checked out item
|
||||
*/
|
||||
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename, $filename);
|
||||
$this->checkoutable->acceptedCheckout($this->assignedTo, $signature_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ class Component extends SnipeModel
|
||||
'company_id' => 'integer|nullable',
|
||||
'min_amt' => 'integer|min:0|nullable',
|
||||
'purchase_date' => 'date|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
'purchase_cost' => 'numeric|nullable',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -65,7 +65,6 @@ class Component extends SnipeModel
|
||||
'order_number',
|
||||
'qty',
|
||||
'serial',
|
||||
'notes',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
@@ -75,7 +74,7 @@ class Component extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'order_number', 'serial', 'purchase_cost', 'purchase_date', 'notes'];
|
||||
protected $searchableAttributes = ['name', 'order_number', 'serial', 'purchase_cost', 'purchase_date'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
|
||||
@@ -27,8 +27,7 @@ class Consumable extends SnipeModel
|
||||
'category_id' => 'integer',
|
||||
'company_id' => 'integer',
|
||||
'qty' => 'integer',
|
||||
'min_amt' => 'integer',
|
||||
];
|
||||
'min_amt' => 'integer', ];
|
||||
|
||||
/**
|
||||
* Category validation rules
|
||||
@@ -39,7 +38,7 @@ class Consumable extends SnipeModel
|
||||
'category_id' => 'required|integer',
|
||||
'company_id' => 'integer|nullable',
|
||||
'min_amt' => 'integer|min:0|nullable',
|
||||
'purchase_cost' => 'numeric|nullable|gte:0',
|
||||
'purchase_cost' => 'numeric|nullable',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -71,7 +70,6 @@ class Consumable extends SnipeModel
|
||||
'qty',
|
||||
'min_amt',
|
||||
'requestable',
|
||||
'notes',
|
||||
];
|
||||
|
||||
use Searchable;
|
||||
@@ -81,7 +79,7 @@ class Consumable extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $searchableAttributes = ['name', 'order_number', 'purchase_cost', 'purchase_date', 'item_no', 'model_number', 'notes'];
|
||||
protected $searchableAttributes = ['name', 'order_number', 'purchase_cost', 'purchase_date', 'item_no', 'model_number'];
|
||||
|
||||
/**
|
||||
* The relations and their attributes that should be included when searching the model.
|
||||
@@ -276,21 +274,6 @@ class Consumable extends SnipeModel
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check how many items within a consumable are checked out
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v5.0]
|
||||
* @return int
|
||||
*/
|
||||
public function numCheckedOut()
|
||||
{
|
||||
$checkedout = 0;
|
||||
$checkedout = $this->users->count();
|
||||
|
||||
return $checkedout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the number of available consumables
|
||||
*
|
||||
|
||||
+7
-9
@@ -37,7 +37,7 @@ class Ldap extends Model
|
||||
public static function connectToLdap()
|
||||
{
|
||||
$ldap_host = Setting::getSettings()->ldap_server;
|
||||
$ldap_version = Setting::getSettings()->ldap_version ?: 3;
|
||||
$ldap_version = Setting::getSettings()->ldap_version;
|
||||
$ldap_server_cert_ignore = Setting::getSettings()->ldap_server_cert_ignore;
|
||||
$ldap_use_tls = Setting::getSettings()->ldap_tls;
|
||||
|
||||
@@ -64,8 +64,8 @@ class Ldap extends Model
|
||||
ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20);
|
||||
|
||||
if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) {
|
||||
ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
||||
ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
||||
ldap_set_option($connection, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path());
|
||||
ldap_set_option($connection, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path());
|
||||
}
|
||||
|
||||
if ($ldap_use_tls=='1') {
|
||||
@@ -208,7 +208,6 @@ class Ldap extends Model
|
||||
$ldap_result_jobtitle = Setting::getSettings()->ldap_jobtitle;
|
||||
$ldap_result_country = Setting::getSettings()->ldap_country;
|
||||
$ldap_result_dept = Setting::getSettings()->ldap_dept;
|
||||
$ldap_result_manager = Setting::getSettings()->ldap_manager;
|
||||
// Get LDAP user data
|
||||
$item = [];
|
||||
$item['username'] = isset($ldapattributes[$ldap_result_username][0]) ? $ldapattributes[$ldap_result_username][0] : '';
|
||||
@@ -220,7 +219,6 @@ class Ldap extends Model
|
||||
$item['jobtitle'] = isset($ldapattributes[$ldap_result_jobtitle][0]) ? $ldapattributes[$ldap_result_jobtitle][0] : '';
|
||||
$item['country'] = isset($ldapattributes[$ldap_result_country][0]) ? $ldapattributes[$ldap_result_country][0] : '';
|
||||
$item['department'] = isset($ldapattributes[$ldap_result_dept][0]) ? $ldapattributes[$ldap_result_dept][0] : '';
|
||||
$item['manager'] = isset($ldapattributes[$ldap_result_manager][0]) ? $ldapattributes[$ldap_result_manager][0] : '';
|
||||
|
||||
return $item;
|
||||
}
|
||||
@@ -233,7 +231,7 @@ class Ldap extends Model
|
||||
* @param $ldapatttibutes
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function createUserFromLdap($ldapatttibutes, $password)
|
||||
public static function createUserFromLdap($ldapatttibutes)
|
||||
{
|
||||
$item = self::parseAndMapLdapAttributes($ldapatttibutes);
|
||||
|
||||
@@ -246,8 +244,7 @@ class Ldap extends Model
|
||||
$user->email = $item['email'];
|
||||
|
||||
if (Setting::getSettings()->ldap_pw_sync == '1') {
|
||||
|
||||
$user->password = bcrypt($password);
|
||||
$user->password = bcrypt(Input::get('password'));
|
||||
} else {
|
||||
$pass = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'), 0, 25);
|
||||
$user->password = bcrypt($pass);
|
||||
@@ -304,13 +301,14 @@ class Ldap extends Model
|
||||
|
||||
// HUGE thanks to this article: https://stackoverflow.com/questions/68275972/how-to-get-paged-ldap-queries-in-php-8-and-read-more-than-1000-entries
|
||||
// which helped me wrap my head around paged results!
|
||||
\Log::info("ldap conn is: ".$ldapconn." basedn is: $base_dn, filter is: $filter - count is: $count. page size is: $page_size"); //FIXME - remove
|
||||
// if a $count is set and it's smaller than $page_size then use that as the page size
|
||||
$ldap_controls = [];
|
||||
//if($count == -1) { //count is -1 means we have to employ paging to query the entire directory
|
||||
$ldap_controls = [['oid' => LDAP_CONTROL_PAGEDRESULTS, 'iscritical' => false, 'value' => ['size'=> $count == -1||$count>$page_size ? $page_size : $count, 'cookie' => $cookie]]];
|
||||
//}
|
||||
$search_results = ldap_search($ldapconn, $base_dn, $filter, [], 0, /* $page_size */ -1, -1, LDAP_DEREF_NEVER, $ldap_controls); // TODO - I hate the @, and I hate that we get a full page even if we ask for 10 records. Can we use an ldap_control?
|
||||
\Log::debug("did the search run? I guess so if you got here!");
|
||||
\Log::info("did the search run? I guess so if you got here!");
|
||||
if (! $search_results) {
|
||||
return redirect()->route('users.index')->with('error', trans('admin/users/message.error.ldap_could_not_search').ldap_error($ldapconn)); // TODO this is never called in any routed context - only from the Artisan command. So this redirect will never work.
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ class License extends Depreciable
|
||||
'notes' => 'string|nullable',
|
||||
'category_id' => 'required|exists:categories,id',
|
||||
'company_id' => 'integer|nullable',
|
||||
'purchase_cost'=> 'numeric|nullable|gte:0',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -187,7 +186,6 @@ class License extends Depreciable
|
||||
];
|
||||
}
|
||||
//Chunk and use DB transactions to prevent timeouts.
|
||||
|
||||
collect($licenseInsert)->chunk(1000)->each(function ($chunk) {
|
||||
DB::transaction(function () use ($chunk) {
|
||||
LicenseSeat::insert($chunk->toArray());
|
||||
@@ -390,7 +388,6 @@ class License extends Depreciable
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the license -> admin user relationship
|
||||
*
|
||||
@@ -620,7 +617,6 @@ class License extends Depreciable
|
||||
->first();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the license -> free seats relationship
|
||||
*
|
||||
|
||||
@@ -103,7 +103,6 @@ class Location extends SnipeModel
|
||||
return $this->hasMany(\App\Models\User::class, 'location_id');
|
||||
}
|
||||
|
||||
|
||||
public function assets()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Asset::class, 'location_id')
|
||||
@@ -130,23 +129,6 @@ class Location extends SnipeModel
|
||||
return $this->hasMany(\App\Models\Asset::class, 'rtd_location_id');
|
||||
}
|
||||
|
||||
public function consumables()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Consumable::class, 'location_id');
|
||||
}
|
||||
|
||||
public function components()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Component::class, 'location_id');
|
||||
}
|
||||
|
||||
public function accessories()
|
||||
{
|
||||
return $this->hasMany(\App\Models\Accessory::class, 'location_id');
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo(self::class, 'parent_id', 'id')
|
||||
|
||||
@@ -114,13 +114,6 @@ trait Loggable
|
||||
$log->location_id = null;
|
||||
$log->note = $note;
|
||||
$log->action_date = $action_date;
|
||||
if (! $log->action_date) {
|
||||
$log->action_date = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
if (! $log->action_date) {
|
||||
$log->action_date = date('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
if (Auth::user()) {
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
||||
@@ -9,6 +9,6 @@ class AdminRecipient extends Recipient
|
||||
public function __construct()
|
||||
{
|
||||
$settings = Setting::getSettings();
|
||||
$this->email = trim($settings->admin_cc_email);
|
||||
$this->email = $settings->admin_cc_email;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class SCIMUser extends User
|
||||
{
|
||||
protected $table = 'users';
|
||||
|
||||
protected $throwValidationExceptions = true; // we want model-level validation to fully THROW, not just return false
|
||||
|
||||
public function __construct(array $attributes = []) {
|
||||
$attributes['password'] = "*NO PASSWORD*";
|
||||
// $attributes['activated'] = 1;
|
||||
parent::__construct($attributes);
|
||||
}
|
||||
}
|
||||
@@ -218,7 +218,6 @@ class Setting extends Model
|
||||
*/
|
||||
public static function fileSizeConvert($bytes): string
|
||||
{
|
||||
$result = 0;
|
||||
$bytes = floatval($bytes);
|
||||
$arBytes = [
|
||||
0 => [
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Helper;
|
||||
use ArieTimmerman\Laravel\SCIMServer\SCIM\Schema;
|
||||
use ArieTimmerman\Laravel\SCIMServer\Attribute\AttributeMapping;
|
||||
|
||||
|
||||
class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig
|
||||
{
|
||||
public function getUserConfig()
|
||||
{
|
||||
$config = parent::getUserConfig();
|
||||
|
||||
// Much of this is copied verbatim from the library, then adjusted for our needs
|
||||
$config['class'] = SCIMUser::class;
|
||||
|
||||
unset($config['mapping']['example:name:space']);
|
||||
|
||||
$config['map_unmapped'] = false; // anything we don't explicitly map will _not_ show up.
|
||||
|
||||
$core_namespace = 'urn:ietf:params:scim:schemas:core:2.0:User';
|
||||
$core = $core_namespace.':';
|
||||
$mappings =& $config['mapping'][$core_namespace]; //grab this entire key, we don't want to be repeating ourselves
|
||||
|
||||
//username - *REQUIRED*
|
||||
$config['validations'][$core.'userName'] = 'required';
|
||||
$mappings['userName'] = AttributeMapping::eloquent('username');
|
||||
|
||||
//human name - *FIRST NAME REQUIRED*
|
||||
$config['validations'][$core.'name.givenName'] = 'required';
|
||||
$config['validations'][$core.'name.familyName'] = 'string'; //not required
|
||||
|
||||
$mappings['name']['familyName'] = AttributeMapping::eloquent("last_name");
|
||||
$mappings['name']['givenName'] = AttributeMapping::eloquent("first_name");
|
||||
$mappings['name']['formatted'] = (new AttributeMapping())->ignoreWrite()->setRead(
|
||||
function (&$object) {
|
||||
return $object->getFullNameAttribute();
|
||||
}
|
||||
);
|
||||
|
||||
$config['validations'][$core.'emails'] = 'nullable|array'; // emails are not required in Snipe-IT...
|
||||
$config['validations'][$core.'emails.*.value'] = 'required|email'; // ...but if you give us one, it better be an email address
|
||||
|
||||
$mappings['emails'] = [[
|
||||
"value" => AttributeMapping::eloquent("email"),
|
||||
"display" => null,
|
||||
"type" => AttributeMapping::constant("work")->ignoreWrite(),
|
||||
"primary" => AttributeMapping::constant(true)->ignoreWrite()
|
||||
]];
|
||||
|
||||
//active
|
||||
$config['validations'][$core.'active'] = 'boolean';
|
||||
|
||||
$mappings['active'] = AttributeMapping::eloquent('activated');
|
||||
|
||||
//phone
|
||||
$config['validations'][$core.'phoneNumbers'] = 'nullable|array';
|
||||
$config['validations'][$core.'phoneNumbers.*.value'] = 'required';
|
||||
|
||||
$mappings['phoneNumbers'] = [[
|
||||
"value" => AttributeMapping::eloquent("phone"),
|
||||
"display" => null,
|
||||
"type" => AttributeMapping::constant("work")->ignoreWrite(),
|
||||
"primary" => AttributeMapping::constant(true)->ignoreWrite()
|
||||
]];
|
||||
|
||||
//address
|
||||
$config['validations'][$core.'addresses'] = 'nullable|array';
|
||||
$config['validations'][$core.'addresses.*.streetAddress'] = 'required';
|
||||
$config['validations'][$core.'addresses.*.locality'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.region'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.postalCode'] = 'string';
|
||||
$config['validations'][$core.'addresses.*.country'] = 'string';
|
||||
|
||||
$mappings['addresses'] = [[
|
||||
'type' => AttributeMapping::constant("work")->ignoreWrite(),
|
||||
'formatted' => AttributeMapping::constant("n/a")->ignoreWrite(), // TODO - is this right? This doesn't look right.
|
||||
'streetAddress' => AttributeMapping::eloquent("address"),
|
||||
'locality' => AttributeMapping::eloquent("city"),
|
||||
'region' => AttributeMapping::eloquent("state"),
|
||||
'postalCode' => AttributeMapping::eloquent("zip"),
|
||||
'country' => AttributeMapping::eloquent("country"),
|
||||
'primary' => AttributeMapping::constant(true)->ignoreWrite() //this isn't in the example?
|
||||
]];
|
||||
|
||||
//title
|
||||
$config['validations'][$core.'title'] = 'string';
|
||||
$mappings['title'] = AttributeMapping::eloquent('jobtitle');
|
||||
|
||||
//Preferred Language
|
||||
$config['validations'][$core.'preferredLanguage'] = 'string';
|
||||
$mappings['preferredLanguage'] = AttributeMapping::eloquent('locale');
|
||||
|
||||
/*
|
||||
more snipe-it attributes I'd like to check out (to map to 'enterprise' maybe?):
|
||||
- website
|
||||
- notes?
|
||||
- remote???
|
||||
- location_id ?
|
||||
- company_id to "organization?"
|
||||
*/
|
||||
|
||||
$enterprise_namespace = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
|
||||
$ent = $enterprise_namespace.':';
|
||||
|
||||
// we remove the 'example' namespace and add the Enterprise one
|
||||
$config['mapping']['schemas'] = AttributeMapping::constant( [$core_namespace, $enterprise_namespace] )->ignoreWrite();
|
||||
|
||||
$config['validations'][$ent.'employeeNumber'] = 'string';
|
||||
$config['validations'][$ent.'department'] = 'string';
|
||||
$config['validations'][$ent.'manager'] = 'nullable';
|
||||
$config['validations'][$ent.'manager.value'] = 'string';
|
||||
|
||||
$config['mapping'][$enterprise_namespace] = [
|
||||
'employeeNumber' => AttributeMapping::eloquent('employee_num'),
|
||||
'department' =>(new AttributeMapping())->setAdd( // FIXME parent?
|
||||
function ($value, &$object) {
|
||||
\Log::error("Department-Add: $value"); //FIXME
|
||||
$department = Department::where("name", $value)->first();
|
||||
if ($department) {
|
||||
$object->department_id = $department->id;
|
||||
}
|
||||
}
|
||||
)->setReplace(
|
||||
function ($value, &$object) {
|
||||
\Log::error("Department-Replace: $value"); //FIXME
|
||||
$department = Department::where("name", $value)->first();
|
||||
if ($department) {
|
||||
$object->department_id = $department->id;
|
||||
}
|
||||
}
|
||||
)->setRead(
|
||||
function (&$object) {
|
||||
\Log::error("Weird department reader firing..."); //FIXME
|
||||
return $object->department ? $object->department->name : null;
|
||||
}
|
||||
),
|
||||
'manager' => [
|
||||
// FIXME - manager writes are disabled. This kinda works but it leaks errors all over the place. Not cool.
|
||||
// '$ref' => (new AttributeMapping())->ignoreWrite()->ignoreRead(),
|
||||
// 'displayName' => (new AttributeMapping())->ignoreWrite()->ignoreRead(),
|
||||
// NOTE: you could probably do a 'plain' Eloquent mapping here, but we don't for future-proofing
|
||||
'value' => (new AttributeMapping())->setAdd(
|
||||
function ($value, &$object) {
|
||||
\Log::error("Manager-Add: $value"); //FIXME
|
||||
$manager = User::find($value);
|
||||
if ($manager) {
|
||||
$object->manager_id = $manager->id;
|
||||
}
|
||||
}
|
||||
)->setReplace(
|
||||
function ($value, &$object) {
|
||||
\Log::error("Manager-Replace: $value"); //FIXME
|
||||
$manager = User::find($value);
|
||||
if ($manager) {
|
||||
$object->manager_id = $manager->id;
|
||||
}
|
||||
}
|
||||
)->setRead(
|
||||
function (&$object) {
|
||||
\Log::error("Weird manager reader firing..."); //FIXME
|
||||
return $object->manager_id;
|
||||
}
|
||||
),
|
||||
]
|
||||
];
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -120,18 +120,6 @@ class Statuslabel extends SnipeModel
|
||||
->where('deployable', '=', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope for undeployable status types
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeUndeployable()
|
||||
{
|
||||
return $this->where('pending', '=', 0)
|
||||
->where('archived', '=', 0)
|
||||
->where('deployable', '=', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine type attributes
|
||||
*
|
||||
|
||||
@@ -17,9 +17,8 @@ trait Acceptable
|
||||
* @param User $acceptedBy
|
||||
* @param string $signature
|
||||
*/
|
||||
public function acceptedCheckout(User $acceptedBy, $signature, $filename = null)
|
||||
public function acceptedCheckout(User $acceptedBy, $signature)
|
||||
{
|
||||
\Log::debug('acceptedCheckout in Acceptable trait fired, tho it doesn\'t do anything?');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+9
-14
@@ -58,7 +58,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
'state',
|
||||
'username',
|
||||
'zip',
|
||||
'remote',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
@@ -74,13 +73,14 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
* @var array
|
||||
*/
|
||||
|
||||
// 'username' => 'required|string|min:1|unique:users,username,NULL,id,deleted_at,NULL',
|
||||
protected $rules = [
|
||||
'first_name' => 'required|string|min:1|max:191',
|
||||
'username' => 'required|string|min:1|unique_undeleted|max:191',
|
||||
'email' => 'email|nullable|max:191',
|
||||
'first_name' => 'required|string|min:1',
|
||||
'username' => 'required|string|min:1|unique_undeleted',
|
||||
'email' => 'email|nullable',
|
||||
'password' => 'required|min:8',
|
||||
'locale' => 'max:10|nullable',
|
||||
'website' => 'url|nullable|max:191',
|
||||
'website' => 'url|nullable',
|
||||
'manager_id' => 'nullable|exists:users,id|cant_manage_self',
|
||||
'location_id' => 'exists:locations,id|nullable',
|
||||
];
|
||||
@@ -258,7 +258,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
return $this->endpoint;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Establishes the user -> assets relationship
|
||||
*
|
||||
@@ -308,7 +307,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
*/
|
||||
public function consumables()
|
||||
{
|
||||
return $this->belongsToMany(\App\Models\Consumable::class, 'consumables_users', 'assigned_to', 'consumable_id')->withPivot('id','created_at')->withTrashed();
|
||||
return $this->belongsToMany(\App\Models\Consumable::class, 'consumables_users', 'assigned_to', 'consumable_id')->withPivot('id')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,15 +497,13 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
$last_name = '';
|
||||
$username = $users_name;
|
||||
} else {
|
||||
|
||||
list($first_name, $last_name) = explode(' ', $users_name, 2);
|
||||
|
||||
// Assume filastname by default
|
||||
$username = str_slug(substr($first_name, 0, 1).$last_name);
|
||||
|
||||
if ($format=='firstname.lastname') {
|
||||
$username = str_slug($first_name) . '.' . str_slug($last_name);
|
||||
|
||||
if ($format == 'firstname.lastname') {
|
||||
$username = str_slug($first_name).'.'.str_slug($last_name);
|
||||
} elseif ($format == 'lastnamefirstinitial') {
|
||||
$username = str_slug($last_name.substr($first_name, 0, 1));
|
||||
} elseif ($format == 'firstintial.lastname') {
|
||||
@@ -530,7 +527,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
$user['last_name'] = $last_name;
|
||||
$user['username'] = strtolower($username);
|
||||
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
@@ -585,8 +581,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
elseif ((Setting::getSettings()->two_factor_enabled == '2') && ($this->two_factor_enrolled)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -644,7 +640,6 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope to order on manager
|
||||
*
|
||||
|
||||
@@ -54,6 +54,7 @@ class CheckinAssetNotification extends Notification
|
||||
* has the corresponding checkbox checked.
|
||||
*/
|
||||
if ($this->item->checkin_email() && $this->target instanceof User && $this->target->email != '') {
|
||||
\Log::debug('use email');
|
||||
$notifyBy[] = 'mail';
|
||||
}
|
||||
|
||||
|
||||
@@ -17,38 +17,20 @@ class AssetObserver
|
||||
*/
|
||||
public function updating(Asset $asset)
|
||||
{
|
||||
$attributes = $asset->getAttributes();
|
||||
$attributesOriginal = $asset->getRawOriginal();
|
||||
$same_checkout_counter = false;
|
||||
$same_checkin_counter = false;
|
||||
|
||||
if (array_key_exists('checkout_counter', $attributes) && array_key_exists('checkout_counter', $attributesOriginal)){
|
||||
$same_checkout_counter = (($attributes['checkout_counter'] == $attributesOriginal['checkout_counter']));
|
||||
}
|
||||
|
||||
if (array_key_exists('checkin_counter', $attributes) && array_key_exists('checkin_counter', $attributesOriginal)){
|
||||
$same_checkin_counter = (($attributes['checkin_counter'] == $attributesOriginal['checkin_counter']));
|
||||
}
|
||||
|
||||
// If the asset isn't being checked out or audited, log the update.
|
||||
// (Those other actions already create log entries.)
|
||||
if (($attributes['assigned_to'] == $attributesOriginal['assigned_to'])
|
||||
&& ($same_checkout_counter) && ($same_checkin_counter)
|
||||
&& ((isset( $attributes['next_audit_date']) ? $attributes['next_audit_date'] : null) == (isset($attributesOriginal['next_audit_date']) ? $attributesOriginal['next_audit_date']: null))
|
||||
&& ($attributes['last_checkout'] == $attributesOriginal['last_checkout']))
|
||||
{
|
||||
if (($asset->getAttributes()['assigned_to'] == $asset->getOriginal()['assigned_to'])
|
||||
&& ($asset->getAttributes()['next_audit_date'] == $asset->getOriginal()['next_audit_date'])
|
||||
&& ($asset->getAttributes()['last_checkout'] == $asset->getOriginal()['last_checkout'])) {
|
||||
$changed = [];
|
||||
|
||||
foreach ($asset->getRawOriginal() as $key => $value) {
|
||||
if ($asset->getRawOriginal()[$key] != $asset->getAttributes()[$key]) {
|
||||
$changed[$key]['old'] = $asset->getRawOriginal()[$key];
|
||||
foreach ($asset->getOriginal() as $key => $value) {
|
||||
if ($asset->getOriginal()[$key] != $asset->getAttributes()[$key]) {
|
||||
$changed[$key]['old'] = $asset->getOriginal()[$key];
|
||||
$changed[$key]['new'] = $asset->getAttributes()[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($changed)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Asset::class;
|
||||
|
||||
@@ -83,18 +83,6 @@ abstract class SnipePermissionsPolicy
|
||||
return $user->hasAccess($this->columnName().'.edit');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the accessory.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return mixed
|
||||
*/
|
||||
public function checkout(User $user, $item = null)
|
||||
{
|
||||
return $user->hasAccess($this->columnName().'.checkout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can delete the accessory.
|
||||
*
|
||||
|
||||
@@ -59,9 +59,7 @@ class AccessoryPresenter extends Presenter
|
||||
'field' => 'manufacturer',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.manufacturer'),
|
||||
'visible' => false,
|
||||
'formatter' => 'manufacturersLinkObjFormatter',
|
||||
], [
|
||||
'field' => 'supplier',
|
||||
@@ -91,7 +89,6 @@ class AccessoryPresenter extends Presenter
|
||||
'field' => 'remaining_qty',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'visible' => false,
|
||||
'title' => trans('admin/accessories/general.remaining'),
|
||||
], [
|
||||
'field' => 'purchase_date',
|
||||
@@ -113,13 +110,6 @@ class AccessoryPresenter extends Presenter
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.order_number'),
|
||||
],[
|
||||
'field' => 'notes',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.notes'),
|
||||
'formatter' => 'notesFormatter'
|
||||
], [
|
||||
'field' => 'change',
|
||||
'searchable' => false,
|
||||
|
||||
@@ -17,10 +17,6 @@ class AssetAuditPresenter extends Presenter
|
||||
public static function dataTableLayout()
|
||||
{
|
||||
$layout = [
|
||||
[
|
||||
'field' => 'checkbox',
|
||||
'checkbox' => true,
|
||||
],
|
||||
[
|
||||
'field' => 'id',
|
||||
'searchable' => false,
|
||||
|
||||
@@ -103,13 +103,6 @@ class ComponentPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'footerFormatter' => 'sumFormatterQuantity',
|
||||
'class' => 'text-right',
|
||||
], [
|
||||
'field' => 'notes',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.notes'),
|
||||
'formatter' => 'notesFormatter',
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
@@ -115,13 +115,6 @@ class ConsumablePresenter extends Presenter
|
||||
'visible' => true,
|
||||
'footerFormatter' => 'sumFormatterQuantity',
|
||||
'class' => 'text-right',
|
||||
], [
|
||||
'field' => 'notes',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'visible' => false,
|
||||
'title' => trans('general.notes'),
|
||||
'formatter' => 'notesFormatter',
|
||||
], [
|
||||
'field' => 'change',
|
||||
'searchable' => false,
|
||||
|
||||
@@ -189,14 +189,6 @@ class LicensePresenter extends Presenter
|
||||
public static function dataTableLayoutSeats()
|
||||
{
|
||||
$layout = [
|
||||
[
|
||||
'field' => 'id',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('general.id'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'name',
|
||||
'searchable' => false,
|
||||
|
||||
@@ -90,14 +90,6 @@ class LocationPresenter extends Presenter
|
||||
'title' => trans('admin/locations/table.address'),
|
||||
'visible' => true,
|
||||
],
|
||||
[
|
||||
'field' => 'address2',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/locations/table.address'),
|
||||
'visible' => false,
|
||||
],
|
||||
[
|
||||
'field' => 'city',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -85,15 +85,6 @@ class UserPresenter extends Presenter
|
||||
'visible' => true,
|
||||
'formatter' => 'usersLinkFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'remote',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'switchable' => true,
|
||||
'title' => trans('admin/users/general.remote'),
|
||||
'visible' => false,
|
||||
'formatter' => 'trueFalseFormatter',
|
||||
],
|
||||
[
|
||||
'field' => 'email',
|
||||
'searchable' => true,
|
||||
|
||||
@@ -8,7 +8,6 @@ use App\Models\Component;
|
||||
use App\Models\Consumable;
|
||||
use App\Models\License;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeSCIMConfig;
|
||||
use App\Observers\AccessoryObserver;
|
||||
use App\Observers\AssetObserver;
|
||||
use App\Observers\ComponentObserver;
|
||||
@@ -81,8 +80,6 @@ class AppServiceProvider extends ServiceProvider
|
||||
if ($this->app->environment(['local', 'develop'])) {
|
||||
$this->app->register(\Laravel\Dusk\DuskServiceProvider::class);
|
||||
}
|
||||
|
||||
$this->app->singleton('ArieTimmerman\Laravel\SCIMServer\SCIMConfig', SnipeSCIMConfig::class); // this overrides the default SCIM configuration with our own
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,6 @@ class AuthServiceProvider extends ServiceProvider
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// -----------------------------------------
|
||||
// Reports
|
||||
// -----------------------------------------
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user