Added: Caching of settings (#6378)

* Fixed missing oauth tables during setup.

* Cache settings

Cache the setting to reduce unnecessary database calls
This commit is contained in:
Wes Hulette 2018-11-01 22:59:50 -04:00 committed by snipe
parent 0730685c29
commit 88b1da4260
13 changed files with 316 additions and 190 deletions

View file

@ -41,7 +41,7 @@ class DisableLDAP extends Command
if ($this->confirm("\n****************************************************\nThis will disable LDAP support. You will not be able \nto login with an account that does not exist \nlocally in the Snipe-IT local database. \n****************************************************\n\nDo you wish to continue? [y|N]")) {
$setting = Setting::first();
$setting = Setting::getSettings();
$setting->ldap_enabled = 0;
if ($setting->save()) {
$this->info('LDAP has been set to disabled.');

View file

@ -52,7 +52,7 @@ class SendExpirationAlerts extends Command
});
// Expiring Assets
$assets = Asset::getExpiringWarrantee(Setting::getSettings()->alert_interval);
$assets = Asset::getExpiringWarrantee($threshold);
if ($assets->count() > 0) {
$this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $threshold]));
Notification::send($recipients, new ExpiringAssetsNotification($assets, $threshold));

View file

@ -0,0 +1,20 @@
<?php
namespace App\Events;
use App\Models\Setting;
class SettingSaved
{
public $settings;
/**
* Create a new event instance.
*
* @param \App\Models\Setting $settings
*/
public function __construct(Setting $settings)
{
$this->settings = $settings;
}
}

View file

@ -173,7 +173,7 @@ class ReportsController extends Controller
if ($asset->location) {
$currency = e($asset->location->currency);
} else {
$currency = e(Setting::first()->default_currency);
$currency = e(Setting::getSettings()->default_currency);
}
$row[] = $asset->purchase_date;

View file

@ -267,7 +267,7 @@ class SettingsController extends Controller
*/
public function index()
{
$settings = Setting::all();
$settings = Setting::getSettings();
return view('settings/index', compact('settings'));
}
@ -283,7 +283,7 @@ class SettingsController extends Controller
*/
public function getEdit()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings/general', compact('setting'));
}
@ -299,7 +299,7 @@ class SettingsController extends Controller
*/
public function getSettings()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings/general', compact('setting'));
}
@ -315,7 +315,7 @@ class SettingsController extends Controller
*/
public function postSettings(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -369,7 +369,7 @@ class SettingsController extends Controller
*/
public function getBranding()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.branding', compact('setting'));
}
@ -385,7 +385,7 @@ class SettingsController extends Controller
*/
public function postBranding(ImageUploadRequest $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -452,7 +452,7 @@ class SettingsController extends Controller
*/
public function getSecurity()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.security', compact('setting'));
}
@ -468,7 +468,7 @@ class SettingsController extends Controller
*/
public function postSecurity(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -512,7 +512,7 @@ class SettingsController extends Controller
*/
public function getLocalization()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.localization', compact('setting'));
}
@ -528,7 +528,7 @@ class SettingsController extends Controller
*/
public function postLocalization(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -558,7 +558,7 @@ class SettingsController extends Controller
*/
public function getAlerts()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.alerts', compact('setting'));
}
@ -574,7 +574,7 @@ class SettingsController extends Controller
*/
public function postAlerts(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -611,7 +611,7 @@ class SettingsController extends Controller
*/
public function getSlack()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.slack', compact('setting'));
}
@ -627,7 +627,7 @@ class SettingsController extends Controller
*/
public function postSlack(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -654,7 +654,7 @@ class SettingsController extends Controller
*/
public function getAssetTags()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.asset_tags', compact('setting'));
}
@ -670,7 +670,7 @@ class SettingsController extends Controller
*/
public function postAssetTags(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -698,7 +698,7 @@ class SettingsController extends Controller
*/
public function getBarcodes()
{
$setting = Setting::first();
$setting = Setting::getSettings();
$is_gd_installed = extension_loaded('gd');
return view('settings.barcodes', compact('setting'))->with('is_gd_installed', $is_gd_installed);
@ -715,7 +715,7 @@ class SettingsController extends Controller
*/
public function postBarcodes(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
@ -763,7 +763,7 @@ class SettingsController extends Controller
*/
public function getLabels()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.labels', compact('setting'));
}
@ -779,7 +779,7 @@ class SettingsController extends Controller
*/
public function postLabels(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}
$setting->labels_per_page = $request->input('labels_per_page');
@ -845,7 +845,7 @@ class SettingsController extends Controller
*/
public function getLdapSettings()
{
$setting = Setting::first();
$setting = Setting::getSettings();
return view('settings.ldap', compact('setting'));
}
@ -861,7 +861,7 @@ class SettingsController extends Controller
*/
public function postLdapSettings(Request $request)
{
if (is_null($setting = Setting::first())) {
if (is_null($setting = Setting::getSettings())) {
return redirect()->to('admin')->with('error', trans('admin/settings/message.update.error'));
}

View file

@ -14,7 +14,10 @@ class CheckForSetup
public function handle($request, Closure $next, $guard = null)
{
// This is dumb
/**
* This is dumb
* @todo Check on removing this, not sure if it's still needed
*/
if ($request->is('_debugbar*')) {
return $next($request);
}

View file

@ -1,52 +1,55 @@
<?php
namespace App\Http\Middleware;
use App\Models\Setting;
use Auth;
use Closure;
use Illuminate\Support\Facades\Schema;
use Log;
use App\Models\Setting;
class CheckForTwoFactor
{
/**
* Routes to ignore for Two Factor Auth
*/
const IGNORE_ROUTES = ['two-factor', 'two-factor-enroll', 'setup', 'logout'];
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param \Illuminate\Http\Request $request
* @param \Closure $next
*
* @return mixed
*/
public function handle($request, Closure $next)
{
// Skip the logic if the user is on the two factor pages or the setup pages
if (($request->route()->getName()=='two-factor') || ($request->route()->getName()=='two-factor-enroll') || ($request->route()->getPrefix()=='setup') || ($request->route()->getName()=='logout')) {
if (in_array($request->route()->getName(), self::IGNORE_ROUTES)) {
return $next($request);
}
// Two-factor is enabled (either optional or required)
if (Setting::getSettings()) {
if (Auth::check() && (Setting::getSettings()->two_factor_enabled!='')) {
if ($settings = Setting::getSettings()) {
if (Auth::check() && ($settings->two_factor_enabled != '')) {
// This user is already 2fa-authed
if ($request->session()->get('2fa_authed')) {
return $next($request);
}
// Two-factor is optional and the user has NOT opted in, let them through
if ((Setting::getSettings()->two_factor_enabled=='1') && (Auth::user()->two_factor_optin!='1')) {
if (($settings->two_factor_enabled == '1') && (Auth::user()->two_factor_optin != '1')) {
return $next($request);
}
// Otherwise make sure they're enrolled and show them the 2FA code screen
if ((Auth::user()->two_factor_secret!='') && (Auth::user()->two_factor_enrolled=='1')) {
if ((Auth::user()->two_factor_secret != '') && (Auth::user()->two_factor_enrolled == '1')) {
return redirect()->route('two-factor')->with('info', 'Please enter your two-factor authentication code.');
}
return redirect()->route('two-factor-enroll')->with('success', 'Please enroll a device in two-factor authentication.');
}
}
return $next($request);
return $next($request);
}
}

View file

@ -4,35 +4,31 @@ namespace App\Http\Middleware;
use Closure;
use Config;
use Route;
use Schema;
use App\Models\Setting;
class CheckLocale
{
/**
* Handle the locale for the user, default to settings otherwise
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
* @return mixed
*/
/**
* Handle the locale for the user, default to settings otherwise.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string|null $guard
*
* @return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Setting::getSettings()) {
if ($settings = Setting::getSettings()) {
// User's preference
if (($request->user()) && ($request->user()->locale)) {
\App::setLocale($request->user()->locale);
// App setting preference
} elseif ((Setting::getSettings()) && (Setting::getSettings()->locale!='')) {
\App::setLocale(Setting::getSettings()->locale);
// App setting preference
} elseif ($settings->locale != '') {
\App::setLocale($settings->locale);
// Default app setting
// Default app setting
} else {
\App::setLocale(config('app.locale'));
}

View file

@ -1,21 +1,24 @@
<?php
namespace App\Http\Traits;
use App\Models\Setting;
trait UniqueSerialTrait
{
/**
* Prepare a unique_ids rule, adding a model identifier if required.
*
* @param array $parameters
* @param string $field
* @param array $parameters
* @param string $field
*
* @return string
*/
protected function prepareUniqueSerialRule($parameters, $field)
{
if ($settings = \App\Models\Setting::first()) {
if ($settings->unique_serial=='1') {
return 'unique_undeleted:'.$this->table.','. $this->getKey();
if ($settings = Setting::getSettings()) {
if ($settings->unique_serial == '1') {
return 'unique_undeleted:'.$this->table.','.$this->getKey();
}
}
}

View file

@ -50,7 +50,7 @@ class Depreciable extends SnipeModel
return $this->purchase_cost;
}
$depreciation = 0;
$setting = Setting::first();
$setting = Setting::getSettings();
switch($setting->depreciation_method) {
case 'half_1':
$depreciation = $this->getHalfYearDepreciatedValue(true);

View file

@ -1,201 +1,297 @@
<?php
namespace App\Models;
use Parsedown;
use App\Events\SettingSaved;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Cache;
use Watson\Validating\ValidatingTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Watson\Validating\ValidatingTrait;
use Schema;
/**
* Settings model.
*/
class Setting extends Model
{
use Notifiable;
protected $injectUniqueIdentifier = true;
use ValidatingTrait;
use Notifiable, ValidatingTrait;
protected $rules = [
'brand' => 'required|min:1|numeric',
'qr_text' => 'max:31|nullable',
'logo_img' => 'mimes:jpeg,bmp,png,gif',
'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email|nullable',
'default_currency' => 'required',
'locale' => 'required',
'slack_endpoint' => 'url|required_with:slack_channel|nullable',
'slack_channel' => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint|nullable',
'slack_botname' => 'string|nullable',
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
'labels_pmargin_left' => 'numeric|nullable',
'labels_pmargin_right' => 'numeric|nullable',
'labels_pmargin_top' => 'numeric|nullable',
'labels_pmargin_bottom' => 'numeric|nullable',
'labels_display_bgutter' => 'numeric|nullable',
'labels_display_sgutter' => 'numeric|nullable',
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
'login_remote_user_enabled' => 'numeric|nullable',
'login_common_disabled' => 'numeric|nullable',
'login_remote_user_custom_logout_url' => 'string|nullable',
'thumbnail_max_h' => 'numeric|max:500|min:25',
'pwd_secure_min' => 'numeric|required|min:5',
'audit_warning_days' => 'numeric|nullable',
'audit_interval' => 'numeric|nullable',
'custom_forgot_pass_url' => 'url|nullable',
'privacy_policy_link' => 'nullable|url'
/**
* The app settings cache key name.
*
* @var string
*/
const APP_SETTINGS_KEY = 'snipeit_app_settings';
/**
* The setup check cache key name.
*
* @var string
*/
const SETUP_CHECK_KEY = 'snipeit_setup_check';
/**
* Whether the model should inject it's identifier to the unique
* validation rules before attempting validation. If this property
* is not set in the model it will default to true.
*
* @var bool
*/
protected $injectUniqueIdentifier = true;
/**
* The event map for the model.
*
* @var array
*/
protected $dispatchesEvents = [
'saved' => SettingSaved::class,
];
protected $fillable = ['site_name','email_domain','email_format','username_format'];
/**
* Model rules.
*
* @var array
*/
protected $rules = [
'brand' => 'required|min:1|numeric',
'qr_text' => 'max:31|nullable',
'logo_img' => 'mimes:jpeg,bmp,png,gif',
'alert_email' => 'email_array|nullable',
'admin_cc_email' => 'email|nullable',
'default_currency' => 'required',
'locale' => 'required',
'slack_endpoint' => 'url|required_with:slack_channel|nullable',
'slack_channel' => 'regex:/(?<!\w)#\w+/|required_with:slack_endpoint|nullable',
'slack_botname' => 'string|nullable',
'labels_per_page' => 'numeric',
'labels_width' => 'numeric',
'labels_height' => 'numeric',
'labels_pmargin_left' => 'numeric|nullable',
'labels_pmargin_right' => 'numeric|nullable',
'labels_pmargin_top' => 'numeric|nullable',
'labels_pmargin_bottom' => 'numeric|nullable',
'labels_display_bgutter' => 'numeric|nullable',
'labels_display_sgutter' => 'numeric|nullable',
'labels_fontsize' => 'numeric|min:5',
'labels_pagewidth' => 'numeric|nullable',
'labels_pageheight' => 'numeric|nullable',
'login_remote_user_enabled' => 'numeric|nullable',
'login_common_disabled' => 'numeric|nullable',
'login_remote_user_custom_logout_url' => 'string|nullable',
'thumbnail_max_h' => 'numeric|max:500|min:25',
'pwd_secure_min' => 'numeric|required|min:5',
'audit_warning_days' => 'numeric|nullable',
'audit_interval' => 'numeric|nullable',
'custom_forgot_pass_url' => 'url|nullable',
'privacy_policy_link' => 'nullable|url',
];
protected $fillable = [
'site_name',
'email_domain',
'email_format',
'username_format',
];
/**
* Get the app settings.
* Cache is expired on Setting model saved in EventServiceProvider.
*
* @author Wes Hulette <jwhulette@gmail.com>
*
* @since 5.0.0
*
* @return \App\Models\Setting
*/
public static function getSettings()
{
static $static_cache = null;
return Cache::rememberForever(self::APP_SETTINGS_KEY, function () {
return self::first();
});
}
if (!$static_cache) {
if (Schema::hasTable('settings')) {
$static_cache = Setting::first();
/**
* Check to see if setup process is complete.
* Cache is expired on Setting model saved in EventServiceProvider.
*
* @return bool
*/
public static function setupCompleted(): bool
{
return Cache::rememberForever(self::SETUP_CHECK_KEY, function () {
try {
$usercount = User::withTrashed()->count();
$settingsCount = self::count();
return $usercount > 0 && $settingsCount > 0;
} catch (\Throwable $th) {
// Catche the error if the tables dont exit
}
}
return $static_cache;
return false;
});
}
public static function setupCompleted()
/**
* Get the current Laravel version.
*
* @return string
*/
public function lar_ver(): string
{
$app = App::getFacadeApplication();
$users_table_exists = Schema::hasTable('users');
$settings_table_exists = Schema::hasTable('settings');
if ($users_table_exists && $settings_table_exists) {
$usercount = User::withTrashed()->count();
$settingsCount = Setting::count();
return ($usercount > 0 && $settingsCount > 0);
}
}
public function lar_ver()
{
$app = \App::getFacadeApplication();
return $app::VERSION;
}
public static function getDefaultEula()
/**
* Get the default EULA text.
*
* @return string|null
*/
public static function getDefaultEula(): ?string
{
$Parsedown = new \Parsedown();
if (Setting::getSettings()->default_eula_text) {
return $Parsedown->text(e(Setting::getSettings()->default_eula_text));
if (self::getSettings()->default_eula_text) {
$parsedown = new Parsedown();
return $parsedown->text(e(self::getSettings()->default_eula_text));
}
return null;
}
public function modellistCheckedValue ($element) {
/**
* Check wether to show in model dropdowns.
*
* @param string $element
*
* @return bool
*/
public function modellistCheckedValue($element): bool
{
$settings = self::getSettings();
// If the value is blank for some reason
if ($this->modellist_displays=='') {
if ($settings->modellist_displays == '') {
return false;
}
$values = explode(',', $this->modellist_displays);
$values = explode(',', $settings->modellist_displays);
foreach ($values as $value) {
if ($value == $element) {
return true;
}
}
return false;
return false;
}
/**
* Escapes the custom CSS, and then un-escapes the greater-than symbol
* so it can work with direct descendant characters for bootstrap
* menu overrides like:
* menu overrides like:.
*
* .skin-blue .sidebar-menu>li.active>a, .skin-blue .sidebar-menu>li:hover>a
*
* Important: Do not remove the e() escaping here, as we output raw in the blade.
*
* @return string escaped CSS
*
* @author A. Gianotto <snipe@snipe.net>
*/
public function show_custom_css()
public function show_custom_css(): string
{
$custom_css = Setting::getSettings()->custom_css;
$custom_css = self::getSettings()->custom_css;
$custom_css = e($custom_css);
// Needed for modifying the bootstrap nav :(
$custom_css = str_ireplace('script', 'SCRIPTS-NOT-ALLOWED-HERE', $custom_css);
$custom_css = str_replace('&gt;', '>', $custom_css);
return $custom_css;
}
/**
* Converts bytes into human readable file size.
*
* @param string $bytes
* @return string human readable file size (2,87 Мб)
* @author Mogilev Arseny
*/
public static function fileSizeConvert($bytes)
* Converts bytes into human readable file size.
*
* @param string $bytes
*
* @return string human readable file size (2,87 Мб)
*
* @author Mogilev Arseny
*/
public static function fileSizeConvert($bytes): string
{
$bytes = floatval($bytes);
$arBytes = array(
0 => array(
"UNIT" => "TB",
"VALUE" => pow(1024, 4)
),
1 => array(
"UNIT" => "GB",
"VALUE" => pow(1024, 3)
),
2 => array(
"UNIT" => "MB",
"VALUE" => pow(1024, 2)
),
3 => array(
"UNIT" => "KB",
"VALUE" => 1024
),
4 => array(
"UNIT" => "B",
"VALUE" => 1
),
);
$arBytes = [
0 => [
'UNIT' => 'TB',
'VALUE' => pow(1024, 4),
],
1 => [
'UNIT' => 'GB',
'VALUE' => pow(1024, 3),
],
2 => [
'UNIT' => 'MB',
'VALUE' => pow(1024, 2),
],
3 => [
'UNIT' => 'KB',
'VALUE' => 1024,
],
4 => [
'UNIT' => 'B',
'VALUE' => 1,
],
];
foreach ($arBytes as $arItem) {
if ($bytes >= $arItem["VALUE"]) {
$result = $bytes / $arItem["VALUE"];
$result = round($result, 2) .$arItem["UNIT"];
break;
}
foreach ($arBytes as $arItem) {
if ($bytes >= $arItem['VALUE']) {
$result = $bytes / $arItem['VALUE'];
$result = round($result, 2).$arItem['UNIT'];
break;
}
return $result;
}
return $result;
}
/**
* The url for slack notifications.
* Used by Notifiable trait.
* @return mixed
* Used by Notifiable trait.
*
* @return string
*/
public function routeNotificationForSlack()
public function routeNotificationForSlack(): string
{
// At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications.
return $this->slack_endpoint;
return self::getSettings()->slack_endpoint;
}
public function routeNotificationForMail()
/**
* Get the mail reply to address from configuration.
*
* @return string
*/
public function routeNotificationForMail(): string
{
// At this point the endpoint is the same for everything.
// In the future this may want to be adapted for individual notifications.
return config('mail.reply_to.address');
}
public static function passwordComplexityRulesSaving($action = 'update')
/**
* Get the password complexity rule.
*
* @return string
*/
public static function passwordComplexityRulesSaving($action = 'update'): string
{
$security_rules = '';
$settings = Setting::getSettings();
$settings = self::getSettings();
// Check if they have uncommon password enforcement selected in settings
if ($settings->pwd_secure_uncommon == 1) {
@ -203,8 +299,8 @@ class Setting extends Model
}
// Check for any secure password complexity rules that may have been selected
if ($settings->pwd_secure_complexity!='') {
$security_rules .= '|'.$settings->pwd_secure_complexity;
if ($settings->pwd_secure_complexity != '') {
$security_rules .= '|'.$settings->pwd_secure_complexity;
}
if ($action == 'update') {
@ -212,9 +308,5 @@ class Setting extends Model
}
return 'required|min:'.$settings->pwd_secure_min.$security_rules;
}
}

View file

@ -57,7 +57,7 @@ class AssetObserver
*/
public function created(Asset $asset)
{
if ($settings = Setting::first()) {
if ($settings = Setting::getSettings()) {
$settings->increment('next_auto_tag_base');
}

View file

@ -2,9 +2,12 @@
namespace App\Providers;
use App\Models\Setting;
use App\Events\SettingSaved;
use App\Listeners\LogListener;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use App\Listeners\CheckoutableListener;
use App\Listeners\LogListener;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
@ -44,6 +47,12 @@ class EventServiceProvider extends ServiceProvider
{
parent::boot();
//
/**
* Clear the LDAP settings cache when the settings model is saved
*/
Event::listen(SettingSaved::class, function () {
Cache::forget(Setting::APP_SETTINGS_KEY);
Cache::forget(Setting::SETUP_CHECK_KEY);
});
}
}