Compare commits

..

6 Commits

Author SHA1 Message Date
snipe 172942878b Added checkin as option in dropdown actions
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:20:13 -08:00
snipe 46279c5f3d Small layout fix
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:56 -08:00
snipe 731dc29bf5 New checkin blade
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:48 -08:00
snipe 530a76881e Added language strings
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:42 -08:00
snipe 257a501d70 Added routing logic for what form should be displayed
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:34 -08:00
snipe e047d5516c Added new bulk checkin routes
Signed-off-by: snipe <snipe@snipe.net>
2022-03-02 14:19:16 -08:00
678 changed files with 287188 additions and 7141 deletions
-36
View File
@@ -2585,42 +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"
]
}
]
}
-7
View File
@@ -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
View File
@@ -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
View File
@@ -38,7 +38,7 @@ IMAGE_LIB=gd
# --------------------------------------------
# OPTIONAL: AWS SETTINGS
# OPTIONAL: AWS S3 SETTINGS
# --------------------------------------------
AWS_SECRET_ACCESS_KEY=null
AWS_ACCESS_KEY_ID=null
+42 -27
View File
@@ -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.
-39
View File
@@ -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
-1
View File
@@ -41,7 +41,6 @@ libmcrypt-dev \
php7.4-dev \
ca-certificates \
unzip \
dnsutils \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+2 -2
View File
@@ -1,5 +1,5 @@
![Build Status](https://app.chipperci.com/projects/0e5f8979-31eb-4ee6-9abf-050b76ab0383/status/master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/snipe-it/localized.svg)](https://crowdin.com/project/snipe-it) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=snipe/snipe-it&amp;utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-286-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
[![All Contributors](https://img.shields.io/badge/all_contributors-284-orange.svg?style=flat-square)](#contributors) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/yZFtShAcKk) [![huntr](https://cdn.huntr.dev/huntr_security_badge_mono.svg)](https://huntr.dev)
## Snipe-IT - Open Source Asset Management System
@@ -131,7 +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/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!
-59
View File
@@ -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!');
}
}
+1 -11
View File
@@ -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,15 +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();
$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
-503
View File
@@ -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.
}
}
}
}
+72 -77
View File
@@ -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.');
}
}
}
+3 -6
View File
@@ -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',
@@ -246,21 +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);
return false;
}
}
if (!feof($sql_contents) || $bytes_read == 0) {
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
}
+2 -4
View File
@@ -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);
}
}
@@ -79,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);
@@ -145,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'));
}
@@ -112,8 +102,7 @@ class AcceptanceController extends Controller
$data_uri = e($request->input('signature_output'));
$encoded_image = explode(',', $data_uri);
$decoded_image = base64_decode($encoded_image[1]);
$acceptance->stored_eula_file = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf';
$path = Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
Storage::put('private_uploads/signatures/'.$sig_filename, (string) $decoded_image);
}
if ($request->input('asset_acceptance') == 'accepted') {
@@ -122,8 +111,6 @@ class AcceptanceController extends Controller
event(new CheckoutAccepted($acceptance));
$return_msg = trans('admin/users/message.accepted');
} else {
$acceptance->decline($sig_filename);
@@ -132,61 +119,6 @@ class AcceptanceController extends Controller
$return_msg = trans('admin/users/message.declined');
}
$item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id);
if ($acceptance->checkoutable_type== 'App\Models\Asset') {
$assigned_to = User::find($item->assigned_to);
$asset_model = AssetModel::find($item->model_id);
$branding_settings = SettingsController::getPDFBranding();
$data = [
'item_tag' => $item->asset_tag,
'item_model' => $asset_model->name,
'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->first_name . ' ' . $assigned_to->last_name,
'company_name' => $branding_settings->site_name,
'signature' => storage_path() . '/private_uploads/signatures/' . $sig_filename,
'logo' => public_path() . '/uploads/' . $branding_settings->logo,
'date_settings' => $branding_settings->date_display_format,
];
$pdf = Pdf::loadView('account.accept.accept-asset-eula', $data);
Storage::put('private_uploads/eula-pdfs/' . $acceptance->stored_eula_file, $pdf->output());
$a = new Actionlog();
$a->stored_eula = $item->getEula();
$a->stored_eula_file = $acceptance->stored_eula_file;
$a->save();
return redirect()->to('account/accept')->with('success', $return_msg);
}
//
$accessory_user= DB::table('checkout_acceptances')->find($acceptance->assigned_to_id);
$assigned_to = User::find($accessory_user->assigned_to_id);
$accessory_model = Accessory::find($item->id);
$branding_settings = SettingsController::getPDFBranding();
$data = [
'item_tag' => $item->model_number,
'item_model' => $accessory_model->name,
'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_by' => self
'assigned_to' => $assigned_to->first_name . ' ' . $assigned_to->last_name,
'company_name' => $branding_settings->site_name,
'signature' => storage_path() . '/private_uploads/signatures/' . $sig_filename,
'logo' => public_path() . '/uploads/' . $branding_settings->logo,
'date_settings' => $branding_settings->date_display_format,
];
$pdf = Pdf::loadView('account.accept.accept-accessory-eula', $data);
Storage::put('private_uploads/eula-pdfs/' . $acceptance->stored_eula_file, $pdf->output());
$a = new Actionlog();
$a->stored_eula = $item->getEula();
$a->stored_eula_file = $acceptance->stored_eula_file;
$a->save();
return redirect()->to('account/accept')->with('success', $return_msg);
}
}
}
+2 -19
View File
@@ -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);
@@ -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);
@@ -731,7 +730,6 @@ class AssetsController extends Controller
$logaction->logaction('restored');
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);
@@ -788,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.
@@ -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'),
];
@@ -52,7 +52,6 @@ class ReportsController extends Controller
'accept_signature',
'action_type',
'note',
'stored_eula_file',
];
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
@@ -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
*
+1 -45
View File
@@ -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.
*
@@ -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
@@ -101,22 +101,14 @@ class AssetCheckinController extends Controller
\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);
@@ -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);
@@ -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');
}
}
+13 -41
View File
@@ -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');
}
@@ -104,18 +100,13 @@ class LoginController extends Controller
*/
private function loginViaSaml(Request $request)
{
\Log::debug('Attempting to login via SAML');
$saml = $this->saml;
$samlData = $request->session()->get('saml_login');
if ($saml->isEnabled() && ! empty($samlData)) {
\Log::debug('SAML is enabled, and the samleData is not empty');
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();
@@ -128,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");
}
/**
@@ -259,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');
}
@@ -358,6 +331,7 @@ class LoginController extends Controller
$secret = Google2FA::generateSecretKey();
$user->two_factor_secret = $secret;
$user->save();
$barcode = new Barcode();
$barcode_obj =
@@ -375,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);
}
@@ -421,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.');
}
@@ -469,6 +441,8 @@ class LoginController extends Controller
return redirect()->away($sloRequestUrl);
}
$request->session()->regenerate(true);
$request->session()->regenerate(true);
Auth::logout();
@@ -499,7 +473,6 @@ class LoginController extends Controller
]);
}
public function username()
{
return 'username';
@@ -526,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);
}
@@ -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);
@@ -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);
@@ -78,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);
@@ -142,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.
+5 -15
View File
@@ -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()->withTrashed()->with(['assignedTo' , 'checkoutable.assignedTo', 'checkoutable.model'])->get();
} else {
$acceptances = CheckoutAcceptance::pending()->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];
@@ -946,7 +946,6 @@ class SettingsController extends Controller
$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.
@@ -51,8 +51,8 @@ class BulkUsersController extends Controller
});
}
}
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,9 +90,7 @@ class BulkUsersController extends Controller
->conditionallyAddItem('department_id')
->conditionallyAddItem('company_id')
->conditionallyAddItem('locale')
->conditionallyAddItem('remote')
->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;
@@ -103,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) {
@@ -178,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);
@@ -189,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,7 +623,7 @@ 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, function (Message $message) use ($user) {
+1 -1
View File
@@ -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',
],
];
@@ -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);
}
}
+1 -7
View File
@@ -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);
}
+15
View File
@@ -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',
];
+2 -2
View File
@@ -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();
+54 -44
View File
@@ -1,4 +1,5 @@
<?php
namespace App\Http\Transformers;
use App\Helpers\Helper;
@@ -8,58 +9,73 @@ 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
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 = [
'id' => (int) $actionlog->id,
'icon' => $icon,
'file' => ($actionlog->filename!='') ?
'file' => ($actionlog->filename != '') ?
[
'url' => route('show/assetfile', ['assetId' => $actionlog->item->id, 'fileId' => $actionlog->id]),
'filename' => $actionlog->filename,
@@ -68,7 +84,7 @@ class ActionlogsTransformer
'item' => ($actionlog->item) ? [
'id' => (int) $actionlog->item->id,
'name' => ($actionlog->itemType()=='user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
'name' => ($actionlog->itemType() == 'user') ? $actionlog->filename : e($actionlog->item->getDisplayNameAttribute()),
'type' => e($actionlog->itemType()),
] : null,
'location' => ($actionlog->location) ? [
@@ -77,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,
@@ -96,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'),
'stored_eula_file' => ($actionlog->stored_eula_file) ? route('log.storedeula.download', ['filename' => $actionlog->stored_eula_file]) : null,
];
//\Log::info("Clean Meta is: ".print_r($clean_meta,true));
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,
@@ -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'),
];
@@ -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) ? [
-3
View File
@@ -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'];
}
+3 -11
View File
@@ -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));
+1 -2
View File
@@ -34,12 +34,11 @@ class LogListener
public function onCheckoutAccepted(CheckoutAccepted $event)
{
$logaction = new Actionlog();
$logaction->item()->associate($event->acceptance->checkoutable);
$logaction->target()->associate($event->acceptance->assignedTo);
$logaction->accept_signature = $event->acceptance->signature_filename;
$logaction->stored_eula_file = $event->acceptance->stored_eula_file;
$logaction->action_type = 'accepted';
// TODO: log the actual license seat that was checked out
+3 -6
View File
@@ -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;
}
/**
+2 -6
View File
@@ -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', 'stored_eula_file'];
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
*
+1 -16
View File
@@ -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);
}
+2 -3
View File
@@ -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.
+3 -5
View File
@@ -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.
-2
View File
@@ -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;
}
-4
View File
@@ -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
*
-7
View File
@@ -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;
+1 -1
View File
@@ -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;
}
}
-16
View File
@@ -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);
}
}
-174
View File
@@ -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;
}
}
-12
View File
@@ -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
*
+9 -14
View File
@@ -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
*
+4 -7
View File
@@ -17,15 +17,12 @@ class AssetObserver
*/
public function updating(Asset $asset)
{
$attributes = $asset->getAttributes();
$attributesOriginal = $asset->getOriginal();
// 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'])
&& ((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->getOriginal() as $key => $value) {
-12
View File
@@ -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.
*
-10
View File
@@ -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,
-4
View File
@@ -17,10 +17,6 @@ class AssetAuditPresenter extends Presenter
public static function dataTableLayout()
{
$layout = [
[
'field' => 'checkbox',
'checkbox' => true,
],
[
'field' => 'id',
'searchable' => false,
-7
View File
@@ -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',
],
];
-7
View File
@@ -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,
-8
View File
@@ -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,
-9
View File
@@ -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,
-3
View File
@@ -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
}
}
-1
View File
@@ -121,7 +121,6 @@ class AuthServiceProvider extends ServiceProvider
}
});
// -----------------------------------------
// Reports
// -----------------------------------------
+1 -1
View File
@@ -24,7 +24,7 @@ class RouteServiceProvider extends ServiceProvider
$this->mapWebRoutes();
require base_path('routes/scim.php');
//
});
}
-3
View File
@@ -130,11 +130,9 @@ class Saml
$this->clearData();
}
\Log::debug('Trying to create a new OneLogin_Saml2_Auth object ');
try {
$this->_auth = new OneLogin_Saml2_Auth($this->_settings);
} catch (Exception $e) {
\Log::error('Trying OneLogin_Saml2_Auth failed. Setting SAML enabled to false. OneLogin_Saml2_Auth error message is: '. $e->getMessage());
$this->_enabled = false;
}
}
@@ -157,7 +155,6 @@ class Saml
$this->_enabled = $setting->saml_enabled == '1';
if ($this->isEnabled()) {
\Log::debug('SAML is enabled according to loadSettings()');
//Let onelogin/php-saml know to use 'X-Forwarded-*' headers if it is from a trusted proxy
OneLogin_Saml2_Utils::setProxyVars(request()->isFromTrustedProxy());
+4 -13
View File
@@ -10,12 +10,6 @@
],
"license": "AGPL-3.0-or-later",
"type": "project",
"repositories": [
{
"type": "vcs",
"url": "https://github.com/grokability/laravel-scim-server"
}
],
"require": {
"php": ">=7.4 <8.1",
"ext-curl": "*",
@@ -24,21 +18,19 @@
"ext-mbstring": "*",
"ext-pdo": "*",
"alek13/slack": "^2.0",
"arietimmerman/laravel-scim-server": "dev-master",
"bacon/bacon-qr-code": "^2.0",
"barryvdh/laravel-debugbar": "^3.6",
"barryvdh/laravel-dompdf": "^1.0",
"doctrine/cache": "^1.10",
"doctrine/common": "^2.12",
"doctrine/dbal": "^3.1",
"doctrine/inflector": "^1.3",
"doctrine/instantiator": "^1.3",
"eduardokum/laravel-mail-auto-embed": "^1.0",
"enshrined/svg-sanitize": "^0.15.0",
"enshrined/svg-sanitize": "^0.13.3",
"erusev/parsedown": "^1.7",
"facade/ignition": "^2.10",
"fideloper/proxy": "^4.3",
"fruitcake/laravel-cors": "^2.2",
"fruitcake/laravel-cors": "^2.0",
"guzzlehttp/guzzle": "^7.0.1",
"intervention/image": "^2.5",
"javiereguiluz/easyslugger": "^1.0",
@@ -68,6 +60,7 @@
"rollbar/rollbar-laravel": "^7.0",
"spatie/laravel-backup": "^6.16",
"tecnickcom/tc-lib-barcode": "^1.15",
"tightenco/ziggy": "v1.2.0",
"unicodeveloper/laravel-password": "^1.0",
"watson/validating": "^6.1"
},
@@ -111,9 +104,7 @@
},
"scripts": {
"post-autoload-dump": [
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
"@php artisan package:discover --ansi",
"@php artisan vendor:publish --force --tag=livewire:assets --ansi"
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump"
],
"post-create-project-cmd": [
"php artisan key:generate"
Generated
+851 -1345
View File
File diff suppressed because it is too large Load Diff
+2 -14
View File
@@ -250,7 +250,6 @@ return [
'enable_csp' => env('ENABLE_CSP', false),
/*
|--------------------------------------------------------------------------
| Require SAML Login
@@ -266,6 +265,7 @@ return [
'require_saml' => env('REQUIRE_SAML', false),
/*
|--------------------------------------------------------------------------
| Demo Mode Lockdown
@@ -328,7 +328,6 @@ return [
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
Barryvdh\DomPDF\ServiceProvider::class,
/*
* Package Service Providers...
@@ -342,6 +341,7 @@ return [
Laravel\Passport\PassportServiceProvider::class,
Laravel\Tinker\TinkerServiceProvider::class,
Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class,
Tightenco\Ziggy\ZiggyServiceProvider::class, // Laravel routes in vue
Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class,
/*
@@ -396,7 +396,6 @@ return [
'Mail' => Illuminate\Support\Facades\Mail::class,
'Notification' => Illuminate\Support\Facades\Notification::class,
'Password' => Illuminate\Support\Facades\Password::class,
'PDF' => Barryvdh\DomPDF\Facade::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
@@ -419,15 +418,4 @@ return [
],
/*
|--------------------------------------------------------------------------
| API Throttling
|--------------------------------------------------------------------------
|
| This value determines the number of API requests permitted per minute
|
*/
'api_throttle_per_minute' => env('API_THROTTLE_PER_MINUTE', 120),
];
+31 -32
View File
@@ -1,49 +1,48 @@
<?php
/**
* ---------------------------------------------------------------------
* THIS IS $allowed_origins code IS NOT PART OF THE ORIGINAL CORS PACKAGE.
* IT IS A MODIFICATION BY SNIPE-IT TO ALLOW ADDING ALLOWED ORIGINS VIA THE ENV.
* ---------------------------------------------------------------------
*
* Since we don't really want people editing config files (lest they get
* overwritten later), this enables the person managing the Snipe-IT
* installation to modify these values without modifying the code.
*
* If APP_CORS_ALLOWED_ORIGINS is not set in the .env (for example if no one added it
* after an upgrade from a previous version that didn't include it in the .env.example) or is null,
* set it to * to allow all. If there is a value, either a single url or a comma-delimited
* list of urls, explode that out into an array to whitelist just those urls.
*/
$allowed_origins = env('CORS_ALLOWED_ORIGINS') !== null ?
explode(',', env('CORS_ALLOWED_ORIGINS')) : [];
/**
* Original Laravel CORS package config file modifications end here
*
*/
return [
'supportsCredentials' => false,
'allowedOrigins' => $allowed_origins,
'allowedHeaders' => ['*'],
'allowedMethods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
'maxAge' => 0,
/*
|--------------------------------------------------------------------------
| Laravel CORS
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| allowedOrigins, allowedHeaders and allowedMethods can be set to array('*')
| to accept any value.
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'supports_credentials' => false,
'allowed_origins' => $allowed_origins,
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'allowed_methods' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
'exposed_headers' => [],
'max_age' => 0,
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
-84
View File
@@ -1,84 +0,0 @@
<?php
return [
/*
* Enable / disable Google2FA.
*/
'enabled' => env('OTP_ENABLED', true),
/*
* Lifetime in minutes.
*
* In case you need your users to be asked for a new one time passwords from time to time.
*/
'lifetime' => env('OTP_LIFETIME', 0), // 0 = eternal
/*
* Renew lifetime at every new request.
*/
'keep_alive' => env('OTP_KEEP_ALIVE', true),
/*
* Auth container binding.
*/
'auth' => 'auth',
/*
* Guard.
*/
'guard' => '',
/*
* 2FA verified session var.
*/
'session_var' => 'google2fa',
/*
* One Time Password request input name.
*/
'otp_input' => 'one_time_password', //should this be 'two_factor_secret'?
/*
* One Time Password Window.
*/
'window' => 1,
/*
* Forbid user to reuse One Time Passwords.
*/
'forbid_old_passwords' => false,
/*
* User's table column for google2fa secret.
*/
'otp_secret_column' => 'google2fa_secret',
/*
* One Time Password View.
*/
'view' => 'google2fa.index', //should this be 'auth.two_factor_enroll'?
/*
* One Time Password error message.
*/
'error_messages' => [
'wrong_otp' => "The 'One Time Password' typed was wrong.",
'cannot_be_empty' => 'One Time Password cannot be empty.',
'unknown' => 'An unknown error has occurred. Please try again.',
],
/*
* Throw exceptions or just fire events?
*/
'throw_exceptions' => env('OTP_THROW_EXCEPTION', true),
/*
* Which image backend to use for generating QR codes?
*
* Supports imagemagick, svg and eps
*/
'qrcode_image_backend' => \PragmaRX\Google2FALaravel\Support\Constants::QRCODE_IMAGE_BACKEND_SVG,
];
+7 -8
View File
@@ -6,7 +6,6 @@
|--------------------------------------------------------------------------
*/
return [
'Global' => [
@@ -98,7 +97,6 @@ return [
'display' => true,
],
[
'permission' => 'assets.view.requestable',
'label' => 'View Requestable Assets',
@@ -180,7 +178,6 @@ return [
],
],
'Licenses' => [
[
'permission' => 'licenses.view',
@@ -226,7 +223,6 @@ return [
],
],
'Components' => [
[
'permission' => 'components.view',
@@ -292,6 +288,13 @@ return [
'note' => '',
'display' => true,
],
[
'permission' => 'kits.checkout',
'label' => 'Checkout ',
'note' => '',
'display' => true,
],
],
'Users' => [
@@ -485,7 +488,6 @@ return [
],
],
'Manufacturers' => [
[
'permission' => 'manufacturers.view',
@@ -594,9 +596,6 @@ return [
],
],
'Self' => [
[
'permission' => 'self.two_factor',
-5
View File
@@ -1,5 +0,0 @@
<?php
return [
"publish_routes" => false
];
+3 -3
View File
@@ -32,9 +32,9 @@ return [
],
'ses' => [
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'stripe' => [
+1 -1
View File
@@ -117,7 +117,7 @@ return [
|
*/
'cookie' => env('COOKIE_NAME', 'snipeitv6_session'),
'cookie' => env('COOKIE_NAME', 'snipeitv4_session'),
/*
|--------------------------------------------------------------------------
+6 -6
View File
@@ -1,10 +1,10 @@
<?php
return array (
'app_version' => 'v6.0.0',
'full_app_version' => 'v6.0.0 - build 6860-g722e88a47',
'build_version' => '6860',
'app_version' => 'v6.0.0-RC3',
'full_app_version' => 'v6.0.0-RC3 - build 6627-g2815e0d36',
'build_version' => '6627',
'prerelease_version' => '',
'hash_version' => 'g722e88a47',
'full_hash' => 'v6.0.0-30-g722e88a47',
'branch' => 'master',
'hash_version' => 'g2815e0d36',
'full_hash' => 'v6.0.0-RC3-6-g2815e0d36',
'branch' => 'develop',
);
+3 -3
View File
@@ -8,6 +8,7 @@ use App\Models\Category;
use App\Models\Location;
use App\Models\Supplier;
use Illuminate\Database\Eloquent\Factories\Factory;
use App\Models\StatusLabel;
/*
|--------------------------------------------------------------------------
@@ -38,16 +39,15 @@ class AssetFactory extends Factory
{
return [
'name' => null,
'rtd_location_id' => Location::all()->random()->id,
'rtd_location_id' => Location::factory()->create(),
'serial' => $this->faker->uuid,
'status_id' => 1,
'status_id' => $this->faker->numberBetween(1,5),
'user_id' => 1,
'asset_tag' => $this->faker->unixTime('now'),
'notes' => 'Created by DB seeder',
'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get()),
'purchase_cost' => $this->faker->randomFloat(2, '299.99', '2999.99'),
'order_number' => $this->faker->numberBetween(1000000, 50000000),
'supplier_id' => Supplier::all()->random()->id,
'requestable' => $this->faker->boolean(),
'assigned_to' => null,
'assigned_type' => null,
+1 -1
View File
@@ -1,4 +1,5 @@
<?php
namespace Database\Factories;
use App\Models\Category;
@@ -98,7 +99,6 @@ class LicenseFactory extends Factory
'seats' => 10,
'category_id' => 14,
];
return $data;
});
@@ -1,7 +1,7 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateCustomFieldCustomFieldset extends Migration
{
@@ -13,14 +13,13 @@ class CreateCustomFieldCustomFieldset extends Migration
public function up()
{
Schema::create('custom_field_custom_fieldset', function (Blueprint $table) {
$table->bigIncrements('id');
$table->integer('custom_field_id');
$table->integer('custom_fieldset_id');
$table->integer('order');
$table->boolean('required');
$table->engine = 'InnoDB';
});
}
/**
@@ -13,22 +13,20 @@ class CreateCheckoutAcceptancesTable extends Migration
*/
public function up()
{
if (!Schema::hasTable('checkout_acceptances')) {
Schema::create('checkout_acceptances', function (Blueprint $table) {
$table->increments('id');
Schema::create('checkout_acceptances', function (Blueprint $table) {
$table->increments('id');
$table->morphs('checkoutable');
$table->integer('assigned_to_id')->nullable();
$table->morphs('checkoutable');
$table->integer('assigned_to_id')->nullable();
$table->string('signature_filename')->nullable();
$table->string('signature_filename')->nullable();
$table->timestamp('accepted_at')->nullable();
$table->timestamp('declined_at')->nullable();
$table->timestamp('accepted_at')->nullable();
$table->timestamp('declined_at')->nullable();
$table->timestamps();
$table->softDeletes();
});
}
$table->timestamps();
$table->softDeletes();
});
}
/**
@@ -38,8 +36,6 @@ class CreateCheckoutAcceptancesTable extends Migration
*/
public function down()
{
if (Schema::hasTable('checkout_acceptances')) {
Schema::dropIfExists('checkout_acceptances');
}
Schema::dropIfExists('checkout_acceptances');
}
}
@@ -1,9 +1,7 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
class AddKitsLicensesTable extends Migration
{
@@ -14,16 +12,15 @@ class AddKitsLicensesTable extends Migration
*/
public function up()
{
if (!Schema::hasTable('kits_licenses')) {
Schema::create('kits_licenses', function ($table) {
$table->increments('id');
$table->integer('kit_id')->nullable()->default(NULL);
$table->integer('license_id')->nullable()->default(NULL);
$table->integer('quantity')->default(1);
$table->timestamps();
});
}
}
//
Schema::create('kits_licenses', function ($table) {
$table->increments('id');
$table->integer('kit_id')->nullable()->default(null);
$table->integer('license_id')->nullable()->default(null);
$table->integer('quantity')->default(1);
$table->timestamps();
});
}
/**
* Reverse the migrations.
@@ -32,9 +29,7 @@ class AddKitsLicensesTable extends Migration
*/
public function down()
{
if (Schema::hasTable('kits_licenses')) {
Schema::drop('kits_licenses');
}
}
//
Schema::drop('kits_licenses');
}
}
@@ -1,8 +1,7 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
class AddKitsTable extends Migration
{
@@ -13,16 +12,14 @@ class AddKitsTable extends Migration
*/
public function up()
{
if (!Schema::hasTable('kits')) {
Schema::create('kits', function ($table) {
$table->increments('id');
$table->string('name')->nullable()->default(NULL);
$table->timestamps();
$table->engine = 'InnoDB';
});
}
}
//
Schema::create('kits', function ($table) {
$table->increments('id');
$table->string('name')->nullable()->default(null);
$table->timestamps();
$table->engine = 'InnoDB';
});
}
/**
* Reverse the migrations.
@@ -31,10 +28,7 @@ class AddKitsTable extends Migration
*/
public function down()
{
if (Schema::hasTable('kits')) {
Schema::drop('kits');
}
}
//
Schema::drop('kits');
}
}
@@ -1,9 +1,7 @@
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
class AddKitsModelsTable extends Migration
{
@@ -14,16 +12,15 @@ class AddKitsModelsTable extends Migration
*/
public function up()
{
if (!Schema::hasTable('kits_models')) {
Schema::create('kits_models', function ($table) {
$table->increments('id');
$table->integer('kit_id')->nullable()->default(NULL);
$table->integer('model_id')->nullable()->default(NULL);
$table->integer('quantity')->default(1);
$table->timestamps();
});
}
}
//
Schema::create('kits_models', function ($table) {
$table->increments('id');
$table->integer('kit_id')->nullable()->default(null);
$table->integer('model_id')->nullable()->default(null);
$table->integer('quantity')->default(1);
$table->timestamps();
});
}
/**
* Reverse the migrations.
@@ -32,9 +29,7 @@ class AddKitsModelsTable extends Migration
*/
public function down()
{
if (Schema::hasTable('kits_models')) {
Schema::drop('kits_models');
}
//
Schema::drop('kits_models');
}
}

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