From da015ec4a8a74b7aa7edecff50da132bd1001905 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 20 Mar 2019 01:24:31 -0700 Subject: [PATCH 01/26] Fixed #6834 and #6402 - use inline QR code generation for 2FA (#6840) * Fixed #6834 and #6402 - use inline QR code generation for * Update auth controllers to use translations * Updated composer lock * Added comments * Moar comments * Typo --- app/Http/Controllers/Auth/LoginController.php | 84 ++++-- composer.json | 3 +- composer.lock | 264 +++++++++++++----- config/app.php | 2 +- resources/lang/en/auth/message.php | 12 + .../views/auth/two_factor_enroll.blade.php | 2 +- 6 files changed, 267 insertions(+), 100 deletions(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index cfd9549d4e..7175e6064c 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -209,26 +209,33 @@ class LoginController extends Controller public function getTwoFactorEnroll() { + // Make sure the user is logged in if (!Auth::check()) { - return redirect()->route('login')->with('error', 'You must be logged in.'); + return redirect()->route('login')->with('error', trans('auth/general.login_prompt')); } + + $settings = Setting::getSettings(); $user = Auth::user(); - $google2fa = app()->make('PragmaRX\Google2FA\Contracts\Google2FA'); - if ($user->two_factor_secret=='') { - $user->two_factor_secret = $google2fa->generateSecretKey(32); - $user->save(); + // We wouldn't normally see this page if 2FA isn't enforced via the + // \App\Http\Middleware\CheckForTwoFactor middleware AND if a device isn't enrolled, + // but let's check check anyway in case there's a browser history or back button thing. + // While you can access this page directly, enrolling a device when 2FA isn't enforced + // won't cause any harm. + + if (($user->two_factor_secret!='') && ($user->two_factor_enrolled==1)) { + return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.already_enrolled')); } + $google2fa = new Google2FA(); + $secret = $google2fa->generateSecretKey(); + $user->two_factor_secret = $secret; + $user->save(); - $google2fa_url = $google2fa->getQRCodeGoogleUrl( - urlencode(Setting::getSettings()->site_name), - urlencode($user->username), - $user->two_factor_secret - ); - - return view('auth.two_factor_enroll')->with('google2fa_url', $google2fa_url); + $barcode = new \Com\Tecnick\Barcode\Barcode(); + $barcode_obj = $barcode->getBarcodeObj('QRCODE', 'otpauth://totp/'.urlencode($settings->site_name).':'.urlencode($user->username).'?secret='.urlencode($secret).'&issuer=Snipe-IT&period=30', 300, 300, 'black', array(-2, -2, -2, -2)); + return view('auth.two_factor_enroll')->with('barcode_obj', $barcode_obj); } @@ -240,6 +247,20 @@ class LoginController extends Controller */ public function getTwoFactorAuth() { + // Check that the user is logged in + if (!Auth::check()) { + return redirect()->route('login')->with('error', trans('auth/general.login_prompt')); + } + + $user = Auth::user(); + + // Check whether there is a device enrolled. + // This *should* be handled via the \App\Http\Middleware\CheckForTwoFactor middleware + // but we're just making sure (in case someone edited the database directly, etc) + if (($user->two_factor_secret=='') || ($user->two_factor_enrolled!=1)) { + return redirect()->route('two-factor-enroll'); + } + return view('auth.two_factor'); } @@ -252,22 +273,25 @@ class LoginController extends Controller { if (!Auth::check()) { - return redirect()->route('login')->with('error', 'You must be logged in.'); + return redirect()->route('login')->with('error', trans('auth/general.login_prompt')); + } + + if (!$request->has('two_factor_secret')) { + return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.code_required')); } $user = Auth::user(); - $secret = $request->get('two_factor_secret'); - $google2fa = app()->make('PragmaRX\Google2FA\Contracts\Google2FA'); - $valid = $google2fa->verifyKey($user->two_factor_secret, $secret); + $google2fa = new Google2FA(); + $secret = $request->input('two_factor_secret'); - if ($valid) { + if ($google2fa->verifyKey($user->two_factor_secret, $secret)) { $user->two_factor_enrolled = 1; $user->save(); $request->session()->put('2fa_authed', 'true'); return redirect()->route('home')->with('success', 'You are logged in!'); } - return redirect()->route('two-factor')->with('error', 'Invalid two-factor code'); + return redirect()->route('two-factor')->with('error', trans('auth/message.two_factor.invalid_code')); } @@ -290,7 +314,7 @@ class LoginController extends Controller return redirect()->away($customLogoutUrl); } - return redirect()->route('login')->with('success', 'You have successfully logged out!'); + return redirect()->route('login')->with('success', trans('auth/general.logout.success')); } @@ -315,11 +339,11 @@ class LoginController extends Controller } /** - * Redirect the user after determining they are locked out. - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse - */ + * Redirect the user after determining they are locked out. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\RedirectResponse + */ protected function sendLockoutResponse(Request $request) { $seconds = $this->limiter()->availableIn( @@ -330,18 +354,18 @@ class LoginController extends Controller $message = \Lang::get('auth/message.throttle', ['minutes' => $minutes]); - return redirect()->back() + return redirect()->back() ->withInput($request->only($this->username(), 'remember')) ->withErrors([$this->username() => $message]); } /** - * Override the lockout time and duration - * - * @param \Illuminate\Http\Request $request - * @return \Illuminate\Http\RedirectResponse - */ + * Override the lockout time and duration + * + * @param \Illuminate\Http\Request $request + * @return bool + */ protected function hasTooManyLoginAttempts(Request $request) { $lockoutTime = config('auth.throttle.lockout_duration'); diff --git a/composer.json b/composer.json index 6822043467..33a5a21d67 100644 --- a/composer.json +++ b/composer.json @@ -27,7 +27,8 @@ "patchwork/utf8": "~1.2", "phpdocumentor/reflection-docblock": "3.2.2", "phpspec/prophecy": "1.6.2", - "pragmarx/google2fa": "^1.0", + "pragmarx/google2fa": "^5.0", + "pragmarx/google2fa-laravel": "^0.3.0", "predis/predis": "^1.1", "rollbar/rollbar-laravel": "2.4.1", "schuppo/password-strength": "~1.5", diff --git a/composer.lock b/composer.lock index e42a3de8d3..8d971265a8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "f44697f67c1de6fd46cb9a7cb8bc20a6", + "content-hash": "a723d895823e1569b8fc1449f47bee53", "packages": [ { "name": "barryvdh/laravel-debugbar", @@ -55,60 +55,6 @@ ], "time": "2017-07-21T11:56:48+00:00" }, - { - "name": "christian-riesen/base32", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/ChristianRiesen/base32.git", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "0.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Base32\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Riesen", - "email": "chris.riesen@gmail.com", - "homepage": "http://christianriesen.com", - "role": "Developer" - } - ], - "description": "Base32 encoder/decoder according to RFC 4648", - "homepage": "https://github.com/ChristianRiesen/base32", - "keywords": [ - "base32", - "decode", - "encode", - "rfc4648" - ], - "time": "2016-05-05T11:49:03+00:00" - }, { "name": "defuse/php-encryption", "version": "v2.2.1", @@ -2306,6 +2252,69 @@ ], "time": "2018-02-28T20:30:58+00:00" }, + { + "name": "paragonie/constant_time_encoding", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/paragonie/constant_time_encoding.git", + "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", + "reference": "2132f0f293d856026d7d11bd81b9f4a23a1dc1f6", + "shasum": "" + }, + "require": { + "php": "^5.3|^7" + }, + "require-dev": { + "paragonie/random_compat": "^1.4|^2", + "phpunit/phpunit": "4.*|5.*", + "vimeo/psalm": "^0.3|^1" + }, + "type": "library", + "autoload": { + "psr-4": { + "ParagonIE\\ConstantTime\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com", + "role": "Maintainer" + }, + { + "name": "Steve 'Sc00bz' Thomas", + "email": "steve@tobtu.com", + "homepage": "https://www.tobtu.com", + "role": "Original Developer" + } + ], + "description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)", + "keywords": [ + "base16", + "base32", + "base32_decode", + "base32_encode", + "base64", + "base64_decode", + "base64_encode", + "bin2hex", + "encoding", + "hex", + "hex2bin", + "rfc4648" + ], + "time": "2018-04-30T17:57:16+00:00" + }, { "name": "paragonie/random_compat", "version": "v2.0.17", @@ -2717,29 +2726,86 @@ }, { "name": "pragmarx/google2fa", - "version": "v1.0.1", + "version": "v5.0.0", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa.git", - "reference": "b346dc138339b745c5831405d00cff7c1351aa0d" + "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/b346dc138339b745c5831405d00cff7c1351aa0d", - "reference": "b346dc138339b745c5831405d00cff7c1351aa0d", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/17c969c82f427dd916afe4be50bafc6299aef1b4", + "reference": "17c969c82f427dd916afe4be50bafc6299aef1b4", "shasum": "" }, "require": { - "christian-riesen/base32": "~1.3", - "paragonie/random_compat": "~1.4|~2.0", + "paragonie/constant_time_encoding": "~1.0|~2.0", + "paragonie/random_compat": ">=1", "php": ">=5.4", "symfony/polyfill-php56": "~1.2" }, "require-dev": { - "phpspec/phpspec": "~2.1" + "phpunit/phpunit": "~4|~5|~6" + }, + "type": "library", + "extra": { + "component": "package", + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "PragmaRX\\Google2FA\\": "src/", + "PragmaRX\\Google2FA\\Tests\\": "tests/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Antonio Carlos Ribeiro", + "email": "acr@antoniocarlosribeiro.com", + "role": "Creator & Designer" + } + ], + "description": "A One Time Password Authentication package, compatible with Google Authenticator.", + "keywords": [ + "2fa", + "Authentication", + "Two Factor Authentication", + "google2fa" + ], + "time": "2019-03-19T22:44:16+00:00" + }, + { + "name": "pragmarx/google2fa-laravel", + "version": "v0.3.0", + "source": { + "type": "git", + "url": "https://github.com/antonioribeiro/google2fa-laravel.git", + "reference": "048026cd55af7d4b019d18f83e5bbf92d4c8b071" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-laravel/zipball/048026cd55af7d4b019d18f83e5bbf92d4c8b071", + "reference": "048026cd55af7d4b019d18f83e5bbf92d4c8b071", + "shasum": "" + }, + "require": { + "laravel/framework": ">=5.2", + "php": ">=5.4", + "pragmarx/google2fa": ">=5.0" + }, + "require-dev": { + "orchestra/testbench-browser-kit": ">=3.4", + "phpunit/phpunit": ">=5.0" }, "suggest": { - "bacon/bacon-qr-code": "Required to generate inline QR Codes." + "bacon/bacon-qr-code": "Required to generate inline QR Codes.", + "pragmarx/recovery": "Generate recovery codes." }, "type": "library", "extra": { @@ -2748,12 +2814,21 @@ "Laravel" ], "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "0.2-dev" + }, + "laravel": { + "providers": [ + "PragmaRX\\Google2FALaravel\\ServiceProvider" + ], + "aliases": { + "Google2FA": "PragmaRX\\Google2FALaravel\\Facade" + } } }, "autoload": { "psr-4": { - "PragmaRX\\Google2FA\\": "src/" + "PragmaRX\\Google2FALaravel\\": "src/", + "PragmaRX\\Google2FALaravel\\Tests\\": "tests/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2774,7 +2849,7 @@ "google2fa", "laravel" ], - "time": "2016-07-18T20:25:04+00:00" + "time": "2019-03-19T23:20:01+00:00" }, { "name": "predis/predis", @@ -4145,7 +4220,7 @@ }, { "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "email": "backendtea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", @@ -5293,6 +5368,60 @@ ], "time": "2016-10-30T11:50:56+00:00" }, + { + "name": "christian-riesen/base32", + "version": "1.3.1", + "source": { + "type": "git", + "url": "https://github.com/ChristianRiesen/base32.git", + "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", + "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*", + "satooshi/php-coveralls": "0.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Base32\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Riesen", + "email": "chris.riesen@gmail.com", + "homepage": "http://christianriesen.com", + "role": "Developer" + } + ], + "description": "Base32 encoder/decoder according to RFC 4648", + "homepage": "https://github.com/ChristianRiesen/base32", + "keywords": [ + "base32", + "decode", + "encode", + "rfc4648" + ], + "time": "2016-05-05T11:49:03+00:00" + }, { "name": "codeception/codeception", "version": "2.3.6", @@ -5930,6 +6059,7 @@ "mock", "xunit" ], + "abandoned": true, "time": "2017-06-30T09:13:00+00:00" }, { diff --git a/config/app.php b/config/app.php index 73091160c5..8f6ae429a3 100755 --- a/config/app.php +++ b/config/app.php @@ -291,7 +291,7 @@ return [ Collective\Html\HtmlServiceProvider::class, Spatie\Backup\BackupServiceProvider::class, Fideloper\Proxy\TrustedProxyServiceProvider::class, - PragmaRX\Google2FA\Vendor\Laravel\ServiceProvider::class, + PragmaRX\Google2FALaravel\ServiceProvider::class, Laravel\Passport\PassportServiceProvider::class, Laravel\Tinker\TinkerServiceProvider::class, Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, diff --git a/resources/lang/en/auth/message.php b/resources/lang/en/auth/message.php index 3aee689e54..7c0cd5b50f 100644 --- a/resources/lang/en/auth/message.php +++ b/resources/lang/en/auth/message.php @@ -9,11 +9,23 @@ return array( 'account_banned' => 'This user account is banned.', 'throttle' => 'Too many failed login attempts. Please try again in :seconds seconds.', + 'two_factor' => array( + 'already_enrolled' => 'Your device is already enrolled.', + 'success' => 'You have successfully logged in.', + 'code_required' => 'Two-factor code is required.', + 'invalid_code' => 'Two-factor code is invalid.', + ), + 'signin' => array( 'error' => 'There was a problem while trying to log you in, please try again.', 'success' => 'You have successfully logged in.', ), + 'logout' => array( + 'error' => 'There was a problem while trying to log you out, please try again.', + 'success' => 'You have successfully logged out.', + ), + 'signup' => array( 'error' => 'There was a problem while trying to create your account, please try again.', 'success' => 'Account sucessfully created.', diff --git a/resources/views/auth/two_factor_enroll.blade.php b/resources/views/auth/two_factor_enroll.blade.php index 1fe9c89c9b..05b367583e 100644 --- a/resources/views/auth/two_factor_enroll.blade.php +++ b/resources/views/auth/two_factor_enroll.blade.php @@ -28,7 +28,7 @@
- + {!! $barcode_obj->getHtmlDiv() !!}
From d1e9fbfa24aaeb18aa7640f03e54f11e59d930e3 Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 20 Mar 2019 02:37:44 -0700 Subject: [PATCH 02/26] Updated compoer --- composer.lock | 482 +++++++++++++++++++++++++------------------------- 1 file changed, 240 insertions(+), 242 deletions(-) diff --git a/composer.lock b/composer.lock index 8d971265a8..d1087c6188 100644 --- a/composer.lock +++ b/composer.lock @@ -732,16 +732,16 @@ }, { "name": "erusev/parsedown", - "version": "1.7.1", + "version": "v1.7.2", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1" + "reference": "d60bcdc46978357759ecb13cb4b078da783f8faf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", - "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/d60bcdc46978357759ecb13cb4b078da783f8faf", + "reference": "d60bcdc46978357759ecb13cb4b078da783f8faf", "shasum": "" }, "require": { @@ -774,7 +774,7 @@ "markdown", "parser" ], - "time": "2018-03-08T01:11:30+00:00" + "time": "2019-03-17T17:19:46+00:00" }, { "name": "fideloper/proxy", @@ -994,32 +994,33 @@ }, { "name": "guzzlehttp/psr7", - "version": "1.4.2", + "version": "1.5.2", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c" + "reference": "9f83dded91781a01c63574e387eaa769be769115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/f5b8a8512e2b58b0071a7280e39f14f72e05d87c", - "reference": "f5b8a8512e2b58b0071a7280e39f14f72e05d87c", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/9f83dded91781a01c63574e387eaa769be769115", + "reference": "9f83dded91781a01c63574e387eaa769be769115", "shasum": "" }, "require": { "php": ">=5.4.0", - "psr/http-message": "~1.0" + "psr/http-message": "~1.0", + "ralouphie/getallheaders": "^2.0.5" }, "provide": { "psr/http-message-implementation": "1.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4-dev" + "dev-master": "1.5-dev" } }, "autoload": { @@ -1049,13 +1050,14 @@ "keywords": [ "http", "message", + "psr-7", "request", "response", "stream", "uri", "url" ], - "time": "2017-03-20T17:10:46+00:00" + "time": "2018-12-04T20:46:45+00:00" }, { "name": "intervention/image", @@ -1562,16 +1564,16 @@ }, { "name": "lcobucci/jwt", - "version": "3.2.4", + "version": "3.2.5", "source": { "type": "git", "url": "https://github.com/lcobucci/jwt.git", - "reference": "c9704b751315d21735dc98d78d4f37bd73596da7" + "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/lcobucci/jwt/zipball/c9704b751315d21735dc98d78d4f37bd73596da7", - "reference": "c9704b751315d21735dc98d78d4f37bd73596da7", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/82be04b4753f8b7693b62852b7eab30f97524f9b", + "reference": "82be04b4753f8b7693b62852b7eab30f97524f9b", "shasum": "" }, "require": { @@ -1616,7 +1618,7 @@ "JWS", "jwt" ], - "time": "2018-08-03T11:23:50+00:00" + "time": "2018-11-11T12:22:26+00:00" }, { "name": "league/csv", @@ -1677,16 +1679,16 @@ }, { "name": "league/event", - "version": "2.1.2", + "version": "2.2.0", "source": { "type": "git", "url": "https://github.com/thephpleague/event.git", - "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd" + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/event/zipball/e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", - "reference": "e4bfc88dbcb60c8d8a2939a71f9813e141bbe4cd", + "url": "https://api.github.com/repos/thephpleague/event/zipball/d2cc124cf9a3fab2bb4ff963307f60361ce4d119", + "reference": "d2cc124cf9a3fab2bb4ff963307f60361ce4d119", "shasum": "" }, "require": { @@ -1694,7 +1696,7 @@ }, "require-dev": { "henrikbjorn/phpspec-code-coverage": "~1.0.1", - "phpspec/phpspec": "~2.0.0" + "phpspec/phpspec": "^2.2" }, "type": "library", "extra": { @@ -1723,20 +1725,20 @@ "event", "listener" ], - "time": "2015-05-21T12:24:47+00:00" + "time": "2018-11-26T11:52:41+00:00" }, { "name": "league/flysystem", - "version": "1.0.48", + "version": "1.0.50", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "a6ded5b2f6055e2db97b4b859fdfca2b952b78aa" + "reference": "dab4e7624efa543a943be978008f439c333f2249" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a6ded5b2f6055e2db97b4b859fdfca2b952b78aa", - "reference": "a6ded5b2f6055e2db97b4b859fdfca2b952b78aa", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/dab4e7624efa543a943be978008f439c333f2249", + "reference": "dab4e7624efa543a943be978008f439c333f2249", "shasum": "" }, "require": { @@ -1807,7 +1809,7 @@ "sftp", "storage" ], - "time": "2018-10-15T13:53:10+00:00" + "time": "2019-02-01T08:50:36+00:00" }, { "name": "league/oauth2-server", @@ -1989,16 +1991,16 @@ }, { "name": "monolog/monolog", - "version": "1.23.0", + "version": "1.24.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4" + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/fd8c787753b3a2ad11bc60c063cff1358a32a3b4", - "reference": "fd8c787753b3a2ad11bc60c063cff1358a32a3b4", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", + "reference": "bfc9ebb28f97e7a24c45bdc3f0ff482e47bb0266", "shasum": "" }, "require": { @@ -2063,7 +2065,7 @@ "logging", "psr-3" ], - "time": "2017-06-19T01:22:40+00:00" + "time": "2018-11-05T09:00:11+00:00" }, { "name": "mtdowling/cron-expression", @@ -2148,16 +2150,16 @@ }, { "name": "nesbot/carbon", - "version": "1.34.0", + "version": "1.36.2", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33" + "reference": "cd324b98bc30290f233dd0e75e6ce49f7ab2a6c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33", - "reference": "1dbd3cb01c5645f3e7deda7aa46ef780d95fcc33", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/cd324b98bc30290f233dd0e75e6ce49f7ab2a6c9", + "reference": "cd324b98bc30290f233dd0e75e6ce49f7ab2a6c9", "shasum": "" }, "require": { @@ -2165,9 +2167,12 @@ "symfony/translation": "~2.6 || ~3.0 || ~4.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2", "phpunit/phpunit": "^4.8.35 || ^5.7" }, + "suggest": { + "friendsofphp/php-cs-fixer": "Needed for the `composer phpcs` command. Allow to automatically fix code style.", + "phpstan/phpstan": "Needed for the `composer phpstan` command. Allow to detect potential errors." + }, "type": "library", "extra": { "laravel": { @@ -2199,7 +2204,7 @@ "datetime", "time" ], - "time": "2018-09-20T19:36:25+00:00" + "time": "2018-12-28T10:07:33+00:00" }, { "name": "nikic/php-parser", @@ -2317,16 +2322,16 @@ }, { "name": "paragonie/random_compat", - "version": "v2.0.17", + "version": "v2.0.18", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d" + "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d", - "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", + "reference": "0a58ef6e3146256cc3dc7cc393927bcc7d1b72db", "shasum": "" }, "require": { @@ -2362,7 +2367,7 @@ "pseudorandom", "random" ], - "time": "2018-07-04T16:31:37+00:00" + "time": "2019-01-03T20:59:08+00:00" }, { "name": "patchwork/utf8", @@ -2571,16 +2576,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "2.0.11", + "version": "2.0.15", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b" + "reference": "11cf67cf78dc4acb18dc9149a57be4aee5036ce0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/7053f06f91b3de78e143d430e55a8f7889efc08b", - "reference": "7053f06f91b3de78e143d430e55a8f7889efc08b", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/11cf67cf78dc4acb18dc9149a57be4aee5036ce0", + "reference": "11cf67cf78dc4acb18dc9149a57be4aee5036ce0", "shasum": "" }, "require": { @@ -2659,7 +2664,7 @@ "x.509", "x509" ], - "time": "2018-04-15T16:55:05+00:00" + "time": "2019-03-10T16:53:45+00:00" }, { "name": "phpspec/prophecy", @@ -2953,16 +2958,16 @@ }, { "name": "psr/log", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", + "reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd", "shasum": "" }, "require": { @@ -2996,7 +3001,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2018-11-20T15:27:04+00:00" }, { "name": "psy/psysh", @@ -3072,6 +3077,46 @@ ], "time": "2018-10-13T15:16:03+00:00" }, + { + "name": "ralouphie/getallheaders", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "reference": "5601c8a83fbba7ef674a7369456d12f1e0d0eafa", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "require-dev": { + "phpunit/phpunit": "~3.7.0", + "satooshi/php-coveralls": ">=1.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "time": "2016-02-11T07:05:27+00:00" + }, { "name": "ramsey/uuid", "version": "3.8.0", @@ -3156,27 +3201,26 @@ }, { "name": "rollbar/rollbar", - "version": "v1.6.3", + "version": "v1.7.5", "source": { "type": "git", "url": "https://github.com/rollbar/rollbar-php.git", - "reference": "149590adc3bd5ed1188c48f8159f257aa1bf2d19" + "reference": "b1b33ae00f0d3f28d351552a85a367a425456ad7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/rollbar/rollbar-php/zipball/149590adc3bd5ed1188c48f8159f257aa1bf2d19", - "reference": "149590adc3bd5ed1188c48f8159f257aa1bf2d19", + "url": "https://api.github.com/repos/rollbar/rollbar-php/zipball/b1b33ae00f0d3f28d351552a85a367a425456ad7", + "reference": "b1b33ae00f0d3f28d351552a85a367a425456ad7", "shasum": "" }, "require": { "ext-curl": "*", - "monolog/monolog": "^1.23", "psr/log": "^1.0.1" }, "require-dev": { "codeclimate/php-test-reporter": "dev-master", "mockery/mockery": "0.9.*", - "monolog/monolog": "^1.23", + "monolog/monolog": "^1.24", "packfire/php5.3-compat": "*", "phpmd/phpmd": "@stable", "phpunit/phpunit": "4.8.*", @@ -3212,7 +3256,7 @@ "logging", "monitoring" ], - "time": "2018-09-06T21:34:17+00:00" + "time": "2019-03-04T08:56:09+00:00" }, { "name": "rollbar/rollbar-laravel", @@ -3744,16 +3788,16 @@ }, { "name": "symfony/console", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "3b2b415d4c48fbefca7dc742aa0a0171bfae4e0b" + "reference": "71ce77f37af0c5ffb9590e43cc4f70e426945c5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/3b2b415d4c48fbefca7dc742aa0a0171bfae4e0b", - "reference": "3b2b415d4c48fbefca7dc742aa0a0171bfae4e0b", + "url": "https://api.github.com/repos/symfony/console/zipball/71ce77f37af0c5ffb9590e43cc4f70e426945c5e", + "reference": "71ce77f37af0c5ffb9590e43cc4f70e426945c5e", "shasum": "" }, "require": { @@ -3765,6 +3809,9 @@ "symfony/dependency-injection": "<3.4", "symfony/process": "<3.3" }, + "provide": { + "psr/log-implementation": "1.0" + }, "require-dev": { "psr/log": "~1.0", "symfony/config": "~3.3|~4.0", @@ -3774,7 +3821,7 @@ "symfony/process": "~3.3|~4.0" }, "suggest": { - "psr/log-implementation": "For using the console logger", + "psr/log": "For using the console logger", "symfony/event-dispatcher": "", "symfony/lock": "", "symfony/process": "" @@ -3809,7 +3856,7 @@ ], "description": "Symfony Console Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:33:53+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "symfony/css-selector", @@ -3866,16 +3913,16 @@ }, { "name": "symfony/debug", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "0a612e9dfbd2ccce03eb174365f31ecdca930ff6" + "reference": "8d8a9e877b3fcdc50ddecf8dcea146059753f782" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/0a612e9dfbd2ccce03eb174365f31ecdca930ff6", - "reference": "0a612e9dfbd2ccce03eb174365f31ecdca930ff6", + "url": "https://api.github.com/repos/symfony/debug/zipball/8d8a9e877b3fcdc50ddecf8dcea146059753f782", + "reference": "8d8a9e877b3fcdc50ddecf8dcea146059753f782", "shasum": "" }, "require": { @@ -3918,20 +3965,20 @@ ], "description": "Symfony Debug Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:33:53+00:00" + "time": "2019-02-24T15:45:11+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb" + "reference": "ec625e2fff7f584eeb91754821807317b2e79236" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb", - "reference": "b2e1f19280c09a42dc64c0b72b80fe44dd6e88fb", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/ec625e2fff7f584eeb91754821807317b2e79236", + "reference": "ec625e2fff7f584eeb91754821807317b2e79236", "shasum": "" }, "require": { @@ -3981,20 +4028,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2018-07-26T09:06:28+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "symfony/finder", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d" + "reference": "fcdde4aa38f48190ce70d782c166f23930084f9b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/54ba444dddc5bd5708a34bd095ea67c6eb54644d", - "reference": "54ba444dddc5bd5708a34bd095ea67c6eb54644d", + "url": "https://api.github.com/repos/symfony/finder/zipball/fcdde4aa38f48190ce70d782c166f23930084f9b", + "reference": "fcdde4aa38f48190ce70d782c166f23930084f9b", "shasum": "" }, "require": { @@ -4030,20 +4077,20 @@ ], "description": "Symfony Finder Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:46:40+00:00" + "time": "2019-02-22T14:44:53+00:00" }, { "name": "symfony/http-foundation", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "3a4498236ade473c52b92d509303e5fd1b211ab1" + "reference": "9a96d77ceb1fd913c9d4a89e8a7e1be87604be8a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/3a4498236ade473c52b92d509303e5fd1b211ab1", - "reference": "3a4498236ade473c52b92d509303e5fd1b211ab1", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9a96d77ceb1fd913c9d4a89e8a7e1be87604be8a", + "reference": "9a96d77ceb1fd913c9d4a89e8a7e1be87604be8a", "shasum": "" }, "require": { @@ -4084,26 +4131,26 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2018-10-03T08:48:18+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "symfony/http-kernel", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a0944a9a1d8845da724236cde9a310964acadb1c" + "reference": "0362368c761cb8d9c79e56ab0db61d2c692db594" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a0944a9a1d8845da724236cde9a310964acadb1c", - "reference": "a0944a9a1d8845da724236cde9a310964acadb1c", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/0362368c761cb8d9c79e56ab0db61d2c692db594", + "reference": "0362368c761cb8d9c79e56ab0db61d2c692db594", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8", "psr/log": "~1.0", - "symfony/debug": "~2.8|~3.0|~4.0", + "symfony/debug": "^3.3.3|~4.0", "symfony/event-dispatcher": "~2.8|~3.0|~4.0", "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", "symfony/polyfill-ctype": "~1.8" @@ -4173,11 +4220,11 @@ ], "description": "Symfony HttpKernel Component", "homepage": "https://symfony.com", - "time": "2018-10-03T12:03:34+00:00" + "time": "2019-03-03T18:52:34+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -4220,7 +4267,7 @@ }, { "name": "Gert de Pagter", - "email": "backendtea@gmail.com" + "email": "BackEndTea@gmail.com" } ], "description": "Symfony polyfill for ctype functions", @@ -4235,16 +4282,16 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8" + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d0cd638f4634c16d8df4508e847f14e9e43168b8", - "reference": "d0cd638f4634c16d8df4508e847f14e9e43168b8", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494", + "reference": "c79c051f5b3a46be09205c73b80b346e4153e494", "shasum": "" }, "require": { @@ -4290,20 +4337,20 @@ "portable", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-21T13:07:52+00:00" }, { "name": "symfony/polyfill-php56", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "7b4fc009172cc0196535b0328bd1226284a28000" + "reference": "ff208829fe1aa48ab9af356992bb7199fed551af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/7b4fc009172cc0196535b0328bd1226284a28000", - "reference": "7b4fc009172cc0196535b0328bd1226284a28000", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/ff208829fe1aa48ab9af356992bb7199fed551af", + "reference": "ff208829fe1aa48ab9af356992bb7199fed551af", "shasum": "" }, "require": { @@ -4346,20 +4393,20 @@ "portable", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-21T06:26:08+00:00" }, { "name": "symfony/polyfill-php70", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934" + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/1e24b0c4a56d55aaf368763a06c6d1c7d3194934", - "reference": "1e24b0c4a56d55aaf368763a06c6d1c7d3194934", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", + "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", "shasum": "" }, "require": { @@ -4405,20 +4452,20 @@ "portable", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-21T06:26:08+00:00" }, { "name": "symfony/polyfill-util", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-util.git", - "reference": "8e15d04ba3440984d23e7964b2ee1d25c8de1581" + "reference": "3b58903eae668d348a7126f999b0da0f2f93611c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/8e15d04ba3440984d23e7964b2ee1d25c8de1581", - "reference": "8e15d04ba3440984d23e7964b2ee1d25c8de1581", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/3b58903eae668d348a7126f999b0da0f2f93611c", + "reference": "3b58903eae668d348a7126f999b0da0f2f93611c", "shasum": "" }, "require": { @@ -4457,20 +4504,20 @@ "polyfill", "shim" ], - "time": "2018-08-06T14:22:27+00:00" + "time": "2018-09-30T16:36:12+00:00" }, { "name": "symfony/process", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "1dc2977afa7d70f90f3fefbcd84152813558910e" + "reference": "009f8dda80930e89e8344a4e310b08f9ff07dd2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1dc2977afa7d70f90f3fefbcd84152813558910e", - "reference": "1dc2977afa7d70f90f3fefbcd84152813558910e", + "url": "https://api.github.com/repos/symfony/process/zipball/009f8dda80930e89e8344a4e310b08f9ff07dd2e", + "reference": "009f8dda80930e89e8344a4e310b08f9ff07dd2e", "shasum": "" }, "require": { @@ -4506,20 +4553,20 @@ ], "description": "Symfony Process Component", "homepage": "https://symfony.com", - "time": "2018-10-02T12:28:39+00:00" + "time": "2019-01-16T13:27:11+00:00" }, { "name": "symfony/psr-http-message-bridge", - "version": "v1.1.0", + "version": "v1.1.1", "source": { "type": "git", "url": "https://github.com/symfony/psr-http-message-bridge.git", - "reference": "53c15a6a7918e6c2ab16ae370ea607fb40cab196" + "reference": "921f8669c36ea0148d2520c0bb7838cda14879e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/53c15a6a7918e6c2ab16ae370ea607fb40cab196", - "reference": "53c15a6a7918e6c2ab16ae370ea607fb40cab196", + "url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/921f8669c36ea0148d2520c0bb7838cda14879e0", + "reference": "921f8669c36ea0148d2520c0bb7838cda14879e0", "shasum": "" }, "require": { @@ -4528,12 +4575,11 @@ "symfony/http-foundation": "^2.3.42 || ^3.4 || ^4.0" }, "require-dev": { - "symfony/phpunit-bridge": "^3.4 || 4.0" + "nyholm/psr7": "^1.1", + "symfony/phpunit-bridge": "^3.4 || ^4.0" }, "suggest": { - "psr/http-factory-implementation": "To use the PSR-17 factory", - "psr/http-message-implementation": "To use the HttpFoundation factory", - "zendframework/zend-diactoros": "To use the Zend Diactoros factory" + "nyholm/psr7": "For a super lightweight PSR-7/17 implementation" }, "type": "symfony-bridge", "extra": { @@ -4544,7 +4590,10 @@ "autoload": { "psr-4": { "Symfony\\Bridge\\PsrHttpMessage\\": "" - } + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -4565,22 +4614,23 @@ "keywords": [ "http", "http-message", + "psr-17", "psr-7" ], - "time": "2018-08-30T16:28:28+00:00" + "time": "2019-03-11T15:23:15+00:00" }, { "name": "symfony/routing", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "585f6e2d740393d546978769dd56e496a6233e0b" + "reference": "6b25a86df5860461ff1990946168c0ef944f83db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/585f6e2d740393d546978769dd56e496a6233e0b", - "reference": "585f6e2d740393d546978769dd56e496a6233e0b", + "url": "https://api.github.com/repos/symfony/routing/zipball/6b25a86df5860461ff1990946168c0ef944f83db", + "reference": "6b25a86df5860461ff1990946168c0ef944f83db", "shasum": "" }, "require": { @@ -4644,20 +4694,20 @@ "uri", "url" ], - "time": "2018-10-02T12:28:39+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "symfony/translation", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "94bc3a79008e6640defedf5e14eb3b4f20048352" + "reference": "3e2966209567ffed8825905b53fc8548446130aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/94bc3a79008e6640defedf5e14eb3b4f20048352", - "reference": "94bc3a79008e6640defedf5e14eb3b4f20048352", + "url": "https://api.github.com/repos/symfony/translation/zipball/3e2966209567ffed8825905b53fc8548446130aa", + "reference": "3e2966209567ffed8825905b53fc8548446130aa", "shasum": "" }, "require": { @@ -4712,20 +4762,20 @@ ], "description": "Symfony Translation Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:33:53+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "symfony/var-dumper", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "ff8ac19e97e5c7c3979236b584719a1190f84181" + "reference": "d34d10236300876d14291e9df85c6ef3d3bb9066" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/ff8ac19e97e5c7c3979236b584719a1190f84181", - "reference": "ff8ac19e97e5c7c3979236b584719a1190f84181", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/d34d10236300876d14291e9df85c6ef3d3bb9066", + "reference": "d34d10236300876d14291e9df85c6ef3d3bb9066", "shasum": "" }, "require": { @@ -4781,7 +4831,7 @@ "debug", "dump" ], - "time": "2018-10-02T16:33:53+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "tecnickcom/tc-lib-barcode", @@ -5095,20 +5145,21 @@ }, { "name": "vlucas/phpdotenv", - "version": "v2.5.1", + "version": "v2.6.1", "source": { "type": "git", "url": "https://github.com/vlucas/phpdotenv.git", - "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e" + "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", - "reference": "8abb4f9aa89ddea9d52112c65bbe8d0125e2fa8e", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/2a7dcf7e3e02dc5e701004e51a6f304b713107d5", + "reference": "2a7dcf7e3e02dc5e701004e51a6f304b713107d5", "shasum": "" }, "require": { - "php": ">=5.3.9" + "php": ">=5.3.9", + "symfony/polyfill-ctype": "^1.9" }, "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.0" @@ -5116,7 +5167,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5-dev" + "dev-master": "2.6-dev" } }, "autoload": { @@ -5141,33 +5192,33 @@ "env", "environment" ], - "time": "2018-07-29T20:33:41+00:00" + "time": "2019-01-29T11:11:52+00:00" }, { "name": "watson/validating", - "version": "3.1.8", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/dwightwatson/validating.git", - "reference": "ddb12d04de1a541961e1ca82837693382dfe8967" + "reference": "b8fa204e59d3a6766185f841b75d8ffa0c47a978" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dwightwatson/validating/zipball/ddb12d04de1a541961e1ca82837693382dfe8967", - "reference": "ddb12d04de1a541961e1ca82837693382dfe8967", + "url": "https://api.github.com/repos/dwightwatson/validating/zipball/b8fa204e59d3a6766185f841b75d8ffa0c47a978", + "reference": "b8fa204e59d3a6766185f841b75d8ffa0c47a978", "shasum": "" }, "require": { - "illuminate/contracts": "5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*", - "illuminate/database": "5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*", - "illuminate/events": "5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*", - "illuminate/support": "5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*", - "illuminate/validation": "5.3.* || 5.4.* || 5.5.* || 5.6.* || 5.7.*", - "php": ">=5.4.0" + "illuminate/contracts": ">= 5.4.0", + "illuminate/database": ">= 5.4.0", + "illuminate/events": ">= 5.4.0", + "illuminate/support": ">= 5.4.0", + "illuminate/validation": ">= 5.4.0", + "php": ">=5.6.4" }, "require-dev": { - "mockery/mockery": "0.9.*", - "phpunit/phpunit": "~4.0" + "mockery/mockery": "~1.0", + "phpunit/phpunit": "~5.0" }, "type": "library", "autoload": { @@ -5191,24 +5242,25 @@ "laravel", "validation" ], - "time": "2018-09-19T23:52:11+00:00" + "time": "2019-03-02T23:37:33+00:00" }, { "name": "webmozart/assert", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a" + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/0df1908962e7a3071564e857d86874dad1ef204a", - "reference": "0df1908962e7a3071564e857d86874dad1ef204a", + "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", + "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", "shasum": "" }, "require": { - "php": "^5.3.3 || ^7.0" + "php": "^5.3.3 || ^7.0", + "symfony/polyfill-ctype": "^1.8" }, "require-dev": { "phpunit/phpunit": "^4.6", @@ -5241,7 +5293,7 @@ "check", "validate" ], - "time": "2018-01-29T19:49:41+00:00" + "time": "2018-12-25T11:19:39+00:00" }, { "name": "zendframework/zend-diactoros", @@ -5368,60 +5420,6 @@ ], "time": "2016-10-30T11:50:56+00:00" }, - { - "name": "christian-riesen/base32", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/ChristianRiesen/base32.git", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ChristianRiesen/base32/zipball/0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", - "reference": "0a31e50c0fa9b1692d077c86ac188eecdcbaf7fa", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "4.*", - "satooshi/php-coveralls": "0.*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Base32\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christian Riesen", - "email": "chris.riesen@gmail.com", - "homepage": "http://christianriesen.com", - "role": "Developer" - } - ], - "description": "Base32 encoder/decoder according to RFC 4648", - "homepage": "https://github.com/ChristianRiesen/base32", - "keywords": [ - "base32", - "decode", - "encode", - "rfc4648" - ], - "time": "2016-05-05T11:49:03+00:00" - }, { "name": "codeception/codeception", "version": "2.3.6", @@ -6341,16 +6339,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.3.2", + "version": "3.4.1", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e" + "reference": "5b4333b4010625d29580eb4a41f1e53251be6baa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/6ad28354c04b364c3c71a34e4a18b629cc3b231e", - "reference": "6ad28354c04b364c3c71a34e4a18b629cc3b231e", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/5b4333b4010625d29580eb4a41f1e53251be6baa", + "reference": "5b4333b4010625d29580eb4a41f1e53251be6baa", "shasum": "" }, "require": { @@ -6383,12 +6381,12 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", "standards" ], - "time": "2018-09-23T23:08:17+00:00" + "time": "2019-03-19T03:22:27+00:00" }, { "name": "stecman/symfony-console-completion", @@ -6437,16 +6435,16 @@ }, { "name": "symfony/browser-kit", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0" + "reference": "c0fadd368c1031109e996316e53ffeb886d37ea1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/f6668d1a6182d5a8dec65a1c863a4c1d963816c0", - "reference": "f6668d1a6182d5a8dec65a1c863a4c1d963816c0", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/c0fadd368c1031109e996316e53ffeb886d37ea1", + "reference": "c0fadd368c1031109e996316e53ffeb886d37ea1", "shasum": "" }, "require": { @@ -6490,7 +6488,7 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2018-07-26T09:06:28+00:00" + "time": "2019-02-23T15:06:07+00:00" }, { "name": "symfony/dom-crawler", @@ -6550,16 +6548,16 @@ }, { "name": "symfony/yaml", - "version": "v3.4.17", + "version": "v3.4.23", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "640b6c27fed4066d64b64d5903a86043f4a4de7f" + "reference": "57f1ce82c997f5a8701b89ef970e36bb657fd09c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/640b6c27fed4066d64b64d5903a86043f4a4de7f", - "reference": "640b6c27fed4066d64b64d5903a86043f4a4de7f", + "url": "https://api.github.com/repos/symfony/yaml/zipball/57f1ce82c997f5a8701b89ef970e36bb657fd09c", + "reference": "57f1ce82c997f5a8701b89ef970e36bb657fd09c", "shasum": "" }, "require": { @@ -6605,7 +6603,7 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2018-10-02T16:33:53+00:00" + "time": "2019-02-23T15:06:07+00:00" } ], "aliases": [], From 25884a893e1f4ce1a7d66a366db726b5e42e976a Mon Sep 17 00:00:00 2001 From: snipe Date: Wed, 20 Mar 2019 02:41:33 -0700 Subject: [PATCH 03/26] Bumped version --- config/version.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/version.php b/config/version.php index 24a0d7e209..7ae4ca516d 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v4.6.14', - 'full_app_version' => 'v4.6.14 - build 4006-gdec77890b', - 'build_version' => '4006', + 'app_version' => 'v4.6.15', + 'full_app_version' => 'v4.6.15 - build 4011-gd1e9fbfa2', + 'build_version' => '4011', 'prerelease_version' => '', - 'hash_version' => 'gdec77890b', - 'full_hash' => 'v4.6.14-18-gdec77890b', + 'hash_version' => 'gd1e9fbfa2', + 'full_hash' => 'v4.6.15-2-gd1e9fbfa2', 'branch' => 'master', ); From a521523d45c1c8d23d2fb157886835fdf2ffabd3 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 18 Apr 2019 14:13:33 -0400 Subject: [PATCH 04/26] Truncate imports table on seed --- database/seeds/DatabaseSeeder.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 85f3e599ad..0a1c97560f 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -43,5 +43,8 @@ class DatabaseSeeder extends Seeder \Log::info($output); Model::reguard(); + + DB::table('imports')->truncate(); + } } From 420e8bc85a5008842542238c7fa8381237645cd1 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 18 Apr 2019 14:13:50 -0400 Subject: [PATCH 05/26] Allow phone number to be changed in Profile --- app/Http/Controllers/ProfileController.php | 3 +++ resources/views/account/profile.blade.php | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/app/Http/Controllers/ProfileController.php b/app/Http/Controllers/ProfileController.php index daa10aa974..a255aa34b6 100755 --- a/app/Http/Controllers/ProfileController.php +++ b/app/Http/Controllers/ProfileController.php @@ -49,6 +49,9 @@ class ProfileController extends Controller $user->last_name = $request->input('last_name'); $user->website = $request->input('website'); $user->gravatar = $request->input('gravatar'); + $user->phone = $request->input('phone'); + + if (!config('app.lock_passwords')) { $user->locale = $request->input('locale', 'en'); diff --git a/resources/views/account/profile.blade.php b/resources/views/account/profile.blade.php index 18a8287035..49e29b05a6 100755 --- a/resources/views/account/profile.blade.php +++ b/resources/views/account/profile.blade.php @@ -58,6 +58,15 @@ + +
+ +
+ + {!! $errors->first('phone', ':message') !!} +
+
+ From 1bb1f7342f5fd2a27a26ec3c154baca7bd51e0db Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 18 Apr 2019 15:49:59 -0400 Subject: [PATCH 06/26] Fixed #6922 - date_add crashing if EOL is null --- app/Presenters/AssetPresenter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Presenters/AssetPresenter.php b/app/Presenters/AssetPresenter.php index d971b09e39..689a87201a 100644 --- a/app/Presenters/AssetPresenter.php +++ b/app/Presenters/AssetPresenter.php @@ -391,7 +391,7 @@ class AssetPresenter extends Presenter public function eol_date() { - if (( $this->purchase_date ) && ( $this->model )) { + if (( $this->purchase_date ) && ( $this->model ) && ($this->model->model->eol) ) { $date = date_create($this->purchase_date); date_add($date, date_interval_create_from_date_string($this->model->model->eol . ' months')); return date_format($date, 'Y-m-d'); From dae26e0378d9f554a5c415b28cc20caa555fe278 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 18 Apr 2019 17:56:08 -0400 Subject: [PATCH 07/26] =?UTF-8?q?Remove=20=E2=80=9CImported=20from=20LDAP?= =?UTF-8?q?=E2=80=9D=20note=20override?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Console/Commands/LdapSync.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/Console/Commands/LdapSync.php b/app/Console/Commands/LdapSync.php index cdd7740a41..47b5f58113 100755 --- a/app/Console/Commands/LdapSync.php +++ b/app/Console/Commands/LdapSync.php @@ -208,8 +208,7 @@ class LdapSync extends Command } } - - $user->notes = 'Imported from LDAP'; + $user->ldap_import = 1; $errors = ''; From dc73dbfbfd3e42bf6979d6dbad204f9146854d15 Mon Sep 17 00:00:00 2001 From: snipe Date: Thu, 2 May 2019 15:20:47 -0700 Subject: [PATCH 08/26] Fixed #6911 - note must be a string on license checkin --- app/Http/Controllers/Api/LicensesController.php | 3 ++- app/Http/Controllers/LicensesController.php | 15 +-------------- resources/views/licenses/view.blade.php | 6 +++--- 3 files changed, 6 insertions(+), 18 deletions(-) diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index 82ab0fc2b5..337e8e8691 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -227,7 +227,8 @@ class LicensesController extends Controller $seats = LicenseSeat::where('license_id', $licenseId)->with('license', 'user', 'asset'); - $offset = request('offset', 0); + $offset = (($seats) && (request('offset') > $seats->count())) ? 0 : request('offset', 0); + $limit = request('limit', 50); $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; diff --git a/app/Http/Controllers/LicensesController.php b/app/Http/Controllers/LicensesController.php index 98a946197c..96a68be311 100755 --- a/app/Http/Controllers/LicensesController.php +++ b/app/Http/Controllers/LicensesController.php @@ -413,20 +413,7 @@ class LicensesController extends Controller return redirect()->back()->withInput(); } - // Declare the rules for the form validation - $rules = array( - 'note' => 'string', - 'notes' => 'string', - ); - // Create a new validator instance from our validation rules - $validator = Validator::make(Input::all(), $rules); - - // If validation fails, we'll exit the operation now. - if ($validator->fails()) { - // Ooops.. something went wrong - return redirect()->back()->withInput()->withErrors($validator); - } $return_to = User::find($licenseSeat->assigned_to); if (!$return_to) { $return_to = Asset::find($licenseSeat->asset_id); @@ -438,7 +425,7 @@ class LicensesController extends Controller // Was the asset updated? if ($licenseSeat->save()) { - $licenseSeat->logCheckin($return_to, e(request('note'))); + $licenseSeat->logCheckin($license, e(request('note'))); if ($backTo=='user') { return redirect()->route("users.show", $return_to->id)->with('success', trans('admin/licenses/message.checkin.success')); } diff --git a/resources/views/licenses/view.blade.php b/resources/views/licenses/view.blade.php index 80f57241a3..1b8347c715 100755 --- a/resources/views/licenses/view.blade.php +++ b/resources/views/licenses/view.blade.php @@ -44,9 +44,9 @@ Date: Sat, 4 May 2019 17:52:17 -0400 Subject: [PATCH 09/26] Added upcoming audit report TODO: Fid diff/threshold math --- .../Commands/SendUpcomingAuditReport.php | 93 +++++++++++++++++++ app/Console/Kernel.php | 2 + .../SendUpcomingAuditNotification.php | 65 +++++++++++++ resources/lang/en/mail.php | 2 + .../markdown/upcoming-audits.blade.php | 20 ++++ 5 files changed, 182 insertions(+) create mode 100644 app/Console/Commands/SendUpcomingAuditReport.php create mode 100644 app/Notifications/SendUpcomingAuditNotification.php create mode 100644 resources/views/notifications/markdown/upcoming-audits.blade.php diff --git a/app/Console/Commands/SendUpcomingAuditReport.php b/app/Console/Commands/SendUpcomingAuditReport.php new file mode 100644 index 0000000000..47286b5ee6 --- /dev/null +++ b/app/Console/Commands/SendUpcomingAuditReport.php @@ -0,0 +1,93 @@ +audit_warning_days from today + $threshold = Carbon::now()->addDays($settings->audit_warning_days); + + + + if (($settings->alert_email != '') && ($settings->audit_warning_days) && ($settings->alerts_enabled == 1)) { + + // Send a rollup to the admin, if settings dictate + $recipients = collect(explode(',', $settings->alert_email))->map(function ($item, $key) { + return new \App\Models\Recipients\AlertRecipient($item); + }); + + // Assets due for auditing + $assets = Asset::whereDate('next_audit_date', '<=', $threshold) + ->orderBy('last_audit_date', 'asc')->get(); + + if ($assets->count() > 0) { + + $this->info(trans_choice('mail.upcoming-audits', $assets->count(), + ['count' => $assets->count(), 'threshold' => $threshold])); + \Notification::send($recipients, new SendUpcomingAuditNotification($assets, $threshold)); + $this->info('Audit report sent to '.$settings->alert_email); + } else { + $this->info('No assets to be audited. No report sent.'); + } + + + + } elseif ($settings->alert_email=='') { + $this->error('Could not send email. No alert email configured in settings'); + } elseif (!$settings->audit_warning_days) { + $this->error('No audit warning days set in Admin Notifications. No mail will be sent.'); + } elseif ($settings->alerts_enabled!=1) { + $this->info('Alerts are disabled in the settings. No mail will be sent'); + } else { + $this->error('Something went wrong. :( '); + $this->error('Admin Notifications Email Setting: '.$settings->alert_email); + $this->error('Admin Audit Warning Setting: '.$settings->audit_warning_days); + $this->error('Admin Alerts Emnabled: '.$settings->alerts_enabled); + } + + + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 3713624422..f8a79a3f29 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,7 @@ namespace App\Console; +use App\Console\Commands\RestoreDeletedUsers; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -31,6 +32,7 @@ class Kernel extends ConsoleKernel Commands\RegenerateAssetTags::class, Commands\SyncAssetCounters::class, Commands\RestoreDeletedUsers::class, + Commands\SendUpcomingAuditReport::class, ]; /** diff --git a/app/Notifications/SendUpcomingAuditNotification.php b/app/Notifications/SendUpcomingAuditNotification.php new file mode 100644 index 0000000000..eb68df6546 --- /dev/null +++ b/app/Notifications/SendUpcomingAuditNotification.php @@ -0,0 +1,65 @@ +assets = $params; + } + + /** + * Get the notification's delivery channels. + * + * @param mixed $notifiable + * @return array + */ + public function via($notifiable) + { + return $notifyBy = ['mail']; + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return \Illuminate\Notifications\Messages\MailMessage + */ + public function toMail($notifiable) + { + $message = (new MailMessage)->markdown('notifications.markdown.upcoming-audits', + [ + 'assets' => $this->assets, + ]) + ->subject(trans_choice('mail.upcoming-audits', $this->assets->count(), ['count' => $this->assets->count()])); + + return $message; + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + return [ + // + ]; + } +} diff --git a/resources/lang/en/mail.php b/resources/lang/en/mail.php index de1bafb3cc..5fd0dab1e7 100644 --- a/resources/lang/en/mail.php +++ b/resources/lang/en/mail.php @@ -64,9 +64,11 @@ return array( 'license_expiring_alert' => 'There is :count license expiring in the next :threshold days.|There are :count licenses expiring in the next :threshold days.', 'to_reset' => 'To reset your :web password, complete this form:', 'type' => 'Type', + 'upcoming-audits' => 'There is :count asset that is coming up for audit within :threshold days.|There are :count assets that are coming up for audit within :threshold days.', 'user' => 'User', 'username' => 'Username', 'welcome' => 'Welcome :name', 'welcome_to' => 'Welcome to :web!', 'your_credentials' => 'Your Snipe-IT credentials', + ); diff --git a/resources/views/notifications/markdown/upcoming-audits.blade.php b/resources/views/notifications/markdown/upcoming-audits.blade.php new file mode 100644 index 0000000000..1d633a6936 --- /dev/null +++ b/resources/views/notifications/markdown/upcoming-audits.blade.php @@ -0,0 +1,20 @@ +@component('mail::message') + +### {{ trans_choice('mail.upcoming-audits', $assets->count(), ['count' => $assets->count()]) }} + +@component('mail::table') +| |{{ trans('mail.name') }}|{{ trans('general.last_audit') }}|{{ trans('general.next_audit_date') }}|{{ trans('mail.Days') }}|{{ trans('mail.supplier') }} | {{ trans('mail.assigned_to') }} +| |:------------- |:-------------|:---------|:---------|:---------|:---------| +@foreach ($assets as $asset) +@php +$next_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->next_audit_date, 'date', false); +$last_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->last_audit_date, 'date', false); +$diff = Carbon::parse($last_audit_date)->diffInDays(Carbon::now()); +$icon = ($diff <= 7) ? '🚨' : (($diff <= 14) ? '⚠️' : ' '); +@endphp +|{{ $icon }}| [{{ $asset->present()->name }}]({{ route('hardware.show', $asset->id) }}) | {{ $last_audit_date }}| {{ $next_audit_date }} | {{ $diff }} | {{ ($asset->supplier ? e($asset->supplier->name) : '') }}|{{ ($asset->assignedTo ? $asset->assignedTo->present()->name() : '') }} +@endforeach +@endcomponent + + +@endcomponent From 52c9e8ad96b5a7476531a036e0277ae9369e6598 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:11:28 -0400 Subject: [PATCH 10/26] Added route to list overdue / upcoming assets via API --- routes/api.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/routes/api.php b/routes/api.php index fffc46d55a..a5d4b1bb5a 100644 --- a/routes/api.php +++ b/routes/api.php @@ -321,13 +321,17 @@ Route::group(['prefix' => 'v1','namespace' => 'Api'], function () { 'uses' => 'AssetsController@selectlist' ]); + Route::get('audit/{audit}', [ + 'as' => 'api.asset.to-audit', + 'uses' => 'AssetsController@index' + ]); + Route::post('audit', [ 'as' => 'api.asset.audit', 'uses' => 'AssetsController@audit' ]); - Route::post('{asset_id}/checkout', [ 'as' => 'api.assets.checkout', From ab060288faa07d1d10dd77a5ca420d52171194a7 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:13:37 -0400 Subject: [PATCH 11/26] Controller/API methods for due/overdue audits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We could probably skip this and just handle it via view in the routes… --- app/Http/Controllers/AssetsController.php | 12 ++++++++++++ routes/web/hardware.php | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/app/Http/Controllers/AssetsController.php b/app/Http/Controllers/AssetsController.php index 8eec3f73c9..71b54cc1b6 100755 --- a/app/Http/Controllers/AssetsController.php +++ b/app/Http/Controllers/AssetsController.php @@ -744,6 +744,18 @@ class AssetsController extends Controller return view('hardware/audit')->with('asset', $asset)->with('next_audit_date', $dt)->with('locations_list'); } + public function dueForAudit() + { + $this->authorize('audit', Asset::class); + return view('hardware/audit-due'); + } + + public function overdueForAudit() + { + $this->authorize('audit', Asset::class); + return view('hardware/audit-overdue'); + } + public function auditStore(AssetFileRequest $request, $id) { diff --git a/routes/web/hardware.php b/routes/web/hardware.php index 081098806a..35decdc2b5 100644 --- a/routes/web/hardware.php +++ b/routes/web/hardware.php @@ -29,6 +29,16 @@ Route::group( 'uses' => 'AssetsController@scan' ]); + Route::get('audit/due', [ + 'as' => 'assets.audit.due', + 'uses' => 'AssetsController@dueForAudit' + ]); + + Route::get('audit/overdue', [ + 'as' => 'assets.audit.overdue', + 'uses' => 'AssetsController@overdueForAudit' + ]); + Route::get('audit/{id}', [ 'as' => 'asset.audit.create', 'uses' => 'AssetsController@audit' From 0e234bac70cab4dfa5a5c5f9bd0e3d636b356a8b Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:14:02 -0400 Subject: [PATCH 12/26] Added query scopes for due and overdue audits --- app/Models/Asset.php | 54 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index bf96e06965..d4ba267215 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -796,6 +796,60 @@ class Asset extends Depreciable }); } + /** + * Query builder scope for Assets that are due for auditing, based on the assets.next_audit_date + * and settings.audit_warning_days. + * + * This is/will be used in the artisan command snipeit:upcoming-audits and also + * for an upcoming API call for retrieving a report on assets that will need to be audited. + * + * Due for audit soon: + * next_audit_date greater than or equal to now (must be in the future) + * and (next_audit_date - threshold days) <= now () + * + * Example: + * next_audit_date = May 4, 2025 + * threshold for alerts = 30 days + * now = May 4, 2019 + * + * @author A. Gianotto + * @since v4.5.17 + * @param Setting $settings + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + + public function scopeDueForAudit($query, $settings) + { + return $query->whereNotNull('assets.next_audit_date') + ->where('assets.next_audit_date', '>=', Carbon::now()) + ->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'") + ->where('assets.archived', '=', 0) + ->NotArchived(); + } + + /** + * Query builder scope for Assets that are OVERDUE for auditing, based on the assets.next_audit_date + * and settings.audit_warning_days. It checks to see if assets.next audit_date is before now + * + * This is/will be used in the artisan command snipeit:upcoming-audits and also + * for an upcoming API call for retrieving a report on overdue assets. + * + * @author A. Gianotto + * @since v4.5.17 + * @param Setting $settings + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + + public function scopeOverdueForAudit($query, $settings) + { + return $query->whereNotNull('assets.next_audit_date') + ->where('assets.next_audit_date', '<', Carbon::now()) + ->where('assets.archived', '=', 0) + ->NotArchived(); + } + /** * Query builder scope for Archived assets * From 996a4cc29b525762fc88dc23a85ec6051e38aa7a Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:15:24 -0400 Subject: [PATCH 13/26] Added audit due console command to kernel --- app/Console/Kernel.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index f8a79a3f29..46b3cde2cb 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -49,6 +49,7 @@ class Kernel extends ConsoleKernel $schedule->command('snipeit:expected-checkin')->daily(); $schedule->command('snipeit:backup')->weekly(); $schedule->command('backup:clean')->daily(); + $schedule->command('snipeit:upcoming-audits')->daily(); } protected function commands() From 0f0ffd39a8784ee05b6f9d0aba252ff05fdafbc7 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:19:56 -0400 Subject: [PATCH 14/26] Added ability to pass audit specs to main API asset search method --- app/Http/Controllers/Api/AssetsController.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index c91c57ab7f..16c3fabfee 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -52,7 +52,7 @@ class AssetsController extends Controller * @since [v4.0] * @return JsonResponse */ - public function index(Request $request) + public function index(Request $request, $audit = null) { $this->authorize('index', Asset::class); @@ -148,6 +148,21 @@ class AssetsController extends Controller $limit = $request->input('limit', 50); $order = $request->input('order') === 'asc' ? 'asc' : 'desc'; + // This is used by the audit reporting routes + if (Gate::allows('audit', Asset::class)) { + + switch ($audit) { + case 'due': + $assets->DueForAudit($settings); + break; + case 'overdue': + $assets->overdueForAudit($settings); + break; + } + } + + + // This is used by the sidenav, mostly // We switched from using query scopes here because of a Laravel bug From 05a85c628f8ebc10714a17cccceb46f0125486e1 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:20:17 -0400 Subject: [PATCH 15/26] Added audit presenter --- app/Presenters/AssetAuditPresenter.php | 273 +++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 app/Presenters/AssetAuditPresenter.php diff --git a/app/Presenters/AssetAuditPresenter.php b/app/Presenters/AssetAuditPresenter.php new file mode 100644 index 0000000000..bfc917eea5 --- /dev/null +++ b/app/Presenters/AssetAuditPresenter.php @@ -0,0 +1,273 @@ + "id", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('general.id'), + "visible" => false + ], [ + "field" => "company", + "searchable" => true, + "sortable" => true, + "switchable" => true, + "title" => trans('general.company'), + "visible" => false, + "formatter" => 'assetCompanyObjFilterFormatter' + ], [ + "field" => "name", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.name'), + "visible" => true, + "formatter" => "hardwareLinkFormatter" + ], [ + "field" => "image", + "searchable" => false, + "sortable" => true, + "switchable" => true, + "title" => trans('admin/hardware/table.image'), + "visible" => false, + "formatter" => "imageFormatter" + ], [ + "field" => "asset_tag", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/table.asset_tag'), + "visible" => true, + "formatter" => "hardwareLinkFormatter" + ], [ + "field" => "serial", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.serial'), + "visible" => true, + "formatter" => "hardwareLinkFormatter" + ], [ + "field" => "model", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.model'), + "visible" => true, + "formatter" => "modelsLinkObjFormatter" + ], [ + "field" => "model_number", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/models/table.modelnumber'), + "visible" => false + ], [ + "field" => "category", + "searchable" => true, + "sortable" => true, + "title" => trans('general.category'), + "visible" => false, + "formatter" => "categoriesLinkObjFormatter" + ], [ + "field" => "status_label", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/table.status'), + "visible" => true, + "formatter" => "statuslabelsLinkObjFormatter" + ], [ + "field" => "assigned_to", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.checkedout_to'), + "visible" => true, + "formatter" => "polymorphicItemFormatter" + ], [ + "field" => "location", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/table.location'), + "visible" => true, + "formatter" => "deployedLocationFormatter" + ], [ + "field" => "rtd_location", + "searchable" => true, + "sortable" => true, + "title" => trans('admin/hardware/form.default_location'), + "visible" => false, + "formatter" => "deployedLocationFormatter" + ], [ + "field" => "manufacturer", + "searchable" => true, + "sortable" => true, + "title" => trans('general.manufacturer'), + "visible" => false, + "formatter" => "manufacturersLinkObjFormatter" + ], [ + "field" => "purchase_date", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.purchase_date'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "purchase_cost", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.purchase_cost'), + "footerFormatter" => 'sumFormatter', + ], [ + "field" => "order_number", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.order_number'), + 'formatter' => "orderNumberObjFilterFormatter" + ], [ + "field" => "eol", + "searchable" => false, + "sortable" => false, + "visible" => false, + "title" => trans('general.eol'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "warranty_months", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('admin/hardware/form.warranty') + ],[ + "field" => "warranty_expires", + "searchable" => false, + "sortable" => false, + "visible" => false, + "title" => trans('admin/hardware/form.warranty_expires'), + "formatter" => "dateDisplayFormatter" + ],[ + "field" => "notes", + "searchable" => true, + "sortable" => true, + "visible" => false, + "title" => trans('general.notes'), + + ], [ + "field" => "checkout_counter", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.checkouts_count') + + ],[ + "field" => "checkin_counter", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.checkins_count') + + ], [ + "field" => "requests_counter", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.user_requests_count') + + ], [ + "field" => "created_at", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.created_at'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "updated_at", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('general.updated_at'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "last_checkout", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('admin/hardware/table.checkout_date'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "expected_checkin", + "searchable" => false, + "sortable" => true, + "visible" => false, + "title" => trans('admin/hardware/form.expected_checkin'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "last_audit_date", + "searchable" => false, + "sortable" => true, + "visible" => true, + "title" => trans('general.last_audit'), + "formatter" => "dateDisplayFormatter" + ], [ + "field" => "next_audit_date", + "searchable" => false, + "sortable" => true, + "visible" => true, + "title" => trans('general.next_audit_date'), + "formatter" => "dateDisplayFormatter" + ], + ]; + + // This looks complicated, but we have to confirm that the custom fields exist in custom fieldsets + // *and* those fieldsets are associated with models, otherwise we'll trigger + // javascript errors on the bootstrap tables side of things, since we're asking for properties + // on fields that will never be passed through the REST API since they're not associated with + // models. We only pass the fieldsets that pertain to each asset (via their model) so that we + // don't junk up the REST API with tons of custom fields that don't apply + + $fields = CustomField::whereHas('fieldset', function ($query) { + $query->whereHas('models'); + })->get(); + + foreach ($fields as $field) { + $layout[] = [ + "field" => 'custom_fields.'.$field->convertUnicodeDbSlug(), + "searchable" => true, + "sortable" => true, + "visible" => false, + "switchable" => true, + "title" => ($field->field_encrypted=='1') ?' '.e($field->name) : e($field->name), + "formatter" => "customFieldsFormatter" + ]; + + } + + + $layout[] = [ + "field" => "actions", + "searchable" => false, + "sortable" => false, + "switchable" => false, + "title" => trans('table.actions'), + "formatter" => "hardwareAuditFormatter", + ]; + + return json_encode($layout); + } + + + +} From 8154d1116c4a608bd2203b9e0a1e698adc4378a6 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:21:06 -0400 Subject: [PATCH 16/26] Added bootstrap-tables presenter formatter to display an audit button --- resources/views/partials/bootstrap-table.blade.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/resources/views/partials/bootstrap-table.blade.php b/resources/views/partials/bootstrap-table.blade.php index b1eadb96c2..3132532326 100644 --- a/resources/views/partials/bootstrap-table.blade.php +++ b/resources/views/partials/bootstrap-table.blade.php @@ -167,6 +167,11 @@ }; } + function hardwareAuditFormatter(value, row) { + return '{{ trans('general.audit') }}'; + } + + // Make the edit/delete buttons function genericActionsFormatter(destination) { return function (value,row) { From 69614a7db4de8cd510e43affab408b4b49c3942c Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:21:26 -0400 Subject: [PATCH 17/26] Added gated sidenav items to left nav --- resources/views/layouts/default.blade.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 03f3037447..f701c9b2f5 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -440,6 +440,19 @@ + @can('audit', \App\Models\Asset::class) +
  • + + Due for Audit + +
  • +
  • + + Overdue for Audit + +
  • + @endcan +
  •  
  • @can('checkout', \App\Models\Asset::class) From 4369d6adc6c29c7ca54d1d1fa7f644038ad51444 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:21:48 -0400 Subject: [PATCH 18/26] Added audit due/overdue blades --- resources/views/hardware/audit-due.blade.php | 73 +++++++++++++++++++ .../views/hardware/audit-overdue.blade.php | 73 +++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 resources/views/hardware/audit-due.blade.php create mode 100644 resources/views/hardware/audit-overdue.blade.php diff --git a/resources/views/hardware/audit-due.blade.php b/resources/views/hardware/audit-due.blade.php new file mode 100644 index 0000000000..03c664aec8 --- /dev/null +++ b/resources/views/hardware/audit-due.blade.php @@ -0,0 +1,73 @@ +@extends('layouts/default') + +@section('title0') + + @if ((Input::get('company_id')) && ($company)) + {{ $company->name }} + @endif + + {{ trans('general.assets') }} + +@stop + +{{-- Page title --}} +@section('title') + @yield('title0') @parent +@stop + +@section('header_right') + {{ trans('general.create') }} +@stop + +{{-- Page content --}} +@section('content') + +
    +
    +
    +
    + {{ Form::open([ + 'method' => 'POST', + 'route' => ['hardware/bulkedit'], + 'class' => 'form-inline', + 'id' => 'bulkForm']) }} +
    +
    + +
    +
    + + + + {{ Form::close() }} + + + + +@stop + +@section('moar_scripts') + @include('partials.bootstrap-table') + +@stop diff --git a/resources/views/hardware/audit-overdue.blade.php b/resources/views/hardware/audit-overdue.blade.php new file mode 100644 index 0000000000..b4e473ffef --- /dev/null +++ b/resources/views/hardware/audit-overdue.blade.php @@ -0,0 +1,73 @@ +@extends('layouts/default') + +@section('title0') + + @if ((Input::get('company_id')) && ($company)) + {{ $company->name }} + @endif + + {{ trans('general.assets') }} + +@stop + +{{-- Page title --}} +@section('title') + @yield('title0') @parent +@stop + +@section('header_right') + {{ trans('general.create') }} +@stop + +{{-- Page content --}} +@section('content') + +
    +
    +
    +
    + {{ Form::open([ + 'method' => 'POST', + 'route' => ['hardware/bulkedit'], + 'class' => 'form-inline', + 'id' => 'bulkForm']) }} +
    +
    + + +
    + +
    +
    + {{ Form::close() }} +
    +
    +
    +
    +@stop + +@section('moar_scripts') + @include('partials.bootstrap-table') + +@stop From 7b194c678cb5e7f12780e76451e0cad1cdb1fe84 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:22:08 -0400 Subject: [PATCH 19/26] Cleanup on audit due/overdue console command --- app/Console/Commands/SendUpcomingAuditReport.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/app/Console/Commands/SendUpcomingAuditReport.php b/app/Console/Commands/SendUpcomingAuditReport.php index 47286b5ee6..b5eaaabba8 100644 --- a/app/Console/Commands/SendUpcomingAuditReport.php +++ b/app/Console/Commands/SendUpcomingAuditReport.php @@ -47,11 +47,6 @@ class SendUpcomingAuditReport extends Command { $settings = Setting::getSettings(); - // Threshold sets the very latest date the next audit could be: $settings->audit_warning_days from today - $threshold = Carbon::now()->addDays($settings->audit_warning_days); - - - if (($settings->alert_email != '') && ($settings->audit_warning_days) && ($settings->alerts_enabled == 1)) { // Send a rollup to the admin, if settings dictate @@ -59,15 +54,18 @@ class SendUpcomingAuditReport extends Command return new \App\Models\Recipients\AlertRecipient($item); }); + // Assets due for auditing - $assets = Asset::whereDate('next_audit_date', '<=', $threshold) - ->orderBy('last_audit_date', 'asc')->get(); + + $assets = Asset::whereNotNull('next_audit_date') + ->dueForAudit($settings) + ->orderBy('last_audit_date', 'asc')->get(); if ($assets->count() > 0) { $this->info(trans_choice('mail.upcoming-audits', $assets->count(), - ['count' => $assets->count(), 'threshold' => $threshold])); - \Notification::send($recipients, new SendUpcomingAuditNotification($assets, $threshold)); + ['count' => $assets->count(), 'threshold' => $settings->audit_warning_days])); + \Notification::send($recipients, new SendUpcomingAuditNotification($assets, $settings->audit_warning_days)); $this->info('Audit report sent to '.$settings->alert_email); } else { $this->info('No assets to be audited. No report sent.'); From e9b9301efb1e9a265bfcc6fee8f28b6f6065d355 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:35:20 -0400 Subject: [PATCH 20/26] Added language strings for audit views --- resources/lang/en/general.php | 8 +++++--- resources/views/hardware/audit-due.blade.php | 5 +---- resources/views/hardware/audit-overdue.blade.php | 5 +---- resources/views/layouts/default.blade.php | 12 ++++++------ 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/resources/lang/en/general.php b/resources/lang/en/general.php index ae2bcf0a44..e068d7fb1e 100644 --- a/resources/lang/en/general.php +++ b/resources/lang/en/general.php @@ -219,7 +219,9 @@ 'years' => 'years', 'yes' => 'Yes', 'zip' => 'Zip', - 'noimage' => 'No image uploaded or image not found.', - 'token_expired' => 'Your form session has expired. Please try again.', - 'login_enabled' => 'Login Enabled', + 'noimage' => 'No image uploaded or image not found.', + 'token_expired' => 'Your form session has expired. Please try again.', + 'login_enabled' => 'Login Enabled', + 'audit_due' => 'Due for Audit', + 'audit_overdue' => 'Overdue for Audit', ]; diff --git a/resources/views/hardware/audit-due.blade.php b/resources/views/hardware/audit-due.blade.php index 03c664aec8..ab99668f0f 100644 --- a/resources/views/hardware/audit-due.blade.php +++ b/resources/views/hardware/audit-due.blade.php @@ -6,7 +6,7 @@ {{ $company->name }} @endif - {{ trans('general.assets') }} + {{ trans('general.audit_due') }} @stop @@ -15,9 +15,6 @@ @yield('title0') @parent @stop -@section('header_right') - {{ trans('general.create') }} -@stop {{-- Page content --}} @section('content') diff --git a/resources/views/hardware/audit-overdue.blade.php b/resources/views/hardware/audit-overdue.blade.php index b4e473ffef..7cea5d0b14 100644 --- a/resources/views/hardware/audit-overdue.blade.php +++ b/resources/views/hardware/audit-overdue.blade.php @@ -6,7 +6,7 @@ {{ $company->name }} @endif - {{ trans('general.assets') }} + {{ trans('general.audit_overdue') }} @stop @@ -15,9 +15,6 @@ @yield('title0') @parent @stop -@section('header_right') - {{ trans('general.create') }} -@stop {{-- Page content --}} @section('content') diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index f701c9b2f5..a37d206e7b 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -441,26 +441,26 @@ @can('audit', \App\Models\Asset::class) -
  • + - Due for Audit + {{ trans('general.audit_due') }}
  • -
  • + - Overdue for Audit + {{ trans('general.audit_overdue') }}
  • @endcan
  •  
  • @can('checkout', \App\Models\Asset::class) - + {{ trans('general.bulk_checkout') }} - + {{ trans('general.requested') }} From 7d416d1175433e79edc1ff5a2308ea84daae68f6 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:57:23 -0400 Subject: [PATCH 21/26] Fixed :threshold placeholder --- app/Notifications/SendUpcomingAuditNotification.php | 4 +++- .../views/notifications/markdown/upcoming-audits.blade.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Notifications/SendUpcomingAuditNotification.php b/app/Notifications/SendUpcomingAuditNotification.php index eb68df6546..0aaf11cda5 100644 --- a/app/Notifications/SendUpcomingAuditNotification.php +++ b/app/Notifications/SendUpcomingAuditNotification.php @@ -20,6 +20,7 @@ class SendUpcomingAuditNotification extends Notification public function __construct($params, $threshold) { $this->assets = $params; + $this->threshold = $threshold; } /** @@ -44,8 +45,9 @@ class SendUpcomingAuditNotification extends Notification $message = (new MailMessage)->markdown('notifications.markdown.upcoming-audits', [ 'assets' => $this->assets, + 'threshold' => $this->threshold, ]) - ->subject(trans_choice('mail.upcoming-audits', $this->assets->count(), ['count' => $this->assets->count()])); + ->subject(trans_choice('mail.upcoming-audits', $this->assets->count(), ['count' => $this->assets->count(), 'threshold' => $this->threshold])); return $message; } diff --git a/resources/views/notifications/markdown/upcoming-audits.blade.php b/resources/views/notifications/markdown/upcoming-audits.blade.php index 1d633a6936..5fd269d1a5 100644 --- a/resources/views/notifications/markdown/upcoming-audits.blade.php +++ b/resources/views/notifications/markdown/upcoming-audits.blade.php @@ -1,6 +1,6 @@ @component('mail::message') -### {{ trans_choice('mail.upcoming-audits', $assets->count(), ['count' => $assets->count()]) }} +### {{ trans_choice('mail.upcoming-audits', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]) }} @component('mail::table') | |{{ trans('mail.name') }}|{{ trans('general.last_audit') }}|{{ trans('general.next_audit_date') }}|{{ trans('mail.Days') }}|{{ trans('mail.supplier') }} | {{ trans('mail.assigned_to') }} From 7497eaf3023582264263818c6c18dd304420668a Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 19:58:08 -0400 Subject: [PATCH 22/26] Removed unused setting variable --- app/Models/Asset.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index d4ba267215..fe5cfe65d7 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -842,7 +842,7 @@ class Asset extends Depreciable * @return \Illuminate\Database\Query\Builder Modified query builder */ - public function scopeOverdueForAudit($query, $settings) + public function scopeOverdueForAudit($query) { return $query->whereNotNull('assets.next_audit_date') ->where('assets.next_audit_date', '<', Carbon::now()) From 00a8a2aff3a7814e21473f5f06cbf32a8c60ffa3 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 20:00:05 -0400 Subject: [PATCH 23/26] Fixed next audit date math --- .../views/notifications/markdown/upcoming-audits.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/notifications/markdown/upcoming-audits.blade.php b/resources/views/notifications/markdown/upcoming-audits.blade.php index 5fd269d1a5..f294ae6e53 100644 --- a/resources/views/notifications/markdown/upcoming-audits.blade.php +++ b/resources/views/notifications/markdown/upcoming-audits.blade.php @@ -9,7 +9,7 @@ @php $next_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->next_audit_date, 'date', false); $last_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->last_audit_date, 'date', false); -$diff = Carbon::parse($last_audit_date)->diffInDays(Carbon::now()); +$diff = Carbon::parse($next_audit_date)->diffInDays(Carbon::now()); $icon = ($diff <= 7) ? '🚨' : (($diff <= 14) ? '⚠️' : ' '); @endphp |{{ $icon }}| [{{ $asset->present()->name }}]({{ route('hardware.show', $asset->id) }}) | {{ $last_audit_date }}| {{ $next_audit_date }} | {{ $diff }} | {{ ($asset->supplier ? e($asset->supplier->name) : '') }}|{{ ($asset->assignedTo ? $asset->assignedTo->present()->name() : '') }} From e4a298ca2a7a08c09634c9855cea7957276cf64a Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 22:13:30 -0400 Subject: [PATCH 24/26] Added scope for both overdue and upcoming --- .../Commands/SendUpcomingAuditReport.php | 2 +- app/Http/Controllers/Api/AssetsController.php | 2 +- app/Models/Asset.php | 23 +++++++++++++++++++ .../markdown/upcoming-audits.blade.php | 2 +- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/app/Console/Commands/SendUpcomingAuditReport.php b/app/Console/Commands/SendUpcomingAuditReport.php index b5eaaabba8..bac5a21698 100644 --- a/app/Console/Commands/SendUpcomingAuditReport.php +++ b/app/Console/Commands/SendUpcomingAuditReport.php @@ -58,7 +58,7 @@ class SendUpcomingAuditReport extends Command // Assets due for auditing $assets = Asset::whereNotNull('next_audit_date') - ->dueForAudit($settings) + ->DueOrOverdueForAudit($settings) ->orderBy('last_audit_date', 'asc')->get(); if ($assets->count() > 0) { diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 16c3fabfee..499ff8b748 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -153,7 +153,7 @@ class AssetsController extends Controller switch ($audit) { case 'due': - $assets->DueForAudit($settings); + $assets->DueOrOverdueForAudit($settings); break; case 'overdue': $assets->overdueForAudit($settings); diff --git a/app/Models/Asset.php b/app/Models/Asset.php index fe5cfe65d7..e3233a3e58 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -850,6 +850,29 @@ class Asset extends Depreciable ->NotArchived(); } + /** + * Query builder scope for Assets that are due for auditing OR overdue, based on the assets.next_audit_date + * and settings.audit_warning_days. + * + * This is/will be used in the artisan command snipeit:upcoming-audits and also + * for an upcoming API call for retrieving a report on assets that will need to be audited. + * + * @author A. Gianotto + * @since v4.5.17 + * @param Setting $settings + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + + public function scopeDueOrOverdueForAudit($query, $settings) + { + return $query->whereNotNull('assets.next_audit_date') + ->whereRaw("DATE_SUB(assets.next_audit_date, INTERVAL $settings->audit_warning_days DAY) <= '".Carbon::now()."'") + ->where('assets.archived', '=', 0) + ->NotArchived(); + } + + /** * Query builder scope for Archived assets * diff --git a/resources/views/notifications/markdown/upcoming-audits.blade.php b/resources/views/notifications/markdown/upcoming-audits.blade.php index f294ae6e53..de6e2a89c7 100644 --- a/resources/views/notifications/markdown/upcoming-audits.blade.php +++ b/resources/views/notifications/markdown/upcoming-audits.blade.php @@ -9,7 +9,7 @@ @php $next_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->next_audit_date, 'date', false); $last_audit_date = \App\Helpers\Helper::getFormattedDateObject($asset->last_audit_date, 'date', false); -$diff = Carbon::parse($next_audit_date)->diffInDays(Carbon::now()); +$diff = Carbon::parse(Carbon::now())->diffInDays($next_audit_date, false); $icon = ($diff <= 7) ? '🚨' : (($diff <= 14) ? '⚠️' : ' '); @endphp |{{ $icon }}| [{{ $asset->present()->name }}]({{ route('hardware.show', $asset->id) }}) | {{ $last_audit_date }}| {{ $next_audit_date }} | {{ $diff }} | {{ ($asset->supplier ? e($asset->supplier->name) : '') }}|{{ ($asset->assignedTo ? $asset->assignedTo->present()->name() : '') }} From a86409868e161c9ceee9d098f37499be9eacf636 Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 22:31:43 -0400 Subject: [PATCH 25/26] Derp. Wrong version --- app/Models/Asset.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index e3233a3e58..03343f8c6c 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -813,7 +813,7 @@ class Asset extends Depreciable * now = May 4, 2019 * * @author A. Gianotto - * @since v4.5.17 + * @since v4.6.16 * @param Setting $settings * * @return \Illuminate\Database\Query\Builder Modified query builder @@ -836,7 +836,7 @@ class Asset extends Depreciable * for an upcoming API call for retrieving a report on overdue assets. * * @author A. Gianotto - * @since v4.5.17 + * @since v4.6.16 * @param Setting $settings * * @return \Illuminate\Database\Query\Builder Modified query builder @@ -858,7 +858,7 @@ class Asset extends Depreciable * for an upcoming API call for retrieving a report on assets that will need to be audited. * * @author A. Gianotto - * @since v4.5.17 + * @since v4.6.16 * @param Setting $settings * * @return \Illuminate\Database\Query\Builder Modified query builder From c6d3c031c7e38bca32c760695fc18384d4c0fabf Mon Sep 17 00:00:00 2001 From: snipe Date: Sun, 5 May 2019 22:32:01 -0400 Subject: [PATCH 26/26] Bumped version (I will release this version officially tomorrow) --- config/version.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/version.php b/config/version.php index 7ae4ca516d..78d3fee89c 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v4.6.15', - 'full_app_version' => 'v4.6.15 - build 4011-gd1e9fbfa2', - 'build_version' => '4011', + 'app_version' => 'v4.6.16', + 'full_app_version' => 'v4.6.16 - build 4018-gce16eae50', + 'build_version' => '4018', 'prerelease_version' => '', - 'hash_version' => 'gd1e9fbfa2', - 'full_hash' => 'v4.6.15-2-gd1e9fbfa2', - 'branch' => 'master', + 'hash_version' => 'gce16eae50', + 'full_hash' => 'v4.6.16-6-gce16eae50', + 'branch' => 'features/6204_email_audit-alerts', );