Merge branch 'develop' of https://github.com/snipe/snipe-it into feature/remove_deleted_user_from_unaccepted_assets_report

This commit is contained in:
sh1hab 2021-05-21 10:09:05 +06:00
commit cd4b1d8acb
62 changed files with 373 additions and 66 deletions

View file

@ -2333,6 +2333,15 @@
"contributions": [ "contributions": [
"code" "code"
] ]
},
{
"login": "tbrconnect",
"name": "tbrconnect",
"avatar_url": "https://avatars.githubusercontent.com/u/11973217?v=4",
"profile": "https://github.com/tbrconnect",
"contributions": [
"code"
]
} }
] ]
} }

View file

@ -1,4 +1,4 @@
FROM alpine:3.12 FROM alpine:3.13
# Apache + PHP # Apache + PHP
RUN apk add --no-cache \ RUN apk add --no-cache \
apache2 \ apache2 \

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) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade) ![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) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Docker Pulls](https://img.shields.io/docker/pulls/snipe/snipe-it.svg)](https://hub.docker.com/r/snipe/snipe-it/) [![Twitter Follow](https://img.shields.io/twitter/follow/snipeitapp.svg?style=social)](https://twitter.com/snipeitapp) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/553ce52037fc43ea99149785afcfe641)](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
[![All Contributors](https://img.shields.io/badge/all_contributors-256-orange.svg?style=flat-square)](#contributors) [![All Contributors](https://img.shields.io/badge/all_contributors-257-orange.svg?style=flat-square)](#contributors)
## Snipe-IT - Open Source Asset Management System ## Snipe-IT - Open Source Asset Management System
@ -125,7 +125,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
| [<img src="https://avatars.githubusercontent.com/u/915514?v=4" width="110px;"/><br /><sub>Kevin Köllmann</sub>](https://www.kevinkoellmann.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koelle25 "Code") | [<img src="https://avatars.githubusercontent.com/u/49025941?v=4" width="110px;"/><br /><sub>sw-mreyes</sub>](https://github.com/sw-mreyes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sw-mreyes "Code") | [<img src="https://avatars.githubusercontent.com/u/70129?v=4" width="110px;"/><br /><sub>Joel Pittet</sub>](https://pittet.ca)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joelpittet "Code") | [<img src="https://avatars.githubusercontent.com/u/792695?v=4" width="110px;"/><br /><sub>Eli Young</sub>](https://elyscape.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=elyscape "Code") | [<img src="https://avatars.githubusercontent.com/u/317015?v=4" width="110px;"/><br /><sub>Raell Dottin</sub>](https://github.com/raelldottin)<br />[💻](https://github.com/snipe/snipe-it/commits?author=raelldottin "Code") | [<img src="https://avatars.githubusercontent.com/u/1446856?v=4" width="110px;"/><br /><sub>Tom Misilo</sub>](https://github.com/misilot)<br />[💻](https://github.com/snipe/snipe-it/commits?author=misilot "Code") | [<img src="https://avatars.githubusercontent.com/u/4496300?v=4" width="110px;"/><br /><sub>David Davenne</sub>](http://david.davenne.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JuustoMestari "Code") | | [<img src="https://avatars.githubusercontent.com/u/915514?v=4" width="110px;"/><br /><sub>Kevin Köllmann</sub>](https://www.kevinkoellmann.de)<br />[💻](https://github.com/snipe/snipe-it/commits?author=koelle25 "Code") | [<img src="https://avatars.githubusercontent.com/u/49025941?v=4" width="110px;"/><br /><sub>sw-mreyes</sub>](https://github.com/sw-mreyes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sw-mreyes "Code") | [<img src="https://avatars.githubusercontent.com/u/70129?v=4" width="110px;"/><br /><sub>Joel Pittet</sub>](https://pittet.ca)<br />[💻](https://github.com/snipe/snipe-it/commits?author=joelpittet "Code") | [<img src="https://avatars.githubusercontent.com/u/792695?v=4" width="110px;"/><br /><sub>Eli Young</sub>](https://elyscape.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=elyscape "Code") | [<img src="https://avatars.githubusercontent.com/u/317015?v=4" width="110px;"/><br /><sub>Raell Dottin</sub>](https://github.com/raelldottin)<br />[💻](https://github.com/snipe/snipe-it/commits?author=raelldottin "Code") | [<img src="https://avatars.githubusercontent.com/u/1446856?v=4" width="110px;"/><br /><sub>Tom Misilo</sub>](https://github.com/misilot)<br />[💻](https://github.com/snipe/snipe-it/commits?author=misilot "Code") | [<img src="https://avatars.githubusercontent.com/u/4496300?v=4" width="110px;"/><br /><sub>David Davenne</sub>](http://david.davenne.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JuustoMestari "Code") |
| [<img src="https://avatars.githubusercontent.com/u/9255772?v=4" width="110px;"/><br /><sub>Mark Stenglein</sub>](https://markstenglein.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [<img src="https://avatars.githubusercontent.com/u/35658596?v=4" width="110px;"/><br /><sub>ajsy</sub>](https://github.com/ajsy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [<img src="https://avatars.githubusercontent.com/u/3628035?v=4" width="110px;"/><br /><sub>Jan Kiesewetter</sub>](https://github.com/t3easy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [<img src="https://avatars.githubusercontent.com/u/79449630?v=4" width="110px;"/><br /><sub>Tetrachloromethane250</sub>](https://github.com/Tetrachloromethane250)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [<img src="https://avatars.githubusercontent.com/u/22004482?v=4" width="110px;"/><br /><sub>Lars Kajes</sub>](https://www.kajes.se/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [<img src="https://avatars.githubusercontent.com/u/13993216?v=4" width="110px;"/><br /><sub>Joly0</sub>](https://github.com/Joly0)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>theburger</sub>](https://github.com/limeless)<br />[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") | | [<img src="https://avatars.githubusercontent.com/u/9255772?v=4" width="110px;"/><br /><sub>Mark Stenglein</sub>](https://markstenglein.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ocelotsloth "Code") | [<img src="https://avatars.githubusercontent.com/u/35658596?v=4" width="110px;"/><br /><sub>ajsy</sub>](https://github.com/ajsy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=ajsy "Code") | [<img src="https://avatars.githubusercontent.com/u/3628035?v=4" width="110px;"/><br /><sub>Jan Kiesewetter</sub>](https://github.com/t3easy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=t3easy "Code") | [<img src="https://avatars.githubusercontent.com/u/79449630?v=4" width="110px;"/><br /><sub>Tetrachloromethane250</sub>](https://github.com/Tetrachloromethane250)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Tetrachloromethane250 "Code") | [<img src="https://avatars.githubusercontent.com/u/22004482?v=4" width="110px;"/><br /><sub>Lars Kajes</sub>](https://www.kajes.se/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=kajes "Code") | [<img src="https://avatars.githubusercontent.com/u/13993216?v=4" width="110px;"/><br /><sub>Joly0</sub>](https://github.com/Joly0)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Joly0 "Code") | [<img src="https://avatars.githubusercontent.com/u/1501022?v=4" width="110px;"/><br /><sub>theburger</sub>](https://github.com/limeless)<br />[💻](https://github.com/snipe/snipe-it/commits?author=limeless "Code") |
| [<img src="https://avatars.githubusercontent.com/u/36065681?v=4" width="110px;"/><br /><sub>David Valin Alonso</sub>](https://github.com/deivishome)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [<img src="https://avatars.githubusercontent.com/u/8290389?v=4" width="110px;"/><br /><sub>andreaci</sub>](https://github.com/andreaci)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [<img src="https://avatars.githubusercontent.com/u/1828542?v=4" width="110px;"/><br /><sub>Jelle Sebreghts</sub>](http://www.jellesebreghts.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [<img src="https://avatars.githubusercontent.com/u/11180862?v=4" width="110px;"/><br /><sub>Michael Pietsch</sub>](https://github.com/Skywalker-11)<br /> | [<img src="https://avatars.githubusercontent.com/u/22068886?v=4" width="110px;"/><br /><sub>Masudul Haque Shihab</sub>](https://github.com/sh1hab)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [<img src="https://avatars.githubusercontent.com/u/16099942?v=4" width="110px;"/><br /><sub>Supapong Areeprasertkul</sub>](http://www.freedomdive.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [<img src="https://avatars.githubusercontent.com/u/207358?v=4" width="110px;"/><br /><sub>Peter Sarossy</sub>](https://github.com/psarossy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") | | [<img src="https://avatars.githubusercontent.com/u/36065681?v=4" width="110px;"/><br /><sub>David Valin Alonso</sub>](https://github.com/deivishome)<br />[💻](https://github.com/snipe/snipe-it/commits?author=deivishome "Code") | [<img src="https://avatars.githubusercontent.com/u/8290389?v=4" width="110px;"/><br /><sub>andreaci</sub>](https://github.com/andreaci)<br />[💻](https://github.com/snipe/snipe-it/commits?author=andreaci "Code") | [<img src="https://avatars.githubusercontent.com/u/1828542?v=4" width="110px;"/><br /><sub>Jelle Sebreghts</sub>](http://www.jellesebreghts.be)<br />[💻](https://github.com/snipe/snipe-it/commits?author=Jelle-S "Code") | [<img src="https://avatars.githubusercontent.com/u/11180862?v=4" width="110px;"/><br /><sub>Michael Pietsch</sub>](https://github.com/Skywalker-11)<br /> | [<img src="https://avatars.githubusercontent.com/u/22068886?v=4" width="110px;"/><br /><sub>Masudul Haque Shihab</sub>](https://github.com/sh1hab)<br />[💻](https://github.com/snipe/snipe-it/commits?author=sh1hab "Code") | [<img src="https://avatars.githubusercontent.com/u/16099942?v=4" width="110px;"/><br /><sub>Supapong Areeprasertkul</sub>](http://www.freedomdive.com/)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zybersup "Code") | [<img src="https://avatars.githubusercontent.com/u/207358?v=4" width="110px;"/><br /><sub>Peter Sarossy</sub>](https://github.com/psarossy)<br />[💻](https://github.com/snipe/snipe-it/commits?author=psarossy "Code") |
| [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/5553884?v=4" width="110px;"/><br /><sub>JohnnyPicnic</sub>](https://github.com/JohnnyPicnic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [<img src="https://avatars.githubusercontent.com/u/8799594?v=4" width="110px;"/><br /><sub>markbrule</sub>](https://github.com/markbrule)<br />[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [<img src="https://avatars.githubusercontent.com/u/1962801?v=4" width="110px;"/><br /><sub>Mike Campbell</sub>](https://github.com/mikecmpbll)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | | [<img src="https://avatars.githubusercontent.com/u/11823649?v=4" width="110px;"/><br /><sub>Renee Margaret McConahy</sub>](https://github.com/nepella)<br />[💻](https://github.com/snipe/snipe-it/commits?author=nepella "Code") | [<img src="https://avatars.githubusercontent.com/u/5553884?v=4" width="110px;"/><br /><sub>JohnnyPicnic</sub>](https://github.com/JohnnyPicnic)<br />[💻](https://github.com/snipe/snipe-it/commits?author=JohnnyPicnic "Code") | [<img src="https://avatars.githubusercontent.com/u/8799594?v=4" width="110px;"/><br /><sub>markbrule</sub>](https://github.com/markbrule)<br />[💻](https://github.com/snipe/snipe-it/commits?author=markbrule "Code") | [<img src="https://avatars.githubusercontent.com/u/1962801?v=4" width="110px;"/><br /><sub>Mike Campbell</sub>](https://github.com/mikecmpbll)<br />[💻](https://github.com/snipe/snipe-it/commits?author=mikecmpbll "Code") | [<img src="https://avatars.githubusercontent.com/u/11973217?v=4" width="110px;"/><br /><sub>tbrconnect</sub>](https://github.com/tbrconnect)<br />[💻](https://github.com/snipe/snipe-it/commits?author=tbrconnect "Code") |
<!-- ALL-CONTRIBUTORS-LIST:END --> <!-- ALL-CONTRIBUTORS-LIST:END -->
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!

View file

@ -81,6 +81,8 @@ class ResetDemoSettings extends Command
$user->save(); $user->save();
} }
\Storage::disk('local_public')->put('snipe-logo.png', file_get_contents(public_path('img/demo/snipe-logo.png')));
\Storage::disk('local_public')->put('snipe-logo-lg.png', file_get_contents(public_path('img/demo/snipe-logo-lg.png')));
} }

View file

@ -0,0 +1,249 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use ZipArchive;
class RestoreFromBackup extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'snipeit:restore
{--force : Skip the danger prompt; assuming you hit "y"}
{filename : The zip file to be migrated}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Restore from a previously created backup';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$dir = getcwd();
print "Current working directory is: $dir\n";
//
$filename = $this->argument('filename');
if (!$filename) {
return $this->error("Missing required filename");
}
if (!$this->option('force') && !$this->confirm('Are you sure you wish to restore from the given backup file? This can lead to MASSIVE DATA LOSS!')) {
return $this->error("Data loss not confirmed");
}
if (config('database.default') != 'mysql') {
return $this->error("DB_CONNECTION must be MySQL in order to perform a restore. Detected: ".config('database.default'));
}
$za = new ZipArchive();
$errcode = $za->open($filename, ZipArchive::RDONLY);
if ($errcode !== true) {
$errors = [
ZipArchive::ER_EXISTS => "File already exists.",
ZipArchive::ER_INCONS => "Zip archive inconsistent.",
ZipArchive::ER_INVAL => "Invalid argument.",
ZipArchive::ER_MEMORY => "Malloc failure.",
ZipArchive::ER_NOENT => "No such file.",
ZipArchive::ER_NOZIP => "Not a zip archive.",
ZipArchive::ER_OPEN => "Can't open file.",
ZipArchive::ER_READ => "Read error.",
ZipArchive::ER_SEEK => "Seek error."
];
return $this->error("Could not access file: ".$filename." - ".array_key_exists($errcode,$errors) ? $errors[$errcode] : " Unknown reason: $errcode");
}
$private_dirs = [
'storage/private_uploads/assets',
'storage/private_uploads/audits',
'storage/private_uploads/imports',
'storage/private_uploads/assetmodels',
'storage/private_uploads/users',
'storage/private_uploads/licenses',
'storage/private_uploads/signatures' // We probably don't want this in the first place.
];
$private_files = [
'storage/oauth-private.key',
'storage/oauth-public.key'
];
$public_dirs = [
'public/uploads/companies',
'public/uploads/components',
'public/uploads/categories',
'public/uploads/manufacturers',
'public/uploads/barcodes', // don't want this neither
'public/uploads/consumables',
'public/uploads/departments',
'public/uploads/avatars',
'public/uploads/suppliers',
'public/uploads/assets', //wait, what?!
'public/uploads/locations',
'public/uploads/accessories',
'public/uploads/models',
];
$public_files = [
'public/uploads/logo.png'
];
$all_files = $private_dirs + $public_dirs;
$sqlfiles = [];
$sqlfile_indices = [];
$interesting_files = [];
for ($i=0; $i<$za->numFiles;$i++) {
$stat_results = $za->statIndex($i);
// echo "index: $i\n";
// print_r($stat_results);
$raw_path = $stat_results['name'];
// skip macOS resource fork files (?!?!?!)
if(strpos($raw_path,"__MACOSX")!==false && strpos($raw_path,"._") !== false) {
//print "SKIPPING macOS Resource fork file: $raw_path\n";
continue;
}
if(strpos($raw_path,'\\')!==false) { //found a backslash, swap it to forward-slash
$raw_path = strtr($raw_path,'\\','/');
//print "Translating file: ".$stat_results['name']." to: ".$raw_path."\n";
}
if(@pathinfo($raw_path)['extension'] == "sql") {
print "Found a sql file!\n";
$sqlfiles[] = $raw_path;
$sqlfile_indices[] = $i;
}
foreach($private_dirs+$public_dirs as $dir) {
$last_pos = strrpos($raw_path,$dir.'/');
if($last_pos !== false ) {
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
print("We would copy $raw_path to $dir.\n"); //FIXME append to a path?
$interesting_files[$raw_path] = ['dest' =>$dir, 'index' => $i];
if($last_pos + strlen($dir) +1 == strlen($raw_path)) {
// we don't care about that; we just want files with the appropriate prefix
//print("FOUND THE EXACT DIRECTORY: $dir AT: $raw_path!!!\n");
}
}
}
foreach($private_files+$public_files as $file) {
$last_pos = strrpos($raw_path,$file); // no trailing slash!
if($last_pos !== false ) {
//print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n");
if($last_pos + strlen($file) == strlen($raw_path)) { //again, no trailing slash
print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though.
$interesting_files[$raw_path] = ['dest' => dirname($file),'index' => $i];
}
}
}
}
// print_r($interesting_files);exit(-1);
if( count($sqlfiles) != 1) {
return $this->error("There should be exactly *one* sql backup file found, found: ".( count($sqlfiles) == 0 ? "None" : implode(", ",$sqlfiles)));
}
if( strpos($sqlfiles[0], "db-dumps") === false ) {
//return $this->error("SQL backup file is missing 'db-dumps' component of full pathname: ".$sqlfiles[0]);
//older Snipe-IT installs don't have the db-dumps subdirectory component
}
//how to invoke the restore?
$pipes = [];
// FIXME - absolutely can *NOT* be hardcoding paths like this!!!!!!! But I don't know how to do it right? (Maybe get the user's ENV and append the MYSQL_PWD to it?)
$env_vars = getenv();
$env_vars['MYSQL_PWD'] = config("database.connections.mysql.password");
$proc_results = proc_open("mysql -h ".escapeshellarg(config('database.connections.mysql.host'))." -u ".escapeshellarg(config('database.connections.mysql.username'))." ".escapeshellarg(config('database.connections.mysql.database')), // yanked -p since we pass via ENV
[0 => ['pipe','r'],1 => ['pipe','w'],2 => ['pipe','w']],
$pipes,
null,
$env_vars); // this is not super-duper awesome-secure, but definitely more secure than showing it on the CLI, or dropping temporary files with passwords in them.
if($proc_results === false) {
return $this->error("Unable to invoke mysql via CLI");
}
// $this->info("Stdout says? ".fgets($pipes[1])); //FIXME: I think we might need to set non-blocking mode to use this properly?
// $this->info("Stderr says? ".fgets($pipes[2])); //FIXME: ditto, same.
// should we read stdout?
// fwrite($pipes[0],config("database.connections.mysql.password")."\n"); //this doesn't work :(
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
$sql_stat = $za->statIndex($sqlfile_indices[0]);
$this->info("SQL Stat is: ".print_r($sql_stat,true));
$sql_contents = $za->getStream($sql_stat['name']);
if ($sql_contents === false) {
$stdout = fgets($pipes[1]);
$this->info($stdout);
$stderr = fgets($pipes[2]);
$this->info($stderr);
return false;
}
while(($buffer = fgets($sql_contents)) !== false ) {
//$this->info("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;
}
}
fclose($pipes[0]);
fclose($sql_contents);
fclose($pipes[1]);
fclose($pipes[2]);
//wait, have to do fclose() on all pipes first?
$close_results = proc_close($proc_results);
if($close_results != 0) {
return $this->error("There may have been a problem with the database import: Error number ".$close_results);
}
//and now copy the files over too (right?)
//FIXME - we don't prune the filesystem space yet!!!!
foreach($interesting_files AS $pretty_file_name => $file_details) {
$ugly_file_name = $za->statIndex($file_details['index'])['name'];
$fp = $za->getStream($ugly_file_name);
$this->info("Weird problem, here are file details? ".print_r($file_details,true));
$migrated_file = fopen($file_details['dest']."/".basename($pretty_file_name),"w");
while(($buffer = fgets($fp))!== false) {
fwrite($migrated_file,$buffer);
}
fclose($migrated_file);
fclose($fp);
$this->info("Wrote $ugly_file_name to $pretty_file_name");
}
}
}

View file

@ -17,6 +17,8 @@ class LicenseSeatsController extends Controller
/** /**
* Display a listing of the resource. * Display a listing of the resource.
* *
* @param \Illuminate\Http\Request $request
* @param int $licenseId
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function index(Request $request, $licenseId) public function index(Request $request, $licenseId)
@ -53,7 +55,8 @@ class LicenseSeatsController extends Controller
/** /**
* Display the specified resource. * Display the specified resource.
* *
* @param int $id * @param int $licenseId
* @param int $seatId
* @return \Illuminate\Http\Response * @return \Illuminate\Http\Response
*/ */
public function show($licenseId, $seatId) public function show($licenseId, $seatId)

View file

@ -99,7 +99,7 @@ class SecurityHeaders
// We have to exclude debug mode here because debugbar pulls from a CDN or two // We have to exclude debug mode here because debugbar pulls from a CDN or two
// and it will break things. // and it will break things.
if ((config('app.debug')!='true') || (config('app.enable_csp')=='true')) { if ((config('app.debug')!='true') && (config('app.enable_csp')=='true')) {
$csp_policy[] = "default-src 'self'"; $csp_policy[] = "default-src 'self'";
$csp_policy[] = "style-src 'self' 'unsafe-inline'"; $csp_policy[] = "style-src 'self' 'unsafe-inline'";
$csp_policy[] = "script-src 'self' 'unsafe-inline' 'unsafe-eval'"; $csp_policy[] = "script-src 'self' 'unsafe-inline' 'unsafe-eval'";

View file

@ -23,7 +23,7 @@ class Location extends SnipeModel
protected $rules = array( protected $rules = array(
'name' => 'required|min:2|max:255|unique_undeleted', 'name' => 'required|min:2|max:255|unique_undeleted',
'city' => 'min:2|max:255|nullable', 'city' => 'min:2|max:255|nullable',
'country' => 'min:2|max:2|nullable', 'country' => 'min:2|max:255|nullable',
'address' => 'max:80|nullable', 'address' => 'max:80|nullable',
'address2' => 'max:80|nullable', 'address2' => 'max:80|nullable',
'zip' => 'min:3|max:10|nullable', 'zip' => 'min:3|max:10|nullable',

View file

@ -135,7 +135,7 @@ class LdapAd extends LdapAdConfiguration
$bind_as_user = true; $bind_as_user = true;
} }
if ($this->ldap->auth()->attempt($login_username, $password, $bind_as_user) === false) { if (($this->ldap) && ($this->ldap->auth()->attempt($login_username, $password, $bind_as_user) === false)) {
throw new Exception('Unable to validate user credentials!'); throw new Exception('Unable to validate user credentials!');
} }

View file

@ -6,5 +6,5 @@ return array (
'prerelease_version' => '', 'prerelease_version' => '',
'hash_version' => 'gd9d5b4d73', 'hash_version' => 'gd9d5b4d73',
'full_hash' => 'v5.1.5-17-gd9d5b4d73', 'full_hash' => 'v5.1.5-17-gd9d5b4d73',
'branch' => 'develop', 'branch' => 'master',
); );

View file

@ -42,8 +42,8 @@ class SettingsSeeder extends Seeder
// Copy the logos from the img/demo directory // Copy the logos from the img/demo directory
Storage::disk('public')->put(public_path('uploads/snipe-logo.png'), file_get_contents(public_path('img/demo/snipe-logo.png'))); Storage::disk('local_public')->put('snipe-logo.png', file_get_contents(public_path('img/demo/snipe-logo.png')));
Storage::disk('public')->put(public_path('uploads/snipe-logo-lg.png'), file_get_contents(public_path('img/demo/snipe-logo-lg.png'))); Storage::disk('local_public')->put('snipe-logo-lg.png', file_get_contents(public_path('img/demo/snipe-logo-lg.png')));
} }
} }

View file

@ -45,6 +45,11 @@ then
cp -a /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/ cp -a /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/
fi fi
if [ "${SESSION_DRIVER}" == "database" ]
then
cp -a /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Console/stubs/database.stub /var/www/html/database/migrations/2021_05_06_0000_create_sessions_table.php
fi
php artisan migrate --force php artisan migrate --force
php artisan config:clear php artisan config:clear
php artisan config:cache php artisan config:cache

View file

@ -48,18 +48,19 @@ then
sed -i "s/^upload_max_filesize.*/upload_max_filesize = ${PHP_UPLOAD_LIMIT}M/" /etc/php/*/apache2/php.ini sed -i "s/^upload_max_filesize.*/upload_max_filesize = ${PHP_UPLOAD_LIMIT}M/" /etc/php/*/apache2/php.ini
fi fi
# If the Oauth DB files are not present copy the vendor files over to the db migrations # If the Oauth DB files are not present copy the vendor files over to the db migrations
if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ] if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ]
then then
cp -ax /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/ cp -ax /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/
fi fi
exec supervisord -c /supervisord.conf if [ $SESSION_DRIVER = "database" ]
then
cp -ax /var/www/html/vendor/laravel/framework/src/Illuminate/Session/Console/stubs/database.stub /var/www/html/database/migrations/2021_05_06_0000_create_sessions_table.php
fi
php artisan migrate --force php artisan migrate --force
php artisan config:clear php artisan config:clear
php artisan config:cache php artisan config:cache
. /etc/apache2/envvars exec supervisord -c /supervisord.conf
exec apache2 -DNO_DETACH < /dev/null

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
public/img/demo/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Binary file not shown.

BIN
public/js/dist/all.js vendored

Binary file not shown.

Binary file not shown.

View file

@ -1,24 +1,24 @@
{ {
"/js/build/app.js": "/js/build/app.js?id=708f0de04f1f8ba0d19d", "/js/build/app.js": "/js/build/app.js?id=b23ec8d1be42f9d3d810",
"/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=5d8ce6b758f170008cd6", "/css/build/AdminLTE.css": "/css/build/AdminLTE.css?id=59413334823616b81341",
"/css/build/app.css": "/css/build/app.css?id=9b6ddbece1a3cfc99036", "/css/build/app.css": "/css/build/app.css?id=032fd8c3fce99c7fd862",
"/css/build/overrides.css": "/css/build/overrides.css?id=0a65220cdae6fbb6d913", "/css/build/overrides.css": "/css/build/overrides.css?id=0b4aefd7ef0c117ef23a",
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=e57a7bb77ae1fb640331", "/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=1f87813d401bf76aa1c0",
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=fdb6630b38435c84c7d2", "/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b09d08f1bce1ce6ef565",
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=5d582ce5e98f591b8c65", "/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=4fce68ca7086890d9029",
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=02e8563844e00840e01c", "/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=caf97a95374a38d8645e",
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=4daaa0e353849ff8cacf", "/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=d6fc509af348f74dbe80",
"/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=c89047b28b272bc07e81", "/css/dist/skins/skin-black.css": "/css/dist/skins/skin-black.css?id=8babe0615220ced5e869",
"/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=9f9013a3ec06e256e1dc", "/css/dist/skins/skin-black-dark.css": "/css/dist/skins/skin-black-dark.css?id=a1be7d448d0a7a677aa4",
"/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=5b4937fd36d26f7a92e3", "/css/dist/skins/skin-red-dark.css": "/css/dist/skins/skin-red-dark.css?id=36c5a414e9b5dfff5010",
"/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=e6239abc2a7a28441911", "/css/dist/skins/skin-purple.css": "/css/dist/skins/skin-purple.css?id=73e98a9a8e41cd044475",
"/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=85ef26204fbc8b2dad5b", "/css/dist/skins/skin-purple-dark.css": "/css/dist/skins/skin-purple-dark.css?id=bc80aa3d9d5ab9f72514",
"/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=84667fc9b0f00d11a9c4", "/css/dist/skins/skin-yellow.css": "/css/dist/skins/skin-yellow.css?id=40988b7e9e4bbd9baa06",
"/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=8e774a0e5435527d63c4", "/css/dist/skins/skin-yellow-dark.css": "/css/dist/skins/skin-yellow-dark.css?id=39a7bdc303ea2cd82641",
"/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=5269656828cfba157e92", "/css/dist/skins/skin-blue-dark.css": "/css/dist/skins/skin-blue-dark.css?id=bd4e8277d360eac19b2b",
"/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=0a4ddc28e3a8228cc11e", "/css/dist/skins/skin-orange-dark.css": "/css/dist/skins/skin-orange-dark.css?id=289676d6c84e2f4980d6",
"/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=b22dc3561eda3d2027a9", "/css/dist/skins/skin-orange.css": "/css/dist/skins/skin-orange.css?id=0426fbe408151f690505",
"/css/dist/all.css": "/css/dist/all.css?id=fc64989106daf3be016b", "/css/dist/all.css": "/css/dist/all.css?id=199fdf677ce0dce6cef8",
"/css/blue.png": "/css/blue.png?id=4c85d6a97173123bd14a", "/css/blue.png": "/css/blue.png?id=4c85d6a97173123bd14a",
"/css/blue@2x.png": "/css/blue@2x.png?id=62c67c6a822439e8a4ac", "/css/blue@2x.png": "/css/blue@2x.png?id=62c67c6a822439e8a4ac",
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced", "/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced",
@ -26,20 +26,20 @@
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=1e77fde04b3f42432581", "/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=1e77fde04b3f42432581",
"/js/build/vendor.js": "/js/build/vendor.js?id=b93877b4a88a76e1b18b", "/js/build/vendor.js": "/js/build/vendor.js?id=b93877b4a88a76e1b18b",
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=fd6e727609678bf04984", "/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=fd6e727609678bf04984",
"/js/dist/all.js": "/js/dist/all.js?id=d0fbb4953b84b70787d4", "/js/dist/all.js": "/js/dist/all.js?id=dde965016a515da2f8d2",
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=02e8563844e00840e01c", "/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=caf97a95374a38d8645e",
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=4daaa0e353849ff8cacf", "/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=d6fc509af348f74dbe80",
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=c89047b28b272bc07e81", "/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=8babe0615220ced5e869",
"/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=9f9013a3ec06e256e1dc", "/css/dist/skins/skin-black-dark.min.css": "/css/dist/skins/skin-black-dark.min.css?id=a1be7d448d0a7a677aa4",
"/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=e57a7bb77ae1fb640331", "/css/dist/skins/skin-blue.min.css": "/css/dist/skins/skin-blue.min.css?id=1f87813d401bf76aa1c0",
"/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=5269656828cfba157e92", "/css/dist/skins/skin-blue-dark.min.css": "/css/dist/skins/skin-blue-dark.min.css?id=bd4e8277d360eac19b2b",
"/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=84667fc9b0f00d11a9c4", "/css/dist/skins/skin-yellow.min.css": "/css/dist/skins/skin-yellow.min.css?id=40988b7e9e4bbd9baa06",
"/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=8e774a0e5435527d63c4", "/css/dist/skins/skin-yellow-dark.min.css": "/css/dist/skins/skin-yellow-dark.min.css?id=39a7bdc303ea2cd82641",
"/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=fdb6630b38435c84c7d2", "/css/dist/skins/skin-red.min.css": "/css/dist/skins/skin-red.min.css?id=b09d08f1bce1ce6ef565",
"/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=5b4937fd36d26f7a92e3", "/css/dist/skins/skin-red-dark.min.css": "/css/dist/skins/skin-red-dark.min.css?id=36c5a414e9b5dfff5010",
"/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=e6239abc2a7a28441911", "/css/dist/skins/skin-purple.min.css": "/css/dist/skins/skin-purple.min.css?id=73e98a9a8e41cd044475",
"/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=85ef26204fbc8b2dad5b", "/css/dist/skins/skin-purple-dark.min.css": "/css/dist/skins/skin-purple-dark.min.css?id=bc80aa3d9d5ab9f72514",
"/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=b22dc3561eda3d2027a9", "/css/dist/skins/skin-orange.min.css": "/css/dist/skins/skin-orange.min.css?id=0426fbe408151f690505",
"/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=0a4ddc28e3a8228cc11e", "/css/dist/skins/skin-orange-dark.min.css": "/css/dist/skins/skin-orange-dark.min.css?id=289676d6c84e2f4980d6",
"/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=5d582ce5e98f591b8c65" "/css/dist/skins/skin-contrast.min.css": "/css/dist/skins/skin-contrast.min.css?id=4fce68ca7086890d9029"
} }

View file

@ -56,6 +56,13 @@ $qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->alt_barcode!='')
padding-top: .11in; padding-top: .11in;
width: 100%; width: 100%;
} }
div.label-logo {
float: right;
display: inline-block;
}
img.label-logo {
height: 0.5in;
}
.qr_text { .qr_text {
width: {{ $settings->labels_width }}in; width: {{ $settings->labels_width }}in;
height: {{ $settings->labels_height }}in; height: {{ $settings->labels_height }}in;
@ -111,6 +118,11 @@ $qr_size = ($settings->alt_barcode_enabled=='1') && ($settings->alt_barcode!='')
@endif @endif
<div class="qr_text"> <div class="qr_text">
@if ($settings->label_logo)
<div class="label-logo">
<img class="label-logo" src="{{ Storage::disk('public')->url('').e($snipeSettings->label_logo) }}">
</div>
@endif
@if ($settings->qr_text!='') @if ($settings->qr_text!='')
<div class="pull-left"> <div class="pull-left">
<strong>{{ $settings->qr_text }}</strong> <strong>{{ $settings->qr_text }}</strong>

View file

@ -722,7 +722,26 @@
{{ ($asset->userRequests) ? (int) $asset->userRequests->count() : '0' }} {{ ($asset->userRequests) ? (int) $asset->userRequests->count() : '0' }}
</div> </div>
</div> </div>
<div class="row">
<div class="col-md-2">
<strong>
Labels
</strong>
</div>
<div class="col-md-6">
{{ Form::open([
'method' => 'POST',
'route' => ['hardware/bulkedit'],
'class' => 'form-inline',
'id' => 'bulkForm']) }}
<input type="hidden" name="bulk_actions" value="labels" />
<input type="hidden" name="ids[{{$asset->id}}]" value="{{ $asset->id }}" />
<button class="btn btn-sm btn-default" id="bulkEdit" ><i class="fa fa-barcode" aria-hidden="true"></i> {{ trans_choice('button.generate_labels', 1) }}</button>
{{ Form::close() }}
</div>
</div>
</div> <!-- end row-striped --> </div> <!-- end row-striped -->
</div><!-- /col-md-8 --> </div><!-- /col-md-8 -->

View file

@ -84,11 +84,11 @@
<tr> <tr>
<td>{{ $counter }}</td> <td>{{ $counter }}</td>
<td>{{ $user->company->name }}</td> <td>{{ (($user) && ($user->company)) ? $user->company->name : '' }}</td>
<td>{{ $user->first_name }} {{ $user->last_name }}</td> <td>{{ ($user) ? $user->first_name .' '. $user->last_name : '' }}</td>
<td>{{ $user->employee_num }}</td> <td>{{ ($user) ? $user->employee_num : '' }}</td>
<td>{{ $user->department->name }}</td> <td>{{ (($user) && ($user->department)) ? $user->department->name : '' }}</td>
<td>{{ $user->location->name }}</td> <td>{{ (($user) && ($user->location)) ? $user->location->name : '' }}</td>
</tr> </tr>
@php @php
$counter++ $counter++
@ -131,9 +131,9 @@
<td>{{ $counter }}</td> <td>{{ $counter }}</td>
<td>{{ $asset->asset_tag }}</td> <td>{{ $asset->asset_tag }}</td>
<td>{{ $asset->name }}</td> <td>{{ $asset->name }}</td>
<td>{{ $asset->model->category->name }}</td> <td>{{ (($asset->model) && ($asset->model->category)) ? $asset->model->category->name : '' }}</td>
<td>{{ $asset->model->manufacturer->name }}</td> <td>{{ (($asset->model) && ($asset->model->manufacturer)) ? $asset->model->manufacturer->name : '' }}</td>
<td>{{ $asset->model->name }} {{ $asset->model->model_number }}</td> <td>{{ ($asset->model) ? $asset->model->name : '' }}</td>
<td>{{ $asset->serial }}</td> <td>{{ $asset->serial }}</td>
<td>{{ $asset->location->name }}</td> <td>{{ $asset->location->name }}</td>
<td>{{ $asset->last_checkout }}</td> <td>{{ $asset->last_checkout }}</td>

View file

@ -30,7 +30,6 @@
id="system-backups" id="system-backups"
class="table table-striped snipe-table"> class="table table-striped snipe-table">
<thead> <thead>
<thead>
<th>File</th> <th>File</th>
<th>Created</th> <th>Created</th>
<th>Size</th> <th>Size</th>

View file

@ -75,7 +75,7 @@ LDAP User Sync
</tr> </tr>
@foreach (Session::get('summary') as $entry) @foreach (Session::get('summary') as $entry)
<tr {!! ($entry['status']=='SUCCESS') ? 'class="success"' : 'class="danger"' !!}> <tr {!! ($entry['status']=='success') ? 'class="success"' : 'class="danger"' !!}>
<td>{{ $entry['username'] }}</td> <td>{{ $entry['username'] }}</td>
<td>{{ $entry['employee_number'] }}</td> <td>{{ $entry['employee_number'] }}</td>
<td>{{ $entry['firstname'] }}</td> <td>{{ $entry['firstname'] }}</td>

View file

@ -85,7 +85,11 @@
<td>{{ $asset->serial }}</td> <td>{{ $asset->serial }}</td>
<td> <td>
{{ $asset->last_checkout }}</td> {{ $asset->last_checkout }}</td>
<td><div><img height="20%" src="{{ asset('/') }}display-sig/{{ $asset->assetlog->first()->accept_signature }}"></img></div></td> <td>
@if ($asset->assetlog->first())
<img height="20%" src="{{ asset('/') }}display-sig/{{ $asset->assetlog->first()->accept_signature }}">
@endif
</td>
</tr> </tr>
@if($settings->show_assigned_assets) @if($settings->show_assigned_assets)
@php @php

View file

@ -248,10 +248,14 @@
</tr> </tr>
@endif @endif
@if (!is_null($user->department)) @if ($user->department)
<tr> <tr>
<td class="text-nowrap">{{ trans('general.department') }}</td> <td class="text-nowrap">{{ trans('general.department') }}</td>
<td><a href="{{ route('departments.show', $user->department) }}">{{ $user->department->name }}</a></td> <td>
<a href="{{ route('departments.show', $user->department) }}">
{{ $user->department->name }}
</a>
</td>
</tr> </tr>
@endif @endif
@if ($user->created_at) @if ($user->created_at)