mirror of
https://github.com/snipe/snipe-it.git
synced 2024-11-09 23:24:06 -08:00
Merge branch 'develop' into snipeit_v7_laravel10
Had to re-generate composer.lock, and re-do package.json and rebuild assets as well.
This commit is contained in:
commit
8f2843bfcf
2
.github/workflows/codacy-analysis.yml
vendored
2
.github/workflows/codacy-analysis.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
||||||
|
|
||||||
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
|
||||||
- name: Run Codacy Analysis CLI
|
- name: Run Codacy Analysis CLI
|
||||||
uses: codacy/codacy-analysis-cli-action@v4.3.0
|
uses: codacy/codacy-analysis-cli-action@v4.4.0
|
||||||
with:
|
with:
|
||||||
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
|
||||||
# You can also omit the token and run the tools that support default configurations
|
# You can also omit the token and run the tools that support default configurations
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM alpine:3.18.5
|
FROM alpine:3.18.6
|
||||||
# Apache + PHP
|
# Apache + PHP
|
||||||
RUN apk add --no-cache \
|
RUN apk add --no-cache \
|
||||||
apache2 \
|
apache2 \
|
||||||
|
@ -29,6 +29,7 @@ RUN apk add --no-cache \
|
||||||
php81-sodium \
|
php81-sodium \
|
||||||
php81-redis \
|
php81-redis \
|
||||||
php81-pecl-memcached \
|
php81-pecl-memcached \
|
||||||
|
php81-exif \
|
||||||
curl \
|
curl \
|
||||||
wget \
|
wget \
|
||||||
vim \
|
vim \
|
||||||
|
|
17
TESTING.md
17
TESTING.md
|
@ -45,8 +45,21 @@ DB_PASSWORD={}
|
||||||
|
|
||||||
Now you are ready to run the entire test suite from your terminal:
|
Now you are ready to run the entire test suite from your terminal:
|
||||||
|
|
||||||
`php artisan test`
|
```shell
|
||||||
|
php artisan test
|
||||||
|
````
|
||||||
|
|
||||||
To run individual test files, you can pass the path to the test that you want to run:
|
To run individual test files, you can pass the path to the test that you want to run:
|
||||||
|
|
||||||
`php artisan test tests/Unit/AccessoryTest.php`
|
```shell
|
||||||
|
php artisan test tests/Unit/AccessoryTest.php
|
||||||
|
```
|
||||||
|
|
||||||
|
Some tests, like ones concerning LDAP, are marked with the `@group` annotation. Those groups can be run, or excluded, using the `--group` or `--exclude-group` flags:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
php artisan test --group=ldap
|
||||||
|
|
||||||
|
php artisan test --exclude-group=ldap
|
||||||
|
```
|
||||||
|
This can be helpful if a set of tests are failing because you don't have an extension, like LDAP, installed.
|
||||||
|
|
|
@ -5,6 +5,151 @@ namespace App\Console\Commands;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
|
|
||||||
|
class SQLStreamer {
|
||||||
|
private $input;
|
||||||
|
private $output;
|
||||||
|
// embed the prefix here?
|
||||||
|
public ?string $prefix;
|
||||||
|
|
||||||
|
private bool $reading_beginning_of_line = true;
|
||||||
|
|
||||||
|
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
|
||||||
|
|
||||||
|
public array $tablenames = [];
|
||||||
|
private bool $should_guess = false;
|
||||||
|
private bool $statement_is_permitted = false;
|
||||||
|
|
||||||
|
public function __construct($input, $output, string $prefix = null)
|
||||||
|
{
|
||||||
|
$this->input = $input;
|
||||||
|
$this->output = $output;
|
||||||
|
$this->prefix = $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse_sql(string $line): string {
|
||||||
|
// take into account the 'start of line or not' setting as an instance variable?
|
||||||
|
// 'continuation' lines for a permitted statement are PERMITTED.
|
||||||
|
if($this->statement_is_permitted && $line[0] === ' ') {
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table_regex = '`?([a-zA-Z0-9_]+)`?';
|
||||||
|
$allowed_statements = [
|
||||||
|
"/^(DROP TABLE (?:IF EXISTS )?)`$table_regex(.*)$/" => false,
|
||||||
|
"/^(CREATE TABLE )$table_regex(.*)$/" => true, //sets up 'continuation'
|
||||||
|
"/^(LOCK TABLES )$table_regex(.*)$/" => false,
|
||||||
|
"/^(INSERT INTO )$table_regex(.*)$/" => false,
|
||||||
|
"/^UNLOCK TABLES/" => false,
|
||||||
|
// "/^\\) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;/" => false, // FIXME not sure what to do here?
|
||||||
|
"/^\\)[a-zA-Z0-9_= ]*;$/" => false
|
||||||
|
// ^^^^^^ that bit should *exit* the 'perimitted' black
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach($allowed_statements as $statement => $statechange) {
|
||||||
|
// $this->info("Checking regex: $statement...\n");
|
||||||
|
$matches = [];
|
||||||
|
if (preg_match($statement,$line,$matches)) {
|
||||||
|
$this->statement_is_permitted = $statechange;
|
||||||
|
// matches are: 1 => first part of the statement, 2 => tablename, 3 => rest of statement
|
||||||
|
// (with of course 0 being "the whole match")
|
||||||
|
if (@$matches[2]) {
|
||||||
|
// print "Found a tablename! It's: ".$matches[2]."\n";
|
||||||
|
if ($this->should_guess) {
|
||||||
|
@$this->tablenames[$matches[2]] += 1;
|
||||||
|
continue; //oh? FIXME
|
||||||
|
} else {
|
||||||
|
$cleaned_tablename = \DB::getTablePrefix().preg_replace('/^'.$this->prefix.'/','',$matches[2]);
|
||||||
|
$line = preg_replace($statement,'$1`'.$cleaned_tablename.'`$3' , $line);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no explicit tablename in this one, leave the line alone
|
||||||
|
}
|
||||||
|
//how do we *replace* the tablename?
|
||||||
|
// print "RETURNING LINE: $line";
|
||||||
|
return $line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// all that is not allowed is denied.
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
//this is used in exactly *TWO* places, and in both cases should return a prefix I think?
|
||||||
|
// first - if you do the --sanitize-only one (which is mostly for testing/development)
|
||||||
|
// next - when you run *without* a guessed prefix, this is run first to figure out the prefix
|
||||||
|
// I think we have to *duplicate* the call to be able to run it again?
|
||||||
|
public static function guess_prefix($input):string
|
||||||
|
{
|
||||||
|
$parser = new self($input, null);
|
||||||
|
$parser->should_guess = true;
|
||||||
|
$parser->line_aware_piping(); // <----- THIS is doing the heavy lifting!
|
||||||
|
|
||||||
|
$check_tables = ['settings' => null, 'migrations' => null /* 'assets' => null */]; //TODO - move to statics?
|
||||||
|
//can't use 'users' because the 'accessories_users' table?
|
||||||
|
// can't use 'assets' because 'ver1_components_assets'
|
||||||
|
foreach($check_tables as $check_table => $_ignore) {
|
||||||
|
foreach ($parser->tablenames as $tablename => $_count) {
|
||||||
|
// print "Comparing $tablename to $check_table\n";
|
||||||
|
if (str_ends_with($tablename,$check_table)) {
|
||||||
|
// print "Found one!\n";
|
||||||
|
$check_tables[$check_table] = substr($tablename,0,-strlen($check_table));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$guessed_prefix = null;
|
||||||
|
foreach ($check_tables as $clean_table => $prefix_guess) {
|
||||||
|
if(is_null($prefix_guess)) {
|
||||||
|
print("Couldn't find table $clean_table\n");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
if(is_null($guessed_prefix)) {
|
||||||
|
$guessed_prefix = $prefix_guess;
|
||||||
|
} else {
|
||||||
|
if ($guessed_prefix != $prefix_guess) {
|
||||||
|
print("Prefix mismatch! Had guessed $guessed_prefix but got $prefix_guess\n");
|
||||||
|
die();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $guessed_prefix;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function line_aware_piping(): int
|
||||||
|
{
|
||||||
|
$bytes_read = 0;
|
||||||
|
if (! $this->input) {
|
||||||
|
throw new \Exception("No Input available for line_aware_piping");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (($buffer = fgets($this->input, SQLStreamer::$buffer_size)) !== false) {
|
||||||
|
$bytes_read += strlen($buffer);
|
||||||
|
if ($this->reading_beginning_of_line) {
|
||||||
|
// \Log::debug("Buffer is: '$buffer'");
|
||||||
|
$cleaned_buffer = $this->parse_sql($buffer);
|
||||||
|
if ($this->output) {
|
||||||
|
$bytes_written = fwrite($this->output, $cleaned_buffer);
|
||||||
|
|
||||||
|
if ($bytes_written === false) {
|
||||||
|
throw new \Exception("Unable to write to pipe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we got a newline at the end of this, then the _next_ read is the beginning of a line
|
||||||
|
if($buffer[strlen($buffer)-1] === "\n") {
|
||||||
|
$this->reading_beginning_of_line = true;
|
||||||
|
} else {
|
||||||
|
$this->reading_beginning_of_line = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return $bytes_read;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RestoreFromBackup extends Command
|
class RestoreFromBackup extends Command
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -12,10 +157,13 @@ class RestoreFromBackup extends Command
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
|
// FIXME - , stripping prefixes and nonstandard SQL statements. Without --prefix, guess and return the correct prefix to strip
|
||||||
protected $signature = 'snipeit:restore
|
protected $signature = 'snipeit:restore
|
||||||
{--force : Skip the danger prompt; assuming you enter "y"}
|
{--force : Skip the danger prompt; assuming you enter "y"}
|
||||||
{filename : The zip file to be migrated}
|
{filename : The zip file to be migrated}
|
||||||
{--no-progress : Don\'t show a progress bar}';
|
{--no-progress : Don\'t show a progress bar}
|
||||||
|
{--sanitize-guess-prefix : Guess and output the table-prefix needed to "sanitize" the SQL}
|
||||||
|
{--sanitize-with-prefix= : "Sanitize" the SQL, using the passed-in table prefix (can be learned from --sanitize-guess-prefix). Pass as just \'--sanitize-with-prefix=\' to use no prefix}';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
|
@ -34,8 +182,6 @@ class RestoreFromBackup extends Command
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static $buffer_size = 1024 * 1024; // use a 1MB buffer, ought to work fine for most cases?
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute the console command.
|
* Execute the console command.
|
||||||
*
|
*
|
||||||
|
@ -55,7 +201,7 @@ class RestoreFromBackup extends Command
|
||||||
return $this->error('Missing required 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!')) {
|
if (! $this->option('force') && ! $this->option('sanitize-guess-prefix') && ! $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');
|
return $this->error('Data loss not confirmed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +342,6 @@ class RestoreFromBackup extends Command
|
||||||
}
|
}
|
||||||
$boring_files[] = $raw_path; //if we've gotten to here and haven't continue'ed our way into the next iteration, we don't want this file
|
$boring_files[] = $raw_path; //if we've gotten to here and haven't continue'ed our way into the next iteration, we don't want this file
|
||||||
} // end of pre-processing the ZIP file for-loop
|
} // end of pre-processing the ZIP file for-loop
|
||||||
|
|
||||||
// print_r($interesting_files);exit(-1);
|
// print_r($interesting_files);exit(-1);
|
||||||
|
|
||||||
if (count($sqlfiles) != 1) {
|
if (count($sqlfiles) != 1) {
|
||||||
|
@ -208,6 +353,17 @@ class RestoreFromBackup extends Command
|
||||||
//older Snipe-IT installs don't have the db-dumps subdirectory component
|
//older Snipe-IT installs don't have the db-dumps subdirectory component
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sql_stat = $za->statIndex($sqlfile_indices[0]);
|
||||||
|
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
|
||||||
|
$sql_contents = $za->getStream($sql_stat['name']); // maybe copy *THIS* thing?
|
||||||
|
|
||||||
|
// OKAY, now that we *found* the sql file if we're doing just the guess-prefix thing, we can do that *HERE* I think?
|
||||||
|
if ($this->option('sanitize-guess-prefix')) {
|
||||||
|
$prefix = SQLStreamer::guess_prefix($sql_contents);
|
||||||
|
$this->line($prefix);
|
||||||
|
return $this->info("Re-run this command with '--sanitize-with-prefix=".$prefix."' to see an attempt to sanitze your SQL.");
|
||||||
|
}
|
||||||
|
|
||||||
//how to invoke the restore?
|
//how to invoke the restore?
|
||||||
$pipes = [];
|
$pipes = [];
|
||||||
|
|
||||||
|
@ -228,6 +384,7 @@ class RestoreFromBackup extends Command
|
||||||
return $this->error('Unable to invoke mysql via CLI');
|
return $this->error('Unable to invoke mysql via CLI');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I'm not sure about these?
|
||||||
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
stream_set_blocking($pipes[1], false); // use non-blocking reads for stdout
|
||||||
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
stream_set_blocking($pipes[2], false); // use non-blocking reads for stderr
|
||||||
|
|
||||||
|
@ -238,9 +395,9 @@ class RestoreFromBackup extends Command
|
||||||
|
|
||||||
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
|
//$sql_contents = fopen($sqlfiles[0], "r"); //NOPE! This isn't a real file yet, silly-billy!
|
||||||
|
|
||||||
$sql_stat = $za->statIndex($sqlfile_indices[0]);
|
// FIXME - this feels like it wants to go somewhere else?
|
||||||
//$this->info("SQL Stat is: ".print_r($sql_stat,true));
|
// and it doesn't seem 'right' - if you can't get a stream to the .sql file,
|
||||||
$sql_contents = $za->getStream($sql_stat['name']);
|
// why do we care what's happening with pipes and stdout and stderr?!
|
||||||
if ($sql_contents === false) {
|
if ($sql_contents === false) {
|
||||||
$stdout = fgets($pipes[1]);
|
$stdout = fgets($pipes[1]);
|
||||||
$this->info($stdout);
|
$this->info($stdout);
|
||||||
|
@ -249,10 +406,12 @@ class RestoreFromBackup extends Command
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$bytes_read = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (($buffer = fgets($sql_contents, self::$buffer_size)) !== false) {
|
if ( $this->option('sanitize-with-prefix') === null) {
|
||||||
|
// "Legacy" direct-piping
|
||||||
|
$bytes_read = 0;
|
||||||
|
while (($buffer = fgets($sql_contents, SQLStreamer::$buffer_size)) !== false) {
|
||||||
$bytes_read += strlen($buffer);
|
$bytes_read += strlen($buffer);
|
||||||
// \Log::debug("Buffer is: '$buffer'");
|
// \Log::debug("Buffer is: '$buffer'");
|
||||||
$bytes_written = fwrite($pipes[0], $buffer);
|
$bytes_written = fwrite($pipes[0], $buffer);
|
||||||
|
@ -261,8 +420,13 @@ class RestoreFromBackup extends Command
|
||||||
throw new Exception("Unable to write to pipe");
|
throw new Exception("Unable to write to pipe");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$sql_importer = new SQLStreamer($sql_contents, $pipes[0], $this->option('sanitize-with-prefix'));
|
||||||
|
$bytes_read = $sql_importer->line_aware_piping();
|
||||||
|
}
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
\Log::error("Error during restore!!!! ".$e->getMessage());
|
\Log::error("Error during restore!!!! ".$e->getMessage());
|
||||||
|
// FIXME - put these back and/or put them in the right places?!
|
||||||
$err_out = fgets($pipes[1]);
|
$err_out = fgets($pipes[1]);
|
||||||
$err_err = fgets($pipes[2]);
|
$err_err = fgets($pipes[2]);
|
||||||
\Log::error("Error OUTPUT: ".$err_out);
|
\Log::error("Error OUTPUT: ".$err_out);
|
||||||
|
@ -271,7 +435,6 @@ class RestoreFromBackup extends Command
|
||||||
$this->error($err_err);
|
$this->error($err_err);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!feof($sql_contents) || $bytes_read == 0) {
|
if (!feof($sql_contents) || $bytes_read == 0) {
|
||||||
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
|
return $this->error("Not at end of file for sql file, or zero bytes read. aborting!");
|
||||||
}
|
}
|
||||||
|
@ -303,7 +466,7 @@ class RestoreFromBackup extends Command
|
||||||
$fp = $za->getStream($ugly_file_name);
|
$fp = $za->getStream($ugly_file_name);
|
||||||
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
//$this->info("Weird problem, here are file details? ".print_r($file_details,true));
|
||||||
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
$migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w');
|
||||||
while (($buffer = fgets($fp, self::$buffer_size)) !== false) {
|
while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) {
|
||||||
fwrite($migrated_file, $buffer);
|
fwrite($migrated_file, $buffer);
|
||||||
}
|
}
|
||||||
fclose($migrated_file);
|
fclose($migrated_file);
|
||||||
|
|
|
@ -4,28 +4,27 @@ namespace App\Http\Controllers\Accessories;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Accessory;
|
use App\Models\Accessory;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Accessory\HttpFoundation\JsonResponse;
|
use Symfony\Accessory\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class AccessoriesFilesController extends Controller
|
class AccessoriesFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a accessory.
|
* Validates and stores files associated with a accessory.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $accessoryId
|
* @param int $accessoryId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $accessoryId = null)
|
public function store(UploadFileRequest $request, $accessoryId = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
|
@ -45,30 +44,7 @@ class AccessoriesFilesController extends Controller
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
|
||||||
$extension = $file->getClientOriginalExtension();
|
$file_name = $request->handleFile('private_uploads/accessories/', 'accessory-'.$accessory->id, $file);
|
||||||
$file_name = 'accessory-'.$accessory->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/accessories/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/accessories/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$accessory->logUpload($file_name, e($request->input('notes')));
|
$accessory->logUpload($file_name, e($request->input('notes')));
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\AccessoriesTransformer;
|
use App\Http\Transformers\AccessoriesTransformer;
|
||||||
|
@ -278,7 +279,7 @@ class AccessoriesController extends Controller
|
||||||
public function checkout(Request $request, $accessoryId)
|
public function checkout(Request $request, $accessoryId)
|
||||||
{
|
{
|
||||||
// Check if the accessory exists
|
// Check if the accessory exists
|
||||||
if (is_null($accessory = Accessory::find($accessoryId))) {
|
if (is_null($accessory = Accessory::withCount('users as users_count')->find($accessoryId))) {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +303,7 @@ class AccessoriesController extends Controller
|
||||||
'note' => $request->get('note'),
|
'note' => $request->get('note'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$accessory->logCheckout($request->input('note'), $user);
|
event(new CheckoutableCheckedOut($accessory, $user, Auth::user(), $request->input('note')));
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success')));
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,8 @@ class AssetMaintenancesController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('view', Asset::class);
|
$this->authorize('view', Asset::class);
|
||||||
|
|
||||||
$maintenances = AssetMaintenance::select('asset_maintenances.*')->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'admin');
|
$maintenances = AssetMaintenance::select('asset_maintenances.*')
|
||||||
|
->with('asset', 'asset.model', 'asset.location', 'asset.defaultLoc', 'supplier', 'asset.company', 'asset.assetstatus', 'admin');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$maintenances = $maintenances->TextSearch($request->input('search'));
|
$maintenances = $maintenances->TextSearch($request->input('search'));
|
||||||
|
@ -47,7 +48,7 @@ class AssetMaintenancesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('supplier_id')) {
|
if ($request->filled('supplier_id')) {
|
||||||
$maintenances->where('supplier_id', '=', $request->input('supplier_id'));
|
$maintenances->where('asset_maintenances.supplier_id', '=', $request->input('supplier_id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('asset_maintenance_type')) {
|
if ($request->filled('asset_maintenance_type')) {
|
||||||
|
@ -70,10 +71,13 @@ class AssetMaintenancesController extends Controller
|
||||||
'notes',
|
'notes',
|
||||||
'asset_tag',
|
'asset_tag',
|
||||||
'asset_name',
|
'asset_name',
|
||||||
|
'serial',
|
||||||
'user_id',
|
'user_id',
|
||||||
'supplier',
|
'supplier',
|
||||||
'is_warranty',
|
'is_warranty',
|
||||||
|
'status_label',
|
||||||
];
|
];
|
||||||
|
|
||||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||||
|
|
||||||
|
@ -90,6 +94,12 @@ class AssetMaintenancesController extends Controller
|
||||||
case 'asset_name':
|
case 'asset_name':
|
||||||
$maintenances = $maintenances->OrderByAssetName($order);
|
$maintenances = $maintenances->OrderByAssetName($order);
|
||||||
break;
|
break;
|
||||||
|
case 'serial':
|
||||||
|
$maintenances = $maintenances->OrderByAssetSerial($order);
|
||||||
|
break;
|
||||||
|
case 'status_label':
|
||||||
|
$maintenances = $maintenances->OrderStatusName($order);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$maintenances = $maintenances->orderBy($sort, $order);
|
$maintenances = $maintenances->orderBy($sort, $order);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -906,6 +906,13 @@ class AssetsController extends Controller
|
||||||
$originalValues['action_date'] = $checkin_at;
|
$originalValues['action_date'] = $checkin_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!empty($asset->licenseseats->all())){
|
||||||
|
foreach ($asset->licenseseats as $seat){
|
||||||
|
$seat->assigned_to = null;
|
||||||
|
$seat->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
event(new CheckoutableCheckedIn($asset, $target, Auth::user(), $request->input('note'), $checkin_at, $originalValues));
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,9 @@ class CompaniesController extends Controller
|
||||||
'components_count',
|
'components_count',
|
||||||
];
|
];
|
||||||
|
|
||||||
$companies = Company::withCount('assets as assets_count', 'licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
$companies = Company::withCount(['assets as assets_count' => function ($query) {
|
||||||
|
$query->AssetsForShow();
|
||||||
|
}])->withCount('licenses as licenses_count', 'accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'users as users_count');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
$companies->TextSearch($request->input('search'));
|
$companies->TextSearch($request->input('search'));
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers\Api;
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Events\CheckoutableCheckedOut;
|
||||||
use App\Helpers\Helper;
|
use App\Helpers\Helper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Transformers\ConsumablesTransformer;
|
use App\Http\Transformers\ConsumablesTransformer;
|
||||||
|
@ -11,6 +12,7 @@ use App\Models\Consumable;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Http\Requests\ImageUploadRequest;
|
use App\Http\Requests\ImageUploadRequest;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class ConsumablesController extends Controller
|
class ConsumablesController extends Controller
|
||||||
{
|
{
|
||||||
|
@ -290,15 +292,7 @@ class ConsumablesController extends Controller
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Log checkout event
|
event(new CheckoutableCheckedOut($consumable, $user, Auth::user(), $request->input('note')));
|
||||||
$logaction = $consumable->logCheckout($request->input('note'), $user);
|
|
||||||
$data['log_id'] = $logaction->id;
|
|
||||||
$data['eula'] = $consumable->getEula();
|
|
||||||
$data['first_name'] = $user->first_name;
|
|
||||||
$data['item_name'] = $consumable->name;
|
|
||||||
$data['checkout_date'] = $logaction->created_at;
|
|
||||||
$data['note'] = $logaction->note;
|
|
||||||
$data['require_acceptance'] = $consumable->requireAcceptance();
|
|
||||||
|
|
||||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.checkout.success')));
|
||||||
|
|
||||||
|
|
|
@ -25,9 +25,27 @@ class LocationsController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('view', Location::class);
|
$this->authorize('view', Location::class);
|
||||||
$allowed_columns = [
|
$allowed_columns = [
|
||||||
'id', 'name', 'address', 'address2', 'city', 'state', 'country', 'zip', 'created_at',
|
'id',
|
||||||
'updated_at', 'manager_id', 'image',
|
'name',
|
||||||
'assigned_assets_count', 'users_count', 'assets_count','assigned_assets_count', 'assets_count', 'rtd_assets_count', 'currency', 'ldap_ou', ];
|
'address',
|
||||||
|
'address2',
|
||||||
|
'city',
|
||||||
|
'state',
|
||||||
|
'country',
|
||||||
|
'zip',
|
||||||
|
'created_at',
|
||||||
|
'updated_at',
|
||||||
|
'manager_id',
|
||||||
|
'image',
|
||||||
|
'assigned_assets_count',
|
||||||
|
'users_count',
|
||||||
|
'assets_count',
|
||||||
|
'assigned_assets_count',
|
||||||
|
'assets_count',
|
||||||
|
'rtd_assets_count',
|
||||||
|
'currency',
|
||||||
|
'ldap_ou',
|
||||||
|
];
|
||||||
|
|
||||||
$locations = Location::with('parent', 'manager', 'children')->select([
|
$locations = Location::with('parent', 'manager', 'children')->select([
|
||||||
'locations.id',
|
'locations.id',
|
||||||
|
@ -50,6 +68,7 @@ class LocationsController extends Controller
|
||||||
])->withCount('assignedAssets as assigned_assets_count')
|
])->withCount('assignedAssets as assigned_assets_count')
|
||||||
->withCount('assets as assets_count')
|
->withCount('assets as assets_count')
|
||||||
->withCount('rtd_assets as rtd_assets_count')
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
|
->withCount('children as children_count')
|
||||||
->withCount('users as users_count');
|
->withCount('users as users_count');
|
||||||
|
|
||||||
if ($request->filled('search')) {
|
if ($request->filled('search')) {
|
||||||
|
@ -80,6 +99,10 @@ class LocationsController extends Controller
|
||||||
$locations->where('locations.country', '=', $request->input('country'));
|
$locations->where('locations.country', '=', $request->input('country'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($request->filled('manager_id')) {
|
||||||
|
$locations->where('locations.manager_id', '=', $request->input('manager_id'));
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the offset and limit are actually integers and do not exceed system limits
|
// Make sure the offset and limit are actually integers and do not exceed system limits
|
||||||
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|
|
@ -33,7 +33,12 @@ class ReportsController extends Controller
|
||||||
|
|
||||||
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
|
if (($request->filled('item_type')) && ($request->filled('item_id'))) {
|
||||||
$actionlogs = $actionlogs->where('item_id', '=', $request->input('item_id'))
|
$actionlogs = $actionlogs->where('item_id', '=', $request->input('item_id'))
|
||||||
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
|
->where('item_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')))
|
||||||
|
->orWhere(function($query) use ($request)
|
||||||
|
{
|
||||||
|
$query->where('target_id', '=', $request->input('item_id'))
|
||||||
|
->where('target_type', '=', 'App\\Models\\'.ucwords($request->input('item_type')));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('action_type')) {
|
if ($request->filled('action_type')) {
|
||||||
|
|
|
@ -148,7 +148,7 @@ class SettingsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
* @return Redirect
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public function ajaxTestEmail()
|
public function ajaxTestEmail()
|
||||||
{
|
{
|
||||||
|
@ -170,7 +170,7 @@ class SettingsController extends Controller
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0.0]
|
* @since [v5.0.0]
|
||||||
* @return Response
|
* @return JsonResponse
|
||||||
*/
|
*/
|
||||||
public function purgeBarcodes()
|
public function purgeBarcodes()
|
||||||
{
|
{
|
||||||
|
@ -211,7 +211,7 @@ class SettingsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @since [v5.0.0]
|
* @since [v5.0.0]
|
||||||
* @param \Illuminate\Http\Request $request
|
* @param \Illuminate\Http\Request $request
|
||||||
* @return array
|
* @return array | JsonResponse
|
||||||
*/
|
*/
|
||||||
public function showLoginAttempts(Request $request)
|
public function showLoginAttempts(Request $request)
|
||||||
{
|
{
|
||||||
|
@ -229,6 +229,12 @@ class SettingsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists backup files
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto]
|
||||||
|
* @return array | JsonResponse
|
||||||
|
*/
|
||||||
public function listBackups() {
|
public function listBackups() {
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$path = 'app/backups';
|
$path = 'app/backups';
|
||||||
|
@ -249,12 +255,12 @@ class SettingsController extends Controller
|
||||||
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
'filesize' => Setting::fileSizeConvert(Storage::size($backup_files[$f])),
|
||||||
'modified_value' => $file_timestamp,
|
'modified_value' => $file_timestamp,
|
||||||
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
'modified_display' => date($settings->date_display_format.' '.$settings->time_display_format, $file_timestamp),
|
||||||
|
'backup_url' => config('app.url').'/settings/backups/download/'.basename($backup_files[$f]),
|
||||||
|
|
||||||
];
|
];
|
||||||
$count++;
|
$count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,15 +270,56 @@ class SettingsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads a backup file.
|
||||||
|
* We use response()->download() here instead of Storage::download() because Storage::download()
|
||||||
|
* exhausts memory on larger files.
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto]
|
||||||
|
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||||
|
*/
|
||||||
public function downloadBackup($file) {
|
public function downloadBackup($file) {
|
||||||
|
|
||||||
$path = 'app/backups';
|
$path = storage_path('app/backups');
|
||||||
if (Storage::exists($path.'/'.$file)) {
|
|
||||||
|
if (Storage::exists('app/backups/'.$file)) {
|
||||||
$headers = ['ContentType' => 'application/zip'];
|
$headers = ['ContentType' => 'application/zip'];
|
||||||
return Storage::download($path.'/'.$file, $file, $headers);
|
return response()->download($path.'/'.$file, $file, $headers);
|
||||||
} else {
|
} else {
|
||||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')));
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines and downloads the latest backup
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto]
|
||||||
|
* @since [v6.3.1]
|
||||||
|
* @return JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||||
|
*/
|
||||||
|
public function downloadLatestBackup() {
|
||||||
|
|
||||||
|
$fileData = collect();
|
||||||
|
foreach (Storage::files('app/backups') as $file) {
|
||||||
|
if (pathinfo($file, PATHINFO_EXTENSION) == 'zip') {
|
||||||
|
$fileData->push([
|
||||||
|
'file' => $file,
|
||||||
|
'date' => Storage::lastModified($file)
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$newest = $fileData->sortByDesc('date')->first();
|
||||||
|
if (Storage::exists($newest['file'])) {
|
||||||
|
$headers = ['ContentType' => 'application/zip'];
|
||||||
|
return response()->download(storage_path($newest['file']), basename($newest['file']), $headers);
|
||||||
|
} else {
|
||||||
|
return response()->json(Helper::formatStandardApiResponse('error', null, trans('general.file_not_found')), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -277,11 +277,6 @@ class UsersController extends Controller
|
||||||
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
|
$offset = ($request->input('offset') > $users->count()) ? $users->count() : app('api_offset_value');
|
||||||
$limit = app('api_limit_value');
|
$limit = app('api_limit_value');
|
||||||
|
|
||||||
\Log::debug('Requested offset: '. $request->input('offset'));
|
|
||||||
\Log::debug('App offset: '. app('api_offset_value'));
|
|
||||||
\Log::debug('Actual offset: '. $offset);
|
|
||||||
\Log::debug('Limit: '. $limit);
|
|
||||||
|
|
||||||
$total = $users->count();
|
$total = $users->count();
|
||||||
$users = $users->skip($offset)->take($limit)->get();
|
$users = $users->skip($offset)->take($limit)->get();
|
||||||
|
|
||||||
|
|
|
@ -148,30 +148,20 @@ class AssetMaintenancesController extends Controller
|
||||||
*/
|
*/
|
||||||
public function edit($assetMaintenanceId = null)
|
public function edit($assetMaintenanceId = null)
|
||||||
{
|
{
|
||||||
|
$this->authorize('update', Asset::class);
|
||||||
|
// Check if the asset maintenance exists
|
||||||
$this->authorize('update', Asset::class);
|
$this->authorize('update', Asset::class);
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||||
// Redirect to the improvement management page
|
// Redirect to the asset maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
|
||||||
->with('error', trans('admin/asset_maintenances/message.not_found'));
|
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
|
||||||
} elseif (! $assetMaintenance->asset) {
|
// Redirect to the asset maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
|
||||||
->with('error', 'The asset associated with this maintenance does not exist.');
|
|
||||||
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||||
return static::getInsufficientPermissionsRedirect();
|
return static::getInsufficientPermissionsRedirect();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($assetMaintenance->completion_date == '0000-00-00') {
|
|
||||||
$assetMaintenance->completion_date = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($assetMaintenance->start_date == '0000-00-00') {
|
|
||||||
$assetMaintenance->start_date = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($assetMaintenance->cost == '0.00') {
|
|
||||||
$assetMaintenance->cost = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare Improvement Type List
|
// Prepare Improvement Type List
|
||||||
$assetMaintenanceType = [
|
$assetMaintenanceType = [
|
||||||
|
@ -203,8 +193,10 @@ class AssetMaintenancesController extends Controller
|
||||||
// Check if the asset maintenance exists
|
// Check if the asset maintenance exists
|
||||||
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
if (is_null($assetMaintenance = AssetMaintenance::find($assetMaintenanceId))) {
|
||||||
// Redirect to the asset maintenance management page
|
// Redirect to the asset maintenance management page
|
||||||
return redirect()->route('maintenances.index')
|
return redirect()->route('maintenances.index')->with('error', trans('admin/asset_maintenances/message.not_found'));
|
||||||
->with('error', trans('admin/asset_maintenances/message.not_found'));
|
} elseif ((!$assetMaintenance->asset) || ($assetMaintenance->asset->deleted_at!='')) {
|
||||||
|
// Redirect to the asset maintenance management page
|
||||||
|
return redirect()->route('maintenances.index')->with('error', 'asset does not exist');
|
||||||
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
} elseif (! Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||||
return static::getInsufficientPermissionsRedirect();
|
return static::getInsufficientPermissionsRedirect();
|
||||||
}
|
}
|
||||||
|
|
|
@ -442,7 +442,6 @@ class AssetModelsController extends Controller
|
||||||
$del_count = 0;
|
$del_count = 0;
|
||||||
|
|
||||||
foreach ($models as $model) {
|
foreach ($models as $model) {
|
||||||
\Log::debug($model->id);
|
|
||||||
|
|
||||||
if ($model->assets_count > 0) {
|
if ($model->assets_count > 0) {
|
||||||
$del_error_count++;
|
$del_error_count++;
|
||||||
|
@ -452,8 +451,6 @@ class AssetModelsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
\Log::debug($del_count);
|
|
||||||
\Log::debug($del_error_count);
|
|
||||||
|
|
||||||
if ($del_error_count == 0) {
|
if ($del_error_count == 0) {
|
||||||
return redirect()->route('models.index')
|
return redirect()->route('models.index')
|
||||||
|
|
|
@ -3,26 +3,25 @@
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\AssetModel;
|
use App\Models\AssetModel;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class AssetModelsFilesController extends Controller
|
class AssetModelsFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Upload a file to the server.
|
* Upload a file to the server.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @param UploadFileRequest $request
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $modelId
|
* @param int $modelId
|
||||||
* @return Redirect
|
* @return Redirect
|
||||||
* @since [v1.0]
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@since [v1.0]
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $modelId = null)
|
public function store(UploadFileRequest $request, $modelId = null)
|
||||||
{
|
{
|
||||||
if (! $model = AssetModel::find($modelId)) {
|
if (! $model = AssetModel::find($modelId)) {
|
||||||
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('models.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
|
@ -37,27 +36,7 @@ class AssetModelsFilesController extends Controller
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
|
||||||
$extension = $file->getClientOriginalExtension();
|
$file_name = $request->handleFile('private_uploads/assetmodels/','model-'.$model->id,$file);
|
||||||
$file_name = 'model-'.$model->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension=='svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/assetmodels/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/assetmodels/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$model->logUpload($file_name, e($request->get('notes')));
|
$model->logUpload($file_name, e($request->get('notes')));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,25 @@ namespace App\Http\Controllers\Assets;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Asset;
|
use App\Models\Asset;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class AssetFilesController extends Controller
|
class AssetFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Upload a file to the server.
|
* Upload a file to the server.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @param UploadFileRequest $request
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $assetId
|
* @param int $assetId
|
||||||
* @return Redirect
|
* @return Redirect
|
||||||
* @since [v1.0]
|
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@since [v1.0]
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $assetId = null)
|
public function store(UploadFileRequest $request, $assetId = null)
|
||||||
{
|
{
|
||||||
if (! $asset = Asset::find($assetId)) {
|
if (! $asset = Asset::find($assetId)) {
|
||||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist'));
|
||||||
|
@ -37,28 +36,7 @@ class AssetFilesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/assets/','hardware-'.$asset->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'hardware-'.$asset->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension=='svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/assets/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/assets/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
$asset->logUpload($file_name, e($request->get('notes')));
|
$asset->logUpload($file_name, e($request->get('notes')));
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,8 @@ class AssetsController extends Controller
|
||||||
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
$asset->next_audit_date = Carbon::now()->addMonths($settings->audit_interval)->toDateString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($asset->assigned_to == '') {
|
// Set location_id to rtd_location_id ONLY if the asset isn't being checked out
|
||||||
|
if (!request('assigned_user') && !request('assigned_asset') && !request('assigned_location')) {
|
||||||
$asset->location_id = $request->input('rtd_location_id', null);
|
$asset->location_id = $request->input('rtd_location_id', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +522,7 @@ class AssetsController extends Controller
|
||||||
public function getBarCode($assetId = null)
|
public function getBarCode($assetId = null)
|
||||||
{
|
{
|
||||||
$settings = Setting::getSettings();
|
$settings = Setting::getSettings();
|
||||||
$asset = Asset::find($assetId);
|
if ($asset = Asset::withTrashed()->find($assetId)) {
|
||||||
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png';
|
$barcode_file = public_path().'/uploads/barcodes/'.str_slug($settings->alt_barcode).'-'.str_slug($asset->asset_tag).'.png';
|
||||||
|
|
||||||
if (isset($asset->id, $asset->asset_tag)) {
|
if (isset($asset->id, $asset->asset_tag)) {
|
||||||
|
@ -547,6 +548,8 @@ class AssetsController extends Controller
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a label for an individual asset.
|
* Return a label for an individual asset.
|
||||||
|
|
|
@ -4,28 +4,27 @@ namespace App\Http\Controllers\Components;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Component;
|
use App\Models\Component;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class ComponentsFilesController extends Controller
|
class ComponentsFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a component.
|
* Validates and stores files associated with a component.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $componentId
|
* @param int $componentId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $componentId = null)
|
public function store(UploadFileRequest $request, $componentId = null)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
|
@ -43,30 +42,7 @@ class ComponentsFilesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/components/','component-'.$component->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'component-'.$component->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/components/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/components/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$component->logUpload($file_name, e($request->input('notes')));
|
$component->logUpload($file_name, e($request->input('notes')));
|
||||||
|
|
|
@ -76,7 +76,6 @@ class ConsumableCheckoutController extends Controller
|
||||||
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
return redirect()->route('consumables.index')->with('error', trans('admin/consumables/message.checkout.unavailable'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$admin_user = Auth::user();
|
$admin_user = Auth::user();
|
||||||
$assigned_to = e($request->input('assigned_to'));
|
$assigned_to = e($request->input('assigned_to'));
|
||||||
|
|
||||||
|
|
|
@ -4,28 +4,27 @@ namespace App\Http\Controllers\Consumables;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\Consumable;
|
use App\Models\Consumable;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
use Symfony\Consumable\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class ConsumablesFilesController extends Controller
|
class ConsumablesFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a consumable.
|
* Validates and stores files associated with a consumable.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $consumableId
|
* @param int $consumableId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $consumableId = null)
|
public function store(UploadFileRequest $request, $consumableId = null)
|
||||||
{
|
{
|
||||||
if (config('app.lock_passwords')) {
|
if (config('app.lock_passwords')) {
|
||||||
return redirect()->route('consumables.show', ['consumable'=>$consumableId])->with('error', trans('general.feature_disabled'));
|
return redirect()->route('consumables.show', ['consumable'=>$consumableId])->with('error', trans('general.feature_disabled'));
|
||||||
|
@ -42,30 +41,7 @@ class ConsumablesFilesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/consumables/','consumable-'.$consumable->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'consumable-'.$consumable->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/consumables/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/consumables/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$consumable->logUpload($file_name, e($request->input('notes')));
|
$consumable->logUpload($file_name, e($request->input('notes')));
|
||||||
|
|
|
@ -4,28 +4,27 @@ namespace App\Http\Controllers\Licenses;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\License;
|
use App\Models\License;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
|
|
||||||
class LicenseFilesController extends Controller
|
class LicenseFilesController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Validates and stores files associated with a license.
|
* Validates and stores files associated with a license.
|
||||||
*
|
*
|
||||||
* @todo Switch to using the AssetFileRequest form request validator.
|
* @param UploadFileRequest $request
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
|
||||||
* @since [v1.0]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $licenseId
|
* @param int $licenseId
|
||||||
* @return \Illuminate\Http\RedirectResponse
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.0]
|
||||||
|
* @todo Switch to using the AssetFileRequest form request validator.
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $licenseId = null)
|
public function store(UploadFileRequest $request, $licenseId = null)
|
||||||
{
|
{
|
||||||
$license = License::find($licenseId);
|
$license = License::find($licenseId);
|
||||||
|
|
||||||
|
@ -38,30 +37,7 @@ class LicenseFilesController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($request->file('file') as $file) {
|
foreach ($request->file('file') as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/licenses/','license-'.$license->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'license-'.$license->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/licenses/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/licenses/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the upload to the log
|
//Log the upload to the log
|
||||||
$license->logUpload($file_name, e($request->input('notes')));
|
$license->logUpload($file_name, e($request->input('notes')));
|
||||||
|
|
|
@ -8,6 +8,7 @@ use App\Models\Location;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Locations for
|
* This controller handles all actions related to Locations for
|
||||||
|
@ -168,7 +169,7 @@ class LocationsController extends Controller
|
||||||
{
|
{
|
||||||
$this->authorize('delete', Location::class);
|
$this->authorize('delete', Location::class);
|
||||||
if (is_null($location = Location::find($locationId))) {
|
if (is_null($location = Location::find($locationId))) {
|
||||||
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.not_found'));
|
return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($location->users()->count() > 0) {
|
if ($location->users()->count() > 0) {
|
||||||
|
@ -238,7 +239,7 @@ class LocationsController extends Controller
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
* @param int $locationId
|
* @param int $locationId
|
||||||
* @since [v6.0.14]
|
* @since [v6.0.14]
|
||||||
* @return View
|
* @return \Illuminate\Contracts\View\View
|
||||||
*/
|
*/
|
||||||
public function getClone($locationId = null)
|
public function getClone($locationId = null)
|
||||||
{
|
{
|
||||||
|
@ -272,8 +273,97 @@ class LocationsController extends Controller
|
||||||
|
|
||||||
}
|
}
|
||||||
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a view that allows the user to bulk delete locations
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v6.3.1]
|
||||||
|
* @return \Illuminate\Contracts\View\View
|
||||||
|
*/
|
||||||
|
public function postBulkDelete(Request $request)
|
||||||
|
{
|
||||||
|
$locations_raw_array = $request->input('ids');
|
||||||
|
|
||||||
|
// Make sure some IDs have been selected
|
||||||
|
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {
|
||||||
|
$locations = Location::whereIn('id', $locations_raw_array)
|
||||||
|
->withCount('assignedAssets as assigned_assets_count')
|
||||||
|
->withCount('assets as assets_count')
|
||||||
|
->withCount('rtd_assets as rtd_assets_count')
|
||||||
|
->withCount('children as children_count')
|
||||||
|
->withCount('users as users_count')->get();
|
||||||
|
|
||||||
|
$valid_count = 0;
|
||||||
|
foreach ($locations as $location) {
|
||||||
|
if ($location->isDeletable()) {
|
||||||
|
$valid_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view('locations/bulk-delete', compact('locations'))->with('valid_count', $valid_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->route('models.index')
|
||||||
|
->with('error', 'You must select at least one model to edit.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that locations can be deleted and deletes them if they can
|
||||||
|
*
|
||||||
|
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v6.3.1]
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function postBulkDeleteStore(Request $request) {
|
||||||
|
$locations_raw_array = $request->input('ids');
|
||||||
|
|
||||||
|
if ((is_array($locations_raw_array)) && (count($locations_raw_array) > 0)) {
|
||||||
|
$locations = Location::whereIn('id', $locations_raw_array)->get();
|
||||||
|
|
||||||
|
$success_count = 0;
|
||||||
|
$error_count = 0;
|
||||||
|
|
||||||
|
foreach ($locations as $location) {
|
||||||
|
|
||||||
|
// Can we delete this location?
|
||||||
|
if ($location->isDeletable()) {
|
||||||
|
$location->delete();
|
||||||
|
$success_count++;
|
||||||
|
} else {
|
||||||
|
$error_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
\Log::debug('Success count: '.$success_count);
|
||||||
|
\Log::debug('Error count: '.$error_count);
|
||||||
|
// Complete success
|
||||||
|
if ($success_count == count($locations_raw_array)) {
|
||||||
|
return redirect()
|
||||||
|
->route('locations.index')
|
||||||
|
->with('success', trans_choice('general.bulk.delete.success', $success_count,
|
||||||
|
['object_type' => trans_choice('general.location_plural', $success_count), 'count' => $success_count]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partial success
|
||||||
|
if ($error_count > 0) {
|
||||||
|
return redirect()
|
||||||
|
->route('locations.index')
|
||||||
|
->with('warning', trans('general.bulk.partial_success',
|
||||||
|
['success' => $success_count, 'error' => $error_count, 'object_type' => trans('general.locations')]
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Nothing was selected - return to the index
|
||||||
|
return redirect()
|
||||||
|
->route('locations.index')
|
||||||
|
->with('error', trans('general.bulk.nothing_selected',
|
||||||
|
['object_type' => trans('general.locations')]
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,9 +295,9 @@ class ReportsController extends Controller
|
||||||
$actionlog->present()->actionType(),
|
$actionlog->present()->actionType(),
|
||||||
e($actionlog->itemType()),
|
e($actionlog->itemType()),
|
||||||
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
|
($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name,
|
||||||
($actionlog->item->serial) ? $actionlog->item->serial : null,
|
($actionlog->item) ? $actionlog->item->serial : null,
|
||||||
($actionlog->item->model) ? htmlspecialchars($actionlog->item->model->name, ENT_NOQUOTES) : null,
|
(($actionlog->item) && ($actionlog->item->model)) ? htmlspecialchars($actionlog->item->model->name, ENT_NOQUOTES) : null,
|
||||||
($actionlog->item->model) ? $actionlog->item->model->model_number : null,
|
(($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null,
|
||||||
$target_name,
|
$target_name,
|
||||||
($actionlog->note) ? e($actionlog->note) : '',
|
($actionlog->note) ? e($actionlog->note) : '',
|
||||||
$actionlog->log_meta,
|
$actionlog->log_meta,
|
||||||
|
@ -616,7 +616,7 @@ class ReportsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($request->filled('url')) {
|
if ($request->filled('url')) {
|
||||||
$header[] = trans('admin/manufacturers/table.url');
|
$header[] = trans('general.url');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ use App\Http\Requests\SlackSettingsRequest;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This controller handles all actions related to Settings for
|
* This controller handles all actions related to Settings for
|
||||||
|
@ -356,6 +357,7 @@ class SettingsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
$setting->default_eula_text = $request->input('default_eula_text');
|
$setting->default_eula_text = $request->input('default_eula_text');
|
||||||
|
$setting->load_remote = $request->input('load_remote', 0);
|
||||||
$setting->thumbnail_max_h = $request->input('thumbnail_max_h');
|
$setting->thumbnail_max_h = $request->input('thumbnail_max_h');
|
||||||
$setting->privacy_policy_link = $request->input('privacy_policy_link');
|
$setting->privacy_policy_link = $request->input('privacy_policy_link');
|
||||||
|
|
||||||
|
@ -424,8 +426,6 @@ class SettingsController extends Controller
|
||||||
$request->validate(['site_name' => 'required']);
|
$request->validate(['site_name' => 'required']);
|
||||||
$setting->site_name = $request->input('site_name');
|
$setting->site_name = $request->input('site_name');
|
||||||
$setting->custom_css = $request->input('custom_css');
|
$setting->custom_css = $request->input('custom_css');
|
||||||
}
|
|
||||||
|
|
||||||
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
$setting = $request->handleImages($setting, 600, 'logo', '', 'logo');
|
||||||
|
|
||||||
if ('1' == $request->input('clear_logo')) {
|
if ('1' == $request->input('clear_logo')) {
|
||||||
|
@ -445,8 +445,8 @@ class SettingsController extends Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
|
||||||
|
|
||||||
|
$setting = $request->handleImages($setting, 600, 'label_logo', '', 'label_logo');
|
||||||
|
|
||||||
if ('1' == $request->input('clear_label_logo')) {
|
if ('1' == $request->input('clear_label_logo')) {
|
||||||
Storage::disk('public')->delete($setting->label_logo);
|
Storage::disk('public')->delete($setting->label_logo);
|
||||||
|
@ -483,6 +483,7 @@ class SettingsController extends Controller
|
||||||
|
|
||||||
// If they are uploading an image, validate it and upload it
|
// If they are uploading an image, validate it and upload it
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($setting->save()) {
|
if ($setting->save()) {
|
||||||
return redirect()->route('settings.index')
|
return redirect()->route('settings.index')
|
||||||
|
@ -636,21 +637,21 @@ class SettingsController extends Controller
|
||||||
// Check if the audit interval has changed - if it has, we want to update ALL of the assets audit dates
|
// Check if the audit interval has changed - if it has, we want to update ALL of the assets audit dates
|
||||||
if ($request->input('audit_interval') != $setting->audit_interval) {
|
if ($request->input('audit_interval') != $setting->audit_interval) {
|
||||||
|
|
||||||
// Be careful - this could be a negative number
|
// This could be a negative number if the user is trying to set the audit interval to a lower number than it was before
|
||||||
$audit_diff_months = ((int)$request->input('audit_interval') - (int)($setting->audit_interval));
|
$audit_diff_months = ((int)$request->input('audit_interval') - (int)($setting->audit_interval));
|
||||||
|
|
||||||
// Grab all of the assets that have an existing next_audit_date
|
// Batch update the dates. We have to use this method to avoid time limit exceeded errors on very large datasets,
|
||||||
$assets = Asset::whereNotNull('next_audit_date')->get();
|
// but it DOES mean this change doesn't get logged in the action logs, since it skips the observer.
|
||||||
|
// @see https://stackoverflow.com/questions/54879160/laravel-observer-not-working-on-bulk-insert
|
||||||
|
$affected = Asset::whereNotNull('next_audit_date')
|
||||||
|
->whereNull('deleted_at')
|
||||||
|
->update(
|
||||||
|
['next_audit_date' => DB::raw('DATE_ADD(next_audit_date, INTERVAL '.$audit_diff_months.' MONTH)')]
|
||||||
|
);
|
||||||
|
|
||||||
|
\Log::debug($affected .' assets affected by audit interval update');
|
||||||
|
|
||||||
// Update all of the assets' next_audit_date values
|
|
||||||
foreach ($assets as $asset) {
|
|
||||||
|
|
||||||
if ($asset->next_audit_date != '') {
|
|
||||||
$old_next_audit = new \DateTime($asset->next_audit_date);
|
|
||||||
$asset->next_audit_date = $old_next_audit->modify($audit_diff_months.' month')->format('Y-m-d');
|
|
||||||
$asset->forceSave();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$alert_email = rtrim($request->input('alert_email'), ',');
|
$alert_email = rtrim($request->input('alert_email'), ',');
|
||||||
|
|
|
@ -4,14 +4,13 @@ namespace App\Http\Controllers\Users;
|
||||||
|
|
||||||
use App\Helpers\StorageHelper;
|
use App\Helpers\StorageHelper;
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\AssetFileRequest;
|
use App\Http\Requests\UploadFileRequest;
|
||||||
use App\Models\Actionlog;
|
use App\Models\Actionlog;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Input;
|
use Illuminate\Support\Facades\Input;
|
||||||
use Illuminate\Support\Facades\Response;
|
use Illuminate\Support\Facades\Response;
|
||||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
use enshrined\svgSanitize\Sanitizer;
|
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
class UserFilesController extends Controller
|
class UserFilesController extends Controller
|
||||||
|
@ -19,14 +18,14 @@ class UserFilesController extends Controller
|
||||||
/**
|
/**
|
||||||
* Return JSON response with a list of user details for the getIndex() view.
|
* Return JSON response with a list of user details for the getIndex() view.
|
||||||
*
|
*
|
||||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
* @param UploadFileRequest $request
|
||||||
* @since [v1.6]
|
|
||||||
* @param AssetFileRequest $request
|
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @return string JSON
|
* @return string JSON
|
||||||
* @throws \Illuminate\Auth\Access\AuthorizationException
|
* @throws \Illuminate\Auth\Access\AuthorizationException
|
||||||
|
*@author [A. Gianotto] [<snipe@snipe.net>]
|
||||||
|
* @since [v1.6]
|
||||||
*/
|
*/
|
||||||
public function store(AssetFileRequest $request, $userId = null)
|
public function store(UploadFileRequest $request, $userId = null)
|
||||||
{
|
{
|
||||||
$user = User::find($userId);
|
$user = User::find($userId);
|
||||||
$destinationPath = config('app.private_uploads').'/users';
|
$destinationPath = config('app.private_uploads').'/users';
|
||||||
|
@ -41,31 +40,7 @@ class UserFilesController extends Controller
|
||||||
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
|
return redirect()->back()->with('error', trans('admin/users/message.upload.nofiles'));
|
||||||
}
|
}
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
|
$file_name = $request->handleFile('private_uploads/users/', 'user-'.$user->id, $file);
|
||||||
$extension = $file->getClientOriginalExtension();
|
|
||||||
$file_name = 'user-'.$user->id.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$extension;
|
|
||||||
|
|
||||||
|
|
||||||
// Check for SVG and sanitize it
|
|
||||||
if ($extension == 'svg') {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
\Log::debug($file_name);
|
|
||||||
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
|
|
||||||
$dirtySVG = file_get_contents($file->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Storage::put('private_uploads/users/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Storage::put('private_uploads/users/'.$file_name, file_get_contents($file));
|
|
||||||
}
|
|
||||||
|
|
||||||
//Log the uploaded file to the log
|
//Log the uploaded file to the log
|
||||||
$logAction = new Actionlog();
|
$logAction = new Actionlog();
|
||||||
|
|
|
@ -42,18 +42,28 @@ class SlackSettingsForm extends Component
|
||||||
"icon" => 'fab fa-slack',
|
"icon" => 'fab fa-slack',
|
||||||
"placeholder" => "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX",
|
"placeholder" => "https://hooks.slack.com/services/XXXXXXXXXXXXXXXXXXXXX",
|
||||||
"link" => 'https://api.slack.com/messaging/webhooks',
|
"link" => 'https://api.slack.com/messaging/webhooks',
|
||||||
|
"test" => "testWebhook"
|
||||||
),
|
),
|
||||||
"general"=> array(
|
"general"=> array(
|
||||||
"name" => trans('admin/settings/general.general_webhook'),
|
"name" => trans('admin/settings/general.general_webhook'),
|
||||||
"icon" => "fab fa-hashtag",
|
"icon" => "fab fa-hashtag",
|
||||||
"placeholder" => trans('general.url'),
|
"placeholder" => trans('general.url'),
|
||||||
"link" => "",
|
"link" => "",
|
||||||
|
"test" => "testWebhook"
|
||||||
|
),
|
||||||
|
"google" => array(
|
||||||
|
"name" => trans('admin/settings/general.google_workspaces'),
|
||||||
|
"icon" => "fa-brands fa-google",
|
||||||
|
"placeholder" => "https://chat.googleapis.com/v1/spaces/xxxxxxxx/messages?key=xxxxxx",
|
||||||
|
"link" => "https://developers.google.com/chat/how-tos/webhooks#register_the_incoming_webhook",
|
||||||
|
"test" => "googleWebhookTest"
|
||||||
),
|
),
|
||||||
"microsoft" => array(
|
"microsoft" => array(
|
||||||
"name" => trans('admin/settings/general.ms_teams'),
|
"name" => trans('admin/settings/general.ms_teams'),
|
||||||
"icon" => "fa-brands fa-microsoft",
|
"icon" => "fa-brands fa-microsoft",
|
||||||
"placeholder" => "https://abcd.webhook.office.com/webhookb2/XXXXXXX",
|
"placeholder" => "https://abcd.webhook.office.com/webhookb2/XXXXXXX",
|
||||||
"link" => "https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet#create-incoming-webhooks-1",
|
"link" => "https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-incoming-webhook?tabs=dotnet#create-incoming-webhooks-1",
|
||||||
|
"test" => "msTeamTestWebhook"
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -64,10 +74,14 @@ class SlackSettingsForm extends Component
|
||||||
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"];
|
$this->webhook_icon = $this->webhook_text[$this->setting->webhook_selected]["icon"];
|
||||||
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"];
|
$this->webhook_placeholder = $this->webhook_text[$this->setting->webhook_selected]["placeholder"];
|
||||||
$this->webhook_link = $this->webhook_text[$this->setting->webhook_selected]["link"];
|
$this->webhook_link = $this->webhook_text[$this->setting->webhook_selected]["link"];
|
||||||
|
$this->webhook_test = $this->webhook_text[$this->setting->webhook_selected]["test"];
|
||||||
$this->webhook_endpoint = $this->setting->webhook_endpoint;
|
$this->webhook_endpoint = $this->setting->webhook_endpoint;
|
||||||
$this->webhook_channel = $this->setting->webhook_channel;
|
$this->webhook_channel = $this->setting->webhook_channel;
|
||||||
$this->webhook_botname = $this->setting->webhook_botname;
|
$this->webhook_botname = $this->setting->webhook_botname;
|
||||||
$this->webhook_options = $this->setting->webhook_selected;
|
$this->webhook_options = $this->setting->webhook_selected;
|
||||||
|
if($this->webhook_selected == 'microsoft' || $this->webhook_selected == 'google'){
|
||||||
|
$this->webhook_channel = '#NA';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if($this->setting->webhook_endpoint != null && $this->setting->webhook_channel != null){
|
if($this->setting->webhook_endpoint != null && $this->setting->webhook_channel != null){
|
||||||
|
@ -87,10 +101,14 @@ class SlackSettingsForm extends Component
|
||||||
$this->webhook_placeholder = $this->webhook_text[$this->webhook_selected]["placeholder"];
|
$this->webhook_placeholder = $this->webhook_text[$this->webhook_selected]["placeholder"];
|
||||||
$this->webhook_endpoint = null;
|
$this->webhook_endpoint = null;
|
||||||
$this->webhook_link = $this->webhook_text[$this->webhook_selected]["link"];
|
$this->webhook_link = $this->webhook_text[$this->webhook_selected]["link"];
|
||||||
|
$this->webhook_test = $this->webhook_text[$this->webhook_selected]["test"];
|
||||||
if($this->webhook_selected != 'slack'){
|
if($this->webhook_selected != 'slack'){
|
||||||
$this->isDisabled= '';
|
$this->isDisabled= '';
|
||||||
$this->save_button = trans('general.save');
|
$this->save_button = trans('general.save');
|
||||||
}
|
}
|
||||||
|
if($this->webhook_selected == 'microsoft' || $this->webhook_selected == 'google'){
|
||||||
|
$this->webhook_channel = '#NA';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +169,7 @@ class SlackSettingsForm extends Component
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function clearSettings(){
|
public function clearSettings(){
|
||||||
|
|
||||||
if (Helper::isDemoMode()) {
|
if (Helper::isDemoMode()) {
|
||||||
|
@ -187,6 +206,34 @@ class SlackSettingsForm extends Component
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public function googleWebhookTest(){
|
||||||
|
|
||||||
|
$payload = [
|
||||||
|
"text" => trans('general.webhook_test_msg', ['app' => $this->webhook_name]),
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = Http::withHeaders([
|
||||||
|
'content-type' => 'applications/json',
|
||||||
|
])->post($this->webhook_endpoint,
|
||||||
|
$payload)->throw();
|
||||||
|
|
||||||
|
|
||||||
|
if (($response->getStatusCode() == 302) || ($response->getStatusCode() == 301)) {
|
||||||
|
return session()->flash('error', trans('admin/settings/message.webhook.error_redirect', ['endpoint' => $this->webhook_endpoint]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->isDisabled='';
|
||||||
|
$this->save_button = trans('general.save');
|
||||||
|
return session()->flash('success' , trans('admin/settings/message.webhook.success', ['webhook_name' => $this->webhook_name]));
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
$this->isDisabled='disabled';
|
||||||
|
$this->save_button = trans('admin/settings/general.webhook_presave');
|
||||||
|
return session()->flash('error' , trans('admin/settings/message.webhook.error', ['error_message' => $e->getMessage(), 'app' => $this->webhook_name]));
|
||||||
|
}
|
||||||
|
}
|
||||||
public function msTeamTestWebhook(){
|
public function msTeamTestWebhook(){
|
||||||
|
|
||||||
$payload =
|
$payload =
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Http\Requests;
|
|
||||||
|
|
||||||
class AssetFileRequest extends Request
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Determine if the user is authorized to make this request.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function authorize()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the validation rules that apply to the request.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function rules()
|
|
||||||
{
|
|
||||||
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
|
|
||||||
|
|
||||||
return [
|
|
||||||
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp|max:'.$max_file_size,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -97,22 +97,41 @@ class ImageUploadRequest extends Request
|
||||||
|
|
||||||
if (!config('app.lock_passwords')) {
|
if (!config('app.lock_passwords')) {
|
||||||
|
|
||||||
$ext = $image->getClientOriginalExtension();
|
$ext = $image->guessExtension();
|
||||||
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
|
$file_name = $type.'-'.$form_fieldname.'-'.$item->id.'-'.str_random(10).'.'.$ext;
|
||||||
|
|
||||||
\Log::info('File name will be: '.$file_name);
|
\Log::info('File name will be: '.$file_name);
|
||||||
\Log::debug('File extension is: '.$ext);
|
\Log::debug('File extension is: '.$ext);
|
||||||
|
|
||||||
if (($image->getClientOriginalExtension() !== 'webp') && ($image->getClientOriginalExtension() !== 'svg')) {
|
if ($image->getMimeType() == 'image/webp') {
|
||||||
|
// If the file is a webp, we need to just move it since webp support
|
||||||
|
// needs to be compiled into gd for resizing to be available
|
||||||
|
|
||||||
|
\Log::debug('This is a webp, just move it');
|
||||||
|
Storage::disk('public')->put($path.'/'.$file_name, file_get_contents($image));
|
||||||
|
} elseif($image->getMimeType() == 'image/svg+xml') {
|
||||||
|
// If the file is an SVG, we need to clean it and NOT encode it
|
||||||
|
\Log::debug('This is an SVG');
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$dirtySVG = file_get_contents($image->getRealPath());
|
||||||
|
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Storage::disk('public')->put($path . '/' . $file_name, $cleanSVG);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::debug($e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
\Log::debug('Not an SVG or webp - resize');
|
\Log::debug('Not an SVG or webp - resize');
|
||||||
\Log::debug('Trying to upload to: '.$path.'/'.$file_name);
|
\Log::debug('Trying to upload to: '.$path.'/'.$file_name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$upload = Image::make($image->getRealPath())->resize(null, $w, function ($constraint) {
|
$upload = Image::make($image->getRealPath())->setFileInfoFromPath($image->getRealPath())->resize(null, $w, function ($constraint) {
|
||||||
$constraint->aspectRatio();
|
$constraint->aspectRatio();
|
||||||
$constraint->upsize();
|
$constraint->upsize();
|
||||||
});
|
})->orientate();
|
||||||
|
|
||||||
} catch(NotReadableException $e) {
|
} catch(NotReadableException $e) {
|
||||||
\Log::debug($e);
|
\Log::debug($e);
|
||||||
$validator = \Validator::make([], []);
|
$validator = \Validator::make([], []);
|
||||||
|
@ -124,27 +143,6 @@ class ImageUploadRequest extends Request
|
||||||
// This requires a string instead of an object, so we use ($string)
|
// This requires a string instead of an object, so we use ($string)
|
||||||
Storage::disk('public')->put($path.'/'.$file_name, (string) $upload->encode());
|
Storage::disk('public')->put($path.'/'.$file_name, (string) $upload->encode());
|
||||||
|
|
||||||
} else {
|
|
||||||
// If the file is a webp, we need to just move it since webp support
|
|
||||||
// needs to be compiled into gd for resizing to be available
|
|
||||||
if ($image->getClientOriginalExtension() == 'webp') {
|
|
||||||
\Log::debug('This is a webp, just move it');
|
|
||||||
Storage::disk('public')->put($path.'/'.$file_name, file_get_contents($image));
|
|
||||||
// If the file is an SVG, we need to clean it and NOT encode it
|
|
||||||
} else {
|
|
||||||
\Log::debug('This is an SVG');
|
|
||||||
$sanitizer = new Sanitizer();
|
|
||||||
$dirtySVG = file_get_contents($image->getRealPath());
|
|
||||||
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
|
||||||
|
|
||||||
try {
|
|
||||||
\Log::debug('Trying to upload to: '.$path.'/'.$file_name);
|
|
||||||
Storage::disk('public')->put($path.'/'.$file_name, $cleanSVG);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
\Log::debug('Upload no workie :( ');
|
|
||||||
\Log::debug($e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove Current image if exists
|
// Remove Current image if exists
|
||||||
|
|
70
app/Http/Requests/UploadFileRequest.php
Normal file
70
app/Http/Requests/UploadFileRequest.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use enshrined\svgSanitize\Sanitizer;
|
||||||
|
use Illuminate\Support\Facades\Storage;
|
||||||
|
|
||||||
|
class UploadFileRequest extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
$max_file_size = \App\Helpers\Helper::file_upload_max_size();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'file.*' => 'required|mimes:png,gif,jpg,svg,jpeg,doc,docx,pdf,txt,zip,rar,xls,xlsx,lic,xml,rtf,json,webp|max:'.$max_file_size,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sanitizes (if needed) and Saves a file to the appropriate location
|
||||||
|
* Returns the 'short' (storage-relative) filename
|
||||||
|
*
|
||||||
|
* TODO - this has a lot of similarities to UploadImageRequest's handleImage; is there
|
||||||
|
* a way to merge them or extend one into the other?
|
||||||
|
*/
|
||||||
|
public function handleFile(string $dirname, string $name_prefix, $file): string
|
||||||
|
{
|
||||||
|
$extension = $file->getClientOriginalExtension();
|
||||||
|
$file_name = $name_prefix.'-'.str_random(8).'-'.str_slug(basename($file->getClientOriginalName(), '.'.$extension)).'.'.$file->guessExtension();
|
||||||
|
|
||||||
|
|
||||||
|
\Log::debug("Your filetype IS: ".$file->getMimeType());
|
||||||
|
// Check for SVG and sanitize it
|
||||||
|
if ($file->getMimeType() === 'image/svg+xml') {
|
||||||
|
\Log::debug('This is an SVG');
|
||||||
|
\Log::debug($file_name);
|
||||||
|
|
||||||
|
$sanitizer = new Sanitizer();
|
||||||
|
$dirtySVG = file_get_contents($file->getRealPath());
|
||||||
|
$cleanSVG = $sanitizer->sanitize($dirtySVG);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Storage::put($dirname.$file_name, $cleanSVG);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::debug('Upload no workie :( ');
|
||||||
|
\Log::debug($e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$put_results = Storage::put($dirname.$file_name, file_get_contents($file));
|
||||||
|
\Log::debug("Here are the '$put_results' (should be 0 or 1 or true or false or something?)");
|
||||||
|
}
|
||||||
|
return $file_name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,12 +28,20 @@ class AssetMaintenancesTransformer
|
||||||
'id' => (int) $assetmaintenance->asset->id,
|
'id' => (int) $assetmaintenance->asset->id,
|
||||||
'name'=> ($assetmaintenance->asset->name) ? e($assetmaintenance->asset->name) : null,
|
'name'=> ($assetmaintenance->asset->name) ? e($assetmaintenance->asset->name) : null,
|
||||||
'asset_tag'=> e($assetmaintenance->asset->asset_tag),
|
'asset_tag'=> e($assetmaintenance->asset->asset_tag),
|
||||||
|
'serial'=> e($assetmaintenance->asset->serial),
|
||||||
|
'deleted_at'=> e($assetmaintenance->asset->deleted_at),
|
||||||
|
'created_at'=> e($assetmaintenance->asset->created_at),
|
||||||
] : null,
|
] : null,
|
||||||
'model' => (($assetmaintenance->asset) && ($assetmaintenance->asset->model)) ? [
|
'model' => (($assetmaintenance->asset) && ($assetmaintenance->asset->model)) ? [
|
||||||
'id' => (int) $assetmaintenance->asset->model->id,
|
'id' => (int) $assetmaintenance->asset->model->id,
|
||||||
'name'=> ($assetmaintenance->asset->model->name) ? e($assetmaintenance->asset->model->name).' '.e($assetmaintenance->asset->model->model_number) : null,
|
'name'=> ($assetmaintenance->asset->model->name) ? e($assetmaintenance->asset->model->name).' '.e($assetmaintenance->asset->model->model_number) : null,
|
||||||
] : null,
|
] : null,
|
||||||
|
'status_label' => ($assetmaintenance->asset->assetstatus) ? [
|
||||||
|
'id' => (int) $assetmaintenance->asset->assetstatus->id,
|
||||||
|
'name'=> e($assetmaintenance->asset->assetstatus->name),
|
||||||
|
'status_type'=> e($assetmaintenance->asset->assetstatus->getStatuslabelType()),
|
||||||
|
'status_meta' => e($assetmaintenance->asset->present()->statusMeta),
|
||||||
|
] : null,
|
||||||
'company' => (($assetmaintenance->asset) && ($assetmaintenance->asset->company)) ? [
|
'company' => (($assetmaintenance->asset) && ($assetmaintenance->asset->company)) ? [
|
||||||
'id' => (int) $assetmaintenance->asset->company->id,
|
'id' => (int) $assetmaintenance->asset->company->id,
|
||||||
'name'=> ($assetmaintenance->asset->company->name) ? e($assetmaintenance->asset->company->name) : null,
|
'name'=> ($assetmaintenance->asset->company->name) ? e($assetmaintenance->asset->company->name) : null,
|
||||||
|
@ -64,7 +72,7 @@ class AssetMaintenancesTransformer
|
||||||
];
|
];
|
||||||
|
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
'update' => Gate::allows('update', Asset::class),
|
'update' => (Gate::allows('update', Asset::class) && ($assetmaintenance->asset->deleted_at=='')) ? true : false,
|
||||||
'delete' => Gate::allows('delete', Asset::class),
|
'delete' => Gate::allows('delete', Asset::class),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,9 @@ class LocationsTransformer
|
||||||
$permissions_array['available_actions'] = [
|
$permissions_array['available_actions'] = [
|
||||||
'update' => Gate::allows('update', Location::class) ? true : false,
|
'update' => Gate::allows('update', Location::class) ? true : false,
|
||||||
'delete' => $location->isDeletable(),
|
'delete' => $location->isDeletable(),
|
||||||
|
'bulk_selectable' => [
|
||||||
|
'delete' => $location->isDeletable()
|
||||||
|
],
|
||||||
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
|
'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -46,10 +46,9 @@ class AccessoryImporter extends ItemImporter
|
||||||
$this->item['min_amt'] = $this->findCsvMatch($row, "min_amt");
|
$this->item['min_amt'] = $this->findCsvMatch($row, "min_amt");
|
||||||
$accessory->fill($this->sanitizeItemForStoring($accessory));
|
$accessory->fill($this->sanitizeItemForStoring($accessory));
|
||||||
|
|
||||||
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
|
// This sets an attribute on the Loggable trait for the action log
|
||||||
// $accessory->unsetEventDispatcher();
|
$accessory->setImported(true);
|
||||||
if ($accessory->save()) {
|
if ($accessory->save()) {
|
||||||
$accessory->logCreate('Imported using CSV Importer');
|
|
||||||
$this->log('Accessory '.$this->item['name'].' was created');
|
$this->log('Accessory '.$this->item['name'].' was created');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -135,10 +135,10 @@ class AssetImporter extends ItemImporter
|
||||||
$asset->{$custom_field} = $val;
|
$asset->{$custom_field} = $val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// This sets an attribute on the Loggable trait for the action log
|
||||||
|
$asset->setImported(true);
|
||||||
if ($asset->save()) {
|
if ($asset->save()) {
|
||||||
|
|
||||||
$asset->logCreate(trans('general.importer.import_note'));
|
|
||||||
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
$this->log('Asset '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||||
|
|
||||||
// If we have a target to checkout to, lets do so.
|
// If we have a target to checkout to, lets do so.
|
||||||
|
|
|
@ -48,10 +48,10 @@ class ComponentImporter extends ItemImporter
|
||||||
$this->log('No matching component, creating one');
|
$this->log('No matching component, creating one');
|
||||||
$component = new Component;
|
$component = new Component;
|
||||||
$component->fill($this->sanitizeItemForStoring($component));
|
$component->fill($this->sanitizeItemForStoring($component));
|
||||||
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
|
|
||||||
$component->unsetEventDispatcher();
|
// This sets an attribute on the Loggable trait for the action log
|
||||||
|
$component->setImported(true);
|
||||||
if ($component->save()) {
|
if ($component->save()) {
|
||||||
$component->logCreate('Imported using CSV Importer');
|
|
||||||
$this->log('Component '.$this->item['name'].' was created');
|
$this->log('Component '.$this->item['name'].' was created');
|
||||||
|
|
||||||
// If we have an asset tag, checkout to that asset.
|
// If we have an asset tag, checkout to that asset.
|
||||||
|
|
|
@ -45,10 +45,10 @@ class ConsumableImporter extends ItemImporter
|
||||||
$this->item['item_no'] = trim($this->findCsvMatch($row, 'item_number'));
|
$this->item['item_no'] = trim($this->findCsvMatch($row, 'item_number'));
|
||||||
$this->item['min_amt'] = trim($this->findCsvMatch($row, "min_amt"));
|
$this->item['min_amt'] = trim($this->findCsvMatch($row, "min_amt"));
|
||||||
$consumable->fill($this->sanitizeItemForStoring($consumable));
|
$consumable->fill($this->sanitizeItemForStoring($consumable));
|
||||||
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
|
|
||||||
$consumable->unsetEventDispatcher();
|
// This sets an attribute on the Loggable trait for the action log
|
||||||
|
$consumable->setImported(true);
|
||||||
if ($consumable->save()) {
|
if ($consumable->save()) {
|
||||||
$consumable->logCreate('Imported using CSV Importer');
|
|
||||||
$this->log('Consumable '.$this->item['name'].' was created');
|
$this->log('Consumable '.$this->item['name'].' was created');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -85,10 +85,10 @@ class LicenseImporter extends ItemImporter
|
||||||
} else {
|
} else {
|
||||||
$license->fill($this->sanitizeItemForStoring($license));
|
$license->fill($this->sanitizeItemForStoring($license));
|
||||||
}
|
}
|
||||||
//FIXME: this disables model validation. Need to find a way to avoid double-logs without breaking everything.
|
|
||||||
// $license->unsetEventDispatcher();
|
// This sets an attribute on the Loggable trait for the action log
|
||||||
|
$license->setImported(true);
|
||||||
if ($license->save()) {
|
if ($license->save()) {
|
||||||
$license->logCreate('Imported using csv importer');
|
|
||||||
$this->log('License '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
$this->log('License '.$this->item['name'].' with serial number '.$this->item['serial'].' was created');
|
||||||
|
|
||||||
// Lets try to checkout seats if the fields exist and we have seats.
|
// Lets try to checkout seats if the fields exist and we have seats.
|
||||||
|
|
|
@ -60,16 +60,18 @@ class CheckoutableListener
|
||||||
if ($this->shouldSendWebhookNotification()) {
|
if ($this->shouldSendWebhookNotification()) {
|
||||||
|
|
||||||
//slack doesn't include the url in its messaging format so this is needed to hit the endpoint
|
//slack doesn't include the url in its messaging format so this is needed to hit the endpoint
|
||||||
if(Setting::getSettings()->webhook_selected =='slack') {
|
|
||||||
|
if(Setting::getSettings()->webhook_selected =='slack' || Setting::getSettings()->webhook_selected =='general') {
|
||||||
|
|
||||||
|
|
||||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||||
->notify($this->getCheckoutNotification($event));
|
->notify($this->getCheckoutNotification($event));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ClientException $e) {
|
} catch (ClientException $e) {
|
||||||
Log::debug("Exception caught during checkout notification: " . $e->getMessage());
|
Log::warning("Exception caught during checkout notification: " . $e->getMessage());
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error("Exception caught during checkout notification: " . $e->getMessage());
|
Log::warning("Exception caught during checkout notification: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,7 +115,7 @@ class CheckoutableListener
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
//slack doesn't include the url in its messaging format so this is needed to hit the endpoint
|
//slack doesn't include the url in its messaging format so this is needed to hit the endpoint
|
||||||
if(Setting::getSettings()->webhook_selected =='slack') {
|
if(Setting::getSettings()->webhook_selected =='slack' || Setting::getSettings()->webhook_selected =='general') {
|
||||||
|
|
||||||
if ($this->shouldSendWebhookNotification()) {
|
if ($this->shouldSendWebhookNotification()) {
|
||||||
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
Notification::route('slack', Setting::getSettings()->webhook_endpoint)
|
||||||
|
@ -122,9 +124,9 @@ class CheckoutableListener
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ClientException $e) {
|
} catch (ClientException $e) {
|
||||||
Log::debug("Exception caught during checkout notification: " . $e->getMessage());
|
Log::warning("Exception caught during checkout notification: " . $e->getMessage());
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Log::error("Exception caught during checkin notification: " . $e->getMessage());
|
Log::warning("Exception caught during checkin notification: " . $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@ class Actionlog extends SnipeModel
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
|
// This is to manually set the source (via setActionSource()) for determineActionSource()
|
||||||
|
protected ?string $source = null;
|
||||||
|
|
||||||
protected $presenter = \App\Presenters\ActionlogPresenter::class;
|
protected $presenter = \App\Presenters\ActionlogPresenter::class;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
use Presentable;
|
use Presentable;
|
||||||
|
@ -341,7 +344,12 @@ class Actionlog extends SnipeModel
|
||||||
* @since v6.3.0
|
* @since v6.3.0
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function determineActionSource() {
|
public function determineActionSource(): string
|
||||||
|
{
|
||||||
|
// This is a manually set source
|
||||||
|
if($this->source) {
|
||||||
|
return $this->source;
|
||||||
|
}
|
||||||
|
|
||||||
// This is an API call
|
// This is an API call
|
||||||
if (((request()->header('content-type') && (request()->header('accept'))=='application/json'))
|
if (((request()->header('content-type') && (request()->header('accept'))=='application/json'))
|
||||||
|
@ -358,4 +366,10 @@ class Actionlog extends SnipeModel
|
||||||
return 'cli/unknown';
|
return 'cli/unknown';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Manually sets $this->source for determineActionSource()
|
||||||
|
public function setActionSource($source = null): void
|
||||||
|
{
|
||||||
|
$this->source = $source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1560,7 +1560,7 @@ class Asset extends Depreciable
|
||||||
*
|
*
|
||||||
* In short, this set of statements tells the query builder to ONLY query against an
|
* In short, this set of statements tells the query builder to ONLY query against an
|
||||||
* actual field that's being passed if it doesn't meet known relational fields. This
|
* actual field that's being passed if it doesn't meet known relational fields. This
|
||||||
* allows us to query custom fields directly in the assetsv table
|
* allows us to query custom fields directly in the assets table
|
||||||
* (regardless of their name) and *skip* any fields that we already know can only be
|
* (regardless of their name) and *skip* any fields that we already know can only be
|
||||||
* searched through relational searches that we do earlier in this method.
|
* searched through relational searches that we do earlier in this method.
|
||||||
*
|
*
|
||||||
|
|
|
@ -62,7 +62,15 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $searchableAttributes = ['title', 'notes', 'asset_maintenance_type', 'cost', 'start_date', 'completion_date'];
|
protected $searchableAttributes =
|
||||||
|
[
|
||||||
|
'title',
|
||||||
|
'notes',
|
||||||
|
'asset_maintenance_type',
|
||||||
|
'cost',
|
||||||
|
'start_date',
|
||||||
|
'completion_date'
|
||||||
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The relations and their attributes that should be included when searching the model.
|
* The relations and their attributes that should be included when searching the model.
|
||||||
|
@ -70,9 +78,10 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $searchableRelations = [
|
protected $searchableRelations = [
|
||||||
'asset' => ['name', 'asset_tag'],
|
'asset' => ['name', 'asset_tag', 'serial'],
|
||||||
'asset.model' => ['name', 'model_number'],
|
'asset.model' => ['name', 'model_number'],
|
||||||
'asset.supplier' => ['name'],
|
'asset.supplier' => ['name'],
|
||||||
|
'asset.assetstatus' => ['name'],
|
||||||
'supplier' => ['name'],
|
'supplier' => ['name'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -197,6 +206,7 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
->orderBy('suppliers_maintenances.name', $order);
|
->orderBy('suppliers_maintenances.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query builder scope to order on admin user
|
* Query builder scope to order on admin user
|
||||||
*
|
*
|
||||||
|
@ -239,4 +249,33 @@ class AssetMaintenance extends Model implements ICompanyableChild
|
||||||
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
|
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
|
||||||
->orderBy('assets.name', $order);
|
->orderBy('assets.name', $order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query builder scope to order on serial
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
|
* @param string $order Order
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
|
*/
|
||||||
|
public function scopeOrderByAssetSerial($query, $order)
|
||||||
|
{
|
||||||
|
return $query->leftJoin('assets', 'asset_maintenances.asset_id', '=', 'assets.id')
|
||||||
|
->orderBy('assets.serial', $order);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query builder scope to order on status label name
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||||
|
* @param text $order Order
|
||||||
|
*
|
||||||
|
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||||
|
*/
|
||||||
|
public function scopeOrderStatusName($query, $order)
|
||||||
|
{
|
||||||
|
return $query->join('assets as maintained_asset', 'asset_maintenances.asset_id', '=', 'maintained_asset.id')
|
||||||
|
->leftjoin('status_labels as maintained_asset_status', 'maintained_asset_status.id', '=', 'maintained_asset.status_id')
|
||||||
|
->orderBy('maintained_asset_status.name', $order);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,14 @@ final class Company extends SnipeModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the company id for the current user taking into
|
||||||
|
* account the full multiple company support setting
|
||||||
|
* and if the current user is a super user.
|
||||||
|
*
|
||||||
|
* @param $unescaped_input
|
||||||
|
* @return int|mixed|string|null
|
||||||
|
*/
|
||||||
public static function getIdForCurrentUser($unescaped_input)
|
public static function getIdForCurrentUser($unescaped_input)
|
||||||
{
|
{
|
||||||
if (! static::isFullMultipleCompanySupportEnabled()) {
|
if (! static::isFullMultipleCompanySupportEnabled()) {
|
||||||
|
|
|
@ -95,7 +95,10 @@ class Location extends SnipeModel
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether or not this location can be deleted
|
* Determine whether or not this location can be deleted.
|
||||||
|
*
|
||||||
|
* This method requires the eager loading of the relationships in order to determine whether
|
||||||
|
* it can be deleted. It's tempting to load those here, but that increases the query load considerably.
|
||||||
*
|
*
|
||||||
* @author A. Gianotto <snipe@snipe.net>
|
* @author A. Gianotto <snipe@snipe.net>
|
||||||
* @since [v3.0]
|
* @since [v3.0]
|
||||||
|
@ -104,9 +107,10 @@ class Location extends SnipeModel
|
||||||
public function isDeletable()
|
public function isDeletable()
|
||||||
{
|
{
|
||||||
return Gate::allows('delete', $this)
|
return Gate::allows('delete', $this)
|
||||||
&& ($this->assignedAssets()->count() === 0)
|
&& ($this->assets_count === 0)
|
||||||
&& ($this->assets()->count() === 0)
|
&& ($this->assigned_assets_count === 0)
|
||||||
&& ($this->users()->count() === 0);
|
&& ($this->children_count === 0)
|
||||||
|
&& ($this->users_count === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -8,6 +8,9 @@ use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
trait Loggable
|
trait Loggable
|
||||||
{
|
{
|
||||||
|
// an attribute for setting whether or not the item was imported
|
||||||
|
public ?bool $imported = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Daniel Meltzer <dmeltzer.devel@gmail.com>
|
* @author Daniel Meltzer <dmeltzer.devel@gmail.com>
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
|
@ -18,6 +21,11 @@ trait Loggable
|
||||||
return $this->morphMany(Actionlog::class, 'item');
|
return $this->morphMany(Actionlog::class, 'item');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setImported(bool $bool): void
|
||||||
|
{
|
||||||
|
$this->imported = $bool;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Daniel Meltzer <dmeltzer.devel@gmail.com>
|
* @author Daniel Meltzer <dmeltzer.devel@gmail.com>
|
||||||
* @since [v3.4]
|
* @since [v3.4]
|
||||||
|
|
|
@ -352,7 +352,6 @@ class Setting extends Model
|
||||||
'ldap_client_tls_cert',
|
'ldap_client_tls_cert',
|
||||||
'ldap_default_group',
|
'ldap_default_group',
|
||||||
'ldap_dept',
|
'ldap_dept',
|
||||||
'ldap_emp_num',
|
|
||||||
'ldap_phone_field',
|
'ldap_phone_field',
|
||||||
'ldap_jobtitle',
|
'ldap_jobtitle',
|
||||||
'ldap_manager',
|
'ldap_manager',
|
||||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -38,13 +43,17 @@ class CheckinAccessoryNotification extends Notification
|
||||||
public function via()
|
public function via()
|
||||||
{
|
{
|
||||||
$notifyBy = [];
|
$notifyBy = [];
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'slack') {
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,34 +63,8 @@ class CheckinAccessoryNotification extends Notification
|
||||||
if ($this->target instanceof User && $this->target->email != '') {
|
if ($this->target instanceof User && $this->target->email != '') {
|
||||||
\Log::debug('The target is a user');
|
\Log::debug('The target is a user');
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an email if the asset requires acceptance,
|
|
||||||
* so the user can accept or decline the asset
|
|
||||||
*/
|
|
||||||
if (($this->item->requireAcceptance()) || ($this->item->getEula()) || ($this->item->checkin_email())) {
|
|
||||||
$notifyBy[] = 'mail';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an email if the asset requires acceptance,
|
|
||||||
* so the user can accept or decline the asset
|
|
||||||
*/
|
|
||||||
if ($this->item->requireAcceptance()) {
|
|
||||||
\Log::debug('This accessory requires acceptance');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an email if the item has a EULA, since the user should always receive it
|
|
||||||
*/
|
|
||||||
if ($this->item->getEula()) {
|
|
||||||
\Log::debug('This accessory has a EULA');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send an email if an email should be sent at checkin/checkout
|
|
||||||
*/
|
|
||||||
if ($this->item->checkin_email()) {
|
if ($this->item->checkin_email()) {
|
||||||
\Log::debug('This accessory has a checkin_email()');
|
$notifyBy[] = 'mail';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +115,32 @@ class CheckinAccessoryNotification extends Notification
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.Accessory_Checkin_Notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.checked_into').': '.$item->location->name ? $item->location->name : '',
|
||||||
|
trans('admin/consumables/general.remaining').': '.$item->numRemaining(),
|
||||||
|
trans('admin/hardware/form.notes').": ".$note ?: '',
|
||||||
|
)
|
||||||
|
->onClick(route('accessories.show', $item->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -10,6 +10,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -46,12 +51,16 @@ class CheckinAssetNotification extends Notification
|
||||||
public function via()
|
public function via()
|
||||||
{
|
{
|
||||||
$notifyBy = [];
|
$notifyBy = [];
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
if (Setting::getSettings()->webhook_selected == 'slack') {
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
\Log::debug('use webhook');
|
\Log::debug('use webhook');
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
@ -108,6 +117,33 @@ class CheckinAssetNotification extends Notification
|
||||||
->fact(trans('admin/hardware/form.status'), $item->assetstatus->name)
|
->fact(trans('admin/hardware/form.status'), $item->assetstatus->name)
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$target = $this->target;
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.Asset_Checkin_Notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.checked_into') ?: '',
|
||||||
|
$item->location->name ? $item->location->name : '',
|
||||||
|
trans('admin/hardware/form.status').": ".$item->assetstatus->name,
|
||||||
|
)
|
||||||
|
->onClick(route('hardware.show', $item->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -43,12 +48,16 @@ class CheckinLicenseSeatNotification extends Notification
|
||||||
{
|
{
|
||||||
$notifyBy = [];
|
$notifyBy = [];
|
||||||
|
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'slack') {
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +122,34 @@ class CheckinLicenseSeatNotification extends Notification
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$target = $this->target;
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.License_Checkin_Notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.checkedin_from') ?: '',
|
||||||
|
$target->present()->fullName() ?: '',
|
||||||
|
trans('admin/consumables/general.remaining').': '.$item->availCount()->count(),
|
||||||
|
)
|
||||||
|
->onClick(route('licenses.show', $item->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -37,13 +42,17 @@ class CheckoutAccessoryNotification extends Notification
|
||||||
public function via()
|
public function via()
|
||||||
{
|
{
|
||||||
$notifyBy = [];
|
$notifyBy = [];
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'slack') {
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,6 +132,34 @@ class CheckoutAccessoryNotification extends Notification
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$target = $this->target;
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.Accessory_Checkout_Notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.assigned_to') ?: '',
|
||||||
|
$target->present()->name ?: '',
|
||||||
|
trans('admin/consumables/general.remaining').": ". $item->numRemaining(),
|
||||||
|
)
|
||||||
|
->onClick(route('users.show', $target->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -11,6 +11,13 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\Enums\Icon;
|
||||||
|
use NotificationChannels\GoogleChat\Enums\ImageStyle;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -54,13 +61,20 @@ class CheckoutAssetNotification extends Notification
|
||||||
*/
|
*/
|
||||||
public function via()
|
public function via()
|
||||||
{
|
{
|
||||||
|
$notifyBy = [];
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
return [MicrosoftTeamsChannel::class];
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
$notifyBy = [];
|
|
||||||
|
|
||||||
if ((Setting::getSettings()) && (Setting::getSettings()->webhook_selected == 'slack')) {
|
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
|
|
||||||
\Log::debug('use webhook');
|
\Log::debug('use webhook');
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
@ -143,6 +157,33 @@ class CheckoutAssetNotification extends Notification
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$target = $this->target;
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.Asset_Checkout_Notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.assigned_to') ?: '',
|
||||||
|
$target->present()->name ?: '',
|
||||||
|
$note ?: '',
|
||||||
|
)
|
||||||
|
->onClick(route('users.show', $target->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -44,13 +49,17 @@ class CheckoutConsumableNotification extends Notification
|
||||||
public function via()
|
public function via()
|
||||||
{
|
{
|
||||||
$notifyBy = [];
|
$notifyBy = [];
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'slack') {
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,6 +137,33 @@ class CheckoutConsumableNotification extends Notification
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
->fact(trans('admin/consumables/general.remaining'), $item->numRemaining())
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$target = $this->target;
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.Consumable_checkout_notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.assigned_to') ?: '',
|
||||||
|
$target->present()->fullName() ?: '',
|
||||||
|
trans('admin/consumables/general.remaining').': '.$item->numRemaining(),
|
||||||
|
)
|
||||||
|
->onClick(route('users.show', $target->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -9,6 +9,11 @@ use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Notifications\Messages\MailMessage;
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
use Illuminate\Notifications\Messages\SlackMessage;
|
use Illuminate\Notifications\Messages\SlackMessage;
|
||||||
use Illuminate\Notifications\Notification;
|
use Illuminate\Notifications\Notification;
|
||||||
|
use NotificationChannels\GoogleChat\Card;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatChannel;
|
||||||
|
use NotificationChannels\GoogleChat\GoogleChatMessage;
|
||||||
|
use NotificationChannels\GoogleChat\Section;
|
||||||
|
use NotificationChannels\GoogleChat\Widgets\KeyValue;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsChannel;
|
||||||
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage;
|
||||||
|
|
||||||
|
@ -43,15 +48,18 @@ class CheckoutLicenseSeatNotification extends Notification
|
||||||
*/
|
*/
|
||||||
public function via()
|
public function via()
|
||||||
{
|
{
|
||||||
|
|
||||||
$notifyBy = [];
|
$notifyBy = [];
|
||||||
|
|
||||||
|
if (Setting::getSettings()->webhook_selected == 'google'){
|
||||||
|
|
||||||
|
$notifyBy[] = GoogleChatChannel::class;
|
||||||
|
}
|
||||||
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
if (Setting::getSettings()->webhook_selected == 'microsoft'){
|
||||||
|
|
||||||
$notifyBy[] = MicrosoftTeamsChannel::class;
|
$notifyBy[] = MicrosoftTeamsChannel::class;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Setting::getSettings()->webhook_selected == 'slack') {
|
if (Setting::getSettings()->webhook_selected == 'slack' || Setting::getSettings()->webhook_selected == 'general' ) {
|
||||||
$notifyBy[] = 'slack';
|
$notifyBy[] = 'slack';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +137,33 @@ class CheckoutLicenseSeatNotification extends Notification
|
||||||
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count())
|
||||||
->fact(trans('mail.notes'), $note ?: '');
|
->fact(trans('mail.notes'), $note ?: '');
|
||||||
}
|
}
|
||||||
|
public function toGoogleChat()
|
||||||
|
{
|
||||||
|
$target = $this->target;
|
||||||
|
$item = $this->item;
|
||||||
|
$note = $this->note;
|
||||||
|
|
||||||
|
return GoogleChatMessage::create()
|
||||||
|
->to($this->settings->webhook_endpoint)
|
||||||
|
->card(
|
||||||
|
Card::create()
|
||||||
|
->header(
|
||||||
|
'<strong>'.trans('mail.License_Checkout_Notification').'</strong>' ?: '',
|
||||||
|
htmlspecialchars_decode($item->present()->name) ?: '',
|
||||||
|
)
|
||||||
|
->section(
|
||||||
|
Section::create(
|
||||||
|
KeyValue::create(
|
||||||
|
trans('mail.assigned_to') ?: '',
|
||||||
|
$target->present()->name ?: '',
|
||||||
|
trans('admin/consumables/general.remaining').': '.$item->availCount()->count(),
|
||||||
|
)
|
||||||
|
->onClick(route('users.show', $target->id))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the mail representation of the notification.
|
* Get the mail representation of the notification.
|
||||||
|
|
|
@ -38,6 +38,9 @@ class AccessoryObserver
|
||||||
$logAction->item_id = $accessory->id;
|
$logAction->item_id = $accessory->id;
|
||||||
$logAction->created_at = date('Y-m-d H:i:s');
|
$logAction->created_at = date('Y-m-d H:i:s');
|
||||||
$logAction->user_id = Auth::id();
|
$logAction->user_id = Auth::id();
|
||||||
|
if($accessory->imported) {
|
||||||
|
$logAction->setActionSource('importer');
|
||||||
|
}
|
||||||
$logAction->logaction('create');
|
$logAction->logaction('create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,9 @@ class AssetObserver
|
||||||
$logAction->item_id = $asset->id;
|
$logAction->item_id = $asset->id;
|
||||||
$logAction->created_at = date('Y-m-d H:i:s');
|
$logAction->created_at = date('Y-m-d H:i:s');
|
||||||
$logAction->user_id = Auth::id();
|
$logAction->user_id = Auth::id();
|
||||||
|
if($asset->imported) {
|
||||||
|
$logAction->setActionSource('importer');
|
||||||
|
}
|
||||||
$logAction->logaction('create');
|
$logAction->logaction('create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ class ComponentObserver
|
||||||
$logAction->item_id = $component->id;
|
$logAction->item_id = $component->id;
|
||||||
$logAction->created_at = date('Y-m-d H:i:s');
|
$logAction->created_at = date('Y-m-d H:i:s');
|
||||||
$logAction->user_id = Auth::id();
|
$logAction->user_id = Auth::id();
|
||||||
|
if($component->imported) {
|
||||||
|
$logAction->setActionSource('importer');
|
||||||
|
}
|
||||||
$logAction->logaction('create');
|
$logAction->logaction('create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ class ConsumableObserver
|
||||||
$logAction->item_id = $consumable->id;
|
$logAction->item_id = $consumable->id;
|
||||||
$logAction->created_at = date('Y-m-d H:i:s');
|
$logAction->created_at = date('Y-m-d H:i:s');
|
||||||
$logAction->user_id = Auth::id();
|
$logAction->user_id = Auth::id();
|
||||||
|
if($consumable->imported) {
|
||||||
|
$logAction->setActionSource('importer');
|
||||||
|
}
|
||||||
$logAction->logaction('create');
|
$logAction->logaction('create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ class LicenseObserver
|
||||||
$logAction->item_id = $license->id;
|
$logAction->item_id = $license->id;
|
||||||
$logAction->created_at = date('Y-m-d H:i:s');
|
$logAction->created_at = date('Y-m-d H:i:s');
|
||||||
$logAction->user_id = Auth::id();
|
$logAction->user_id = Auth::id();
|
||||||
|
if($license->imported) {
|
||||||
|
$logAction->setActionSource('importer');
|
||||||
|
}
|
||||||
$logAction->logaction('create');
|
$logAction->logaction('create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,19 @@ class AssetMaintenancesPresenter extends Presenter
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'title' => trans('admin/hardware/table.asset_tag'),
|
'title' => trans('admin/hardware/table.asset_tag'),
|
||||||
'formatter' => 'assetTagLinkFormatter',
|
'formatter' => 'assetTagLinkFormatter',
|
||||||
|
], [
|
||||||
|
'field' => 'serial',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('admin/hardware/table.serial'),
|
||||||
|
'formatter' => 'assetSerialLinkFormatter',
|
||||||
|
], [
|
||||||
|
'field' => 'status_label',
|
||||||
|
'searchable' => true,
|
||||||
|
'sortable' => true,
|
||||||
|
'title' => trans('admin/hardware/table.status'),
|
||||||
|
'visible' => true,
|
||||||
|
'formatter' => 'statuslabelsLinkObjFormatter',
|
||||||
], [
|
], [
|
||||||
'field' => 'model',
|
'field' => 'model',
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
|
|
|
@ -14,7 +14,11 @@ class LocationPresenter extends Presenter
|
||||||
public static function dataTableLayout()
|
public static function dataTableLayout()
|
||||||
{
|
{
|
||||||
$layout = [
|
$layout = [
|
||||||
|
[
|
||||||
|
'field' => 'bulk_selectable',
|
||||||
|
'checkbox' => true,
|
||||||
|
'formatter' => 'checkboxEnabledFormatter',
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'field' => 'id',
|
'field' => 'id',
|
||||||
'searchable' => false,
|
'searchable' => false,
|
||||||
|
|
|
@ -45,7 +45,7 @@ class ManufacturerPresenter extends Presenter
|
||||||
'searchable' => true,
|
'searchable' => true,
|
||||||
'sortable' => true,
|
'sortable' => true,
|
||||||
'switchable' => true,
|
'switchable' => true,
|
||||||
'title' => trans('admin/manufacturers/table.url'),
|
'title' => trans('general.url'),
|
||||||
'visible' => true,
|
'visible' => true,
|
||||||
'formatter' => 'externalLinkFormatter',
|
'formatter' => 'externalLinkFormatter',
|
||||||
],
|
],
|
||||||
|
|
|
@ -39,24 +39,12 @@ class SettingsServiceProvider extends ServiceProvider
|
||||||
$limit = abs($int_limit);
|
$limit = abs($int_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// \Log::debug('Max in env: '.config('app.max_results'));
|
|
||||||
// \Log::debug('Original requested limit: '.request('limit'));
|
|
||||||
// \Log::debug('Int limit: '.$int_limit);
|
|
||||||
// \Log::debug('Modified limit: '.$limit);
|
|
||||||
// \Log::debug('------------------------------');
|
|
||||||
|
|
||||||
|
|
||||||
return $limit;
|
return $limit;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure the offset is actually set and is an integer
|
// Make sure the offset is actually set and is an integer
|
||||||
\App::singleton('api_offset_value', function () {
|
\App::singleton('api_offset_value', function () {
|
||||||
$offset = intval(request('offset'));
|
$offset = intval(request('offset'));
|
||||||
// \Log::debug('Original requested offset: '.request('offset'));
|
|
||||||
// \Log::debug('Modified offset: '.$offset);
|
|
||||||
// \Log::debug('------------------------------');
|
|
||||||
|
|
||||||
|
|
||||||
return $offset;
|
return $offset;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -90,14 +90,10 @@ class Label implements View
|
||||||
$assetData->put('id', $asset->id);
|
$assetData->put('id', $asset->id);
|
||||||
$assetData->put('tag', $asset->asset_tag);
|
$assetData->put('tag', $asset->asset_tag);
|
||||||
|
|
||||||
if ($template->getSupportTitle()) {
|
if ($template->getSupportTitle() && !empty($settings->label2_title)) {
|
||||||
|
$title = str_replace('{COMPANY}', data_get($asset, 'company.name'), $settings->label2_title);
|
||||||
if ($asset->company && !empty($settings->label2_title)) {
|
|
||||||
$title = str_replace('{COMPANY}', $asset->company->name, $settings->label2_title);
|
|
||||||
$settings->qr_text;
|
|
||||||
$assetData->put('title', $title);
|
$assetData->put('title', $title);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($template->getSupportLogo()) {
|
if ($template->getSupportLogo()) {
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
"intervention/image": "^2.5",
|
"intervention/image": "^2.5",
|
||||||
"javiereguiluz/easyslugger": "^1.0",
|
"javiereguiluz/easyslugger": "^1.0",
|
||||||
"laravel/framework": "^10.0",
|
"laravel/framework": "^10.0",
|
||||||
|
"laravel-notification-channels/google-chat": "^3.0",
|
||||||
"laravel-notification-channels/microsoft-teams": "^1.1",
|
"laravel-notification-channels/microsoft-teams": "^1.1",
|
||||||
"laravel/helpers": "^1.4",
|
"laravel/helpers": "^1.4",
|
||||||
"laravel/passport": "^11.0",
|
"laravel/passport": "^11.0",
|
||||||
|
@ -69,7 +70,8 @@
|
||||||
"watson/validating": "^8.1"
|
"watson/validating": "^8.1"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"ext-ldap": "*"
|
"ext-ldap": "*",
|
||||||
|
"ext-zip": "*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"brianium/paratest": "^v6.4.4",
|
"brianium/paratest": "^v6.4.4",
|
||||||
|
|
934
composer.lock
generated
934
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,10 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
return array (
|
return array (
|
||||||
'app_version' => 'v6.3.0',
|
'app_version' => 'v6.3.1',
|
||||||
'full_app_version' => 'v6.3.0 - build 12490-g9136415bb',
|
'full_app_version' => 'v6.3.1 - build 12672-g00cea3eb3',
|
||||||
'build_version' => '12490',
|
'build_version' => '12672',
|
||||||
'prerelease_version' => '',
|
'prerelease_version' => '',
|
||||||
'hash_version' => 'g9136415bb',
|
'hash_version' => 'g00cea3eb3',
|
||||||
'full_hash' => 'v6.3.0-729-g9136415bb',
|
'full_hash' => 'v6.3.1-180-g00cea3eb3',
|
||||||
'branch' => 'develop',
|
'branch' => 'master',
|
||||||
);
|
);
|
|
@ -8,6 +8,7 @@ use App\Models\Location;
|
||||||
use App\Models\Manufacturer;
|
use App\Models\Manufacturer;
|
||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
class AccessoryFactory extends Factory
|
class AccessoryFactory extends Factory
|
||||||
|
@ -33,7 +34,7 @@ class AccessoryFactory extends Factory
|
||||||
$this->faker->randomElement(['Keyboard', 'Wired'])
|
$this->faker->randomElement(['Keyboard', 'Wired'])
|
||||||
),
|
),
|
||||||
'user_id' => User::factory()->superuser(),
|
'user_id' => User::factory()->superuser(),
|
||||||
'category_id' => Category::factory(),
|
'category_id' => Category::factory()->forAccessories(),
|
||||||
'model_number' => $this->faker->numberBetween(1000000, 50000000),
|
'model_number' => $this->faker->numberBetween(1000000, 50000000),
|
||||||
'location_id' => Location::factory(),
|
'location_id' => Location::factory(),
|
||||||
'qty' => 1,
|
'qty' => 1,
|
||||||
|
@ -114,4 +115,42 @@ class AccessoryFactory extends Factory
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withoutItemsRemaining()
|
||||||
|
{
|
||||||
|
return $this->state(function () {
|
||||||
|
return [
|
||||||
|
'qty' => 1,
|
||||||
|
];
|
||||||
|
})->afterCreating(function ($accessory) {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
$accessory->users()->attach($accessory->id, [
|
||||||
|
'accessory_id' => $accessory->id,
|
||||||
|
'created_at' => now(),
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'assigned_to' => $user->id,
|
||||||
|
'note' => '',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiringAcceptance()
|
||||||
|
{
|
||||||
|
return $this->afterCreating(function ($accessory) {
|
||||||
|
$accessory->category->update(['require_acceptance' => 1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkedOutToUser(User $user = null)
|
||||||
|
{
|
||||||
|
return $this->afterCreating(function (Accessory $accessory) use ($user) {
|
||||||
|
$accessory->users()->attach($accessory->id, [
|
||||||
|
'accessory_id' => $accessory->id,
|
||||||
|
'created_at' => Carbon::now(),
|
||||||
|
'user_id' => 1,
|
||||||
|
'assigned_to' => $user->id ?? User::factory()->create()->id,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,4 +172,10 @@ class CategoryFactory extends Factory
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function forAccessories()
|
||||||
|
{
|
||||||
|
return $this->state([
|
||||||
|
'category_type' => 'accessory',
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,4 +91,29 @@ class ConsumableFactory extends Factory
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withoutItemsRemaining()
|
||||||
|
{
|
||||||
|
return $this->state(function () {
|
||||||
|
return [
|
||||||
|
'qty' => 1,
|
||||||
|
];
|
||||||
|
})->afterCreating(function (Consumable $consumable) {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
|
||||||
|
$consumable->users()->attach($consumable->id, [
|
||||||
|
'consumable_id' => $consumable->id,
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'assigned_to' => $user->id,
|
||||||
|
'note' => '',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function requiringAcceptance()
|
||||||
|
{
|
||||||
|
return $this->afterCreating(function (Consumable $consumable) {
|
||||||
|
$consumable->category->update(['require_acceptance' => 1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
30
package-lock.json
generated
30
package-lock.json
generated
|
@ -10,13 +10,13 @@
|
||||||
"acorn-import-assertions": "^1.9.0",
|
"acorn-import-assertions": "^1.9.0",
|
||||||
"admin-lte": "^2.4.18",
|
"admin-lte": "^2.4.18",
|
||||||
"ajv": "^6.12.6",
|
"ajv": "^6.12.6",
|
||||||
"alpinejs": "^3.13.3",
|
"alpinejs": "^3.13.5",
|
||||||
"blueimp-file-upload": "^9.34.0",
|
"blueimp-file-upload": "^9.34.0",
|
||||||
"bootstrap": "^3.4.1",
|
"bootstrap": "^3.4.1",
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"bootstrap-colorpicker": "^2.5.3",
|
||||||
"bootstrap-datepicker": "^1.10.0",
|
"bootstrap-datepicker": "^1.10.0",
|
||||||
"bootstrap-less": "^3.3.8",
|
"bootstrap-less": "^3.3.8",
|
||||||
"bootstrap-table": "1.22.1",
|
"bootstrap-table": "1.22.2",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"css-loader": "^5.0.0",
|
"css-loader": "^5.0.0",
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
"sheetjs": "^2.0.0",
|
"sheetjs": "^2.0.0",
|
||||||
"tableexport.jquery.plugin": "1.28.0",
|
"tableexport.jquery.plugin": "1.28.0",
|
||||||
"tether": "^1.4.0",
|
"tether": "^1.4.0",
|
||||||
"webpack": "^5.89.0"
|
"webpack": "^5.90.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"all-contributors-cli": "^6.26.1",
|
"all-contributors-cli": "^6.26.1",
|
||||||
|
@ -3058,9 +3058,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/alpinejs": {
|
"node_modules/alpinejs": {
|
||||||
"version": "3.13.3",
|
"version": "3.13.5",
|
||||||
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.3.tgz",
|
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.5.tgz",
|
||||||
"integrity": "sha512-WZ6WQjkAOl+WdW/jukzNHq9zHFDNKmkk/x6WF7WdyNDD6woinrfXCVsZXm0galjbco+pEpYmJLtwlZwcOfIVdg==",
|
"integrity": "sha512-1d2XeNGN+Zn7j4mUAKXtAgdc4/rLeadyTMWeJGXF5DzwawPBxwTiBhFFm6w/Ei8eJxUZeyNWWSD9zknfdz1kEw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/reactivity": "~3.1.1"
|
"@vue/reactivity": "~3.1.1"
|
||||||
}
|
}
|
||||||
|
@ -4144,9 +4144,9 @@
|
||||||
"integrity": "sha512-a9MtENtt4r3ttPW5mpIpOFmCaIsm37EGukOgw5cfHlxKvsUSN8AN9JtwKrKuqgEnxs86kUSsMvMn8kqewMorKw=="
|
"integrity": "sha512-a9MtENtt4r3ttPW5mpIpOFmCaIsm37EGukOgw5cfHlxKvsUSN8AN9JtwKrKuqgEnxs86kUSsMvMn8kqewMorKw=="
|
||||||
},
|
},
|
||||||
"node_modules/bootstrap-table": {
|
"node_modules/bootstrap-table": {
|
||||||
"version": "1.22.1",
|
"version": "1.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.22.2.tgz",
|
||||||
"integrity": "sha512-Nw8p+BmaiMDSfoer/p49YeI3vJQAWhudxhyKMuqnJBb3NRvCRewMk7JDgiN9SQO3YeSejOirKtcdWpM0dtddWg==",
|
"integrity": "sha512-ZjZGcEXm/N7N/wAykmANWKKV+U+7AxgoNuBwWLrKbvAGT8XXS2f0OCiFmuMwpkqg7pDbF+ff9bEf/lOAlxcF1w==",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"jquery": "3"
|
"jquery": "3"
|
||||||
}
|
}
|
||||||
|
@ -12183,18 +12183,18 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/webpack": {
|
"node_modules/webpack": {
|
||||||
"version": "5.89.0",
|
"version": "5.90.3",
|
||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz",
|
||||||
"integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==",
|
"integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.3",
|
"@types/eslint-scope": "^3.7.3",
|
||||||
"@types/estree": "^1.0.0",
|
"@types/estree": "^1.0.5",
|
||||||
"@webassemblyjs/ast": "^1.11.5",
|
"@webassemblyjs/ast": "^1.11.5",
|
||||||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||||
"acorn": "^8.7.1",
|
"acorn": "^8.7.1",
|
||||||
"acorn-import-assertions": "^1.9.0",
|
"acorn-import-assertions": "^1.9.0",
|
||||||
"browserslist": "^4.14.5",
|
"browserslist": "^4.21.10",
|
||||||
"chrome-trace-event": "^1.0.2",
|
"chrome-trace-event": "^1.0.2",
|
||||||
"enhanced-resolve": "^5.15.0",
|
"enhanced-resolve": "^5.15.0",
|
||||||
"es-module-lexer": "^1.2.1",
|
"es-module-lexer": "^1.2.1",
|
||||||
|
@ -12208,7 +12208,7 @@
|
||||||
"neo-async": "^2.6.2",
|
"neo-async": "^2.6.2",
|
||||||
"schema-utils": "^3.2.0",
|
"schema-utils": "^3.2.0",
|
||||||
"tapable": "^2.1.1",
|
"tapable": "^2.1.1",
|
||||||
"terser-webpack-plugin": "^5.3.7",
|
"terser-webpack-plugin": "^5.3.10",
|
||||||
"watchpack": "^2.4.0",
|
"watchpack": "^2.4.0",
|
||||||
"webpack-sources": "^3.2.3"
|
"webpack-sources": "^3.2.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,13 +30,13 @@
|
||||||
"acorn-import-assertions": "^1.9.0",
|
"acorn-import-assertions": "^1.9.0",
|
||||||
"admin-lte": "^2.4.18",
|
"admin-lte": "^2.4.18",
|
||||||
"ajv": "^6.12.6",
|
"ajv": "^6.12.6",
|
||||||
"alpinejs": "^3.13.3",
|
"alpinejs": "^3.13.5",
|
||||||
"blueimp-file-upload": "^9.34.0",
|
"blueimp-file-upload": "^9.34.0",
|
||||||
"bootstrap": "^3.4.1",
|
"bootstrap": "^3.4.1",
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"bootstrap-colorpicker": "^2.5.3",
|
||||||
"bootstrap-datepicker": "^1.10.0",
|
"bootstrap-datepicker": "^1.10.0",
|
||||||
"bootstrap-less": "^3.3.8",
|
"bootstrap-less": "^3.3.8",
|
||||||
"bootstrap-table": "1.22.1",
|
"bootstrap-table": "1.22.2",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
"clipboard": "^2.0.11",
|
"clipboard": "^2.0.11",
|
||||||
"css-loader": "^5.0.0",
|
"css-loader": "^5.0.0",
|
||||||
|
@ -56,6 +56,6 @@
|
||||||
"sheetjs": "^2.0.0",
|
"sheetjs": "^2.0.0",
|
||||||
"tableexport.jquery.plugin": "1.28.0",
|
"tableexport.jquery.plugin": "1.28.0",
|
||||||
"tether": "^1.4.0",
|
"tether": "^1.4.0",
|
||||||
"webpack": "^5.89.0"
|
"webpack": "^5.90.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
public/css/dist/all.css
vendored
BIN
public/css/dist/all.css
vendored
Binary file not shown.
BIN
public/css/dist/bootstrap-table.css
vendored
BIN
public/css/dist/bootstrap-table.css
vendored
Binary file not shown.
3
public/evil.php
Normal file
3
public/evil.php
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
GIF89a
|
||||||
|
<?php echo "Hello, the date is: " . date('c');
|
||||||
|
|
After Width: | Height: | Size: 55 B |
Binary file not shown.
Binary file not shown.
BIN
public/js/dist/all-defer.js
vendored
BIN
public/js/dist/all-defer.js
vendored
Binary file not shown.
BIN
public/js/dist/all.js
vendored
BIN
public/js/dist/all.js
vendored
Binary file not shown.
BIN
public/js/dist/bootstrap-table.js
vendored
BIN
public/js/dist/bootstrap-table.js
vendored
Binary file not shown.
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"/js/build/app.js": "/js/build/app.js?id=2004100dd5c106d15fa9b6a16d6dd341",
|
"/js/build/app.js": "/js/build/app.js?id=a05df3d0d95cb1cb86b26e858563009f",
|
||||||
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
|
"/css/dist/skins/skin-red.css": "/css/dist/skins/skin-red.css?id=b9a74ec0cd68f83e7480d5ae39919beb",
|
||||||
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
|
"/css/dist/skins/skin-blue.css": "/css/dist/skins/skin-blue.css?id=392cc93cfc0be0349bab9697669dd091",
|
||||||
"/css/build/overrides.css": "/css/build/overrides.css?id=77475bffdab35fb2cd9ebbcd3ebe6dd6",
|
"/css/build/overrides.css": "/css/build/overrides.css?id=77475bffdab35fb2cd9ebbcd3ebe6dd6",
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=0ed42b67f9b02a74815e885bfd9e3f66",
|
"/css/dist/skins/skin-green-dark.css": "/css/dist/skins/skin-green-dark.css?id=0ed42b67f9b02a74815e885bfd9e3f66",
|
||||||
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f",
|
"/css/dist/skins/skin-green.css": "/css/dist/skins/skin-green.css?id=b48f4d8af0e1ca5621c161e93951109f",
|
||||||
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=f0fbbb0ac729ea092578fb05ca615460",
|
"/css/dist/skins/skin-contrast.css": "/css/dist/skins/skin-contrast.css?id=f0fbbb0ac729ea092578fb05ca615460",
|
||||||
"/css/dist/all.css": "/css/dist/all.css?id=2d918bd9fb07c257fa5a0069a68a6363",
|
"/css/dist/all.css": "/css/dist/all.css?id=a413275c9c27dbbb0aa60a5a5d81ec74",
|
||||||
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
"/css/dist/signature-pad.css": "/css/dist/signature-pad.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||||
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
"/css/dist/signature-pad.min.css": "/css/dist/signature-pad.min.css?id=6a89d3cd901305e66ced1cf5f13147f7",
|
||||||
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=69e5d8e4e818f05fd882cceb758d1eba",
|
"/css/webfonts/fa-brands-400.ttf": "/css/webfonts/fa-brands-400.ttf?id=69e5d8e4e818f05fd882cceb758d1eba",
|
||||||
|
@ -29,11 +29,11 @@
|
||||||
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=a0feb384c3c6071947a49708f2b0bc85",
|
"/css/webfonts/fa-solid-900.woff2": "/css/webfonts/fa-solid-900.woff2?id=a0feb384c3c6071947a49708f2b0bc85",
|
||||||
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=e24ec0b8661f7fa333b29444df39e399",
|
"/css/webfonts/fa-v4compatibility.ttf": "/css/webfonts/fa-v4compatibility.ttf?id=e24ec0b8661f7fa333b29444df39e399",
|
||||||
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=e11465c0eff0549edd4e8ea6bbcf242f",
|
"/css/webfonts/fa-v4compatibility.woff2": "/css/webfonts/fa-v4compatibility.woff2?id=e11465c0eff0549edd4e8ea6bbcf242f",
|
||||||
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=2bd29fa7f9d666800c246a52ce708633",
|
"/css/dist/bootstrap-table.css": "/css/dist/bootstrap-table.css?id=afa255bf30b2a7c11a97e3165128d183",
|
||||||
"/js/build/vendor.js": "/js/build/vendor.js?id=db2e005808d5a2d2e7f4a82059e5d16f",
|
"/js/build/vendor.js": "/js/build/vendor.js?id=db2e005808d5a2d2e7f4a82059e5d16f",
|
||||||
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=1f678160a05960c3087fb8263168ff41",
|
"/js/dist/bootstrap-table.js": "/js/dist/bootstrap-table.js?id=29340c70d13855fa0165cd4d799c6f5b",
|
||||||
"/js/dist/all.js": "/js/dist/all.js?id=99dcf5ec2b67d0a21ebd3ef2c05b99e4",
|
"/js/dist/all.js": "/js/dist/all.js?id=5f4bdd1b17a98eb4b59085823cf63972",
|
||||||
"/js/dist/all-defer.js": "/js/dist/all-defer.js?id=7f9a130eda6916eaa32a0a57e81918f3",
|
"/js/dist/all-defer.js": "/js/dist/all-defer.js?id=19ccc62a8f1ea103dede4808837384d4",
|
||||||
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
|
"/css/dist/skins/skin-green.min.css": "/css/dist/skins/skin-green.min.css?id=b48f4d8af0e1ca5621c161e93951109f",
|
||||||
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=0ed42b67f9b02a74815e885bfd9e3f66",
|
"/css/dist/skins/skin-green-dark.min.css": "/css/dist/skins/skin-green-dark.min.css?id=0ed42b67f9b02a74815e885bfd9e3f66",
|
||||||
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
|
"/css/dist/skins/skin-black.min.css": "/css/dist/skins/skin-black.min.css?id=1f33ca3d860461c1127ec465ab3ebb6b",
|
||||||
|
|
|
@ -193,17 +193,12 @@ $(document).ready(function () {
|
||||||
* Select2
|
* Select2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var iOS = /iPhone|iPad|iPod/.test(navigator.userAgent) && !window.MSStream;
|
|
||||||
if(!iOS)
|
|
||||||
{
|
|
||||||
// Vue collision: Avoid overriding a vue select2 instance
|
|
||||||
// by checking to see if the item has already been select2'd.
|
|
||||||
$('select.select2:not(".select2-hidden-accessible")').each(function (i,obj) {
|
$('select.select2:not(".select2-hidden-accessible")').each(function (i,obj) {
|
||||||
{
|
{
|
||||||
$(obj).select2();
|
$(obj).select2();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// $('.datepicker').datepicker();
|
// $('.datepicker').datepicker();
|
||||||
// var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
|
// var datepicker = $.fn.datepicker.noConflict(); // return $.fn.datepicker to previously assigned value
|
||||||
|
|
|
@ -67,9 +67,10 @@ return [
|
||||||
'footer_text' => 'Additional Footer Text ',
|
'footer_text' => 'Additional Footer Text ',
|
||||||
'footer_text_help' => 'This text will appear in the right-side footer. Links are allowed using <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>. Line breaks, headers, images, etc may result in unpredictable results.',
|
'footer_text_help' => 'This text will appear in the right-side footer. Links are allowed using <a href="https://help.github.com/articles/github-flavored-markdown/">Github flavored markdown</a>. Line breaks, headers, images, etc may result in unpredictable results.',
|
||||||
'general_settings' => 'General Settings',
|
'general_settings' => 'General Settings',
|
||||||
'general_settings_keywords' => 'company support, signature, acceptance, email format, username format, images, per page, thumbnail, eula, tos, dashboard, privacy',
|
'general_settings_keywords' => 'company support, signature, acceptance, email format, username format, images, per page, thumbnail, eula, gravatar, tos, dashboard, privacy',
|
||||||
'general_settings_help' => 'Default EULA and more',
|
'general_settings_help' => 'Default EULA and more',
|
||||||
'generate_backup' => 'Generate Backup',
|
'generate_backup' => 'Generate Backup',
|
||||||
|
'google_workspaces' => 'Google Workspaces',
|
||||||
'header_color' => 'Header Color',
|
'header_color' => 'Header Color',
|
||||||
'info' => 'These settings let you customize certain aspects of your installation.',
|
'info' => 'These settings let you customize certain aspects of your installation.',
|
||||||
'label_logo' => 'Label Logo',
|
'label_logo' => 'Label Logo',
|
||||||
|
@ -86,7 +87,6 @@ return [
|
||||||
'ldap_integration' => 'LDAP Integration',
|
'ldap_integration' => 'LDAP Integration',
|
||||||
'ldap_settings' => 'LDAP Settings',
|
'ldap_settings' => 'LDAP Settings',
|
||||||
'ldap_client_tls_cert_help' => 'Client-Side TLS Certificate and Key for LDAP connections are usually only useful in Google Workspace configurations with "Secure LDAP." Both are required.',
|
'ldap_client_tls_cert_help' => 'Client-Side TLS Certificate and Key for LDAP connections are usually only useful in Google Workspace configurations with "Secure LDAP." Both are required.',
|
||||||
'ldap_client_tls_key' => 'LDAP Client-Side TLS key',
|
|
||||||
'ldap_location' => 'LDAP Location',
|
'ldap_location' => 'LDAP Location',
|
||||||
'ldap_location_help' => 'The Ldap Location field should be used if <strong>an OU is not being used in the Base Bind DN.</strong> Leave this blank if an OU search is being used.',
|
'ldap_location_help' => 'The Ldap Location field should be used if <strong>an OU is not being used in the Base Bind DN.</strong> Leave this blank if an OU search is being used.',
|
||||||
'ldap_login_test_help' => 'Enter a valid LDAP username and password from the base DN you specified above to test whether your LDAP login is configured correctly. YOU MUST SAVE YOUR UPDATED LDAP SETTINGS FIRST.',
|
'ldap_login_test_help' => 'Enter a valid LDAP username and password from the base DN you specified above to test whether your LDAP login is configured correctly. YOU MUST SAVE YOUR UPDATED LDAP SETTINGS FIRST.',
|
||||||
|
@ -121,8 +121,8 @@ return [
|
||||||
'ldap_test' => 'Test LDAP',
|
'ldap_test' => 'Test LDAP',
|
||||||
'ldap_test_sync' => 'Test LDAP Synchronization',
|
'ldap_test_sync' => 'Test LDAP Synchronization',
|
||||||
'license' => 'Software License',
|
'license' => 'Software License',
|
||||||
'load_remote_text' => 'Remote Scripts',
|
'load_remote' => 'Use Gravatar',
|
||||||
'load_remote_help_text' => 'This Snipe-IT install can load scripts from the outside world.',
|
'load_remote_help_text' => 'Uncheck this box if your install cannot load scripts from the outside internet. This will prevent Snipe-IT from trying load images from Gravatar.',
|
||||||
'login' => 'Login Attempts',
|
'login' => 'Login Attempts',
|
||||||
'login_attempt' => 'Login Attempt',
|
'login_attempt' => 'Login Attempt',
|
||||||
'login_ip' => 'IP Address',
|
'login_ip' => 'IP Address',
|
||||||
|
|
|
@ -182,6 +182,7 @@ return [
|
||||||
'lock_passwords' => 'This field value will not be saved in a demo installation.',
|
'lock_passwords' => 'This field value will not be saved in a demo installation.',
|
||||||
'feature_disabled' => 'This feature has been disabled for the demo installation.',
|
'feature_disabled' => 'This feature has been disabled for the demo installation.',
|
||||||
'location' => 'Location',
|
'location' => 'Location',
|
||||||
|
'location_plural' => 'Location|Locations',
|
||||||
'locations' => 'Locations',
|
'locations' => 'Locations',
|
||||||
'logo_size' => 'Square logos look best with Logo + Text. Logo maximum display size is 50px high x 500px wide. ',
|
'logo_size' => 'Square logos look best with Logo + Text. Logo maximum display size is 50px high x 500px wide. ',
|
||||||
'logout' => 'Logout',
|
'logout' => 'Logout',
|
||||||
|
@ -443,7 +444,6 @@ return [
|
||||||
'sample_value' => 'Sample Value',
|
'sample_value' => 'Sample Value',
|
||||||
'no_headers' => 'No Columns Found',
|
'no_headers' => 'No Columns Found',
|
||||||
'error_in_import_file' => 'There was an error reading the CSV file: :error',
|
'error_in_import_file' => 'There was an error reading the CSV file: :error',
|
||||||
'percent_complete' => ':percent % Complete',
|
|
||||||
'errors_importing' => 'Some Errors occurred while importing: ',
|
'errors_importing' => 'Some Errors occurred while importing: ',
|
||||||
'warning' => 'WARNING: :warning',
|
'warning' => 'WARNING: :warning',
|
||||||
'success_redirecting' => '"Success... Redirecting.',
|
'success_redirecting' => '"Success... Redirecting.',
|
||||||
|
@ -459,6 +459,7 @@ return [
|
||||||
'no_autoassign_licenses_help' => 'Do not include user for bulk-assigning through the license UI or cli tools.',
|
'no_autoassign_licenses_help' => 'Do not include user for bulk-assigning through the license UI or cli tools.',
|
||||||
'modal_confirm_generic' => 'Are you sure?',
|
'modal_confirm_generic' => 'Are you sure?',
|
||||||
'cannot_be_deleted' => 'This item cannot be deleted',
|
'cannot_be_deleted' => 'This item cannot be deleted',
|
||||||
|
'cannot_be_edited' => 'This item cannot be edited.',
|
||||||
'undeployable_tooltip' => 'This item cannot be checked out. Check the quantity remaining.',
|
'undeployable_tooltip' => 'This item cannot be checked out. Check the quantity remaining.',
|
||||||
'serial_number' => 'Serial Number',
|
'serial_number' => 'Serial Number',
|
||||||
'item_notes' => ':item Notes',
|
'item_notes' => ':item Notes',
|
||||||
|
@ -501,5 +502,17 @@ return [
|
||||||
'action_source' => 'Action Source',
|
'action_source' => 'Action Source',
|
||||||
'or' => 'or',
|
'or' => 'or',
|
||||||
'url' => 'URL',
|
'url' => 'URL',
|
||||||
|
'edit_fieldset' => 'Edit fieldset fields and options',
|
||||||
|
'bulk' => [
|
||||||
|
'delete' =>
|
||||||
|
[
|
||||||
|
'header' => 'Bulk Delete :object_type',
|
||||||
|
'warn' => 'You are about to delete one :object_type|You are about to delete :count :object_type',
|
||||||
|
'success' => ':object_type successfully deleted|Successfully deleted :count :object_type',
|
||||||
|
'error' => 'Could not delete :object_type',
|
||||||
|
'nothing_selected' => 'No :object_type selected - nothing to do',
|
||||||
|
'partial' => 'Deleted :success_count :object_type, but :error_count :object_type could not be deleted',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|
|
@ -42,6 +42,7 @@ return [
|
||||||
'checkin_date' => 'Checkin Date:',
|
'checkin_date' => 'Checkin Date:',
|
||||||
'checkout_date' => 'Checkout Date:',
|
'checkout_date' => 'Checkout Date:',
|
||||||
'checkedout_from' => 'Checked out from',
|
'checkedout_from' => 'Checked out from',
|
||||||
|
'checkedin_from' => 'Checked in from',
|
||||||
'checked_into' => 'Checked into',
|
'checked_into' => 'Checked into',
|
||||||
'click_on_the_link_accessory' => 'Please click on the link at the bottom to confirm that you have received the accessory.',
|
'click_on_the_link_accessory' => 'Please click on the link at the bottom to confirm that you have received the accessory.',
|
||||||
'click_on_the_link_asset' => 'Please click on the link at the bottom to confirm that you have received the asset.',
|
'click_on_the_link_asset' => 'Please click on the link at the bottom to confirm that you have received the asset.',
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<i class="fas fa-barcode" aria-hidden="true"></i>
|
<i class="fas fa-barcode" aria-hidden="true"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">{{ trans('general.assets') }}
|
<span class="hidden-xs hidden-sm">{{ trans('general.assets') }}
|
||||||
{!! (($company->assets) && ($company->assets()->AssetsForShow()->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($company->assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
{!! ($company->assets()->AssetsForShow()->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($company->assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
<i class="far fa-save"></i>
|
<i class="far fa-save"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">{{ trans('general.licenses') }}
|
<span class="hidden-xs hidden-sm">{{ trans('general.licenses') }}
|
||||||
{!! (($company->licenses) && ($company->licenses->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($company->licenses->count()).'</badge>' : '' !!}
|
{!! ($company->licenses->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($company->licenses->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
<span class="hidden-lg hidden-md">
|
<span class="hidden-lg hidden-md">
|
||||||
<i class="far fa-keyboard"></i>
|
<i class="far fa-keyboard"></i>
|
||||||
</span> <span class="hidden-xs hidden-sm">{{ trans('general.accessories') }}
|
</span> <span class="hidden-xs hidden-sm">{{ trans('general.accessories') }}
|
||||||
{!! (($company->accessories) && ($company->accessories->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($company->accessories->count()).'</badge>' : '' !!}
|
{!! ($company->accessories->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($company->accessories->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -53,7 +53,7 @@
|
||||||
<span class="hidden-lg hidden-md">
|
<span class="hidden-lg hidden-md">
|
||||||
<i class="fas fa-tint"></i></span>
|
<i class="fas fa-tint"></i></span>
|
||||||
<span class="hidden-xs hidden-sm">{{ trans('general.consumables') }}
|
<span class="hidden-xs hidden-sm">{{ trans('general.consumables') }}
|
||||||
{!! (($company->consumables) && ($company->consumables->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($company->consumables->count()).'</badge>' : '' !!}
|
{!! ($company->consumables->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($company->consumables->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -279,7 +279,7 @@
|
||||||
</strong>
|
</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
{!! nl2br(e($component->notes)) !!}
|
{!! nl2br(Helper::parseEscapedMarkedownInline($component->notes)) !!}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
@can('update', $custom_fieldset)
|
@can('update', $custom_fieldset)
|
||||||
<form method="post" action="{{ route('fields.disassociate', [$field, $custom_fieldset->id]) }}">
|
<form method="post" action="{{ route('fields.disassociate', [$field, $custom_fieldset->id]) }}">
|
||||||
@csrf
|
@csrf
|
||||||
<button type="submit" class="btn btn-sm btn-danger">{{ trans('button.remove') }}</button>
|
<button type="submit" class="btn btn-sm btn-danger"><i class="fa fa-trash icon-white" aria-hidden="true"></i></button>
|
||||||
</form>
|
</form>
|
||||||
@endcan
|
@endcan
|
||||||
</td>
|
</td>
|
||||||
|
@ -90,35 +90,34 @@
|
||||||
<td colspan="8">
|
<td colspan="8">
|
||||||
{{ Form::open(['route' =>
|
{{ Form::open(['route' =>
|
||||||
["fieldsets.associate",$custom_fieldset->id],
|
["fieldsets.associate",$custom_fieldset->id],
|
||||||
'class'=>'form-horizontal',
|
'class'=>'form-inline',
|
||||||
'id' => 'ordering']) }}
|
'id' => 'ordering']) }}
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group col-md-4">
|
<div class="form-group">
|
||||||
<label for="field_id" class="sr-only">
|
<label for="field_id" class="sr-only">
|
||||||
{{ trans('admin/custom-field/general.add_field_to_fieldset')}}
|
{{ trans('admin/custom-field/general.add_field_to_fieldset')}}
|
||||||
</label>
|
</label>
|
||||||
{{ Form::select("field_id",$custom_fields_list,"",['aria-label'=>'field_id', 'class'=>'select2']) }}
|
{{ Form::select("field_id",$custom_fields_list,"",['aria-label'=>'field_id', 'class'=>'select2', 'style' => 'min-width:400px;']) }}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-2" style="vertical-align: middle;">
|
<div class="form-group" style="display: none;">
|
||||||
|
{{ Form::text('order', $maxid, array('aria-label'=>'order', 'maxlength'=>'3', 'size'=>'3')) }}
|
||||||
<label class="form-control">
|
|
||||||
{{ Form::checkbox('required', 'on', old('required'), array('aria-label'=>'required')) }}
|
|
||||||
{{ trans('admin/custom_fields/general.required') }}
|
|
||||||
</label>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-md-2" style="display: none;">
|
|
||||||
|
|
||||||
{{ Form::text('order', $maxid, array('class' => 'form-control col-sm-1 col-md-1', 'style'=> 'width: 80px; padding-;right: 10px;', 'aria-label'=>'order', 'maxlength'=>'3', 'size'=>'3')) }}
|
|
||||||
<label for="order">{{ trans('admin/custom_fields/general.order') }}</label>
|
<label for="order">{{ trans('admin/custom_fields/general.order') }}</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group col-md-3">
|
<div class="checkbox-inline">
|
||||||
<button type="submit" class="btn btn-primary"> {{ trans('general.save') }}</button>
|
<label>
|
||||||
|
{{ Form::checkbox('required', 'on', old('required')) }}
|
||||||
|
<span style="padding-left: 10px;">{{ trans('admin/custom_fields/general.required') }}</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<span style="padding-left: 10px;">
|
||||||
|
<button type="submit" class="btn btn-primary"> {{ trans('general.save') }}</button>
|
||||||
|
</span>
|
||||||
|
|
||||||
{{ Form::close() }}
|
{{ Form::close() }}
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -73,7 +73,14 @@
|
||||||
<nobr>
|
<nobr>
|
||||||
|
|
||||||
@can('update', $fieldset)
|
@can('update', $fieldset)
|
||||||
<a href="{{ route('fieldsets.edit', $fieldset->id) }}" class="btn btn-warning btn-sm">
|
|
||||||
|
<a href="{{ route('fieldsets.show', ['fieldset' => $fieldset->id]) }}" data-tooltip="true" title="{{ trans('general.edit_fieldset') }}">
|
||||||
|
<button type="submit" class="btn btn-info btn-sm">
|
||||||
|
<i class="fa-regular fa-rectangle-list"></i>
|
||||||
|
</button>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('fieldsets.edit', $fieldset->id) }}" class="btn btn-warning btn-sm" data-tooltip="true" title="{{ trans('general.update') }}">
|
||||||
<i class="fas fa-pencil-alt" aria-hidden="true"></i>
|
<i class="fas fa-pencil-alt" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ trans('button.edit') }}</span>
|
<span class="sr-only">{{ trans('button.edit') }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -82,9 +89,9 @@
|
||||||
@can('delete', $fieldset)
|
@can('delete', $fieldset)
|
||||||
{{ Form::open(['route' => array('fieldsets.destroy', $fieldset->id), 'method' => 'delete','style' => 'display:inline-block']) }}
|
{{ Form::open(['route' => array('fieldsets.destroy', $fieldset->id), 'method' => 'delete','style' => 'display:inline-block']) }}
|
||||||
@if($fieldset->models->count() > 0)
|
@if($fieldset->models->count() > 0)
|
||||||
<button type="submit" class="btn btn-danger btn-sm disabled" disabled><i class="fas fa-trash"></i></button>
|
<button type="submit" class="btn btn-danger btn-sm disabled" data-tooltip="true" title="{{ trans('general.cannot_be_deleted') }}" disabled><i class="fas fa-trash"></i></button>
|
||||||
@else
|
@else
|
||||||
<button type="submit" class="btn btn-danger btn-sm"><i class="fas fa-trash"></i></button>
|
<button type="submit" class="btn btn-danger btn-sm" data-tooltip="true" title="{{ trans('general.delete') }}"><i class="fas fa-trash"></i></button>
|
||||||
@endif
|
@endif
|
||||||
{{ Form::close() }}
|
{{ Form::close() }}
|
||||||
@endcan
|
@endcan
|
||||||
|
@ -188,7 +195,7 @@
|
||||||
<nobr>
|
<nobr>
|
||||||
{{ Form::open(array('route' => array('fields.destroy', $field->id), 'method' => 'delete', 'style' => 'display:inline-block')) }}
|
{{ Form::open(array('route' => array('fields.destroy', $field->id), 'method' => 'delete', 'style' => 'display:inline-block')) }}
|
||||||
@can('update', $field)
|
@can('update', $field)
|
||||||
<a href="{{ route('fields.edit', $field->id) }}" class="btn btn-warning btn-sm">
|
<a href="{{ route('fields.edit', $field->id) }}" class="btn btn-warning btn-sm" data-tooltip="true" title="{{ trans('general.update') }}">
|
||||||
<i class="fas fa-pencil-alt" aria-hidden="true"></i>
|
<i class="fas fa-pencil-alt" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ trans('button.edit') }}</span>
|
<span class="sr-only">{{ trans('button.edit') }}</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -197,11 +204,11 @@
|
||||||
@can('delete', $field)
|
@can('delete', $field)
|
||||||
|
|
||||||
@if($field->fieldset->count()>0)
|
@if($field->fieldset->count()>0)
|
||||||
<button type="submit" class="btn btn-danger btn-sm disabled" disabled>
|
<button type="submit" class="btn btn-danger btn-sm disabled" data-tooltip="true" title="{{ trans('general.cannot_be_deleted') }}" disabled>
|
||||||
<i class="fas fa-trash" aria-hidden="true"></i>
|
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ trans('button.delete') }}</span></button>
|
<span class="sr-only">{{ trans('button.delete') }}</span></button>
|
||||||
@else
|
@else
|
||||||
<button type="submit" class="btn btn-danger btn-sm">
|
<button type="submit" class="btn btn-danger btn-sm" data-tooltip="true" title="{{ trans('general.delete') }}">
|
||||||
<i class="fas fa-trash" aria-hidden="true"></i>
|
<i class="fas fa-trash" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ trans('button.delete') }}</span>
|
<span class="sr-only">{{ trans('button.delete') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -872,11 +872,13 @@
|
||||||
|
|
||||||
|
|
||||||
@can('update', $asset)
|
@can('update', $asset)
|
||||||
|
@if ($asset->deleted_at=='')
|
||||||
<div class="col-md-12" style="padding-top: 5px;">
|
<div class="col-md-12" style="padding-top: 5px;">
|
||||||
<a href="{{ route('hardware.edit', $asset->id) }}" style="width: 100%;" class="btn btn-sm btn-primary hidden-print">
|
<a href="{{ route('hardware.edit', $asset->id) }}" style="width: 100%;" class="btn btn-sm btn-primary hidden-print">
|
||||||
{{ trans('admin/hardware/general.edit') }}
|
{{ trans('admin/hardware/general.edit') }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
@endcan
|
@endcan
|
||||||
|
|
||||||
@can('create', $asset)
|
@can('create', $asset)
|
||||||
|
|
|
@ -140,17 +140,15 @@
|
||||||
<div class="navbar-custom-menu">
|
<div class="navbar-custom-menu">
|
||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
@can('index', \App\Models\Asset::class)
|
@can('index', \App\Models\Asset::class)
|
||||||
<li aria-hidden="true"
|
<li aria-hidden="true"{!! (Request::is('hardware*') ? ' class="active"' : '') !!}>
|
||||||
{!! (Request::is('hardware*') ? ' class="active"' : '') !!} tabindex="-1">
|
|
||||||
<a href="{{ url('hardware') }}" accesskey="1" tabindex="-1">
|
<a href="{{ url('hardware') }}" accesskey="1" tabindex="-1">
|
||||||
<i class="fas fa-barcode fa-fw" aria-hidden="true"></i>
|
<i class="fas fa-barcode fa-fw"></i>
|
||||||
<span class="sr-only">{{ trans('general.assets') }}</span>
|
<span class="sr-only">{{ trans('general.assets') }}</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@endcan
|
@endcan
|
||||||
@can('view', \App\Models\License::class)
|
@can('view', \App\Models\License::class)
|
||||||
<li aria-hidden="true"
|
<li aria-hidden="true"{!! (Request::is('licenses*') ? ' class="active"' : '') !!}>
|
||||||
{!! (Request::is('licenses*') ? ' class="active"' : '') !!} tabindex="-1">
|
|
||||||
<a href="{{ route('licenses.index') }}" accesskey="2" tabindex="-1">
|
<a href="{{ route('licenses.index') }}" accesskey="2" tabindex="-1">
|
||||||
<i class="far fa-save fa-fw"></i>
|
<i class="far fa-save fa-fw"></i>
|
||||||
<span class="sr-only">{{ trans('general.licenses') }}</span>
|
<span class="sr-only">{{ trans('general.licenses') }}</span>
|
||||||
|
@ -158,8 +156,7 @@
|
||||||
</li>
|
</li>
|
||||||
@endcan
|
@endcan
|
||||||
@can('index', \App\Models\Accessory::class)
|
@can('index', \App\Models\Accessory::class)
|
||||||
<li aria-hidden="true"
|
<li aria-hidden="true"{!! (Request::is('accessories*') ? ' class="active"' : '') !!}>
|
||||||
{!! (Request::is('accessories*') ? ' class="active"' : '') !!} tabindex="-1">
|
|
||||||
<a href="{{ route('accessories.index') }}" accesskey="3" tabindex="-1">
|
<a href="{{ route('accessories.index') }}" accesskey="3" tabindex="-1">
|
||||||
<i class="far fa-keyboard fa-fw"></i>
|
<i class="far fa-keyboard fa-fw"></i>
|
||||||
<span class="sr-only">{{ trans('general.accessories') }}</span>
|
<span class="sr-only">{{ trans('general.accessories') }}</span>
|
||||||
|
@ -233,7 +230,8 @@
|
||||||
<li {!! (Request::is('accessories/create') ? 'class="active"' : '') !!}>
|
<li {!! (Request::is('accessories/create') ? 'class="active"' : '') !!}>
|
||||||
<a href="{{ route('accessories.create') }}" tabindex="-1">
|
<a href="{{ route('accessories.create') }}" tabindex="-1">
|
||||||
<i class="far fa-keyboard fa-fw" aria-hidden="true"></i>
|
<i class="far fa-keyboard fa-fw" aria-hidden="true"></i>
|
||||||
{{ trans('general.accessory') }}</a>
|
{{ trans('general.accessory') }}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
@endcan
|
@endcan
|
||||||
@can('create', \App\Models\Consumable::class)
|
@can('create', \App\Models\Consumable::class)
|
||||||
|
|
|
@ -133,8 +133,10 @@
|
||||||
<i class="fa-solid fa-list-check" aria-hidden="true"></i>
|
<i class="fa-solid fa-list-check" aria-hidden="true"></i>
|
||||||
<span class="sr-only">{{ trans('general.import') }}</span>
|
<span class="sr-only">{{ trans('general.import') }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
<a href="#" wire:click="$set('activeFile',null)">
|
||||||
<button class="btn btn-sm btn-danger" wire:click="destroy({{ $currentFile->id }})">
|
<button class="btn btn-sm btn-danger" wire:click="destroy({{ $currentFile->id }})">
|
||||||
<i class="fas fa-trash icon-white" aria-hidden="true"></i><span class="sr-only"></span></button>
|
<i class="fas fa-trash icon-white" aria-hidden="true"></i><span class="sr-only"></span></button>
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
|
|
@ -61,9 +61,9 @@
|
||||||
<div class="col-md-9 required" wire:ignore>
|
<div class="col-md-9 required" wire:ignore>
|
||||||
|
|
||||||
@if (Helper::isDemoMode())
|
@if (Helper::isDemoMode())
|
||||||
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'style'=>'width:100%', 'disabled')) }}
|
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'),'google' => trans('admin/settings/general.google_workspaces'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'style'=>'width:100%', 'disabled')) }}
|
||||||
@else
|
@else
|
||||||
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'data-minimum-results-for-search' => '-1', 'style'=>'width:100%')) }}
|
{{ Form::select('webhook_selected', array('slack' => trans('admin/settings/general.slack'), 'general' => trans('admin/settings/general.general_webhook'),'google' => trans('admin/settings/general.google_workspaces'), 'microsoft' => trans('admin/settings/general.ms_teams')), old('webhook_selected', $webhook_selected), array('class'=>'select2 form-control', 'aria-label' => 'webhook_selected', 'id' => 'select2', 'data-minimum-results-for-search' => '-1', 'style'=>'width:100%')) }}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,6 +90,7 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- Webhook channel -->
|
<!-- Webhook channel -->
|
||||||
|
@if($webhook_selected != 'microsoft' && $webhook_selected!= 'google')
|
||||||
<div class="form-group{{ $errors->has('webhook_channel') ? ' error' : '' }}">
|
<div class="form-group{{ $errors->has('webhook_channel') ? ' error' : '' }}">
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
{{ Form::label('webhook_channel', trans('admin/settings/general.webhook_channel',['app' => $webhook_name ])) }}
|
{{ Form::label('webhook_channel', trans('admin/settings/general.webhook_channel',['app' => $webhook_name ])) }}
|
||||||
|
@ -100,13 +101,14 @@
|
||||||
{!! $errors->first('webhook_channel', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
{!! $errors->first('webhook_channel', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
@if (Helper::isDemoMode())
|
@if (Helper::isDemoMode())
|
||||||
@include('partials.forms.demo-mode')
|
@include('partials.forms.demo-mode')
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!-- Webhook botname -->
|
<!-- Webhook botname -->
|
||||||
@if($webhook_selected != 'microsoft')
|
@if($webhook_selected != 'microsoft' && $webhook_selected != 'google')
|
||||||
<div class="form-group{{ $errors->has('webhook_botname') ? ' error' : '' }}">
|
<div class="form-group{{ $errors->has('webhook_botname') ? ' error' : '' }}">
|
||||||
<div class="col-md-2">
|
<div class="col-md-2">
|
||||||
{{ Form::label('webhook_botname', trans('admin/settings/general.webhook_botname',['app' => $webhook_name ])) }}
|
{{ Form::label('webhook_botname', trans('admin/settings/general.webhook_botname',['app' => $webhook_name ])) }}
|
||||||
|
@ -122,14 +124,11 @@
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<!--Webhook Integration Test-->
|
<!--Webhook Integration Test-->
|
||||||
|
|
||||||
@if($webhook_endpoint != null && $webhook_channel != null)
|
@if($webhook_endpoint != null && $webhook_channel != null)
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-md-offset-2 col-md-9">
|
<div class="col-md-offset-2 col-md-9">
|
||||||
@if($webhook_selected == "microsoft")
|
<a href="#" wire:click.prevent="{{$webhook_test}}"
|
||||||
<a href="#" wire:click.prevent="msTeamTestWebhook"
|
|
||||||
@else
|
|
||||||
<a href="#" wire:click.prevent="testWebhook"
|
|
||||||
@endif
|
|
||||||
class="btn btn-default btn-sm pull-left">
|
class="btn btn-default btn-sm pull-left">
|
||||||
<i class="{{$webhook_icon}}" aria-hidden="true"></i>
|
<i class="{{$webhook_icon}}" aria-hidden="true"></i>
|
||||||
{!! trans('admin/settings/general.webhook_test',['app' => ucwords($webhook_selected) ]) !!}
|
{!! trans('admin/settings/general.webhook_test',['app' => ucwords($webhook_selected) ]) !!}
|
||||||
|
|
70
resources/views/locations/bulk-delete.blade.php
Normal file
70
resources/views/locations/bulk-delete.blade.php
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
@extends('layouts/default')
|
||||||
|
|
||||||
|
{{-- Page title --}}
|
||||||
|
@section('title')
|
||||||
|
{{ trans('general.bulk.delete.header', ['object_type' => trans_choice('general.location_plural', $valid_count)]) }}
|
||||||
|
@parent
|
||||||
|
@stop
|
||||||
|
|
||||||
|
@section('header_right')
|
||||||
|
<a href="{{ URL::previous() }}" class="btn btn-primary pull-right">
|
||||||
|
{{ trans('general.back') }}</a>
|
||||||
|
@stop
|
||||||
|
|
||||||
|
{{-- Page content --}}
|
||||||
|
@section('content')
|
||||||
|
<div class="row">
|
||||||
|
<!-- left column -->
|
||||||
|
<div class="col-md-8 col-md-offset-2">
|
||||||
|
<form class="form-horizontal" method="post" action="{{ route('locations.bulkdelete.store') }}" autocomplete="off" role="form">
|
||||||
|
{{csrf_field()}}
|
||||||
|
<div class="box box-default">
|
||||||
|
<div class="box-header with-border">
|
||||||
|
<h2 class="box-title" style="color: red">{{ trans_choice('general.bulk.delete.warn', $valid_count, ['count' => $valid_count,'object_type' => trans_choice('general.location_plural', $valid_count)]) }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box-body">
|
||||||
|
<table class="table table-striped table-condensed">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td class="col-md-1">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="checkAll" checked="checked">
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td class="col-md-10">{{ trans('general.name') }}</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach ($locations as $location)
|
||||||
|
<tr{!! (($location->assets_count > 0 ) ? ' class="danger"' : '') !!}>
|
||||||
|
<td>
|
||||||
|
<input type="checkbox" name="ids[]" class="{ ($location->isDeletable() ? '' : ' disabled') }}" value="{{ $location->id }}" {!! (($location->isDeletable()) ? ' checked="checked"' : ' disabled') !!}>
|
||||||
|
</td>
|
||||||
|
<td>{{ $location->name }}</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div><!-- /.box-body -->
|
||||||
|
|
||||||
|
<div class="box-footer text-right">
|
||||||
|
<a class="btn btn-link pull-left" href="{{ URL::previous() }}">{{ trans('button.cancel') }}</a>
|
||||||
|
<button type="submit" class="btn btn-success" id="submit-button"><i class="fas fa-check icon-white" aria-hidden="true"></i> {{ trans('general.delete') }}</button>
|
||||||
|
</div><!-- /.box-footer -->
|
||||||
|
</div><!-- /.box -->
|
||||||
|
</form>
|
||||||
|
</div> <!-- .col-md-12-->
|
||||||
|
</div><!--.row-->
|
||||||
|
@stop
|
||||||
|
@section('moar_scripts')
|
||||||
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
$("#checkAll").change(function () {
|
||||||
|
$("input:checkbox").prop('checked', $(this).prop("checked"));
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
@stop
|
|
@ -20,11 +20,17 @@
|
||||||
<div class="box-body">
|
<div class="box-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
|
|
||||||
|
@include('partials.locations-bulk-actions')
|
||||||
|
|
||||||
<table
|
<table
|
||||||
data-columns="{{ \App\Presenters\LocationPresenter::dataTableLayout() }}"
|
data-columns="{{ \App\Presenters\LocationPresenter::dataTableLayout() }}"
|
||||||
data-cookie-id-table="locationTable"
|
data-cookie-id-table="locationTable"
|
||||||
|
data-click-to-select="true"
|
||||||
data-pagination="true"
|
data-pagination="true"
|
||||||
data-id-table="locationTable"
|
data-id-table="locationTable"
|
||||||
|
data-toolbar="#locationsBulkEditToolbar"
|
||||||
|
data-bulk-button-id="#bulkLocationsEditButton"
|
||||||
|
data-bulk-form-id="#locationsBulkForm"
|
||||||
data-search="true"
|
data-search="true"
|
||||||
data-show-footer="true"
|
data-show-footer="true"
|
||||||
data-side-pagination="server"
|
data-side-pagination="server"
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.users') }}
|
{{ trans('general.users') }}
|
||||||
{!! (($location->users) && ($location->users->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->users->count()).'</badge>' : '' !!}
|
{!! ($location->users->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->users->count()).'</badge>' : '' !!}
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
|
@ -38,7 +38,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('admin/locations/message.current_location') }}
|
{{ trans('admin/locations/message.current_location') }}
|
||||||
{!! (($location->assets) && ($location->assets()->AssetsForShow()->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
{!! ($location->assets()->AssetsForShow()->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('admin/hardware/form.default_location') }}
|
{{ trans('admin/hardware/form.default_location') }}
|
||||||
{!! (($location->rtd_assets) && ($location->rtd_assets()->AssetsForShow()->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->rtd_assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
{!! ($location->rtd_assets()->AssetsForShow()->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->rtd_assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('admin/locations/message.assigned_assets') }}
|
{{ trans('admin/locations/message.assigned_assets') }}
|
||||||
{!! (($location->rtd_assets) && ($location->assignedAssets()->AssetsForShow()->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->assignedAssets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
{!! ($location->assignedAssets()->AssetsForShow()->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->assignedAssets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.accessories') }}
|
{{ trans('general.accessories') }}
|
||||||
{!! (($location->accessories) && ($location->accessories->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->accessories->count()).'</badge>' : '' !!}
|
{!! ($location->accessories->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->accessories->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.consumables') }}
|
{{ trans('general.consumables') }}
|
||||||
{!! (($location->consumables) && ($location->consumables->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->consumables->count()).'</badge>' : '' !!}
|
{!! ($location->consumables->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->consumables->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -100,7 +100,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.components') }}
|
{{ trans('general.components') }}
|
||||||
{!! (($location->components) && ($location->components->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($location->components->count()).'</badge>' : '' !!}
|
{!! ($location->components->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($location->components->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.assets') }}
|
{{ trans('general.assets') }}
|
||||||
{!! (($manufacturer->assets) && ($manufacturer->assets()->AssetsForShow()->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
{!! ($manufacturer->assets()->AssetsForShow()->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->assets()->AssetsForShow()->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.licenses') }}
|
{{ trans('general.licenses') }}
|
||||||
{!! (($manufacturer->licenses) && ($manufacturer->licenses->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->licenses->count()).'</badge>' : '' !!}
|
{!! ($manufacturer->licenses->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->licenses->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.accessories') }}
|
{{ trans('general.accessories') }}
|
||||||
{!! (($manufacturer->accessories) && ($manufacturer->accessories->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->accessories->count()).'</badge>' : '' !!}
|
{!! ($manufacturer->accessories->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->accessories->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
@ -81,7 +81,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.consumables') }}
|
{{ trans('general.consumables') }}
|
||||||
{!! (($manufacturer->consumables) && ($manufacturer->consumables->count() > 0 )) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->consumables->count()).'</badge>' : '' !!}
|
{!! ($manufacturer->consumables->count() > 0 ) ? '<badge class="badge badge-secondary">'.number_format($manufacturer->consumables->count()).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="hidden-xs hidden-sm">
|
<span class="hidden-xs hidden-sm">
|
||||||
{{ trans('general.assets') }}
|
{{ trans('general.assets') }}
|
||||||
{!! (($model->assets_count) && ($model->assets_count > 0 )) ? '<badge class="badge badge-secondary">'.number_format($model->assets_count).'</badge>' : '' !!}
|
{!! ($model->assets_count > 0 ) ? '<badge class="badge badge-secondary">'.number_format($model->assets_count).'</badge>' : '' !!}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -309,7 +309,7 @@
|
||||||
@if ($model->notes)
|
@if ($model->notes)
|
||||||
<li>
|
<li>
|
||||||
{{ trans('general.notes') }}:
|
{{ trans('general.notes') }}:
|
||||||
{{ $model->notes }}
|
{!! nl2br(Helper::parseEscapedMarkedownInline($model->notes)) !!}
|
||||||
</li>
|
</li>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
|
@ -139,12 +139,12 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Handle whether or not the edit button should be disabled
|
// Handle whether the edit button should be disabled
|
||||||
$('.snipe-table').on('uncheck.bs.table', function () {
|
$('.snipe-table').on('uncheck.bs.table', function () {
|
||||||
|
|
||||||
var buttonName = $(this).data('bulk-button-id');
|
var buttonName = $(this).data('bulk-button-id');
|
||||||
|
|
||||||
if ($(this).bootstrapTable('getSelections').length == 0) {
|
if ($(this).bootstrapTable('getSelections').length == 0) {
|
||||||
|
|
||||||
$(buttonName).attr('disabled', 'disabled');
|
$(buttonName).attr('disabled', 'disabled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -296,6 +296,10 @@
|
||||||
|
|
||||||
if ((row.available_actions) && (row.available_actions.update === true)) {
|
if ((row.available_actions) && (row.available_actions.update === true)) {
|
||||||
actions += '<a href="{{ config('app.url') }}/' + dest + '/' + row.id + '/edit" class="actions btn btn-sm btn-warning" data-tooltip="true" title="{{ trans('general.update') }}"><i class="fas fa-pencil-alt" aria-hidden="true"></i><span class="sr-only">{{ trans('general.update') }}</span></a> ';
|
actions += '<a href="{{ config('app.url') }}/' + dest + '/' + row.id + '/edit" class="actions btn btn-sm btn-warning" data-tooltip="true" title="{{ trans('general.update') }}"><i class="fas fa-pencil-alt" aria-hidden="true"></i><span class="sr-only">{{ trans('general.update') }}</span></a> ';
|
||||||
|
} else {
|
||||||
|
if ((row.available_actions) && (row.available_actions.update != true)) {
|
||||||
|
actions += '<span data-tooltip="true" title="{{ trans('general.cannot_be_edited') }}"><a class="btn btn-warning btn-sm disabled" onClick="return false;"><i class="fas fa-pencil-alt"></i></a></span> ';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((row.available_actions) && (row.available_actions.delete === true)) {
|
if ((row.available_actions) && (row.available_actions.delete === true)) {
|
||||||
|
@ -394,17 +398,35 @@
|
||||||
// Convert line breaks to <br>
|
// Convert line breaks to <br>
|
||||||
function notesFormatter(value) {
|
function notesFormatter(value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
return value.replace(/(?:\r\n|\r|\n)/g, '<br />');;
|
return value.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if checkbox should be selectable
|
||||||
|
// Selectability is determined by the API field "selectable" which is set at the Presenter/API Transformer
|
||||||
|
// However since different bulk actions have different requirements, we have to walk through the available_actions object
|
||||||
|
// to determine whether to disable it
|
||||||
|
function checkboxEnabledFormatter (value, row) {
|
||||||
|
|
||||||
|
// add some stuff to get the value of the select2 option here?
|
||||||
|
|
||||||
|
if ((row.available_actions) && (row.available_actions.bulk_selectable) && (row.available_actions.bulk_selectable.delete !== true)) {
|
||||||
|
console.log('value for ID ' + row.id + ' is NOT true:' + row.available_actions.bulk_selectable.delete);
|
||||||
|
return {
|
||||||
|
disabled:true,
|
||||||
|
//checked: false, <-- not sure this will work the way we want?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('value for ID ' + row.id + ' IS true:' + row.available_actions.bulk_selectable.delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// We need a special formatter for license seats, since they don't work exactly the same
|
// We need a special formatter for license seats, since they don't work exactly the same
|
||||||
// Checkouts need the license ID, checkins need the specific seat ID
|
// Checkouts need the license ID, checkins need the specific seat ID
|
||||||
|
|
||||||
function licenseSeatInOutFormatter(value, row) {
|
function licenseSeatInOutFormatter(value, row) {
|
||||||
// The user is allowed to check the license seat out and it's available
|
// The user is allowed to check the license seat out and it's available
|
||||||
if ((row.available_actions.checkout == true) && (row.user_can_checkout == true) && ((!row.asset_id) && (!row.assigned_to))) {
|
if ((row.available_actions.checkout === true) && (row.user_can_checkout === true) && ((!row.asset_id) && (!row.assigned_to))) {
|
||||||
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
|
return '<a href="{{ config('app.url') }}/licenses/' + row.license_id + '/checkout/'+row.id+'" class="btn btn-sm bg-maroon" data-tooltip="true" title="{{ trans('general.checkout_tooltip') }}">{{ trans('general.checkout') }}</a>';
|
||||||
} else {
|
} else {
|
||||||
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check in this license seat.">{{ trans('general.checkin') }}</a>';
|
return '<a href="{{ config('app.url') }}/licenses/' + row.id + '/checkin" class="btn btn-sm bg-purple" data-tooltip="true" title="Check in this license seat.">{{ trans('general.checkin') }}</a>';
|
||||||
|
@ -623,6 +645,9 @@
|
||||||
|
|
||||||
function assetTagLinkFormatter(value, row) {
|
function assetTagLinkFormatter(value, row) {
|
||||||
if ((row.asset) && (row.asset.id)) {
|
if ((row.asset) && (row.asset.id)) {
|
||||||
|
if (row.asset.deleted_at!='') {
|
||||||
|
return '<span style="white-space: nowrap;"><i class="fas fa-times text-danger"></i><span class="sr-only">deleted</span> <del><a href="{{ config('app.url') }}/hardware/' + row.asset.id + '" data-tooltip="true" title="{{ trans('admin/hardware/general.deleted') }}">' + row.asset.asset_tag + '</a></del></span>';
|
||||||
|
}
|
||||||
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.asset_tag + '</a>';
|
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.asset_tag + '</a>';
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
@ -640,7 +665,17 @@
|
||||||
if ((row.asset) && (row.asset.name)) {
|
if ((row.asset) && (row.asset.name)) {
|
||||||
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.name + '</a>';
|
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.name + '</a>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assetSerialLinkFormatter(value, row) {
|
||||||
|
|
||||||
|
if ((row.asset) && (row.asset.serial)) {
|
||||||
|
if (row.asset.deleted_at!='') {
|
||||||
|
return '<span style="white-space: nowrap;"><i class="fas fa-times text-danger"></i><span class="sr-only">deleted</span> <del><a href="{{ config('app.url') }}/hardware/' + row.asset.id + '" data-tooltip="true" title="{{ trans('admin/hardware/general.deleted') }}">' + row.asset.serial + '</a></del></span>';
|
||||||
|
}
|
||||||
|
return '<a href="{{ config('app.url') }}/hardware/' + row.asset.id + '">' + row.asset.serial + '</a>';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function trueFalseFormatter(value) {
|
function trueFalseFormatter(value) {
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
{!! $errors->first('image', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
{!! $errors->first('image', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 col-md-offset-3" aria-hidden="true">
|
<div class="col-md-4 col-md-offset-3" aria-hidden="true">
|
||||||
<img id="uploadFile-imagePreview" style="max-width: 300px; display: none;" alt="{{ trans('partials/forms/general.alt_uploaded_image_thumbnail') }}">
|
<img id="uploadFile-imagePreview" style="max-width: 300px; display: none;" alt="{{ trans('general.alt_uploaded_image_thumbnail') }}">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,10 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-9">
|
<div class="col-md-9">
|
||||||
<label class="btn btn-default">
|
<label class="btn btn-default{{ (config('app.lock_passwords')) ? ' disabled' : '' }}">
|
||||||
{{ trans('button.select_file') }}
|
{{ trans('button.select_file') }}
|
||||||
<input type="file" name="{{ $logoVariable }}" class="js-uploadFile" id="{{ $logoId }}" accept="image/gif,image/jpeg,image/webp,image/png,image/svg,image/svg+xml" data-maxsize="{{ $maxSize ?? Helper::file_upload_max_size() }}"
|
<input type="file" name="{{ $logoVariable }}" class="js-uploadFile" id="{{ $logoId }}" accept="{{ (isset($allowedTypes) ? $allowedTypes : "image/gif,image/jpeg,image/webp,image/png,image/svg,image/svg+xml") }}" data-maxsize="{{ $maxSize ?? Helper::file_upload_max_size() }}"
|
||||||
style="display:none; max-width: 90%">
|
style="display:none; max-width: 90%"{{ (config('app.lock_passwords')) ? ' disabled' : '' }}>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<span class='label label-default' id="{{ $logoId }}-info"></span>
|
<span class='label label-default' id="{{ $logoId }}-info"></span>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue