Compare commits
115 Commits
v4.0-beta
...
v4.0-beta6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aff104fa5d | ||
|
|
a5764351f7 | ||
|
|
348becbbec | ||
|
|
922d6937ae | ||
|
|
c53dae4b72 | ||
|
|
e7d72beb88 | ||
|
|
01e3f4a4db | ||
|
|
1b76880b0e | ||
|
|
6c283de60a | ||
|
|
4e7a6c0ccf | ||
|
|
eba145503b | ||
|
|
ae8c9d6afc | ||
|
|
faeca4139d | ||
|
|
47909b93f7 | ||
|
|
472658b2fe | ||
|
|
42a03a0436 | ||
|
|
ae0573b3da | ||
|
|
34f816097e | ||
|
|
c651c9f1ed | ||
|
|
7c390cee2c | ||
|
|
987536930c | ||
|
|
10f322198f | ||
|
|
761371509d | ||
|
|
3518ea7e7d | ||
|
|
c92eed2b3e | ||
|
|
0054ce3071 | ||
|
|
b0f74466bb | ||
|
|
b4a0484295 | ||
|
|
bb874012d9 | ||
|
|
bb8583eb14 | ||
|
|
8d2c229bc3 | ||
|
|
48e6208214 | ||
|
|
22233e3ba6 | ||
|
|
e439f15a64 | ||
|
|
42175782a5 | ||
|
|
c7a21e0e4d | ||
|
|
d98ffd94f9 | ||
|
|
6ad5da44f3 | ||
|
|
479f422e68 | ||
|
|
e10cdd57a5 | ||
|
|
bf157773c8 | ||
|
|
fba3949530 | ||
|
|
abc3dea8ac | ||
|
|
51d74ac06d | ||
|
|
af835d6efc | ||
|
|
a7a10455ae | ||
|
|
bd02b9ed62 | ||
|
|
16f57e16cb | ||
|
|
af6f208c43 | ||
|
|
52270fa4db | ||
|
|
bf3731d65c | ||
|
|
233ebf06ee | ||
|
|
e27f6a483d | ||
|
|
19670f9dd8 | ||
|
|
1448229cd2 | ||
|
|
4721cab928 | ||
|
|
08f3e78d26 | ||
|
|
62227ec27d | ||
|
|
10711245ba | ||
|
|
29a7c8577d | ||
|
|
dfb1ff81e6 | ||
|
|
021e723acf | ||
|
|
14c0c314aa | ||
|
|
d23ea70b08 | ||
|
|
1b047c768b | ||
|
|
e6323e0a1b | ||
|
|
73ce5f98bb | ||
|
|
a37cb616eb | ||
|
|
659d953f3f | ||
|
|
c1dcc22217 | ||
|
|
6a67426140 | ||
|
|
4ba474cf73 | ||
|
|
fb6caa35ff | ||
|
|
a5870c888e | ||
|
|
f35f8477d3 | ||
|
|
d0637d38f3 | ||
|
|
7141968d64 | ||
|
|
0f7b7d8e6a | ||
|
|
ca78b3ed7c | ||
|
|
2d2cae10b9 | ||
|
|
5e9331f5ae | ||
|
|
6e30fa6922 | ||
|
|
58b3f0519d | ||
|
|
f119c69698 | ||
|
|
57f4c986af | ||
|
|
2958630923 | ||
|
|
72dacda4f9 | ||
|
|
9c2b986bb0 | ||
|
|
06c5bce3c7 | ||
|
|
a0cbca85bf | ||
|
|
9bda62d295 | ||
|
|
1d7e243d0a | ||
|
|
63bc2ec09f | ||
|
|
d5cadeab1a | ||
|
|
31516abef9 | ||
|
|
d2535582f3 | ||
|
|
eaaea303f4 | ||
|
|
8c5312b931 | ||
|
|
4ef6e292d1 | ||
|
|
6310670835 | ||
|
|
15bb30acd6 | ||
|
|
148d41d8dc | ||
|
|
71c1c74164 | ||
|
|
9c02526a37 | ||
|
|
25dc26aac3 | ||
|
|
afc763ebac | ||
|
|
6a73ec6537 | ||
|
|
481143b891 | ||
|
|
cef67695cd | ||
|
|
4576cb6f56 | ||
|
|
56f88d2c22 | ||
|
|
c1d1cb8122 | ||
|
|
54279f22a3 | ||
|
|
dfea47a272 | ||
|
|
f0d78091d2 |
@@ -719,6 +719,24 @@
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "zwerch",
|
||||
"name": "Robin Temme",
|
||||
"avatar_url": "https://avatars2.githubusercontent.com/u/2809241?v=4",
|
||||
"profile": "https://github.com/zwerch",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "imanghafoori1",
|
||||
"name": "Iman",
|
||||
"avatar_url": "https://avatars0.githubusercontent.com/u/6961695?v=4",
|
||||
"profile": "https://github.com/imanghafoori1",
|
||||
"contributions": [
|
||||
"code"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ FILESYSTEM_DISK=local
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=localhost
|
||||
DB_DATABASE=snipeit_unit
|
||||
DB_USERNAME=travis
|
||||
DB_USERNAME=root
|
||||
DB_PASSWORD=null
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
@@ -6,6 +6,9 @@ sudo: false
|
||||
# see http://about.travis-ci.org/docs/user/languages/php/ for more hints
|
||||
language: php
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
||||
# list any PHP version you want to test against
|
||||
php:
|
||||
- 5.6
|
||||
@@ -15,7 +18,10 @@ php:
|
||||
before_script:
|
||||
- phantomjs --webdriver=4444 &
|
||||
- sleep 4
|
||||
- mysql -e "create database IF NOT EXISTS snipeit_unit;" -utravis
|
||||
- mysql -e 'CREATE DATABASE snipeit_unit;'
|
||||
- mysql -e 'CREATE USER "travis'@'localhost";'
|
||||
- mysql -e 'GRANT ALL PRIVILEGES ON * . * TO "travis'@'localhost";'
|
||||
- mysql -e 'FLUSH PRIVILEGES;'
|
||||
- composer self-update
|
||||
- composer install -n --prefer-source
|
||||
- chmod -R 777 storage
|
||||
|
||||
@@ -13,6 +13,7 @@ php7.0-gd \
|
||||
php7.0-xml \
|
||||
php7.0-mbstring \
|
||||
php7.0-zip \
|
||||
php7.0-bcmath \
|
||||
patch \
|
||||
curl \
|
||||
vim \
|
||||
@@ -23,6 +24,7 @@ mysql-client \
|
||||
|
||||
RUN phpenmod mcrypt
|
||||
RUN phpenmod gd
|
||||
RUN phpenmod bcmath
|
||||
|
||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.0/apache2/php.ini
|
||||
RUN sed -i 's/variables_order = .*/variables_order = "EGPCS"/' /etc/php/7.0/cli/php.ini
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[](https://travis-ci.org/snipe/snipe-it) [](http://waffle.io/snipe/snipe-it) []() [](https://crowdin.com/project/snipe-it) [](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeyhead) [](https://zenhub.io) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[](#contributors)
|
||||
[](https://travis-ci.org/snipe/snipe-it) [](http://waffle.io/snipe/snipe-it) []() [](https://crowdin.com/project/snipe-it) [](https://gitter.im/snipe/snipe-it?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [](https://hub.docker.com/r/snipe/snipe-it/) [](https://twitter.com/snipeyhead) [](https://zenhub.io) [](https://www.codacy.com/app/snipe/snipe-it?utm_source=github.com&utm_medium=referral&utm_content=snipe/snipe-it&utm_campaign=Badge_Grade)
|
||||
[](#contributors)
|
||||
|
||||
|
||||
## Snipe-IT - Open Source Asset Management System
|
||||
@@ -67,6 +67,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken
|
||||
| [<img src="https://avatars0.githubusercontent.com/u/8341172?v=3" width="110px;"/><br /><sub>Jay Richards</sub>](http://www.cordeos.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=technogenus "Code") | [<img src="https://avatars2.githubusercontent.com/u/7295127?v=3" width="110px;"/><br /><sub>Alexander Innes</sub>](https://necurity.co.uk)<br />[💻](https://github.com/snipe/snipe-it/commits?author=leostat "Code") | [<img src="https://avatars2.githubusercontent.com/u/334485?v=3" width="110px;"/><br /><sub>Danny Garcia</sub>](https://buzzedword.codes)<br />[💻](https://github.com/snipe/snipe-it/commits?author=buzzedword "Code") | [<img src="https://avatars2.githubusercontent.com/u/366855?v=3" width="110px;"/><br /><sub>archpoint</sub>](https://github.com/archpoint)<br />[💻](https://github.com/snipe/snipe-it/commits?author=archpoint "Code") | [<img src="https://avatars1.githubusercontent.com/u/67991?v=3" width="110px;"/><br /><sub>Jake McGraw</sub>](http://www.jakemcgraw.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jakemcgraw "Code") | [<img src="https://avatars1.githubusercontent.com/u/1714374?v=3" width="110px;"/><br /><sub>FleischKarussel</sub>](https://github.com/FleischKarussel)<br />[📖](https://github.com/snipe/snipe-it/commits?author=FleischKarussel "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/319644?v=3" width="110px;"/><br /><sub>Dylan Yi</sub>](https://github.com/feeva)<br />[💻](https://github.com/snipe/snipe-it/commits?author=feeva "Code") |
|
||||
| [<img src="https://avatars2.githubusercontent.com/u/857740?v=3" width="110px;"/><br /><sub>Gil Rutkowski</sub>](http://FlashingCursor.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=flashingcursor "Code") | [<img src="https://avatars3.githubusercontent.com/u/129360?v=3" width="110px;"/><br /><sub>Desmond Morris</sub>](http://www.desmondmorris.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=desmondmorris "Code") | [<img src="https://avatars2.githubusercontent.com/u/52936?v=3" width="110px;"/><br /><sub>Nick Peelman</sub>](http://peelman.us)<br />[💻](https://github.com/snipe/snipe-it/commits?author=peelman "Code") | [<img src="https://avatars0.githubusercontent.com/u/53161?v=3" width="110px;"/><br /><sub>Abraham Vegh</sub>](https://abrahamvegh.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=abrahamvegh "Code") | [<img src="https://avatars0.githubusercontent.com/u/2818680?v=3" width="110px;"/><br /><sub>Mohamed Rashid</sub>](https://github.com/rashivkp)<br />[📖](https://github.com/snipe/snipe-it/commits?author=rashivkp "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/1509456?v=3" width="110px;"/><br /><sub>Kasey</sub>](http://hinchk.github.io)<br />[💻](https://github.com/snipe/snipe-it/commits?author=HinchK "Code") | [<img src="https://avatars2.githubusercontent.com/u/10522541?v=3" width="110px;"/><br /><sub>Brett</sub>](https://github.com/BrettFagerlund)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=BrettFagerlund "Tests") |
|
||||
| [<img src="https://avatars2.githubusercontent.com/u/16108587?v=3" width="110px;"/><br /><sub>Jason Spriggs</sub>](http://jasonspriggs.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=jasonspriggs "Code") | [<img src="https://avatars2.githubusercontent.com/u/1134568?v=3" width="110px;"/><br /><sub>Nate Felton</sub>](http://n8felton.wordpress.com)<br />[💻](https://github.com/snipe/snipe-it/commits?author=n8felton "Code") | [<img src="https://avatars2.githubusercontent.com/u/14036694?v=3" width="110px;"/><br /><sub>Manasses Ferreira</sub>](http://homepages.dcc.ufmg.br/~manassesferreira)<br />[💻](https://github.com/snipe/snipe-it/commits?author=manassesferreira "Code") | [<img src="https://avatars0.githubusercontent.com/u/15913949?v=3" width="110px;"/><br /><sub>Steve</sub>](https://github.com/steveelwood)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=steveelwood "Tests") | [<img src="https://avatars1.githubusercontent.com/u/3361683?v=3" width="110px;"/><br /><sub>matc</sub>](http://twitter.com/matc)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=matc "Tests") | [<img src="https://avatars3.githubusercontent.com/u/7405702?v=3" width="110px;"/><br /><sub>Cole R. Davis</sub>](http://www.davisracingteam.com)<br />[⚠️](https://github.com/snipe/snipe-it/commits?author=VanillaNinjaD "Tests") | [<img src="https://avatars2.githubusercontent.com/u/10167681?v=3" width="110px;"/><br /><sub>gibsonjoshua55</sub>](https://github.com/gibsonjoshua55)<br />[💻](https://github.com/snipe/snipe-it/commits?author=gibsonjoshua55 "Code") |
|
||||
| [<img src="https://avatars2.githubusercontent.com/u/2809241?v=4" width="110px;"/><br /><sub>Robin Temme</sub>](https://github.com/zwerch)<br />[💻](https://github.com/snipe/snipe-it/commits?author=zwerch "Code") | [<img src="https://avatars0.githubusercontent.com/u/6961695?v=4" width="110px;"/><br /><sub>Iman</sub>](https://github.com/imanghafoori1)<br />[💻](https://github.com/snipe/snipe-it/commits?author=imanghafoori1 "Code") |
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
||||
|
||||
164
app/Console/Commands/RecryptFromMcrypt.php
Normal file
164
app/Console/Commands/RecryptFromMcrypt.php
Normal file
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\CustomField;
|
||||
use Illuminate\Console\Command;
|
||||
use App\LegacyEncrypter\McryptEncrypter;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class RecryptFromMcrypt extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'snipeit:legacy-recrypt';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'This command allows upgrading users to de-encrypt their deprecated mcrypt encrypted fields and re-encrypt them using the current OpenSSL encryption.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
|
||||
|
||||
// Check and see if they have a legacy app key listed in their .env
|
||||
// If not, we can try to use the current APP_KEY if looks like it's old
|
||||
$legacy_key = env('LEGACY_APP_KEY');
|
||||
$key_parts = explode(':', $legacy_key);
|
||||
$errors = array();
|
||||
|
||||
if (!$legacy_key) {
|
||||
$this->error('ERROR: You do not have a LEGACY_APP_KEY set in your .env file. Please locate your old APP_KEY and ADD a line to your .env file like: LEGACY_APP_KEY=YOUR_OLD_APP_KEY');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Do some basic legacy app key length checks
|
||||
if (strlen($legacy_key) == 32) {
|
||||
$legacy_length_check = true;
|
||||
} elseif (array_key_exists('1', $key_parts) && (strlen($key_parts[1])==44)) {
|
||||
$legacy_length_check = true;
|
||||
} else {
|
||||
$legacy_length_check = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Check that the app key is 32 characters
|
||||
if ($legacy_length_check === true) {
|
||||
$this->comment('INFO: Your LEGACY_APP_KEY looks correct. Okay to continue.');
|
||||
} else {
|
||||
$this->error('ERROR: Your LEGACY_APP_KEY is not the correct length (32 characters or base64 followed by 44 characters for later versions). Please locate your old APP_KEY and use that as your LEGACY_APP_KEY in your .env file to continue.');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->error('================================!!!! WARNING !!!!================================');
|
||||
$this->error('================================!!!! WARNING !!!!================================');
|
||||
$this->comment("This tool will attempt to decrypt your old Snipe-IT (mcrypt, now deprecated) encrypted data and re-encrypt it using OpenSSL. \n\nYou should only continue if you have backed up any and all old APP_KEYs and have backed up your data.");
|
||||
|
||||
if ($this->confirm("Are you SURE you wish to continue?")) {
|
||||
|
||||
$backup_file = 'backups/env-backups/'.'app_key-'.date('Y-m-d-gis');
|
||||
|
||||
try {
|
||||
Storage::disk('local')->put($backup_file, 'APP_KEY: '.config('app.key'));
|
||||
Storage::disk('local')->append($backup_file, 'LEGACY_APP_KEY: '.$legacy_key);
|
||||
} catch (\Exception $e) {
|
||||
$this->info('WARNING: Could not backup app keys');
|
||||
}
|
||||
|
||||
|
||||
$mcrypter = new McryptEncrypter($legacy_key);
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
if ($settings->ldap_password=='') {
|
||||
$this->comment('INFO: No LDAP password found. Skipping... ');
|
||||
}
|
||||
|
||||
$custom_fields = CustomField::where('field_encrypted','=', 1)->get();
|
||||
$this->comment('INFO: Retrieving encrypted custom fields...');
|
||||
|
||||
$query = Asset::withTrashed();
|
||||
|
||||
foreach ($custom_fields as $custom_field) {
|
||||
$this->comment('FIELD TO RECRYPT: '.$custom_field->name .' ('.$custom_field->db_column.')');
|
||||
$query->orWhereNotNull($custom_field->db_column);
|
||||
}
|
||||
|
||||
|
||||
// Get all assets with a value in any of the fields that were encrypted
|
||||
$assets = $query->get();
|
||||
|
||||
$bar = $this->output->createProgressBar(count($assets));
|
||||
|
||||
foreach ($custom_fields as $encrypted_field) {
|
||||
|
||||
// Try to decrypt the payload using the legacy app key
|
||||
try {
|
||||
$decrypted_field = $mcrypter->decrypt($encrypted_field);
|
||||
$this->comment($decrypted_field);
|
||||
} catch (\Exception $e) {
|
||||
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
|
||||
}
|
||||
$bar->advance();
|
||||
}
|
||||
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
foreach ($custom_fields as $encrypted_field) {
|
||||
|
||||
// Make sure the value isn't null
|
||||
if ($asset->{$encrypted_field}!='') {
|
||||
// Try to decrypt the payload using the legacy app key
|
||||
try {
|
||||
$decrypted_field = $mcrypter->decrypt($asset->{$encrypted_field});
|
||||
$asset->{$encrypted_field} = \Crypt::encrypt($decrypted_field);
|
||||
$this->comment($decrypted_field);
|
||||
} catch (\Exception $e) {
|
||||
$errors[] = ' - ERROR: Could not decrypt field ['.$encrypted_field->name.']: '.$e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
$asset->save();
|
||||
$bar->advance();
|
||||
}
|
||||
|
||||
|
||||
|
||||
$bar->finish();
|
||||
|
||||
if (count($errors) > 0) {
|
||||
$this->comment("\n\n");
|
||||
$this->error("The decrypter encountered some errors: \n");
|
||||
foreach ($errors as $error) {
|
||||
$this->error($error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
64
app/Console/Commands/SendExpectedCheckinAlerts.php
Normal file
64
app/Console/Commands/SendExpectedCheckinAlerts.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Console\Command;
|
||||
use App\Notifications\ExpectedCheckinNotification;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SendExpectedCheckinAlerts extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* The console command name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name = 'snipeit:expected-checkin';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Check for overdue or upcoming expected checkins.';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function fire()
|
||||
{
|
||||
|
||||
$whenNotify = Carbon::now()->addDays(7);
|
||||
$assets = Asset::with('assignedTo')->whereNotNull('expected_checkin')->where('expected_checkin', '<=', $whenNotify)->get();
|
||||
|
||||
$this->info($whenNotify.' is deadline');
|
||||
$this->info($assets->count().' assets');
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
if ($asset->assignedTo && $asset->checkoutOutToUser()) {
|
||||
$asset->assignedTo->notify((new ExpectedCheckinNotification($asset)));
|
||||
//$this->info($asset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,15 @@ class Kernel extends ConsoleKernel
|
||||
Commands\CreateAdmin::class,
|
||||
Commands\SendExpirationAlerts::class,
|
||||
Commands\SendInventoryAlerts::class,
|
||||
Commands\SendExpectedCheckinAlerts::class,
|
||||
Commands\ObjectImportCommand::class,
|
||||
Commands\Versioning::class,
|
||||
Commands\SystemBackup::class,
|
||||
Commands\DisableLDAP::class,
|
||||
Commands\Purge::class,
|
||||
Commands\LdapSync::class,
|
||||
Commands\FixDoubleEscape::class
|
||||
Commands\FixDoubleEscape::class,
|
||||
Commands\RecryptFromMcrypt::class
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -37,6 +39,7 @@ class Kernel extends ConsoleKernel
|
||||
|
||||
$schedule->command('snipeit:inventory-alerts')->daily();
|
||||
$schedule->command('snipeit:expiring-alerts')->daily();
|
||||
$schedule->command('snipeit:expected-checkins')->daily();
|
||||
$schedule->command('snipeit:backup')->weekly();
|
||||
$schedule->command('backup:clean')->daily();
|
||||
}
|
||||
|
||||
12
app/Exceptions/CheckoutNotAllowed.php
Normal file
12
app/Exceptions/CheckoutNotAllowed.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
class CheckoutNotAllowed extends Exception
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
"A checkout is not allowed under these circumstances";
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class Handler extends ExceptionHandler
|
||||
|
||||
}
|
||||
}
|
||||
// Try to parse 500 Errors ina bit nicer way when debug is enabled.
|
||||
// Try to parse 500 Errors in a bit nicer way when debug is enabled.
|
||||
if (config('app.debug')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, "An Error has occured! " . $e->getMessage()), 500);
|
||||
}
|
||||
|
||||
@@ -683,12 +683,11 @@ class Helper
|
||||
public static function formatStandardApiResponse($status, $payload = null, $messages = null) {
|
||||
|
||||
$array['status'] = $status;
|
||||
($payload) ? $array['payload'] = $payload : '';
|
||||
|
||||
$array['messages'] = $messages;
|
||||
if (($messages) && (count($messages) > 0)) {
|
||||
$array['messages'] = $messages;
|
||||
}
|
||||
|
||||
($payload) ? $array['payload'] = $payload : $array['payload'] = null;
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ class AccessoriesController extends Controller
|
||||
'assigned_to' => $request->get('assigned_to')
|
||||
]);
|
||||
|
||||
$logaction = $accessory->logCheckout(e(Input::get('note')));
|
||||
$logaction = $accessory->logCheckout(e(Input::get('note')), $user);
|
||||
|
||||
DB::table('accessories_users')->where('assigned_to', '=', $accessory->assigned_to)->where('accessory_id', '=', $accessory->id)->first();
|
||||
|
||||
|
||||
227
app/Http/Controllers/Api/AssetMaintenancesController.php
Normal file
227
app/Http/Controllers/Api/AssetMaintenancesController.php
Normal file
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Transformers\AssetMaintenancesTransformer;
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetMaintenance;
|
||||
use App\Models\Company;
|
||||
use Auth;
|
||||
use Carbon\Carbon;
|
||||
use Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Input;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Asset Maintenance for
|
||||
* the Snipe-IT Asset Management application.
|
||||
*
|
||||
* @version v2.0
|
||||
*/
|
||||
class AssetMaintenancesController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Generates the JSON response for asset maintenances listing view.
|
||||
*
|
||||
* @see AssetMaintenancesController::getIndex() method that generates view
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
* @return String JSON
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$maintenances = AssetMaintenance::with('asset', 'supplier', 'asset.company', 'admin');
|
||||
|
||||
if (Input::has('search')) {
|
||||
$maintenances = $maintenances->TextSearch(e($request->input('search')));
|
||||
}
|
||||
|
||||
$offset = request('offset', 0);
|
||||
$limit = request('limit', 50);
|
||||
|
||||
$allowed_columns = ['id','title','asset_maintenance_time','asset_maintenance_type','cost','start_date','completion_date','notes','user_id'];
|
||||
$order = Input::get('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array(Input::get('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
|
||||
switch ($sort) {
|
||||
case 'user_id':
|
||||
$maintenances = $maintenances->OrderAdmin($order);
|
||||
break;
|
||||
default:
|
||||
$maintenances = $maintenances->orderBy($sort, $order);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$maintenances = $maintenances->skip($offset)->take($limit)->get();
|
||||
|
||||
|
||||
return (new AssetMaintenancesTransformer())->transformAssetMaintenances($maintenances, $maintenances->count());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates and stores the new asset maintenance
|
||||
*
|
||||
* @see AssetMaintenancesController::getCreate() method for the form
|
||||
* @author Vincent Sposato <vincent.sposato@gmail.com>
|
||||
* @version v1.0
|
||||
* @since [v1.8]
|
||||
* @return String JSON
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
// create a new model instance
|
||||
$assetMaintenance = new AssetMaintenance();
|
||||
$assetMaintenance->supplier_id = $request->input('supplier_id');
|
||||
$assetMaintenance->is_warranty = $request->input('is_warranty');
|
||||
$assetMaintenance->cost = e($request->input('cost'));
|
||||
$assetMaintenance->notes = e($request->input('notes'));
|
||||
$asset = Asset::find(e($request->input('asset_id')));
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot add a maintenance for that asset'));
|
||||
}
|
||||
|
||||
// Save the asset maintenance data
|
||||
$assetMaintenance->asset_id = $request->input('asset_id');
|
||||
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||
$assetMaintenance->title = $request->input('title');
|
||||
$assetMaintenance->start_date = $request->input('start_date');
|
||||
$assetMaintenance->completion_date = $request->input('completion_date');
|
||||
$assetMaintenance->user_id = Auth::id();
|
||||
|
||||
if (( $assetMaintenance->completion_date !== null )
|
||||
&& ( $assetMaintenance->start_date !== "" )
|
||||
&& ( $assetMaintenance->start_date !== "0000-00-00" )
|
||||
) {
|
||||
$startDate = Carbon::parse($assetMaintenance->start_date);
|
||||
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
||||
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
|
||||
}
|
||||
|
||||
// Was the asset maintenance created?
|
||||
if ($assetMaintenance->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.create.success')));
|
||||
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates and stores an update to an asset maintenance
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @param int $assetMaintenanceId
|
||||
* @param int $request
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
* @return String JSON
|
||||
*/
|
||||
public function update(Request $request, $assetMaintenanceId = null)
|
||||
{
|
||||
// Check if the asset maintenance exists
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset'));
|
||||
}
|
||||
|
||||
$assetMaintenance->supplier_id = e($request->input('supplier_id'));
|
||||
$assetMaintenance->is_warranty = e($request->input('is_warranty'));
|
||||
$assetMaintenance->cost = Helper::ParseFloat(e($request->input('cost')));
|
||||
$assetMaintenance->notes = e($request->input('notes'));
|
||||
|
||||
$asset = Asset::find(request('asset_id'));
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot edit a maintenance for that asset'));
|
||||
}
|
||||
|
||||
// Save the asset maintenance data
|
||||
$assetMaintenance->asset_id = $request->input('asset_id');
|
||||
$assetMaintenance->asset_maintenance_type = $request->input('asset_maintenance_type');
|
||||
$assetMaintenance->title = $request->input('title');
|
||||
$assetMaintenance->start_date = $request->input('start_date');
|
||||
$assetMaintenance->completion_date = $request->input('completion_date');
|
||||
|
||||
if (( $assetMaintenance->completion_date == null )
|
||||
) {
|
||||
if (( $assetMaintenance->asset_maintenance_time !== 0 )
|
||||
|| ( !is_null($assetMaintenance->asset_maintenance_time) )
|
||||
) {
|
||||
$assetMaintenance->asset_maintenance_time = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (( $assetMaintenance->completion_date !== null )
|
||||
&& ( $assetMaintenance->start_date !== "" )
|
||||
&& ( $assetMaintenance->start_date !== "0000-00-00" )
|
||||
) {
|
||||
$startDate = Carbon::parse($assetMaintenance->start_date);
|
||||
$completionDate = Carbon::parse($assetMaintenance->completion_date);
|
||||
$assetMaintenance->asset_maintenance_time = $completionDate->diffInDays($startDate);
|
||||
}
|
||||
|
||||
// Was the asset maintenance created?
|
||||
if ($assetMaintenance->save()) {
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.edit.success')));
|
||||
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetMaintenance->getErrors()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an asset maintenance
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
* @return String JSON
|
||||
*/
|
||||
public function destroy($assetMaintenanceId)
|
||||
{
|
||||
// Check if the asset maintenance exists
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot delete a maintenance for that asset'));
|
||||
}
|
||||
|
||||
$assetMaintenance->delete();
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $assetMaintenance, trans('admin/asset_maintenances/message.delete.success')));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* View an asset maintenance
|
||||
*
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @param int $assetMaintenanceId
|
||||
* @version v1.0
|
||||
* @since [v4.0]
|
||||
* @return String JSON
|
||||
*/
|
||||
public function show($assetMaintenanceId)
|
||||
{
|
||||
$assetMaintenance = AssetMaintenance::findOrFail($assetMaintenanceId);
|
||||
if (!Company::isCurrentUserHasAccess($assetMaintenance->asset)) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'You cannot view a maintenance for that asset'));
|
||||
}
|
||||
return (new AssetMaintenancesTransformer())->transformAssetMaintenance($assetMaintenance);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ class AssetModelsController extends Controller
|
||||
$assetmodel->fill($request->all());
|
||||
|
||||
if ($assetmodel->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/assetmodels/message.create.success')));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $assetmodel, trans('admin/models/message.create.success')));
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $assetmodel->getErrors()));
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ use TCPDF;
|
||||
use Validator;
|
||||
use View;
|
||||
|
||||
|
||||
/**
|
||||
* This class controls all actions related to assets for
|
||||
* the Snipe-IT Asset Management application.
|
||||
@@ -83,9 +84,8 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
$assets = Company::scopeCompanyables(Asset::select('assets.*'))->with(
|
||||
'assetLoc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset', 'assigneduser','supplier');
|
||||
|
||||
'assetloc', 'assetstatus', 'defaultLoc', 'assetlog', 'company',
|
||||
'model.category', 'model.manufacturer', 'model.fieldset','supplier');
|
||||
// If we should search on everything
|
||||
if (($request->has('search')) && (count($filter) == 0)) {
|
||||
$assets->TextSearch($request->input('search'));
|
||||
@@ -96,7 +96,6 @@ class AssetsController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// These are used by the API to query against specific ID numbers
|
||||
if ($request->has('status_id')) {
|
||||
$assets->where('status_id', '=', $request->input('status_id'));
|
||||
@@ -231,7 +230,8 @@ class AssetsController extends Controller
|
||||
*/
|
||||
public function store(AssetRequest $request)
|
||||
{
|
||||
// $this->authorize('create', Asset::class);
|
||||
|
||||
$this->authorize('create', Asset::class);
|
||||
|
||||
$asset = new Asset();
|
||||
$asset->model()->associate(AssetModel::find((int) $request->get('model_id')));
|
||||
@@ -279,6 +279,7 @@ class AssetsController extends Controller
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $asset, trans('admin/hardware/message.create.success')));
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $asset->getErrors()), 200);
|
||||
}
|
||||
|
||||
@@ -493,5 +494,52 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('success', ['asset'=> e($asset->asset_tag)], trans('admin/hardware/message.checkin.error')));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark an asset as audited
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @param int $id
|
||||
* @since [v4.0]
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function audit(Request $request) {
|
||||
|
||||
|
||||
$this->authorize('audit', Asset::class);
|
||||
$rules = array(
|
||||
'asset_tag' => 'required',
|
||||
'location_id' => 'exists:locations,id|nullable|numeric',
|
||||
'next_audit_date' => 'date|nullable'
|
||||
);
|
||||
|
||||
$validator = Validator::make($request->all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
||||
}
|
||||
|
||||
$asset = Asset::where('asset_tag','=', $request->input('asset_tag'))->first();
|
||||
|
||||
|
||||
if ($asset) {
|
||||
$asset->next_audit_date = $request->input('next_audit_date');
|
||||
if ($asset->save()) {
|
||||
$log = $asset->logAudit(request('note'),request('location_id'));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', [
|
||||
'asset_tag'=> e($asset->asset_tag),
|
||||
'note'=> e($request->input('note')),
|
||||
'next_audit_date' => Helper::getFormattedDateObject($log->calcNextAuditDate())
|
||||
], trans('admin/hardware/message.audit.success')));
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json(Helper::formatStandardApiResponse('error', ['asset_tag'=> e($request->input('asset_tag'))], 'Asset with tag '.$request->input('asset_tag').' not found'));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class CategoriesController extends Controller
|
||||
$this->authorize('view', Category::class);
|
||||
$allowed_columns = ['id', 'name','category_type','use_default_eula','require_acceptance','checkin_email'];
|
||||
|
||||
$categories = Category::select(['id', 'name','category_type','use_default_eula','require_acceptance','checkin_email'])
|
||||
$categories = Category::select(['id', 'created_at', 'updated_at', 'name','category_type','use_default_eula','require_acceptance','checkin_email'])
|
||||
->withCount('assets', 'accessories', 'consumables', 'components');
|
||||
|
||||
if ($request->has('search')) {
|
||||
@@ -75,7 +75,8 @@ class CategoriesController extends Controller
|
||||
{
|
||||
$this->authorize('view', Category::class);
|
||||
$category = Category::findOrFail($id);
|
||||
return $category;
|
||||
return (new CategoriesTransformer)->transformCategory($category);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -148,4 +148,47 @@ class ConsumablesController extends Controller
|
||||
$consumable->delete();
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/consumables/message.delete.success')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JSON response containing details on the users associated with this consumable.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see ConsumablesController::getView() method that returns the form.
|
||||
* @since [v1.0]
|
||||
* @param int $consumableId
|
||||
* @return array
|
||||
*/
|
||||
public function getDataView($consumableId)
|
||||
{
|
||||
//$consumable = Consumable::find($consumableID);
|
||||
$consumable = Consumable::with(array('consumableAssignments'=>
|
||||
function ($query) {
|
||||
$query->orderBy('created_at', 'DESC');
|
||||
},
|
||||
'consumableAssignments.admin'=> function ($query) {
|
||||
},
|
||||
'consumableAssignments.user'=> function ($query) {
|
||||
},
|
||||
))->find($consumableId);
|
||||
|
||||
// $consumable->load('consumableAssignments.admin','consumableAssignments.user');
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($consumable)) {
|
||||
return ['total' => 0, 'rows' => []];
|
||||
}
|
||||
$this->authorize('view', Component::class);
|
||||
$rows = array();
|
||||
|
||||
foreach ($consumable->consumableAssignments as $consumable_assignment) {
|
||||
$rows[] = [
|
||||
'name' => $consumable_assignment->user->present()->nameUrl(),
|
||||
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
|
||||
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : '',
|
||||
];
|
||||
}
|
||||
|
||||
$consumableCount = $consumable->users->count();
|
||||
$data = array('total' => $consumableCount, 'rows' => $rows);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Transformers\CustomFieldsTransformer;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\CustomFieldset;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CustomFieldsController extends Controller
|
||||
{
|
||||
@@ -16,6 +18,15 @@ class CustomFieldsController extends Controller
|
||||
* @since [v3.0]
|
||||
* @return Array
|
||||
*/
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->authorize('index', CustomFields::class);
|
||||
$fields = CustomField::get();
|
||||
|
||||
$total = count($fields);
|
||||
return (new CustomFieldsTransformer)->transformCustomFields($fields, $total);
|
||||
}
|
||||
public function postReorder(Request $request, $id)
|
||||
{
|
||||
$fieldset = CustomFieldset::find($id);
|
||||
|
||||
@@ -99,16 +99,14 @@ class DepartmentsController extends Controller
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
if (is_null($department = Department::find($id))) {
|
||||
return redirect()->to(route('departments.index'))->with('error', trans('admin/departments/message.not_found'));
|
||||
}
|
||||
$department = Department::findOrFail($id);
|
||||
|
||||
if ($department->users->count() > 0) {
|
||||
return redirect()->to(route('departments.index'))->with('error', trans('admin/departments/message.assoc_users'));
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/departments/message.assoc_users')));
|
||||
}
|
||||
|
||||
$department->delete();
|
||||
return redirect()->to(route('departments.index'))->with('success', trans('admin/departments/message.delete.success'));
|
||||
return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/departments/message.delete.success')));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class LicensesController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->authorize('view', License::class);
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer'));
|
||||
$licenses = Company::scopeCompanyables(License::with('company', 'licenseSeatsRelation', 'manufacturer', 'supplier'));
|
||||
|
||||
if ($request->has('search')) {
|
||||
$licenses = $licenses->TextSearch($request->input('search'));
|
||||
@@ -59,6 +59,10 @@ class LicensesController extends Controller
|
||||
$licenses->where('manufacturer_id','=',$request->input('manufacturer_id'));
|
||||
}
|
||||
|
||||
if ($request->has('supplier_id')) {
|
||||
$licenses->where('supplier_id','=',$request->input('supplier_id'));
|
||||
}
|
||||
|
||||
if ($request->has('depreciation_id')) {
|
||||
$licenses->where('depreciation_id','=',$request->input('depreciation_id'));
|
||||
}
|
||||
@@ -69,22 +73,26 @@ class LicensesController extends Controller
|
||||
|
||||
$offset = request('offset', 0);
|
||||
$limit = request('limit', 50);
|
||||
|
||||
$allowed_columns = ['id','name','purchase_cost','expiration_date','purchase_order','order_number','notes','purchase_date','serial','manufacturer','company','license_name','license_email'];
|
||||
$order = $request->input('order') === 'asc' ? 'asc' : 'desc';
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
|
||||
switch ($sort) {
|
||||
|
||||
switch ($request->input('sort')) {
|
||||
case 'manufacturer':
|
||||
$licenses = $licenses->OrderManufacturer($order);
|
||||
break;
|
||||
case 'supplier':
|
||||
$licenses = $licenses->OrderSupplier($order);
|
||||
break;
|
||||
case 'company':
|
||||
$licenses = $licenses->OrderCompany($order);
|
||||
break;
|
||||
default:
|
||||
$allowed_columns = ['id','name','purchase_cost','expiration_date','purchase_order','order_number','notes','purchase_date','serial','company','license_name','license_email'];
|
||||
$sort = in_array($request->input('sort'), $allowed_columns) ? e($request->input('sort')) : 'created_at';
|
||||
$licenses = $licenses->orderBy($sort, $order);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
$total = $licenses->count();
|
||||
$licenses = $licenses->skip($offset)->take($limit)->get();
|
||||
|
||||
@@ -21,7 +21,7 @@ class LocationsController extends Controller
|
||||
{
|
||||
$this->authorize('view', Location::class);
|
||||
$allowed_columns = ['id','name','address','address2','city','state','country','zip','created_at',
|
||||
'updated_at','parent_id'];
|
||||
'updated_at','parent_id', 'manager_id'];
|
||||
|
||||
$locations = Location::select([
|
||||
'locations.id',
|
||||
@@ -33,6 +33,7 @@ class LocationsController extends Controller
|
||||
'locations.zip',
|
||||
'locations.country',
|
||||
'locations.parent_id',
|
||||
'locations.manager_id',
|
||||
'locations.created_at',
|
||||
'locations.updated_at',
|
||||
'locations.currency'
|
||||
|
||||
@@ -19,7 +19,7 @@ class ReportsController extends Controller
|
||||
public function index(Request $request)
|
||||
{
|
||||
|
||||
$actionlogs = Actionlog::with('item', 'user', 'target');
|
||||
$actionlogs = Actionlog::with('item', 'user', 'target','location');
|
||||
|
||||
if ($request->has('search')) {
|
||||
$actionlogs = $actionlogs->TextSearch(e($request->input('search')));
|
||||
@@ -36,6 +36,10 @@ class ReportsController extends Controller
|
||||
->where('item_type','=',"App\\Models\\".ucwords($request->input('item_type')));
|
||||
}
|
||||
|
||||
if ($request->has('action_type')) {
|
||||
$actionlogs = $actionlogs->where('action_type','=',$request->input('action_type'))->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
$allowed_columns = [
|
||||
'id',
|
||||
'created_at'
|
||||
|
||||
@@ -53,9 +53,20 @@ class StatuslabelsController extends Controller
|
||||
public function store(Request $request)
|
||||
{
|
||||
$this->authorize('create', Statuslabel::class);
|
||||
$request->except('deployable', 'pending','archived');
|
||||
|
||||
if (!$request->has('type')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, ["type" => ["Status label type is required."]]));
|
||||
}
|
||||
|
||||
$statuslabel = new Statuslabel;
|
||||
$statuslabel->fill($request->all());
|
||||
|
||||
$statusType = Statuslabel::getStatuslabelTypesForDB($request->input('type'));
|
||||
$statuslabel->deployable = $statusType['deployable'];
|
||||
$statuslabel->pending = $statusType['pending'];
|
||||
$statuslabel->archived = $statusType['archived'];
|
||||
|
||||
if ($statuslabel->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.create.success')));
|
||||
}
|
||||
@@ -75,7 +86,7 @@ class StatuslabelsController extends Controller
|
||||
{
|
||||
$this->authorize('view', Statuslabel::class);
|
||||
$statuslabel = Statuslabel::findOrFail($id);
|
||||
return $statuslabel;
|
||||
return (new StatuslabelsTransformer)->transformStatuslabel($statuslabel);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,8 +103,20 @@ class StatuslabelsController extends Controller
|
||||
{
|
||||
$this->authorize('edit', Statuslabel::class);
|
||||
$statuslabel = Statuslabel::findOrFail($id);
|
||||
|
||||
$request->except('deployable', 'pending','archived');
|
||||
|
||||
if (!$request->has('type')) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, 'Status label type is required.'));
|
||||
}
|
||||
|
||||
$statuslabel->fill($request->all());
|
||||
|
||||
$statusType = Statuslabel::getStatuslabelTypesForDB($request->input('type'));
|
||||
$statuslabel->deployable = $statusType['deployable'];
|
||||
$statuslabel->pending = $statusType['pending'];
|
||||
$statuslabel->archived = $statusType['archived'];
|
||||
|
||||
if ($statuslabel->save()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('success', $statuslabel, trans('admin/statuslabels/message.update.success')));
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ use App\Http\Transformers\UsersTransformer;
|
||||
use App\Models\Company;
|
||||
use App\Models\User;
|
||||
use App\Helpers\Helper;
|
||||
use App\Http\Requests\SaveUserRequest;
|
||||
use App\Models\Asset;
|
||||
|
||||
class UsersController extends Controller
|
||||
{
|
||||
@@ -50,6 +52,12 @@ class UsersController extends Controller
|
||||
$users = $users->TextSearch($request->input('search'));
|
||||
}
|
||||
|
||||
|
||||
if (($request->has('deleted')) && ($request->input('deleted')=='true')) {
|
||||
$users = $users->GetDeleted();
|
||||
}
|
||||
|
||||
|
||||
if ($request->has('company_id')) {
|
||||
$users = $users->where('company_id', '=', $request->input('company_id'));
|
||||
}
|
||||
@@ -102,7 +110,7 @@ class UsersController extends Controller
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
public function store(SaveUserRequest $request)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$user = new User;
|
||||
@@ -139,7 +147,7 @@ class UsersController extends Controller
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
public function update(SaveUserRequest $request, $id)
|
||||
{
|
||||
$this->authorize('edit', User::class);
|
||||
$user = User::findOrFail($id);
|
||||
@@ -181,4 +189,19 @@ class UsersController extends Controller
|
||||
}
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/users/message.error.delete')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of assets assigned to a user.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @param $userId
|
||||
* @return string JSON
|
||||
*/
|
||||
public function assets($id)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$assets = Asset::where('assigned_to', '=', $id)->with('model')->get();
|
||||
return response()->json($assets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +414,7 @@ class AssetModelsController extends Controller
|
||||
$manufacturer_list = $nochange + Helper::manufacturerList();
|
||||
|
||||
|
||||
return view('models/bulk-edit', compact('models'))
|
||||
return view('models/bulk-edit', compact('models'))
|
||||
->with('manufacturer_list', $manufacturer_list)
|
||||
->with('category_list', $category_list)
|
||||
->with('fieldset_list', $fieldset_list)
|
||||
|
||||
@@ -116,9 +116,9 @@ class AssetsController extends Controller
|
||||
->with('statuslabel_list', Helper::statusLabelList())
|
||||
->with('location_list', Helper::locationsList())
|
||||
->with('item', new Asset)
|
||||
->with('manufacturer', Helper::manufacturerList())
|
||||
->with('category', Helper::categoryList('asset'))
|
||||
->with('statuslabel_types', Helper::statusTypeList())
|
||||
->with('manufacturer', Helper::manufacturerList()) //handled in modal now?
|
||||
->with('category', Helper::categoryList('asset')) //handled in modal now?
|
||||
->with('statuslabel_types', Helper::statusTypeList()) //handled in modal now?
|
||||
->with('users_list', Helper::usersList())
|
||||
->with('assets_list', Helper::assetsList())
|
||||
->with('locations_list', Helper::locationsList());
|
||||
@@ -537,17 +537,18 @@ class AssetsController extends Controller
|
||||
$this->authorize('checkin', $asset);
|
||||
|
||||
$admin = Auth::user();
|
||||
$user = $asset->assignedUser;
|
||||
if($asset->assignedType() == Asset::USER) {
|
||||
$user = $asset->assignedTo;
|
||||
}
|
||||
if (is_null($target = $asset->assignedTo)) {
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.checkin.already_checked_in'));
|
||||
}
|
||||
|
||||
// This is just used for the redirect
|
||||
$return_to = $asset->assigned_to;
|
||||
$asset->expected_checkin = null;
|
||||
$asset->last_checkout = null;
|
||||
$asset->assigned_to = null;
|
||||
$asset->assignedTo()->disassociate($asset);
|
||||
$asset->assigned_type = null;
|
||||
$asset->accepted = null;
|
||||
$asset->name = e(Input::get('name'));
|
||||
|
||||
@@ -566,7 +567,7 @@ class AssetsController extends Controller
|
||||
$data['item_serial'] = $asset->serial;
|
||||
$data['note'] = $logaction->note;
|
||||
|
||||
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!config('app.lock_passwords'))) {
|
||||
if ((($asset->checkin_email()=='1')) && (isset($user)) && (!empty($user->email)) && (!config('app.lock_passwords'))) {
|
||||
Mail::send('emails.checkin-asset', $data, function ($m) use ($user) {
|
||||
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
|
||||
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
|
||||
@@ -575,7 +576,7 @@ class AssetsController extends Controller
|
||||
}
|
||||
|
||||
if ($backto=='user') {
|
||||
return redirect()->to("admin/users/".$return_to.'/view')->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
return redirect()->to("admin/users/".$user->id.'/view')->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
}
|
||||
return redirect()->route("hardware.index")->with('success', trans('admin/hardware/message.checkin.success'));
|
||||
}
|
||||
@@ -595,9 +596,12 @@ class AssetsController extends Controller
|
||||
*/
|
||||
public function show($assetId = null)
|
||||
{
|
||||
|
||||
$asset = Asset::withTrashed()->find($assetId);
|
||||
$settings = Setting::getSettings();
|
||||
$this->authorize('view', $asset);
|
||||
$settings = Setting::getSettings();
|
||||
$audit_log = Actionlog::where('action_type','=','audit')->where('item_id','=',$assetId)->where('item_type','=',Asset::class)->orderBy('created_at','DESC')->first();
|
||||
|
||||
|
||||
if (isset($asset)) {
|
||||
|
||||
@@ -617,7 +621,8 @@ class AssetsController extends Controller
|
||||
'url' => route('qr_code/hardware', $asset->id)
|
||||
);
|
||||
|
||||
return view('hardware/view', compact('asset', 'qr_code', 'settings'))->with('use_currency', $use_currency);
|
||||
return view('hardware/view', compact('asset', 'qr_code', 'settings'))
|
||||
->with('use_currency', $use_currency)->with('audit_log',$audit_log);
|
||||
}
|
||||
|
||||
return redirect()->route('hardware.index')->with('error', trans('admin/hardware/message.does_not_exist', compact('id')));
|
||||
@@ -953,7 +958,7 @@ class AssetsController extends Controller
|
||||
* @since [v1.0]
|
||||
* @return View
|
||||
*/
|
||||
public function getDeleteFile($assetId = null, $fileId = null)
|
||||
public function deleteFile($assetId = null, $fileId = null)
|
||||
{
|
||||
$asset = Asset::find($assetId);
|
||||
$this->authorize('update', $asset);
|
||||
@@ -1233,4 +1238,47 @@ class AssetsController extends Controller
|
||||
// Redirect to the asset management page with error
|
||||
return redirect()->to("hardware/bulk-checkout")->with('error', trans('admin/hardware/message.checkout.error'))->withErrors($errors);
|
||||
}
|
||||
|
||||
|
||||
public function quickScan(Request $request)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
$dt = Carbon::now()->addMonths(12)->toDateString();
|
||||
return view('hardware/quickscan')->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList());
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function audit(Request $request, $id)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
$dt = Carbon::now()->addMonths(12)->toDateString();
|
||||
$asset = Asset::findOrFail($id);
|
||||
return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list', Helper::locationsList());
|
||||
}
|
||||
|
||||
public function auditStore(Request $request, $id)
|
||||
{
|
||||
$this->authorize('audit', Asset::class);
|
||||
|
||||
$rules = array(
|
||||
'location_id' => 'exists:locations,id|nullable|numeric',
|
||||
'next_audit_date' => 'date|nullable'
|
||||
);
|
||||
|
||||
$validator = \Validator::make($request->all(), $rules);
|
||||
if ($validator->fails()) {
|
||||
return response()->json(Helper::formatStandardApiResponse('error', null, $validator->errors()->all()));
|
||||
}
|
||||
|
||||
$asset = Asset::findOrFail($id);
|
||||
$asset->next_audit_date = $request->input('next_audit_date');
|
||||
|
||||
if ($asset->save()) {
|
||||
$asset->logAudit(request('note'),request('location_id'));
|
||||
return redirect()->to("hardware")->with('success', trans('admin/hardware/message.audit.success'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ class ComponentsController extends Controller
|
||||
'asset_id' => $asset_id
|
||||
]);
|
||||
|
||||
$component->logCheckout(e(Input::get('note')), $asset_id);
|
||||
$component->logCheckout(e(Input::get('note')), $asset);
|
||||
return redirect()->route('components.index')->with('success', trans('admin/components/message.checkout.success'));
|
||||
}
|
||||
|
||||
|
||||
@@ -250,7 +250,7 @@ class ConsumablesController extends Controller
|
||||
'assigned_to' => e(Input::get('assigned_to'))
|
||||
]);
|
||||
|
||||
$logaction = $consumable->logCheckout(e(Input::get('note')));
|
||||
$logaction = $consumable->logCheckout(e(Input::get('note')), $user);
|
||||
$data['log_id'] = $logaction->id;
|
||||
$data['eula'] = $consumable->getEula();
|
||||
$data['first_name'] = $user->first_name;
|
||||
@@ -273,47 +273,4 @@ class ConsumablesController extends Controller
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a JSON response containing details on the users associated with this consumable.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see ConsumablesController::getView() method that returns the form.
|
||||
* @since [v1.0]
|
||||
* @param int $consumableId
|
||||
* @return array
|
||||
*/
|
||||
public function getDataView($consumableId)
|
||||
{
|
||||
//$consumable = Consumable::find($consumableID);
|
||||
$consumable = Consumable::with(array('consumableAssigments'=>
|
||||
function ($query) {
|
||||
$query->orderBy('created_at', 'DESC');
|
||||
},
|
||||
'consumableAssigments.admin'=> function ($query) {
|
||||
},
|
||||
'consumableAssigments.user'=> function ($query) {
|
||||
},
|
||||
))->find($consumableId);
|
||||
|
||||
// $consumable->load('consumableAssigments.admin','consumableAssigments.user');
|
||||
|
||||
if (!Company::isCurrentUserHasAccess($consumable)) {
|
||||
return ['total' => 0, 'rows' => []];
|
||||
}
|
||||
$this->authorize('view', Component::class);
|
||||
$rows = array();
|
||||
|
||||
foreach ($consumable->consumableAssigments as $consumable_assignment) {
|
||||
$rows[] = [
|
||||
'name' => $consumable_assignment->user->present()->nameUrl(),
|
||||
'created_at' => ($consumable_assignment->created_at->format('Y-m-d H:i:s')=='-0001-11-30 00:00:00') ? '' : $consumable_assignment->created_at->format('Y-m-d H:i:s'),
|
||||
'admin' => ($consumable_assignment->admin) ? $consumable_assignment->admin->present()->nameUrl() : '',
|
||||
];
|
||||
}
|
||||
|
||||
$consumableCount = $consumable->users->count();
|
||||
$data = array('total' => $consumableCount, 'rows' => $rows);
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,22 +291,22 @@ class LicensesController extends Controller
|
||||
// Ooops.. something went wrong
|
||||
return redirect()->back()->withInput()->withErrors($validator);
|
||||
}
|
||||
|
||||
$target = null;
|
||||
if ($assigned_to!='') {
|
||||
// Check if the user exists
|
||||
if (is_null($is_assigned_to = User::find($assigned_to))) {
|
||||
if (is_null($target = User::find($assigned_to))) {
|
||||
// Redirect to the asset management page with error
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.user_does_not_exist'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($asset_id!='') {
|
||||
if (is_null($asset = Asset::find($asset_id))) {
|
||||
if (is_null($target = Asset::find($asset_id))) {
|
||||
// Redirect to the asset management page with error
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.asset_does_not_exist'));
|
||||
}
|
||||
|
||||
if (($asset->assigned_to!='') && (($asset->assigned_to!=$assigned_to)) && ($assigned_to!='')) {
|
||||
if (($target->assigned_to!='') && (($target->assigned_to!=$assigned_to)) && ($target!='')) {
|
||||
return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.owner_doesnt_match_asset'));
|
||||
}
|
||||
}
|
||||
@@ -332,7 +332,7 @@ class LicensesController extends Controller
|
||||
|
||||
// Was the asset updated?
|
||||
if ($licenseSeat->save()) {
|
||||
$licenseSeat->logCheckout($request->input('note'));
|
||||
$licenseSeat->logCheckout($request->input('note'), $target);
|
||||
|
||||
$data['license_id'] =$licenseSeat->license_id;
|
||||
$data['note'] = $request->input('note');
|
||||
|
||||
@@ -63,7 +63,8 @@ class LocationsController extends Controller
|
||||
|
||||
return view('locations/edit')
|
||||
->with('location_options', $location_options)
|
||||
->with('item', new Location);
|
||||
->with('item', new Location)
|
||||
->with('manager_list', Helper::managerList());
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +89,7 @@ class LocationsController extends Controller
|
||||
$location->state = Input::get('state');
|
||||
$location->country = Input::get('country');
|
||||
$location->zip = Input::get('zip');
|
||||
$location->manager_id = Input::get('manager_id');
|
||||
$location->user_id = Auth::id();
|
||||
|
||||
if ($location->save()) {
|
||||
@@ -154,7 +156,10 @@ class LocationsController extends Controller
|
||||
$location_options = Location::flattenLocationsArray($location_options_array);
|
||||
$location_options = array('' => 'Top Level') + $location_options;
|
||||
|
||||
return view('locations/edit', compact('item'))->with('location_options', $location_options);
|
||||
|
||||
return view('locations/edit', compact('item'))
|
||||
->with('location_options', $location_options)
|
||||
->with('manager_list', Helper::managerList());
|
||||
}
|
||||
|
||||
|
||||
@@ -185,6 +190,7 @@ class LocationsController extends Controller
|
||||
$location->country = Input::get('country');
|
||||
$location->zip = Input::get('zip');
|
||||
$location->ldap_ou = Input::get('ldap_ou');
|
||||
$location->manager_id = Input::get('manager_id');
|
||||
|
||||
// Was the location updated?
|
||||
if ($location->save()) {
|
||||
@@ -232,8 +238,6 @@ class LocationsController extends Controller
|
||||
* the content for the locations detail page.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see LocationsController::getDataViewUsers() method that returns JSON for location users
|
||||
* @see LocationsController::getDataViewAssets() method that returns JSON for location assets
|
||||
* @param int $locationId
|
||||
* @since [v1.0]
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
@@ -252,78 +256,4 @@ class LocationsController extends Controller
|
||||
return redirect()->route('locations.index')->with('error', $error);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a JSON response that contains the users association with the
|
||||
* selected location, to be used by the location detail view.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see LocationsController::getView() method that creates the display view
|
||||
* @param $locationID
|
||||
* @return array
|
||||
* @internal param int $locationId
|
||||
* @since [v1.8]
|
||||
*/
|
||||
public function getDataViewUsers($locationID)
|
||||
{
|
||||
$location = Location::find($locationID);
|
||||
$users = User::where('location_id', '=', $location->id);
|
||||
|
||||
if (Input::has('search')) {
|
||||
$users = $users->TextSearch(e(Input::get('search')));
|
||||
}
|
||||
|
||||
$users = $users->get();
|
||||
$rows = array();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$rows[] = array(
|
||||
'name' => (string)link_to_route('users.show', e($user->present()->fullName()), ['user'=>$user->id])
|
||||
);
|
||||
}
|
||||
|
||||
$data = array('total' => $users->count(), 'rows' => $rows);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a JSON response that contains the assets association with the
|
||||
* selected location, to be used by the location detail view.
|
||||
*
|
||||
* @todo This is broken for accessories and consumables.
|
||||
* @todo This is a very naive implementation. Should clean this up with query scopes.
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @see LocationsController::getView() method that creates the display view
|
||||
* @param int $locationID
|
||||
* @since [v1.8]
|
||||
* @return array
|
||||
*/
|
||||
public function getDataViewAssets($locationID)
|
||||
{
|
||||
$location = Location::find($locationID)->load('assignedassets.model');
|
||||
$assets = Asset::AssetsByLocation($location);
|
||||
|
||||
if (Input::has('search')) {
|
||||
$assets = $assets->TextSearch(e(Input::get('search')));
|
||||
}
|
||||
|
||||
$assets = $assets->get();
|
||||
|
||||
$rows = array();
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
$rows[] = [
|
||||
'name' => (string)link_to_route('hardware.show', e($asset->present()->name()), ['hardware' => $asset->id]),
|
||||
'asset_tag' => e($asset->asset_tag),
|
||||
'serial' => e($asset->serial),
|
||||
'model' => e($asset->model->name),
|
||||
];
|
||||
}
|
||||
|
||||
$data = array('total' => $assets->count(), 'rows' => $rows);
|
||||
return $data;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
32
app/Http/Controllers/ModalController.php
Normal file
32
app/Http/Controllers/ModalController.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
|
||||
class ModalController extends Controller
|
||||
{
|
||||
function location() {
|
||||
return view('modals.location');
|
||||
}
|
||||
|
||||
function model() {
|
||||
return view('modals.model')
|
||||
->with('manufacturer', Helper::manufacturerList())
|
||||
->with('category', Helper::categoryList('asset'));
|
||||
}
|
||||
|
||||
function statuslabel() {
|
||||
return view('modals.statuslabel')->with('statuslabel_types', Helper::statusTypeList());
|
||||
}
|
||||
|
||||
function supplier() {
|
||||
return view('modals.supplier');
|
||||
}
|
||||
|
||||
function user() {
|
||||
return view('modals.user');
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,13 @@ namespace App\Http\Controllers;
|
||||
use Image;
|
||||
use Input;
|
||||
use Redirect;
|
||||
use App\Models\Location;
|
||||
use View;
|
||||
use Auth;
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Setting;
|
||||
use Gate;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to User Profiles for
|
||||
@@ -87,4 +88,60 @@ class ProfileController extends Controller
|
||||
public function api() {
|
||||
return view('account/api');
|
||||
}
|
||||
|
||||
/**
|
||||
* User change email page.
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function password()
|
||||
{
|
||||
$user = Auth::user();
|
||||
return view('account/change-password', compact('user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Users change password form processing page.
|
||||
*
|
||||
* @return Redirect
|
||||
*/
|
||||
public function passwordSave(Request $request)
|
||||
{
|
||||
|
||||
if (config('app.lock_passwords')) {
|
||||
return redirect()->route('account.password.index')->with('error', Lang::get('admin/users/table.lock_passwords'));
|
||||
}
|
||||
|
||||
$user = Auth::user();
|
||||
if ($user->ldap_import=='1') {
|
||||
return redirect()->route('account.password.index')->with('error', Lang::get('admin/users/message.error.password_ldap'));
|
||||
}
|
||||
|
||||
$rules = array(
|
||||
'current_password' => 'required',
|
||||
'password' => Setting::passwordComplexityRulesSaving('store'),
|
||||
'password_confirm' => 'required|same:password',
|
||||
);
|
||||
|
||||
$validator = \Validator::make($request->all(), $rules);
|
||||
$validator->after(function($validator) use ($request, $user) {
|
||||
|
||||
if (!Hash::check($request->input('current_password'), $user->password)) {
|
||||
$validator->errors()->add('current_password', trans('validation.hashed_pass'));
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (!$validator->fails()) {
|
||||
$user->password = Hash::make($request->input('password'));
|
||||
$user->save();
|
||||
return redirect()->route('account.password.index')->with('success', 'Password updated!');
|
||||
|
||||
}
|
||||
return redirect()->back()->withInput()->withErrors($validator);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ class ReportsController extends Controller
|
||||
{
|
||||
|
||||
// Grab all the assets
|
||||
$assets = Asset::with('model', 'assignedTo', 'assetstatus', 'defaultLoc', 'assetlog', 'company')
|
||||
$assets = Asset::with( 'assignedTo', 'assetstatus', 'defaultLoc', 'assetloc', 'assetlog', 'company', 'model.category', 'model.depreciation')
|
||||
->orderBy('created_at', 'DESC')->get();
|
||||
|
||||
return view('reports/depreciation', compact('assets'));
|
||||
@@ -271,6 +271,20 @@ class ReportsController extends Controller
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays audit report.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v4.0]
|
||||
* @return View
|
||||
*/
|
||||
public function audit()
|
||||
{
|
||||
return view('reports/audit');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Displays activity report.
|
||||
*
|
||||
@@ -376,7 +390,7 @@ class ReportsController extends Controller
|
||||
*/
|
||||
public function postCustom()
|
||||
{
|
||||
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assigneduser', 'assetloc', 'defaultLoc', 'assigneduser.userloc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
|
||||
$assets = Asset::orderBy('created_at', 'DESC')->with('company', 'assignedTo', 'assetloc', 'defaultLoc', 'model', 'supplier', 'assetstatus', 'model.manufacturer')->get();
|
||||
$customfields = CustomField::get();
|
||||
|
||||
$rows = [ ];
|
||||
@@ -538,8 +552,8 @@ class ReportsController extends Controller
|
||||
|
||||
if (e(Input::get('username')) == '1') {
|
||||
// Only works if we're checked out to a user, not anything else.
|
||||
if ($asset->assigneduser) {
|
||||
$row[] = '"' .e($asset->assigneduser->username). '"';
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = '"' .e($asset->assignedTo->username). '"';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
@@ -547,8 +561,8 @@ class ReportsController extends Controller
|
||||
|
||||
if (e(Input::get('employee_num')) == '1') {
|
||||
// Only works if we're checked out to a user, not anything else.
|
||||
if ($asset->assigneduser) {
|
||||
$row[] = '"' .e($asset->assigneduser->employee_num). '"';
|
||||
if ($asset->checkedOutToUser()) {
|
||||
$row[] = '"' .e($asset->assignedTo->employee_num). '"';
|
||||
} else {
|
||||
$row[] = ''; // Empty string if unassigned
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ use Auth;
|
||||
use App\Models\User;
|
||||
use App\Http\Requests\SetupUserRequest;
|
||||
use App\Http\Requests\ImageUploadRequest;
|
||||
use App\Http\Requests\SettingsLdapRequest;
|
||||
|
||||
/**
|
||||
* This controller handles all actions related to Settings for
|
||||
@@ -184,6 +185,7 @@ class SettingsController extends Controller
|
||||
$settings->site_name = e(Input::get('site_name'));
|
||||
$settings->alert_email = e(Input::get('email'));
|
||||
$settings->alerts_enabled = 1;
|
||||
$settings->pwd_secure_min = 10;
|
||||
$settings->brand = 1;
|
||||
$settings->locale = 'en';
|
||||
$settings->default_currency = 'USD';
|
||||
@@ -259,6 +261,13 @@ class SettingsController extends Controller
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
|
||||
$output = Artisan::output();
|
||||
|
||||
if ((!file_exists(storage_path().'/oauth-private.key')) || (!file_exists(storage_path().'/oauth-public.key'))) {
|
||||
Artisan::call('passport:install');
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
}
|
||||
|
||||
|
||||
return view('setup/migrate')
|
||||
->with('output', $output)
|
||||
->with('step', 2)
|
||||
@@ -462,6 +471,15 @@ class SettingsController extends Controller
|
||||
|
||||
}
|
||||
|
||||
$setting->pwd_secure_uncommon = (int) $request->input('pwd_secure_uncommon');
|
||||
$setting->pwd_secure_min = (int) $request->input('pwd_secure_min');
|
||||
$setting->pwd_secure_complexity = '';
|
||||
|
||||
if ($request->has('pwd_secure_complexity')) {
|
||||
$setting->pwd_secure_complexity = implode('|', $request->input('pwd_secure_complexity'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
if ($setting->save()) {
|
||||
return redirect()->route('settings.index')
|
||||
@@ -545,10 +563,12 @@ class SettingsController extends Controller
|
||||
$alert_email = rtrim($request->input('alert_email'), ',');
|
||||
$alert_email = trim($alert_email);
|
||||
|
||||
$setting->alert_email = e($alert_email);
|
||||
$setting->alert_email = $alert_email;
|
||||
$setting->alerts_enabled = $request->input('alerts_enabled', '0');
|
||||
$setting->alert_interval = $request->input('alert_interval');
|
||||
$setting->alert_threshold = $request->input('alert_threshold');
|
||||
$setting->audit_interval = $request->input('audit_interval');
|
||||
$setting->audit_warning_days = $request->input('audit_warning_days');
|
||||
|
||||
if ($setting->save()) {
|
||||
return redirect()->route('settings.index')
|
||||
|
||||
@@ -12,9 +12,7 @@ use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\License;
|
||||
use App\Models\Setting;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Http\Requests\SaveUserRequest;
|
||||
use App\Http\Requests\UpdateUserRequest;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use App\Models\User;
|
||||
use App\Models\Ldap;
|
||||
@@ -23,7 +21,6 @@ use Config;
|
||||
use Crypt;
|
||||
use DB;
|
||||
use HTML;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Input;
|
||||
use Lang;
|
||||
use League\Csv\Reader;
|
||||
@@ -169,7 +166,7 @@ class UsersController extends Controller
|
||||
* @since [v1.8]
|
||||
* @return string JSON
|
||||
*/
|
||||
public function apiStore(Request $request)
|
||||
public function apiStore(SaveUserRequest $request)
|
||||
{
|
||||
$this->authorize('create', User::class);
|
||||
|
||||
@@ -270,7 +267,7 @@ class UsersController extends Controller
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function update(UpdateUserRequest $request, $id = null)
|
||||
public function update(SaveUserRequest $request, $id = null)
|
||||
{
|
||||
// We need to reverse the UI specific logic for our
|
||||
// permissions here before we update the user.
|
||||
@@ -309,14 +306,11 @@ class UsersController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Do we want to update the user password?
|
||||
if ($request->has('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
if ($request->has('username')) {
|
||||
$user->username = e($request->input('username'));
|
||||
$user->username = $request->input('username');
|
||||
}
|
||||
$user->email = e($request->input('email'));
|
||||
$user->email = $request->input('email');
|
||||
|
||||
|
||||
// Update the user
|
||||
@@ -334,6 +328,12 @@ class UsersController extends Controller
|
||||
$user->notes = $request->input('notes');
|
||||
$user->department_id = $request->input('department_id', null);
|
||||
|
||||
|
||||
// Do we want to update the user password?
|
||||
if ($request->has('password')) {
|
||||
$user->password = bcrypt($request->input('password'));
|
||||
}
|
||||
|
||||
// Strip out the superuser permission if the user isn't a superadmin
|
||||
$permissions_array = $request->input('permission');
|
||||
|
||||
@@ -376,7 +376,6 @@ class UsersController extends Controller
|
||||
}
|
||||
|
||||
if ($user->licenses()->count() > 0) {
|
||||
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->licenses()->count() . ' licenses associated with them.');
|
||||
}
|
||||
@@ -386,6 +385,11 @@ class UsersController extends Controller
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->accessories()->count() . ' accessories associated with them.');
|
||||
}
|
||||
|
||||
if ($user->managedLocations()->count() > 0) {
|
||||
// Redirect to the user management page
|
||||
return redirect()->route('users.index')->with('error', 'This user still has ' . $user->managedLocations()->count() . ' locations that they manage.');
|
||||
}
|
||||
|
||||
// Delete the user
|
||||
$user->delete();
|
||||
|
||||
@@ -1147,21 +1151,7 @@ class UsersController extends Controller
|
||||
}
|
||||
return redirect()->route('ldap/user')->with('success', "LDAP Import successful.")->with('summary', $summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON containing a list of assets assigned to a user.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.0]
|
||||
* @param $userId
|
||||
* @return string JSON
|
||||
*/
|
||||
public function getAssetList($userId)
|
||||
{
|
||||
$this->authorize('view', User::class);
|
||||
$assets = Asset::where('assigned_to', '=', $userId)->with('model')->get();
|
||||
return response()->json($assets);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports users to CSV
|
||||
|
||||
@@ -68,8 +68,8 @@ class ViewAssetsController extends Controller
|
||||
public function getRequestableIndex()
|
||||
{
|
||||
|
||||
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo')->Hardware()->RequestableAssets()->get();
|
||||
$models = AssetModel::with('category')->RequestableModels()->get();
|
||||
$assets = Asset::with('model', 'defaultLoc', 'assetloc', 'assignedTo', 'requests')->Hardware()->RequestableAssets()->get();
|
||||
$models = AssetModel::with('category', 'requests', 'assets')->RequestableModels()->get();
|
||||
|
||||
return view('account/requestable-assets', compact('user', 'assets', 'models'));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use App\Models\Setting;
|
||||
|
||||
class SaveUserRequest extends Request
|
||||
{
|
||||
@@ -23,12 +24,38 @@ class SaveUserRequest extends Request
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'first_name' => 'required|string|min:1',
|
||||
'email' => 'email',
|
||||
'password' => 'required|min:6',
|
||||
'password_confirm' => 'sometimes|required_with:password',
|
||||
'username' => 'required|string|min:2|unique:users,username,NULL,deleted_at',
|
||||
];
|
||||
|
||||
$rules = [];
|
||||
|
||||
switch($this->method())
|
||||
{
|
||||
|
||||
// Brand new asset
|
||||
case 'POST':
|
||||
{
|
||||
$rules['first_name'] = 'required|string|min:1';
|
||||
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
|
||||
$rules['password'] = Setting::passwordComplexityRulesSaving('store');
|
||||
}
|
||||
|
||||
// Save all fields
|
||||
case 'PUT':
|
||||
$rules['first_name'] = 'required|string|min:1';
|
||||
$rules['username'] = 'required_unless:ldap_import,1|string|min:1';
|
||||
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
|
||||
|
||||
// Save only what's passed
|
||||
case 'PATCH':
|
||||
{
|
||||
$rules['password'] = Setting::passwordComplexityRulesSaving('update');
|
||||
}
|
||||
|
||||
default:break;
|
||||
}
|
||||
|
||||
$rules['password_confirm'] = 'sometimes|required_with:password';
|
||||
|
||||
return $rules;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
50
app/Http/Requests/SettingsLdapRequest.php
Normal file
50
app/Http/Requests/SettingsLdapRequest.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
use Session;
|
||||
|
||||
class SettingsLdapRequest 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()
|
||||
{
|
||||
$rules = [
|
||||
"ldap_server" => 'sometimes|required_if:ldap_enabled,1|url|nullable',
|
||||
"ldap_uname" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_basedn" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_filter" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_username_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_fname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
"ldap_version" => 'sometimes|required_if:ldap_enabled,1|nullable',
|
||||
];
|
||||
|
||||
return $rules;
|
||||
|
||||
}
|
||||
|
||||
public function response(array $errors)
|
||||
{
|
||||
$this->session()->flash('errors', Session::get('errors', new \Illuminate\Support\ViewErrorBag)
|
||||
->put('default', new \Illuminate\Support\MessageBag($errors)));
|
||||
\Input::flash();
|
||||
return parent::response($errors);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use App\Http\Requests\Request;
|
||||
|
||||
class UpdateUserRequest 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()
|
||||
{
|
||||
return [
|
||||
'first_name' => 'required|string|min:1',
|
||||
'email' => 'email',
|
||||
'password_confirm' => 'sometimes|required_with:password',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Models\Actionlog;
|
||||
use App\Models\Setting;
|
||||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use App\Helpers\Helper;
|
||||
@@ -12,23 +13,32 @@ class ActionlogsTransformer
|
||||
public function transformActionlogs (Collection $actionlogs, $total)
|
||||
{
|
||||
$array = array();
|
||||
$settings = Setting::getSettings();
|
||||
foreach ($actionlogs as $actionlog) {
|
||||
$array[] = self::transformActionlog($actionlog);
|
||||
$array[] = self::transformActionlog($actionlog, $settings);
|
||||
}
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformActionlog (Actionlog $actionlog)
|
||||
public function transformActionlog (Actionlog $actionlog, $settings = null)
|
||||
{
|
||||
$array = [
|
||||
'id' => (int) $actionlog->id,
|
||||
'icon' => $actionlog->present()->icon(),
|
||||
'image' => (method_exists($actionlog->item, 'getImageUrl')) ? $actionlog->item->getImageUrl() : null,
|
||||
'item' => ($actionlog->item) ? [
|
||||
'id' => (int) $actionlog->item->id,
|
||||
'name' => e($actionlog->item->getDisplayNameAttribute()),
|
||||
'type' => e($actionlog->itemType()),
|
||||
] : null,
|
||||
'location' => ($actionlog->location) ? [
|
||||
'id' => (int) $actionlog->location->id,
|
||||
'name' => e($actionlog->location->name)
|
||||
] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($actionlog->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($actionlog->updated_at, 'datetime'),
|
||||
'next_audit_date' => ($actionlog->itemType()=='asset') ? Helper::getFormattedDateObject($actionlog->calcNextAuditDate(), 'date'): null,
|
||||
'days_to_next_audit' => $actionlog->daysUntilNextAudit($settings->audit_interval, $actionlog->item),
|
||||
'action_type' => $actionlog->present()->actionType(),
|
||||
'admin' => ($actionlog->user) ? [
|
||||
'id' => (int) $actionlog->user->id,
|
||||
|
||||
54
app/Http/Transformers/AssetMaintenancesTransformer.php
Normal file
54
app/Http/Transformers/AssetMaintenancesTransformer.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
namespace App\Http\Transformers;
|
||||
|
||||
use App\Models\AssetMaintenance;
|
||||
use Gate;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use App\Helpers\Helper;
|
||||
|
||||
class AssetMaintenancesTransformer
|
||||
{
|
||||
|
||||
public function transformAssetMaintenances (Collection $assetmaintenances, $total)
|
||||
{
|
||||
$array = array();
|
||||
foreach ($assetmaintenances as $assetmaintenance) {
|
||||
$array[] = self::transformAssetMaintenance($assetmaintenance);
|
||||
}
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformAssetMaintenance (AssetMaintenance $assetmaintenance)
|
||||
{
|
||||
$array = [
|
||||
'id' => (int) $assetmaintenance->id,
|
||||
'asset_name' => ($assetmaintenance->asset) ? ['id' => $assetmaintenance->asset->id,'name'=> e($assetmaintenance->asset->name)] : null,
|
||||
'title' => ($assetmaintenance->title) ? e($assetmaintenance->title) : null,
|
||||
'notes' => ($assetmaintenance->notes) ? e($assetmaintenance->notes) : null,
|
||||
'supplier' => ($assetmaintenance->supplier) ? ['id' => $assetmaintenance->supplier->id,'name'=> e($assetmaintenance->supplier->name)] : null,
|
||||
'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost),
|
||||
'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type),
|
||||
'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'datetime'),
|
||||
'asset_maintenance_time' => $assetmaintenance->asset_maintenance_time,
|
||||
'completion_date' => Helper::getFormattedDateObject($assetmaintenance->completion_date, 'datetime'),
|
||||
'user_id' => ($assetmaintenance->admin) ? ['id' => $assetmaintenance->admin->id,'name'=> e($assetmaintenance->admin->getFullNameAttribute())] : null,
|
||||
'created_at' => Helper::getFormattedDateObject($assetmaintenance->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($assetmaintenance->updated_at, 'datetime'),
|
||||
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => (bool) Gate::allows('update', Asset::class),
|
||||
'delete' => (bool) Gate::allows('delete', Asset::class),
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -62,14 +62,7 @@ class AssetsTransformer
|
||||
'name'=> e($asset->defaultLoc->name)
|
||||
] : null,
|
||||
'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null,
|
||||
'assigned_to' => ($asset->assigneduser) ? [
|
||||
'id' => (int) $asset->assigneduser->id,
|
||||
'username' => e($asset->assigneduser->username),
|
||||
'name' => e($asset->assigneduser->getFullNameAttribute()),
|
||||
'first_name'=> e($asset->assigneduser->first_name),
|
||||
'last_name'=> e($asset->assigneduser->last_name),
|
||||
'employee_number' => e($asset->assigneduser->employee_num),
|
||||
] : null,
|
||||
'assigned_to' => $this->transformAssignedTo($asset),
|
||||
'warranty' => ($asset->warranty_months > 0) ? e($asset->warranty_months . ' ' . trans('admin/hardware/form.months')) : null,
|
||||
'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null,
|
||||
'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'),
|
||||
@@ -110,6 +103,8 @@ class AssetsTransformer
|
||||
//array += $fields_array;
|
||||
$array['custom_fields'] = $fields_array;
|
||||
}
|
||||
} else {
|
||||
$array['custom_fields'] = array();
|
||||
}
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
@@ -128,4 +123,24 @@ class AssetsTransformer
|
||||
{
|
||||
return (new DatatablesTransformer)->transformDatatables($assets);
|
||||
}
|
||||
|
||||
public function transformAssignedTo($asset)
|
||||
{
|
||||
if ($asset->checkedOutToUser()) {
|
||||
return $asset->assignedTo ? [
|
||||
'id' => (int) $asset->assignedTo->id,
|
||||
'username' => e($asset->assignedTo->username),
|
||||
'name' => e($asset->assignedTo->getFullNameAttribute()),
|
||||
'first_name'=> e($asset->assignedTo->first_name),
|
||||
'last_name'=> e($asset->assignedTo->last_name),
|
||||
'employee_number' => e($asset->assignedTo->employee_num),
|
||||
'type' => 'user'
|
||||
] : null;
|
||||
}
|
||||
return $asset->assignedTo ? [
|
||||
'id' => $asset->assignedTo->id,
|
||||
'name' => $asset->assignedTo->display_name,
|
||||
'type' => $asset->assignedType()
|
||||
] : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Transformers;
|
||||
use App\Models\Category;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Gate;
|
||||
use App\Helpers\Helper;
|
||||
|
||||
class CategoriesTransformer
|
||||
{
|
||||
@@ -22,15 +23,18 @@ class CategoriesTransformer
|
||||
if ($category) {
|
||||
|
||||
$array = [
|
||||
'id' => e($category->id),
|
||||
'id' => (int) $category->id,
|
||||
'name' => e($category->name),
|
||||
'type' => e($category->category_type),
|
||||
'use_default_eula' => ($category->use_default_eula =='1') ? true : false,
|
||||
'checkin_email' => ($category->checkin_email =='1') ? true : false,
|
||||
'require_acceptance' => ($category->require_acceptance =='1') ? true : false,
|
||||
'assets_count' => $category->assets_count,
|
||||
'accessories_count' => $category->accessories_count,
|
||||
'consumables_count' => $category->consumables_count,
|
||||
'components_count' => $category->components_count,
|
||||
'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($category->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
|
||||
@@ -23,7 +23,7 @@ class CompaniesTransformer
|
||||
if ($company) {
|
||||
|
||||
$array = [
|
||||
'id' => e($company->id),
|
||||
'id' => (int) $company->id,
|
||||
'name' => e($company->name),
|
||||
"created_at" => Helper::getFormattedDateObject($company->created_at, 'datetime'),
|
||||
"updated_at" => Helper::getFormattedDateObject($company->updated_at, 'datetime'),
|
||||
|
||||
@@ -25,7 +25,7 @@ class CustomFieldsTransformer
|
||||
'name' => e($field->name),
|
||||
'db_column_name' => e($field->db_column_name()),
|
||||
'format' => e($field->format),
|
||||
'required' => $field->pivot->required,
|
||||
'required' => $field->pivot ? $field->pivot->required : false,
|
||||
'created_at' => Helper::getFormattedDateObject($field->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($field->updated_at, 'datetime'),
|
||||
];
|
||||
|
||||
@@ -9,7 +9,7 @@ use App\Helpers\Helper;
|
||||
class LocationsTransformer
|
||||
{
|
||||
|
||||
public function transformLocations (Collection $locations, $total)
|
||||
public function transformLocations(Collection $locations, $total)
|
||||
{
|
||||
$array = array();
|
||||
foreach ($locations as $location) {
|
||||
@@ -18,18 +18,16 @@ class LocationsTransformer
|
||||
return (new DatatablesTransformer)->transformDatatables($array, $total);
|
||||
}
|
||||
|
||||
public function transformLocation (Location $location = null)
|
||||
public function transformLocation(Location $location = null)
|
||||
{
|
||||
if ($location) {
|
||||
|
||||
$assets_arr = [];
|
||||
foreach($location->assets() as $asset) {
|
||||
$assets_arr = ['id' => $asset->id];
|
||||
}
|
||||
|
||||
$children_arr = [];
|
||||
foreach($location->childLocations() as $child) {
|
||||
$children_arr = ['id' => $child->id];
|
||||
foreach($location->childLocations as $child) {
|
||||
$children_arr[] = [
|
||||
'id' => (int) $child->id,
|
||||
'name' => $child->name
|
||||
];
|
||||
}
|
||||
|
||||
$array = [
|
||||
@@ -41,10 +39,15 @@ class LocationsTransformer
|
||||
'assets_checkedout' => $location->assets()->count(),
|
||||
'assets_default' => $location->assignedassets()->count(),
|
||||
'country' => e($location->country),
|
||||
'assets' => $assets_arr,
|
||||
'created_at' => Helper::getFormattedDateObject($location->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($location->updated_at, 'datetime'),
|
||||
'parent_id' => ($location->parent_id) ? (int) $location->parent_id : null,
|
||||
'parent' => ($location->parent) ? [
|
||||
'id' => (int) $location->parent->id,
|
||||
'name'=> e($location->parent->name)
|
||||
] : null,
|
||||
'manager' => ($location->manager) ? (new UsersTransformer)->transformUser($location->manager) : null,
|
||||
|
||||
|
||||
'children' => $children_arr,
|
||||
];
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ class SuppliersTransformer
|
||||
'city' => ($supplier->city) ? e($supplier->city) : null,
|
||||
'state' => ($supplier->state) ? e($supplier->state) : null,
|
||||
'country' => ($supplier->country) ? e($supplier->country) : null,
|
||||
'zip' => ($supplier->zip) ? e($supplier->zip) : null,
|
||||
'fax' => ($supplier->fax) ? e($supplier->fax) : null,
|
||||
'phone' => ($supplier->phone) ? e($supplier->phone) : null,
|
||||
'email' => ($supplier->email) ? e($supplier->email) : null,
|
||||
@@ -37,6 +38,7 @@ class SuppliersTransformer
|
||||
'assets_count' => (int) $supplier->assets_count,
|
||||
'licenses_count' => (int) $supplier->licenses_count,
|
||||
'image' => ($supplier->image) ? e($supplier->image) : null,
|
||||
'notes' => ($supplier->notes) ? e($supplier->notes) : null,
|
||||
'created_at' => Helper::getFormattedDateObject($supplier->created_at, 'datetime'),
|
||||
'updated_at' => Helper::getFormattedDateObject($supplier->updated_at, 'datetime'),
|
||||
|
||||
|
||||
@@ -32,11 +32,6 @@ class UsersTransformer
|
||||
'id' => (int) $user->manager->id,
|
||||
'name'=> e($user->manager->username)
|
||||
] : null,
|
||||
|
||||
'groups' => ($user->groups) ? [
|
||||
'id' => (int) $user->userloc->id,
|
||||
'name'=> e($user->userloc->name)
|
||||
] : null,
|
||||
'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null,
|
||||
'email' => e($user->email),
|
||||
'department' => ($user->department) ? [
|
||||
@@ -61,13 +56,32 @@ class UsersTransformer
|
||||
];
|
||||
|
||||
$permissions_array['available_actions'] = [
|
||||
'update' => Gate::allows('update', User::class) ? true : false,
|
||||
'delete' => Gate::allows('delete', User::class) ? true : false,
|
||||
'clone' => Gate::allows('create', User::class) ? true : false,
|
||||
'update' => (Gate::allows('update', User::class) && ($user->deleted_at=='')) ? true : false,
|
||||
'delete' => (Gate::allows('delete', User::class) && ($user->deleted_at=='')) ? true : false,
|
||||
'clone' => (Gate::allows('create', User::class) && ($user->deleted_at=='')) ,
|
||||
'restore' => (Gate::allows('create', User::class) && ($user->deleted_at!='')) ? true : false,
|
||||
];
|
||||
|
||||
$array += $permissions_array;
|
||||
|
||||
|
||||
$numGroups = count($user->groups);
|
||||
if($numGroups > 0)
|
||||
{
|
||||
$groups["total"] = $numGroups;
|
||||
foreach($user->groups as $group)
|
||||
{
|
||||
$groups["rows"][] = [
|
||||
'id' => (int) $group->id,
|
||||
'name' => e($group->name)
|
||||
];
|
||||
}
|
||||
$array["groups"] = $groups;
|
||||
}
|
||||
else {
|
||||
$array["groups"] = null;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,7 +63,9 @@ class AssetImporter extends ItemImporter
|
||||
$this->item['image'] = $this->findCsvMatch($row, "image");
|
||||
$this->item['warranty_months'] = intval($this->findCsvMatch($row, "warranty"));
|
||||
$this->item['model_id'] = $this->createOrFetchAssetModel($row);
|
||||
if (!$this->item['status_id'] && !$editingAsset) {
|
||||
|
||||
// If no status ID is found
|
||||
if (!array_key_exists('status_id', $this->item) && !$editingAsset) {
|
||||
$this->log("No status field found, defaulting to first status.");
|
||||
$this->item['status_id'] = $this->defaultStatusLabelId;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,15 @@ abstract class Importer
|
||||
{
|
||||
$headerRow = $this->csv->fetchOne();
|
||||
$results = $this->normalizeInputArray($this->csv->fetchAssoc());
|
||||
$this->customFields = CustomField::All(['name']);
|
||||
|
||||
// Stolen From https://adamwathan.me/2016/07/14/customizing-keys-when-mapping-collections/
|
||||
// This 'inverts' the fields such that we have a collection of fields indexed by name.
|
||||
$cFs = CustomField::All();
|
||||
$this->customFields = $cFs->reduce(function ($nameLookup, $field) {
|
||||
$nameLookup[$field['name']] = $field;
|
||||
return $nameLookup;
|
||||
});
|
||||
|
||||
DB::transaction(function () use (&$results) {
|
||||
Model::unguard();
|
||||
$resultsCount = sizeof($results);
|
||||
@@ -136,14 +144,12 @@ abstract class Importer
|
||||
* @param $default string
|
||||
* @return string
|
||||
*/
|
||||
public function findCsvMatch(array $array, $key, $default = '')
|
||||
public function findCsvMatch(array $array, $key, $default = null)
|
||||
{
|
||||
|
||||
$val = $default;
|
||||
|
||||
if ($customKey = $this->lookupCustomKey($key)) {
|
||||
$key = $customKey;
|
||||
}
|
||||
$key = $this->lookupCustomKey($key);
|
||||
|
||||
$this->log("Custom Key: ${key}");
|
||||
if (array_key_exists($key, $array)) {
|
||||
@@ -163,13 +169,12 @@ abstract class Importer
|
||||
*/
|
||||
public function lookupCustomKey($key)
|
||||
{
|
||||
// dd($this->fieldMap);
|
||||
|
||||
if (array_key_exists($key, $this->fieldMap)) {
|
||||
$this->log("Found a match in our custom map: {$key} is " . $this->fieldMap[$key]);
|
||||
return $this->fieldMap[$key];
|
||||
}
|
||||
return null;
|
||||
// Otherwise no custom key, return original.
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\Location;
|
||||
use App\Models\Manufacturer;
|
||||
use App\Models\Statuslabel;
|
||||
use App\Models\Supplier;
|
||||
use App\Models\User;
|
||||
|
||||
class ItemImporter extends Importer
|
||||
{
|
||||
@@ -68,6 +69,7 @@ class ItemImporter extends Importer
|
||||
if(get_class($this) !== UserImporter::class) {
|
||||
if ($this->item["user"] = $this->createOrFetchUser($row)) {
|
||||
$this->item['assigned_to'] = $this->item['user']->id;
|
||||
$this->item['assigned_type'] = User::class;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,7 +92,6 @@ class ItemImporter extends Importer
|
||||
$item = collect($this->item);
|
||||
// First Filter the item down to the model's fillable fields
|
||||
$item = $item->only($model->getFillable());
|
||||
|
||||
// Then iterate through the item and, if we are updating, remove any blank values.
|
||||
if ($updating) {
|
||||
$item = $item->reject(function ($value) {
|
||||
|
||||
81
app/LegacyEncrypter/BaseEncrypter.php
Normal file
81
app/LegacyEncrypter/BaseEncrypter.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace App\LegacyEncrypter;
|
||||
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
|
||||
abstract class BaseEncrypter
|
||||
{
|
||||
/**
|
||||
* The encryption key.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $key;
|
||||
|
||||
/**
|
||||
* Create a MAC for the given value.
|
||||
*
|
||||
* @param string $iv
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
protected function hash($iv, $value)
|
||||
{
|
||||
return hash_hmac('sha256', $iv.$value, $this->key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON array from the given payload.
|
||||
*
|
||||
* @param string $payload
|
||||
* @return array
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Encryption\DecryptException
|
||||
*/
|
||||
protected function getJsonPayload($payload)
|
||||
{
|
||||
$payload = json_decode(base64_decode($payload), true);
|
||||
|
||||
// If the payload is not valid JSON or does not have the proper keys set we will
|
||||
// assume it is invalid and bail out of the routine since we will not be able
|
||||
// to decrypt the given value. We'll also check the MAC for this encryption.
|
||||
if (! $payload || $this->invalidPayload($payload)) {
|
||||
throw new DecryptException('The payload is invalid.');
|
||||
}
|
||||
|
||||
if (! $this->validMac($payload)) {
|
||||
throw new DecryptException('The MAC is invalid.');
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that the encryption payload is valid.
|
||||
*
|
||||
* @param array|mixed $data
|
||||
* @return bool
|
||||
*/
|
||||
protected function invalidPayload($data)
|
||||
{
|
||||
return ! is_array($data) || ! isset($data['iv']) || ! isset($data['value']) || ! isset($data['mac']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the MAC for the given payload is valid.
|
||||
*
|
||||
* @param array $payload
|
||||
* @return bool
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function validMac(array $payload)
|
||||
{
|
||||
$bytes = random_bytes(16);
|
||||
|
||||
$calcMac = hash_hmac('sha256', $this->hash($payload['iv'], $payload['value']), $bytes, true);
|
||||
|
||||
return hash_equals(hash_hmac('sha256', $payload['mac'], $bytes, true), $calcMac);
|
||||
}
|
||||
}
|
||||
214
app/LegacyEncrypter/McryptEncrypter.php
Normal file
214
app/LegacyEncrypter/McryptEncrypter.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace App\LegacyEncrypter;
|
||||
|
||||
use Exception;
|
||||
use RuntimeException;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Contracts\Encryption\EncryptException;
|
||||
use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;
|
||||
|
||||
/**
|
||||
* @deprecated since version 5.1. Use Illuminate\Encryption\Encrypter.
|
||||
*/
|
||||
class McryptEncrypter extends BaseEncrypter implements EncrypterContract
|
||||
{
|
||||
/**
|
||||
* The algorithm used for encryption.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $cipher;
|
||||
|
||||
/**
|
||||
* The block size of the cipher.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $block;
|
||||
|
||||
/**
|
||||
* Create a new encrypter instance.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $cipher
|
||||
* @return void
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __construct($key, $cipher = MCRYPT_RIJNDAEL_128)
|
||||
{
|
||||
$key = (string) $key;
|
||||
|
||||
if (static::supported($key, $cipher)) {
|
||||
$this->key = $key;
|
||||
$this->cipher = $cipher;
|
||||
$this->block = mcrypt_get_iv_size($this->cipher, MCRYPT_MODE_CBC);
|
||||
} else {
|
||||
throw new RuntimeException('The only supported ciphers are MCRYPT_RIJNDAEL_128 and MCRYPT_RIJNDAEL_256.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given key and cipher combination is valid.
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $cipher
|
||||
* @return bool
|
||||
*/
|
||||
public static function supported($key, $cipher)
|
||||
{
|
||||
return defined('MCRYPT_RIJNDAEL_128') &&
|
||||
($cipher === MCRYPT_RIJNDAEL_128 || $cipher === MCRYPT_RIJNDAEL_256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypt the given value.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Encryption\EncryptException
|
||||
*/
|
||||
public function encrypt($value, $serialize = true)
|
||||
{
|
||||
$iv = mcrypt_create_iv($this->getIvSize(), $this->getRandomizer());
|
||||
|
||||
$value = base64_encode($this->padAndMcrypt($value, $iv));
|
||||
|
||||
// Once we have the encrypted value we will go ahead base64_encode the input
|
||||
// vector and create the MAC for the encrypted value so we can verify its
|
||||
// authenticity. Then, we'll JSON encode the data in a "payload" array.
|
||||
$mac = $this->hash($iv = base64_encode($iv), $value);
|
||||
|
||||
$json = json_encode(compact('iv', 'value', 'mac'));
|
||||
|
||||
if (! is_string($json)) {
|
||||
throw new EncryptException('Could not encrypt the data.');
|
||||
}
|
||||
|
||||
return base64_encode($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pad and use mcrypt on the given value and input vector.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $iv
|
||||
* @return string
|
||||
*/
|
||||
protected function padAndMcrypt($value, $iv)
|
||||
{
|
||||
$value = $this->addPadding(serialize($value));
|
||||
|
||||
return mcrypt_encrypt($this->cipher, $this->key, $value, MCRYPT_MODE_CBC, $iv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypt the given value.
|
||||
*
|
||||
* @param string $payload
|
||||
* @return string
|
||||
*/
|
||||
public function decrypt($payload, $unserialize = true)
|
||||
{
|
||||
$payload = $this->getJsonPayload($payload);
|
||||
|
||||
// We'll go ahead and remove the PKCS7 padding from the encrypted value before
|
||||
// we decrypt it. Once we have the de-padded value, we will grab the vector
|
||||
// and decrypt the data, passing back the unserialized from of the value.
|
||||
$value = base64_decode($payload['value']);
|
||||
|
||||
$iv = base64_decode($payload['iv']);
|
||||
|
||||
return unserialize($this->stripPadding($this->mcryptDecrypt($value, $iv)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the mcrypt decryption routine for the value.
|
||||
*
|
||||
* @param string $value
|
||||
* @param string $iv
|
||||
* @return string
|
||||
*
|
||||
* @throws \Illuminate\Contracts\Encryption\DecryptException
|
||||
*/
|
||||
protected function mcryptDecrypt($value, $iv)
|
||||
{
|
||||
try {
|
||||
return mcrypt_decrypt($this->cipher, $this->key, $value, MCRYPT_MODE_CBC, $iv);
|
||||
} catch (Exception $e) {
|
||||
throw new DecryptException($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add PKCS7 padding to a given value.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
protected function addPadding($value)
|
||||
{
|
||||
$pad = $this->block - (strlen($value) % $this->block);
|
||||
|
||||
return $value.str_repeat(chr($pad), $pad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the padding from the given value.
|
||||
*
|
||||
* @param string $value
|
||||
* @return string
|
||||
*/
|
||||
protected function stripPadding($value)
|
||||
{
|
||||
$pad = ord($value[($len = strlen($value)) - 1]);
|
||||
|
||||
return $this->paddingIsValid($pad, $value) ? substr($value, 0, $len - $pad) : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given padding for a value is valid.
|
||||
*
|
||||
* @param string $pad
|
||||
* @param string $value
|
||||
* @return bool
|
||||
*/
|
||||
protected function paddingIsValid($pad, $value)
|
||||
{
|
||||
$beforePad = strlen($value) - $pad;
|
||||
|
||||
return substr($value, $beforePad) == str_repeat(substr($value, -1), $pad);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IV size for the cipher.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getIvSize()
|
||||
{
|
||||
return mcrypt_get_iv_size($this->cipher, MCRYPT_MODE_CBC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the random data source available for the OS.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getRandomizer()
|
||||
{
|
||||
if (defined('MCRYPT_DEV_URANDOM')) {
|
||||
return MCRYPT_DEV_URANDOM;
|
||||
}
|
||||
|
||||
if (defined('MCRYPT_DEV_RANDOM')) {
|
||||
return MCRYPT_DEV_RANDOM;
|
||||
}
|
||||
|
||||
mt_srand();
|
||||
|
||||
return MCRYPT_RAND;
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ class Accessory extends SnipeModel
|
||||
'purchase_cost',
|
||||
'purchase_date',
|
||||
'model_number',
|
||||
'manufacturer_id',
|
||||
'qty',
|
||||
'requestable'
|
||||
];
|
||||
|
||||
@@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Response;
|
||||
use Carbon;
|
||||
|
||||
/**
|
||||
* Model for the Actionlog (the table that keeps a historical log of
|
||||
@@ -123,6 +124,10 @@ class Actionlog extends SnipeModel
|
||||
return $this->belongsTo('\App\Models\ActionLog', 'thread_id');
|
||||
}
|
||||
|
||||
public function location() {
|
||||
return $this->belongsTo('\App\Models\Location', 'location_id' )->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the file exists, and if it does, force a download
|
||||
**/
|
||||
@@ -149,6 +154,33 @@ class Actionlog extends SnipeModel
|
||||
}
|
||||
}
|
||||
|
||||
public function daysUntilNextAudit($monthInterval = 12, $asset = null) {
|
||||
|
||||
$now = Carbon::now();
|
||||
$last_audit_date = $this->created_at;
|
||||
$next_audit = $last_audit_date->addMonth($monthInterval);
|
||||
$next_audit_days = $now->diffInDays($next_audit);
|
||||
|
||||
// Override the default setting for interval if the asset has its own next audit date
|
||||
if (($asset) && ($asset->next_audit_date)) {
|
||||
$override_default_next = \Carbon::parse($asset->next_audit_date);
|
||||
$next_audit_days = $override_default_next->diffInDays($now);
|
||||
}
|
||||
|
||||
return $next_audit_days;
|
||||
}
|
||||
|
||||
public function calcNextAuditDate($monthInterval = 12, $asset = null) {
|
||||
|
||||
$last_audit_date = Carbon::parse($this->created_at);
|
||||
// If there is an asset-specific next date already given,
|
||||
if (($asset) && ($asset->next_audit_date)) {
|
||||
return \Carbon::parse($asset->next_audit_date);
|
||||
}
|
||||
|
||||
return \Carbon::parse($last_audit_date)->addMonths($monthInterval)->toDateString();
|
||||
}
|
||||
|
||||
/**
|
||||
* getListingOfActionLogsChronologicalOrder
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace App\Models;
|
||||
|
||||
use App\Exceptions\CheckoutNotAllowed;
|
||||
use App\Http\Traits\UniqueUndeletedTrait;
|
||||
use App\Presenters\Presentable;
|
||||
use AssetPresenter;
|
||||
@@ -10,6 +11,7 @@ use Config;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Log;
|
||||
use Watson\Validating\ValidatingTrait;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
/**
|
||||
* Model for Assets.
|
||||
@@ -19,7 +21,7 @@ use Watson\Validating\ValidatingTrait;
|
||||
class Asset extends Depreciable
|
||||
{
|
||||
protected $presenter = 'App\Presenters\AssetPresenter';
|
||||
use Loggable, Requestable, Presentable;
|
||||
use Loggable, Requestable, Presentable, Notifiable;
|
||||
use SoftDeletes;
|
||||
|
||||
const LOCATION = 'location';
|
||||
@@ -66,6 +68,7 @@ class Asset extends Depreciable
|
||||
'asset_tag' => 'required|min:1|max:255|unique_undeleted',
|
||||
'status' => 'integer',
|
||||
'purchase_cost' => 'numeric|nullable',
|
||||
'next_audit_date' => 'date|nullable',
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -76,6 +79,7 @@ class Asset extends Depreciable
|
||||
protected $fillable = [
|
||||
'asset_tag',
|
||||
'assigned_to',
|
||||
'assigned_type',
|
||||
'company_id',
|
||||
'image',
|
||||
'model_id',
|
||||
@@ -140,7 +144,7 @@ class Asset extends Depreciable
|
||||
* @return bool
|
||||
*/
|
||||
//FIXME: The admin parameter is never used. Can probably be removed.
|
||||
public function checkOut($target, $admin, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
|
||||
public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null)
|
||||
{
|
||||
if (!$target) {
|
||||
return false;
|
||||
@@ -160,41 +164,19 @@ class Asset extends Depreciable
|
||||
}
|
||||
|
||||
if ($this->requireAcceptance()) {
|
||||
if(get_class($target) != User::class) {
|
||||
throw new CheckoutNotAllowed;
|
||||
}
|
||||
$this->accepted="pending";
|
||||
}
|
||||
|
||||
if ($this->save()) {
|
||||
$this->logCheckout($note, $target);
|
||||
// if ((($this->requireAcceptance()=='1') || ($this->getEula())) && ($user->email!='')) {
|
||||
// $this->checkOutNotifyMail($log->id, $user, $checkout_at, $expected_checkin, $note);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function checkOutNotifyMail($log_id, $user, $checkout_at, $expected_checkin, $note)
|
||||
{
|
||||
$data['log_id'] = $log_id;
|
||||
$data['eula'] = $this->getEula();
|
||||
$data['first_name'] = $user->first_name;
|
||||
$data['item_name'] = $this->present()->name();
|
||||
$data['checkout_date'] = $checkout_at;
|
||||
$data['expected_checkin'] = $expected_checkin;
|
||||
$data['item_tag'] = $this->asset_tag;
|
||||
$data['note'] = $note;
|
||||
$data['item_serial'] = $this->serial;
|
||||
$data['require_acceptance'] = $this->requireAcceptance();
|
||||
|
||||
if ((($this->requireAcceptance()=='1') || ($this->getEula())) && (!config('app.lock_passwords'))) {
|
||||
\Mail::send('emails.accept-asset', $data, function ($m) use ($user) {
|
||||
$m->to($user->email, $user->first_name . ' ' . $user->last_name);
|
||||
$m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
|
||||
$m->subject(trans('mail.Confirm_asset_delivery'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public function getDetailedNameAttribute()
|
||||
{
|
||||
if ($this->assignedTo) {
|
||||
@@ -246,16 +228,14 @@ class Asset extends Depreciable
|
||||
->orderBy('created_at', 'desc');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Even though we allow allow for checkout to things beyond users
|
||||
* this method is an easy way of seeing if we are checked out to a user.
|
||||
* @return mixed
|
||||
*/
|
||||
public function assigneduser()
|
||||
public function checkedOutToUser()
|
||||
{
|
||||
return $this->belongsTo('\App\Models\User', 'assigned_to')
|
||||
->withTrashed();
|
||||
return $this->assignedType() === self::USER;
|
||||
}
|
||||
|
||||
public function assignedTo()
|
||||
@@ -274,15 +254,19 @@ class Asset extends Depreciable
|
||||
public function assetLoc()
|
||||
{
|
||||
if (!empty($this->assignedType())) {
|
||||
// dd($this->assignedType());
|
||||
if ($this->assignedType() == self::ASSET) {
|
||||
return $this->assignedTo->assetloc(); // Recurse until we have a final location
|
||||
} elseif ($this->assignedType() == self::LOCATION) {
|
||||
return $this->assignedto->assetloc(); // Recurse until we have a final location
|
||||
}
|
||||
if ($this->assignedType() == self::LOCATION) {
|
||||
return $this->assignedTo();
|
||||
} elseif (!$this->assignedTo) {
|
||||
return $this->defaultLoc();
|
||||
} elseif ($this->assignedType() == self::USER) {
|
||||
}
|
||||
if ($this->assignedType() == self::USER) {
|
||||
return $this->assignedTo->userLoc();
|
||||
}
|
||||
if (!$this->assignedTo) {
|
||||
return $this->defaultLoc();
|
||||
}
|
||||
}
|
||||
return $this->defaultLoc();
|
||||
}
|
||||
@@ -544,7 +528,7 @@ class Asset extends Depreciable
|
||||
|
||||
|
||||
/**
|
||||
* Query builder scope for pending assets
|
||||
* Query builder scope for searching location
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
*
|
||||
@@ -554,8 +538,17 @@ class Asset extends Depreciable
|
||||
public function scopeAssetsByLocation($query, $location)
|
||||
{
|
||||
return $query->where(function ($query) use ($location) {
|
||||
$query->whereHas('assigneduser', function ($query) use ($location) {
|
||||
$query->where('users.location_id', '=', $location->id);
|
||||
$query->whereHas('assignedTo', function ($query) use ($location) {
|
||||
$query->where([
|
||||
['users.location_id', '=', $location->id],
|
||||
['assets.assigned_type', '=', User::class]
|
||||
])->orWhere([
|
||||
['locations.id', '=', $location->id],
|
||||
['assets.assigned_type', '=', Location::class]
|
||||
])->orWhere([
|
||||
['assets.rtd_location_id', '=', $location->id],
|
||||
['assets.assigned_type', '=', Asset::class]
|
||||
]);
|
||||
})->orWhere(function ($query) use ($location) {
|
||||
$query->where('assets.rtd_location_id', '=', $location->id);
|
||||
$query->whereNull('assets.assigned_to');
|
||||
@@ -775,18 +768,26 @@ class Asset extends Depreciable
|
||||
$query->whereHas('defaultLoc', function ($query) use ($search) {
|
||||
$query->where('locations.name', 'LIKE', '%'.$search.'%');
|
||||
});
|
||||
})->orWhere(function ($query) use ($search) {
|
||||
$query->whereHas('assigneduser', function ($query) use ($search) {
|
||||
$query->where(function ($query) use ($search) {
|
||||
$query->where('users.first_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('users.last_name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere(function ($query) use ($search) {
|
||||
$query->whereHas('userloc', function ($query) use ($search) {
|
||||
$query->where('locations.name', 'LIKE', '%'.$search.'%');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
//FIXME: This needs attention to work with checkout to not-users.
|
||||
// })->orWhere(function ($query) use ($search) {
|
||||
// $query->whereHas('assignedTo', function ($query) use ($search) {
|
||||
// $query->where(function ($query) use ($search) {
|
||||
// $query->where('assets.assigned_type', '=', User::class)
|
||||
// ->join('users', 'users.id', '=', 'assets.assigned_to')
|
||||
// ->where(function($query) use ($search) {
|
||||
// $query->where('users.first_name', 'LIKE', '%'.$search.'%')
|
||||
// ->orWhere('users.last_name', 'LIKE', '%'.$search.'%');
|
||||
// });
|
||||
// })->orWhere(function ($query) use ($search) {
|
||||
// $query->where('assets.assigned_type', '=', Location::class)
|
||||
// ->join('locations', 'locations.id', '=', 'assets.assigned_to')
|
||||
// ->where('locations.name', 'LIKE', '%'.$search.'%');
|
||||
// })->orWhere(function ($query) use ($search) {
|
||||
// $query->where('assets.assigned_type', '=', Asset::class)
|
||||
// ->join('assets as assigned_asset', 'assigned_assets.id', '=', 'assets.assigned_to')
|
||||
// ->where('assigned_assets.name', 'LIKE', '%'.$search.'%');
|
||||
// });
|
||||
// });
|
||||
})->orWhere('assets.name', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assets.asset_tag', 'LIKE', '%'.$search.'%')
|
||||
->orWhere('assets.serial', 'LIKE', '%'.$search.'%')
|
||||
@@ -1088,14 +1089,16 @@ class Asset extends Depreciable
|
||||
return $query->where(function ($query) use ($search) {
|
||||
$query->whereHas('defaultLoc', function ($query) use ($search) {
|
||||
$query->where('locations.id', '=', $search);
|
||||
})->whereNull('assigned_to');
|
||||
})->orWhere(function ($query) use ($search) {
|
||||
$query->whereHas('assigneduser', function ($query) use ($search) {
|
||||
$query->whereHas('userloc', function ($query) use ($search) {
|
||||
$query->where('locations.id', '=', $search);
|
||||
});
|
||||
});
|
||||
});
|
||||
// FIXME: This needs porting to checkout to non-user.
|
||||
// ->orWhere(function ($query) use ($search) {
|
||||
// $query->whereHas('assigneduser', function ($query) use ($search) {
|
||||
// $query->whereHas('userloc', function ($query) use ($search) {
|
||||
// $query->where('locations.id', '=', $search);
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ class AssetModel extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['name','manufacturer_id','category_id','eol', 'user_id', 'fieldset_id'];
|
||||
protected $fillable = ['name','manufacturer_id','category_id','eol', 'user_id', 'fieldset_id', 'model_number', 'notes'];
|
||||
|
||||
public function assets()
|
||||
{
|
||||
|
||||
@@ -73,7 +73,7 @@ class Consumable extends SnipeModel
|
||||
return $this->belongsTo('\App\Models\User', 'user_id');
|
||||
}
|
||||
|
||||
public function consumableAssigments()
|
||||
public function consumableAssignments()
|
||||
{
|
||||
return $this->hasMany('\App\Models\ConsumableAssignment');
|
||||
}
|
||||
|
||||
@@ -38,12 +38,10 @@ class CustomField extends Model
|
||||
public static function boot()
|
||||
{
|
||||
self::created(function ($custom_field) {
|
||||
\Log::debug("\n\nCreating Original Name: ".$custom_field->name);
|
||||
\Log::debug('Creating Column Name: '.$custom_field->convertUnicodeDbSlug());
|
||||
|
||||
|
||||
// column exists - nothing to do here
|
||||
if (Schema::hasColumn(CustomField::$table_name, $custom_field->convertUnicodeDbSlug())) {
|
||||
\Log::debug('Column exists. Nothing to do here.');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -57,18 +55,13 @@ class CustomField extends Model
|
||||
|
||||
|
||||
self::updating(function ($custom_field) {
|
||||
\Log::debug('Updating column name');
|
||||
\Log::debug('Updating Original Name: '.$custom_field->getOriginal("name"));
|
||||
\Log::debug('Updating New Column Name: '.$custom_field->convertUnicodeDbSlug());
|
||||
|
||||
// Column already exists. Nothing to update.
|
||||
if ($custom_field->isDirty("name")) {
|
||||
if (Schema::hasColumn(CustomField::$table_name, $custom_field->convertUnicodeDbSlug())) {
|
||||
\Log::debug('Column already exists. Nothing to update.');
|
||||
return true;
|
||||
}
|
||||
|
||||
\Log::debug('Updating column name to.'.$custom_field->convertUnicodeDbSlug());
|
||||
|
||||
return Schema::table(CustomField::$table_name, function ($table) use ($custom_field) {
|
||||
$table->renameColumn($custom_field->convertUnicodeDbSlug($custom_field->getOriginal("name")), $custom_field->convertUnicodeDbSlug());
|
||||
});
|
||||
@@ -85,7 +78,7 @@ class CustomField extends Model
|
||||
|
||||
public function fieldset()
|
||||
{
|
||||
return $this->belongsToMany('\App\Models\CustomFieldset'); //?!?!?!?!?!?
|
||||
return $this->belongsToMany('\App\Models\CustomFieldset');
|
||||
}
|
||||
|
||||
public function user()
|
||||
@@ -102,10 +95,9 @@ class CustomField extends Model
|
||||
public function db_column_name()
|
||||
{
|
||||
return $this->db_column;
|
||||
// return self::convertUnicodeDbSlug();
|
||||
}
|
||||
|
||||
//mutators for 'format' attribute
|
||||
// mutators for 'format' attribute
|
||||
public function getFormatAttribute($value)
|
||||
{
|
||||
foreach (self::$PredefinedFormats as $name => $pattern) {
|
||||
@@ -116,6 +108,13 @@ class CustomField extends Model
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a value string as an array for select boxes and checkboxes.
|
||||
*
|
||||
* @author [A. Gianotto] [<snipe@snipe.net>]
|
||||
* @since [v3.4]
|
||||
* @return Array
|
||||
*/
|
||||
public function setFormatAttribute($value)
|
||||
{
|
||||
if (isset(self::$PredefinedFormats[$value])) {
|
||||
|
||||
@@ -110,7 +110,7 @@ class Ldap extends Model
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$user = array_change_key_case(ldap_get_attributes($connection, $entry), CASE_LOWER)) {
|
||||
if (!$user = ldap_get_attributes($connection, $entry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -401,6 +401,20 @@ class License extends Depreciable
|
||||
->orderBy('manufacturers.name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on supplier
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query Query builder instance
|
||||
* @param text $order Order
|
||||
*
|
||||
* @return \Illuminate\Database\Query\Builder Modified query builder
|
||||
*/
|
||||
public function scopeOrderSupplier($query, $order)
|
||||
{
|
||||
return $query->leftJoin('suppliers', 'licenses.supplier_id', '=', 'suppliers.id')->select('licenses.*')
|
||||
->orderBy('suppliers.name', $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query builder scope to order on company
|
||||
*
|
||||
|
||||
@@ -24,6 +24,7 @@ class Location extends SnipeModel
|
||||
'address' => 'max:80|nullable',
|
||||
'address2' => 'max:80|nullable',
|
||||
'zip' => 'min:3|max:10|nullable',
|
||||
// 'manager_id' => 'exists:users'
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -63,7 +64,12 @@ class Location extends SnipeModel
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('\App\Models\Location', 'parent_id');
|
||||
return $this->belongsTo('\App\Models\Location', 'parent_id','id');
|
||||
}
|
||||
|
||||
public function manager()
|
||||
{
|
||||
return $this->belongsTo('\App\Models\User', 'manager_id');
|
||||
}
|
||||
|
||||
public function childLocations()
|
||||
|
||||
@@ -7,6 +7,7 @@ use App\Models\Asset;
|
||||
use App\Models\CheckoutRequest;
|
||||
use App\Models\User;
|
||||
use App\Notifications\CheckinNotification;
|
||||
use App\Notifications\AuditNotification;
|
||||
use App\Notifications\CheckoutNotification;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
@@ -29,11 +30,56 @@ trait Loggable
|
||||
* @since [v3.4]
|
||||
* @return \App\Models\Actionlog
|
||||
*/
|
||||
public function logCheckout($note, $target = null /*target is overridable for components*/)
|
||||
public function logCheckout($note, $target /* What are we checking out to? */)
|
||||
{
|
||||
$log = new Actionlog;
|
||||
$log = $this->determineLogItemType($log);
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
||||
// We need to special case licenses because of license_seat vs license. So much for clean polymorphism :)
|
||||
if (!isset($target)) {
|
||||
throw new Exception('All checkout logs require a target');
|
||||
return;
|
||||
}
|
||||
$log->target_type = get_class($target);
|
||||
$log->target_id = $target->id;
|
||||
|
||||
$class = get_class($target);
|
||||
if ($class == Location::class) {
|
||||
// We can checkout to a location
|
||||
$log->location_id = $target->id;
|
||||
} else if ($class== Asset::class) {
|
||||
$log->location_id = $target->rtd_location_id;
|
||||
} else {
|
||||
$log->location_id = $target->location_id;
|
||||
}
|
||||
$log->note = $note;
|
||||
$log->logaction('checkout');
|
||||
|
||||
$params = [
|
||||
'item' => $this,
|
||||
'target' => $target,
|
||||
'admin' => $log->user,
|
||||
'note' => $note,
|
||||
'log_id' => $log->id
|
||||
];
|
||||
|
||||
if ($settings = Setting::getSettings()) {
|
||||
$settings->notify(new CheckoutNotification($params));
|
||||
}
|
||||
|
||||
if (method_exists($target, 'notify')) {
|
||||
$target->notify(new CheckoutNotification($params));
|
||||
}
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to determine the log item type
|
||||
*/
|
||||
private function determineLogItemType($log)
|
||||
{
|
||||
// We need to special case licenses because of license_seat vs license. So much for clean polymorphism :
|
||||
if (static::class == LicenseSeat::class) {
|
||||
$log->item_type = License::class;
|
||||
$log->item_id = $this->license_id;
|
||||
@@ -42,49 +88,8 @@ trait Loggable
|
||||
$log->item_id = $this->id;
|
||||
}
|
||||
|
||||
$log->user_id = Auth::user()->id;
|
||||
|
||||
// @FIXME This needs to be generalized with new asset checkout.
|
||||
if(isset($target)) {
|
||||
$log->target_type = get_class($target);
|
||||
$log->target_id = $target->id;
|
||||
} else {
|
||||
if (!is_null($this->asset_id)) {
|
||||
$log->target_type = Asset::class;
|
||||
$log->target_id = $this->asset_id;
|
||||
} elseif (!is_null($this->assigned_to)) {
|
||||
$log->target_type = User::class;
|
||||
$log->target_id = $this->assigned_to;
|
||||
}
|
||||
}
|
||||
|
||||
$item = call_user_func(array($log->target_type, 'find'), $log->target_id);
|
||||
if($this->assignedTo) {
|
||||
$item = $this->assignedTo;
|
||||
}
|
||||
$class = get_class($item);
|
||||
if($class == Location::class) {
|
||||
// We can checkout to a location
|
||||
$log->location_id = $item->id;
|
||||
} else if ($class== Asset::class) {
|
||||
$log->location_id = $item->rtd_location_id;
|
||||
} else {
|
||||
$log->location_id = $item->location_id;
|
||||
}
|
||||
$log->note = $note;
|
||||
$log->logaction('checkout');
|
||||
|
||||
$params = [
|
||||
'item' => $log->item,
|
||||
'target' => $log->target,
|
||||
'admin' => $log->user,
|
||||
'note' => $note
|
||||
];
|
||||
Setting::getSettings()->notify(new CheckoutNotification($params));
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
|
||||
* @since [v3.4]
|
||||
@@ -117,6 +122,41 @@ trait Loggable
|
||||
return $log;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @author A. Gianotto <snipe@snipe.net>
|
||||
* @since [v4.0]
|
||||
* @return \App\Models\Actionlog
|
||||
*/
|
||||
public function logAudit($note, $location_id)
|
||||
{
|
||||
$log = new Actionlog;
|
||||
$location = Location::find($location_id);
|
||||
if (static::class == LicenseSeat::class) {
|
||||
$log->item_type = License::class;
|
||||
$log->item_id = $this->license_id;
|
||||
} else {
|
||||
$log->item_type = static::class;
|
||||
$log->item_id = $this->id;
|
||||
}
|
||||
$log->location_id = ($location_id) ? $location_id : null;
|
||||
$log->note = $note;
|
||||
$log->user_id = Auth::user()->id;
|
||||
$log->logaction('audit');
|
||||
|
||||
$params = [
|
||||
'item' => $log->item,
|
||||
'admin' => $log->user,
|
||||
'location' => ($location) ? $location->name : '',
|
||||
'note' => $note
|
||||
];
|
||||
Setting::getSettings()->notify(new AuditNotification($params));
|
||||
|
||||
return $log;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author Daniel Meltzer <parallelgrapefruit@gmail.com
|
||||
* @since [v3.5]
|
||||
|
||||
@@ -19,9 +19,9 @@ trait Requestable
|
||||
|
||||
public function isRequestedBy(User $user)
|
||||
{
|
||||
return $this->requests()
|
||||
->where('user_id', $user->id)
|
||||
->exists();
|
||||
$requests = $this->requests->where('user_id', $user->id);
|
||||
|
||||
return $requests->count() > 0;
|
||||
}
|
||||
|
||||
public function scopeRequestedBy($query, User $user)
|
||||
|
||||
@@ -14,36 +14,30 @@ class Setting extends Model
|
||||
|
||||
protected $rules = [
|
||||
"brand" => 'required|min:1|numeric',
|
||||
"qr_text" => 'max:31',
|
||||
"qr_text" => 'max:31|nullable',
|
||||
"logo_img" => 'mimes:jpeg,bmp,png,gif',
|
||||
"alert_email" => 'email_array',
|
||||
"alert_email" => 'email_array|nullable',
|
||||
"default_currency" => 'required',
|
||||
"locale" => 'required',
|
||||
"slack_endpoint" => 'url|required_with:slack_channel',
|
||||
"slack_channel" => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint',
|
||||
"slack_endpoint" => 'url|required_with:slack_channel|nullable',
|
||||
"slack_channel" => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint|nullable',
|
||||
"slack_botname" => 'string|nullable',
|
||||
'labels_per_page' => 'numeric',
|
||||
'labels_width' => 'numeric',
|
||||
'labels_height' => 'numeric',
|
||||
'labels_pmargin_left' => 'numeric',
|
||||
'labels_pmargin_right' => 'numeric',
|
||||
'labels_pmargin_top' => 'numeric',
|
||||
'labels_pmargin_bottom' => 'numeric',
|
||||
'labels_display_bgutter' => 'numeric',
|
||||
'labels_display_sgutter' => 'numeric',
|
||||
'labels_pmargin_left' => 'numeric|nullable',
|
||||
'labels_pmargin_right' => 'numeric|nullable',
|
||||
'labels_pmargin_top' => 'numeric|nullable',
|
||||
'labels_pmargin_bottom' => 'numeric|nullable',
|
||||
'labels_display_bgutter' => 'numeric|nullable',
|
||||
'labels_display_sgutter' => 'numeric|nullable',
|
||||
'labels_fontsize' => 'numeric|min:5',
|
||||
'labels_pagewidth' => 'numeric',
|
||||
'labels_pageheight' => 'numeric',
|
||||
"ldap_server" => 'sometimes|required_if:ldap_enabled,1|url',
|
||||
"ldap_uname" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_basedn" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_filter" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_username_field" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_fname_field" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_lname_field" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_auth_filter_query" => 'sometimes|required_if:ldap_enabled,1',
|
||||
"ldap_version" => 'sometimes|required_if:ldap_enabled,1',
|
||||
'labels_pagewidth' => 'numeric|nullable',
|
||||
'labels_pageheight' => 'numeric|nullable',
|
||||
"thumbnail_max_h" => 'numeric|max:500|min:25',
|
||||
"pwd_secure_min" => "numeric|required|min:5",
|
||||
"audit_warning_days" => "numeric|nullable",
|
||||
"audit_interval" => "numeric|nullable",
|
||||
];
|
||||
|
||||
protected $fillable = ['site_name','email_domain','email_format','username_format'];
|
||||
@@ -158,4 +152,30 @@ class Setting extends Model
|
||||
// In the future this may want to be adapted for individual notifications.
|
||||
return $this->slack_endpoint;
|
||||
}
|
||||
|
||||
public static function passwordComplexityRulesSaving($action = 'update')
|
||||
{
|
||||
$security_rules = '';
|
||||
$settings = Setting::getSettings();
|
||||
|
||||
// Check if they have uncommon password enforcement selected in settings
|
||||
if ($settings->pwd_secure_uncommon == 1) {
|
||||
$security_rules .= '|dumbpwd';
|
||||
}
|
||||
|
||||
// Check for any secure password complexity rules that may have been selected
|
||||
if ($settings->pwd_secure_complexity!='') {
|
||||
$security_rules .= '|'.$settings->pwd_secure_complexity;
|
||||
}
|
||||
|
||||
if ($action == 'update') {
|
||||
return 'nullable|min:'.$settings->pwd_secure_min.$security_rules;
|
||||
}
|
||||
|
||||
return 'required|min:'.$settings->pwd_secure_min.$security_rules;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class Supplier extends SnipeModel
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['name'];
|
||||
protected $fillable = ['name','address','address2','city','state','country','zip','phone','fax','email','contact','url','notes'];
|
||||
|
||||
|
||||
// Eager load counts.
|
||||
|
||||
@@ -51,9 +51,9 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
|
||||
protected $rules = [
|
||||
'first_name' => 'required|string|min:1',
|
||||
'username' => 'required|string|min:1|unique_undeleted',
|
||||
'email' => 'email',
|
||||
'email' => 'email|nullable',
|
||||
'password' => 'required|min:6',
|
||||
'locale' => 'max:10'
|
||||
'locale' => 'max:10|nullable'
|
||||
];
|
||||
|
||||
|
||||
@@ -205,6 +205,14 @@ class User extends SnipeModel implements AuthenticatableContract, CanResetPasswo
|
||||
return $this->belongsTo('\App\Models\User', 'manager_id')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any locations the user manages.
|
||||
**/
|
||||
public function managedLocations()
|
||||
{
|
||||
return $this->hasMany('\App\Models\Location', 'manager_id')->withTrashed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user groups
|
||||
*/
|
||||
|
||||
88
app/Notifications/AuditNotification.php
Normal file
88
app/Notifications/AuditNotification.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
|
||||
class AuditNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
//
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$notifyBy = [];
|
||||
if (Setting::getSettings()->slack_endpoint) {
|
||||
$notifyBy[] = 'slack';
|
||||
}
|
||||
|
||||
return $notifyBy;
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
return (new SlackMessage)
|
||||
->success()
|
||||
->content(class_basename(get_class($this->params['item'])) . " Audited")
|
||||
->attachment(function ($attachment) use ($notifiable) {
|
||||
$item = $this->params['item'];
|
||||
$admin_user = $this->params['admin'];
|
||||
$fields = [
|
||||
'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->present()->fullName().'>'
|
||||
];
|
||||
array_key_exists('note', $this->params) && $fields['Notes'] = $this->params['note'];
|
||||
array_key_exists('location', $this->params) && $fields['Location'] = $this->params['location'];
|
||||
|
||||
$attachment->title($item->present()->name, $item->present()->viewUrl())
|
||||
->fields($fields);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,11 @@ namespace App\Notifications;
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class CheckoutNotification extends Notification
|
||||
{
|
||||
@@ -43,11 +44,12 @@ class CheckoutNotification extends Notification
|
||||
}
|
||||
$item = $this->params['item'];
|
||||
|
||||
if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
|
||||
|| (method_exists($item, 'getEula') && ($item->getEula()))
|
||||
) {
|
||||
$notifyBy[] = 'mail';
|
||||
}
|
||||
$notifyBy[]='mail';
|
||||
// if ((method_exists($item, 'requireAcceptance') && ($item->requireAcceptance()=='1'))
|
||||
// || (method_exists($item, 'getEula') && ($item->getEula()))
|
||||
// ) {
|
||||
// $notifyBy[] = 'mail';
|
||||
// }
|
||||
return $notifyBy;
|
||||
}
|
||||
|
||||
@@ -79,10 +81,30 @@ class CheckoutNotification extends Notification
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
//TODO: Expand for non assets.
|
||||
$item = $this->params['item'];
|
||||
$admin_user = $this->params['admin'];
|
||||
$target = $this->params['target'];
|
||||
$data = [
|
||||
'eula' => method_exists($item, 'getEula') ? $item->getEula() : '',
|
||||
'first_name' => $target->present()->fullName(),
|
||||
'item_name' => $item->present()->name(),
|
||||
'checkout_date' => $item->last_checkout,
|
||||
'expected_checkin' => $item->expected_checkin,
|
||||
'item_tag' => $item->asset_tag,
|
||||
'note' => $this->params['note'],
|
||||
'item_serial' => $item->serial,
|
||||
'require_acceptance' => $item->requireAcceptance(),
|
||||
'log_id' => $this->params['log_id'],
|
||||
];
|
||||
return (new MailMessage)
|
||||
->line('The introduction to the notification.')
|
||||
->action('Notification Action', 'https://laravel.com')
|
||||
->line('Thank you for using our application!');
|
||||
->view('emails.accept-asset', $data)
|
||||
->subject(trans('mail.Confirm_asset_delivery'));
|
||||
// \Mail::send('emails.accept-asset', $data, function ($m) use ($target) {
|
||||
// $m->to($target->email, $target->first_name . ' ' . $target->last_name);
|
||||
// $m->replyTo(config('mail.reply_to.address'), config('mail.reply_to.name'));
|
||||
// $m->subject(trans('mail.Confirm_asset_delivery'));
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
86
app/Notifications/ExpectedCheckinNotification.php
Normal file
86
app/Notifications/ExpectedCheckinNotification.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use App\Models\Setting;
|
||||
use App\Models\SnipeModel;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class ExpectedCheckinNotification extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
/**
|
||||
* @var
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @param $params
|
||||
*/
|
||||
public function __construct($params)
|
||||
{
|
||||
$this->params = $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
$notifyBy = [];
|
||||
$item = $this->params['item'];
|
||||
|
||||
$notifyBy[]='mail';
|
||||
return $notifyBy;
|
||||
}
|
||||
|
||||
public function toSlack($notifiable)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $asset
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($params)
|
||||
{
|
||||
$formatted_due = Carbon::parse($this->params->expected_checkin)->format('D, M j, Y');
|
||||
return (new MailMessage)
|
||||
->error()
|
||||
->subject('Reminder: '.$this->params->present()->name().' checkin deadline approaching')
|
||||
->line('Hi, '.$this->params->assignedto->first_name)
|
||||
->greeting('An asset checked out to you is due to be checked back in on '.$formatted_due.'.')
|
||||
->line('Asset: '.$this->params->present()->name())
|
||||
->line('Serial: '.$this->params->serial)
|
||||
->line('Asset Tag: '.$this->params->asset_tag)
|
||||
->action('View Your Assets', route('view-assets'));
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -28,8 +28,7 @@ class AccessoryObserver
|
||||
|
||||
|
||||
/**
|
||||
* Listen to the Accessory created event, and increment
|
||||
* the next_auto_tag_base value in the settings table when i
|
||||
* Listen to the Accessory created event when
|
||||
* a new accessory is created.
|
||||
*
|
||||
* @param Accessory $accessory
|
||||
@@ -37,9 +36,6 @@ class AccessoryObserver
|
||||
*/
|
||||
public function created(Accessory $accessory)
|
||||
{
|
||||
$settings = Setting::first();
|
||||
$settings->increment('next_auto_tag_base');
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Accessory::class;
|
||||
$logAction->item_id = $accessory->id;
|
||||
|
||||
@@ -18,7 +18,9 @@ class AssetObserver
|
||||
public function updating(Asset $asset)
|
||||
{
|
||||
|
||||
if (($asset->getAttributes()['assigned_to'] == $asset->getOriginal()['assigned_to'])
|
||||
|
||||
if ((isset($asset->getOriginal()['assigned_to'])) && ($asset->getAttributes()['assigned_to'] == $asset->getOriginal()['assigned_to'])
|
||||
&& ($asset->getAttributes()['next_audit_date'] == $asset->getOriginal()['next_audit_date'])
|
||||
&& ($asset->getAttributes()['last_checkout'] == $asset->getOriginal()['last_checkout'])
|
||||
&& ($asset->getAttributes()['status_id'] == $asset->getOriginal()['status_id']))
|
||||
{
|
||||
@@ -43,8 +45,9 @@ class AssetObserver
|
||||
*/
|
||||
public function created(Asset $asset)
|
||||
{
|
||||
$settings = Setting::first();
|
||||
$settings->increment('next_auto_tag_base');
|
||||
if ($settings = Setting::first()) {
|
||||
$settings->increment('next_auto_tag_base');
|
||||
}
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Asset::class;
|
||||
|
||||
@@ -28,8 +28,7 @@ class ComponentObserver
|
||||
|
||||
|
||||
/**
|
||||
* Listen to the Component created event, and increment
|
||||
* the next_auto_tag_base value in the settings table when i
|
||||
* Listen to the Component created event when
|
||||
* a new component is created.
|
||||
*
|
||||
* @param Component $component
|
||||
@@ -37,9 +36,6 @@ class ComponentObserver
|
||||
*/
|
||||
public function created(Component $component)
|
||||
{
|
||||
$settings = Setting::first();
|
||||
$settings->increment('next_auto_tag_base');
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Component::class;
|
||||
$logAction->item_id = $component->id;
|
||||
|
||||
@@ -28,8 +28,7 @@ class ConsumableObserver
|
||||
|
||||
|
||||
/**
|
||||
* Listen to the Consumable created event, and increment
|
||||
* the next_auto_tag_base value in the settings table when i
|
||||
* Listen to the Consumable created event when
|
||||
* a new consumable is created.
|
||||
*
|
||||
* @param Consumable $consumable
|
||||
@@ -37,8 +36,6 @@ class ConsumableObserver
|
||||
*/
|
||||
public function created(Consumable $consumable)
|
||||
{
|
||||
$settings = Setting::first();
|
||||
$settings->increment('next_auto_tag_base');
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = Consumable::class;
|
||||
|
||||
@@ -28,8 +28,7 @@ class LicenseObserver
|
||||
|
||||
|
||||
/**
|
||||
* Listen to the License created event, and increment
|
||||
* the next_auto_tag_base value in the settings table when i
|
||||
* Listen to the License created event when
|
||||
* a new license is created.
|
||||
*
|
||||
* @param License $license
|
||||
@@ -37,8 +36,6 @@ class LicenseObserver
|
||||
*/
|
||||
public function created(License $license)
|
||||
{
|
||||
$settings = Setting::first();
|
||||
$settings->increment('next_auto_tag_base');
|
||||
|
||||
$logAction = new Actionlog();
|
||||
$logAction->item_type = License::class;
|
||||
|
||||
@@ -98,15 +98,14 @@ class AssetPresenter extends Presenter
|
||||
"sortable" => true,
|
||||
"title" => trans('admin/hardware/form.checkedout_to'),
|
||||
"visible" => true,
|
||||
"formatter" => "usersLinkObjFormatter"
|
||||
"formatter" => "polymorphicItemFormatter"
|
||||
], [
|
||||
"field" => "assigned_to",
|
||||
"field" => "employee_number",
|
||||
"searchable" => false,
|
||||
"sortable" => false,
|
||||
"title" => trans('admin/users/table.employee_num'),
|
||||
"visible" => false,
|
||||
"formatter" => "employeeNumFormatter"
|
||||
|
||||
],[
|
||||
"field" => "location",
|
||||
"searchable" => true,
|
||||
|
||||
@@ -61,6 +61,14 @@ class LicensePresenter extends Presenter
|
||||
"searchable" => true,
|
||||
"sortable" => true,
|
||||
"title" => trans('admin/licenses/form.to_name'),
|
||||
], [
|
||||
"field" => "supplier",
|
||||
"searchable" => true,
|
||||
"sortable" => true,
|
||||
"switchable" => true,
|
||||
"title" => trans('general.supplier'),
|
||||
"visible" => false,
|
||||
"formatter" => "suppliersLinkObjFormatter"
|
||||
], [
|
||||
"field" => "manufacturer",
|
||||
"searchable" => true,
|
||||
|
||||
@@ -42,4 +42,8 @@ class LocationPresenter extends Presenter
|
||||
{
|
||||
return '<i class="fa fa-globe"></i>';
|
||||
}
|
||||
|
||||
public function fullName() {
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,11 @@ abstract class Presenter
|
||||
return '';
|
||||
}
|
||||
|
||||
public function name()
|
||||
{
|
||||
return $this->model->name;
|
||||
}
|
||||
|
||||
public function __get($property)
|
||||
{
|
||||
if (method_exists($this, $property)) {
|
||||
|
||||
@@ -67,11 +67,15 @@ class AppServiceProvider extends ServiceProvider
|
||||
// This works around the use case where multiple deleted items have the same unique attribute.
|
||||
// (I think this is a bug in Laravel's validator?)
|
||||
Validator::extend('unique_undeleted', function ($attribute, $value, $parameters, $validator) {
|
||||
$count = DB::table($parameters[0])->select('id')->where($attribute, '=', $value)->whereNull('deleted_at')->where('id', '!=', $parameters[1])->count();
|
||||
return $count < 1;
|
||||
|
||||
if (count($parameters)) {
|
||||
$count = DB::table($parameters[0])->select('id')->where($attribute, '=', $value)->whereNull('deleted_at')->where('id', '!=', $parameters[1])->count();
|
||||
return $count < 1;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// Share common variables with all views.
|
||||
// Share common setting variables with all views.
|
||||
view()->composer('*', function ($view) {
|
||||
$view->with('snipeSettings', \App\Models\Setting::getSettings());
|
||||
});
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -15,7 +15,7 @@
|
||||
"fideloper/proxy": "^3.1",
|
||||
"intervention/image": "^2.3",
|
||||
"javiereguiluz/easyslugger": "^1.0",
|
||||
"laravel/framework": "5.4.27",
|
||||
"laravel/framework": "5.4.20",
|
||||
"laravel/passport": "^1.0",
|
||||
"laravel/tinker": "^1.0",
|
||||
"laravelcollective/html": "^5.3",
|
||||
@@ -24,9 +24,13 @@
|
||||
"neitanod/forceutf8": "^2.0",
|
||||
"patchwork/utf8": "~1.2",
|
||||
"pragmarx/google2fa": "^1.0",
|
||||
"schuppo/password-strength": "~1.5",
|
||||
"spatie/laravel-backup": "^3.0.0",
|
||||
"tecnickcom/tc-lib-barcode": "^1.15",
|
||||
"watson/validating": "^3.0"
|
||||
"unicodeveloper/laravel-password": "^1.0",
|
||||
"watson/validating": "^3.0",
|
||||
"doctrine/instantiator": "1.0.5",
|
||||
"doctrine/inflector": "1.0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"fzaninotto/faker": "~1.4",
|
||||
@@ -34,7 +38,8 @@
|
||||
"symfony/css-selector": "3.1.*",
|
||||
"symfony/dom-crawler": "3.1.*",
|
||||
"codeception/codeception": "2.2.9",
|
||||
"squizlabs/php_codesniffer": "*"
|
||||
"squizlabs/php_codesniffer": "*",
|
||||
"phpunit/php-token-stream": "1.4.11"
|
||||
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
731
composer.lock
generated
731
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -220,6 +220,8 @@ return [
|
||||
PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider::class,
|
||||
Laravel\Passport\PassportServiceProvider::class,
|
||||
Laravel\Tinker\TinkerServiceProvider::class,
|
||||
Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class,
|
||||
Schuppo\PasswordStrength\PasswordStrengthServiceProvider::class,
|
||||
|
||||
|
||||
/*
|
||||
|
||||
@@ -85,8 +85,8 @@ return array(
|
||||
array(
|
||||
'permission' => 'assets.audit',
|
||||
'label' => 'Audit ',
|
||||
'note' => '',
|
||||
'display' => false,
|
||||
'note' => 'Allows the user to mark an asset as physically inventoried.',
|
||||
'display' => true,
|
||||
),
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
return array (
|
||||
'app_version' => 'v4.0-beta',
|
||||
'build_version' => '1',
|
||||
'hash_version' => 'gcb1e3b7',
|
||||
'full_hash' => 'v4.0-beta-244-gcb1e3b7',
|
||||
);
|
||||
'app_version' => 'v4.0',
|
||||
'build_version' => 'beta5',
|
||||
'hash_version' => '9',
|
||||
'full_hash' => 'v4.0-beta5-9-ga576435',
|
||||
);
|
||||
@@ -20,7 +20,7 @@ $factory->defineAs(Actionlog::class, 'asset-checkout', function (Faker\Generator
|
||||
$user = factory(App\Models\User::class)->create(['company_id' => $company->id]);
|
||||
$target = factory(App\Models\User::class)->create(['company_id' => $company->id]);
|
||||
// $item = factory(App\Models\Asset::class)->create(['company_id' => $company->id]);
|
||||
|
||||
// dd($item);
|
||||
return [
|
||||
'user_id' => $user->id,
|
||||
'action_type' => 'checkout',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Asset;
|
||||
use App\Models\AssetModel;
|
||||
use App\Models\Category;
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
@@ -69,6 +71,13 @@ $factory->state(Asset::class, 'assigned-to-asset', function ($faker) {
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Asset::class, 'requires-acceptance', function ($faker) {
|
||||
$cat = factory(Category::class)->states('asset-category', 'requires-acceptance')->create();
|
||||
$model = factory(AssetModel::class)->create(['category_id' => $cat->id]);
|
||||
return [
|
||||
'model_id' => $model->id
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(App\Models\AssetModel::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
|
||||
@@ -15,7 +15,7 @@ $factory->define(App\Models\Category::class, function (Faker\Generator $faker) {
|
||||
'name' => $faker->text(20),
|
||||
'category_type' => $faker->randomElement(['asset', 'accessory', 'component', 'consumable']),
|
||||
'eula_text' => $faker->paragraph(),
|
||||
'require_acceptance' => $faker->boolean(),
|
||||
'require_acceptance' => false,
|
||||
'use_default_eula' => $faker->boolean(),
|
||||
'checkin_email' => $faker->boolean()
|
||||
];
|
||||
@@ -44,3 +44,9 @@ $factory->state(App\Models\Category::class, 'consumable-category', function ($fa
|
||||
'category_type' => 'consumable',
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(App\Models\Category::class, 'requires-acceptance', function ($faker) {
|
||||
return [
|
||||
'require_acceptance' => true,
|
||||
];
|
||||
});
|
||||
|
||||
17
database/factories/CustomFieldsFactory.php
Normal file
17
database/factories/CustomFieldsFactory.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
$factory->define(App\Models\CustomField::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->catchPhrase,
|
||||
'format' => 'IP',
|
||||
'element' => 'text',
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(App\Models\CustomFieldset::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->catchPhrase,
|
||||
'user_id' => Auth::id()
|
||||
];
|
||||
});
|
||||
@@ -97,14 +97,6 @@ $factory->define(App\Models\Consumable::class, function (Faker\Generator $faker)
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(App\Models\CustomField::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->catchPhrase,
|
||||
'format' => 'IP',
|
||||
'element' => 'text',
|
||||
];
|
||||
});
|
||||
|
||||
$factory->define(App\Models\Department::class, function (Faker\Generator $faker) {
|
||||
return [
|
||||
'name' => $faker->catchPhrase,
|
||||
@@ -210,5 +202,6 @@ $factory->define(App\Models\Setting::class, function ($faker) {
|
||||
'brand' => 1,
|
||||
'default_currency' => $faker->currencyCode,
|
||||
'locale' => $faker->locale,
|
||||
'pwd_secure_min' => 5,
|
||||
];
|
||||
});
|
||||
|
||||
@@ -21,7 +21,7 @@ use Illuminate\Database\Schema\Blueprint;
|
||||
function updateLegacyColumnName($customfield) {
|
||||
|
||||
$name_to_db_name = CustomField::name_to_db_name($customfield->name);
|
||||
\Log::debug('Trying to rename '.$name_to_db_name." to ".$customfield->convertUnicodeDbSlug()."...\n");
|
||||
//\Log::debug('Trying to rename '.$name_to_db_name." to ".$customfield->convertUnicodeDbSlug()."...\n");
|
||||
|
||||
if (Schema::hasColumn(CustomField::$table_name, $name_to_db_name)) {
|
||||
|
||||
@@ -32,7 +32,7 @@ function updateLegacyColumnName($customfield) {
|
||||
);
|
||||
|
||||
} else {
|
||||
\Log::debug('Legacy DB column '.$name_to_db_name.' was not found on the assets table.');
|
||||
//\Log::debug('Legacy DB column '.$name_to_db_name.' was not found on the assets table.');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddManagerToLocationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('locations', function (Blueprint $table) {
|
||||
//
|
||||
$table->integer('manager_id')->nullable()->default(null);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('locations', function (Blueprint $table) {
|
||||
//
|
||||
$table->dropColumn('manager_id');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ class AddNextAutoincrementToSettings extends Migration
|
||||
$table->bigInteger('next_auto_tag_base')->default('1');
|
||||
});
|
||||
|
||||
\Log::debug('Setting '.$next.' as default auto-increment');
|
||||
//\Log::debug('Setting '.$next.' as default auto-increment');
|
||||
|
||||
if ($settings = App\Models\Setting::first()) {
|
||||
$settings->next_auto_tag_base = $next;
|
||||
|
||||
@@ -13,6 +13,9 @@ class SetAssetArchivedToZeroDefault extends Migration
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
$platform = Schema::getConnection()->getDoctrineSchemaManager()->getDatabasePlatform();
|
||||
$platform->registerDoctrineTypeMapping('enum', 'string');
|
||||
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
$table->boolean('archived')->default(0)->change();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddSecurePasswordOptions extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->boolean('pwd_secure_uncommon')->default('0');
|
||||
$table->string('pwd_secure_complexity')->nullable()->default(NULL);
|
||||
$table->integer('pwd_secure_min')->default('8');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->dropColumn('pwd_secure_uncommon');
|
||||
$table->dropColumn('pwd_secure_complexity');
|
||||
$table->dropColumn('pwd_secure_min');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddAuditingTables extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
$table->date('next_audit_date')->nullable()->default(NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('assets', function (Blueprint $table) {
|
||||
$table->dropColumn('next_audit_date');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddAuditingToSettings extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->integer('audit_interval')->nullable()->default(NULL);
|
||||
$table->integer('audit_warning_days')->nullable()->default(NULL);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('settings', function (Blueprint $table) {
|
||||
$table->dropColumn('audit_interval');
|
||||
$table->dropColumn('audit_warning_days');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Asset;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class FixAssignedTypeNotBeingNulled extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
* There was a point in the v4 beta process where assigned_type was not nulled on checkin
|
||||
* This manually nulls all assets where there is an assigned_type but not an assigned_to.
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
// There was a point in the v4 beta process where assigned_type was not nulled on checkin
|
||||
// This manually nulls all assets where there is an assigned_type but not an assigned_to.
|
||||
Asset::whereNotNull('assigned_type')->whereNull('assigned_to')->update(['assigned_type' => null]);
|
||||
|
||||
// Additionally, the importer did not set assigned_type when importing.
|
||||
// In the case where we have an assigned_to but not an assigned_type, set the assigned_type to User.
|
||||
Asset::whereNotNull('assigned_to')->whereNull('assigned_type')->update(['assigned_type' => 'App\Models\User']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user