2016-03-25 01:18:05 -07:00
< ? php
2018-10-03 10:06:24 -07:00
2016-03-25 01:18:05 -07:00
namespace App\Http\Controllers ;
2020-04-21 04:08:25 -07:00
use App\Helpers\Helper ;
2021-06-10 13:15:52 -07:00
use App\Helpers\StorageHelper ;
2020-04-21 04:08:25 -07:00
use App\Http\Requests\ImageUploadRequest ;
2020-05-05 07:06:19 -07:00
use App\Http\Requests\SettingsSamlRequest ;
2018-10-03 10:06:24 -07:00
use App\Http\Requests\SetupUserRequest ;
2016-03-25 01:18:05 -07:00
use App\Models\Setting ;
2022-02-16 20:19:38 -08:00
use App\Models\Asset ;
2016-03-25 19:26:22 -07:00
use App\Models\User ;
2018-03-03 14:37:42 -08:00
use App\Notifications\FirstAdminNotification ;
2018-10-03 10:06:24 -07:00
use App\Notifications\MailTest ;
use Auth ;
use Crypt ;
2016-03-25 01:18:05 -07:00
use DB ;
2021-06-10 13:15:52 -07:00
use enshrined\svgSanitize\Sanitizer ;
2018-10-03 10:06:24 -07:00
use Illuminate\Http\Request ;
2018-09-29 21:33:52 -07:00
use Illuminate\Support\Facades\Storage ;
2016-03-25 01:18:05 -07:00
use Image ;
2018-10-03 10:06:24 -07:00
use Input ;
use Redirect ;
2016-03-25 01:18:05 -07:00
use Response ;
2021-12-08 17:54:15 -08:00
use App\Http\Requests\SlackSettingsRequest ;
2021-11-10 00:07:17 -08:00
use Illuminate\Support\Str ;
use Illuminate\Support\Facades\Artisan ;
2016-12-27 17:31:53 -08:00
2016-03-25 01:18:05 -07:00
/**
2016-04-07 13:21:09 -07:00
* This controller handles all actions related to Settings for
* the Snipe - IT Asset Management application .
*
* @ version v1 . 0
2016-03-25 01:18:05 -07:00
*/
class SettingsController extends Controller
{
/**
2018-10-03 10:06:24 -07:00
* Checks to see whether or not the database has a migrations table
* and a user , otherwise display the setup view .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v3 . 0 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function getSetupIndex ()
{
2018-08-02 21:36:18 -07:00
$start_settings [ 'php_version_min' ] = false ;
2016-03-25 01:18:05 -07:00
2018-08-02 21:36:18 -07:00
if ( version_compare ( PHP_VERSION , config ( 'app.min_php' ), '<' )) {
2021-06-10 13:15:52 -07:00
return response ( '<center><h1>This software requires PHP version ' . config ( 'app.min_php' ) . ' or greater. This server is running ' . PHP_VERSION . '. </h1><h2>Please upgrade PHP on this server and try again. </h2></center>' , 500 );
2018-08-02 21:36:18 -07:00
}
2016-03-25 01:18:05 -07:00
try {
2021-06-10 13:15:52 -07:00
$conn = DB :: select ( 'select 2 + 2' );
$start_settings [ 'db_conn' ] = true ;
$start_settings [ 'db_name' ] = DB :: connection () -> getDatabaseName ();
2016-03-25 01:18:05 -07:00
$start_settings [ 'db_error' ] = null ;
} catch ( \PDOException $e ) {
2021-06-10 13:15:52 -07:00
$start_settings [ 'db_conn' ] = false ;
$start_settings [ 'db_name' ] = config ( 'database.connections.mysql.database' );
2016-03-25 01:18:05 -07:00
$start_settings [ 'db_error' ] = $e -> getMessage ();
}
2018-10-03 10:06:24 -07:00
$protocol = array_key_exists ( 'HTTPS' , $_SERVER ) && ( 'on' == $_SERVER [ 'HTTPS' ]) ? 'https://' : 'http://' ;
2016-05-14 15:04:59 -07:00
2018-02-22 21:46:58 -08:00
$host = array_key_exists ( 'SERVER_NAME' , $_SERVER ) ? $_SERVER [ 'SERVER_NAME' ] : null ;
$port = array_key_exists ( 'SERVER_PORT' , $_SERVER ) ? $_SERVER [ 'SERVER_PORT' ] : null ;
2018-10-03 10:06:24 -07:00
if (( 'http://' === $protocol && '80' != $port ) || ( 'https://' === $protocol && '443' != $port )) {
2021-06-10 13:15:52 -07:00
$host .= ':' . $port ;
2016-03-25 01:18:05 -07:00
}
2021-06-10 13:15:52 -07:00
$pageURL = $protocol . $host . $_SERVER [ 'REQUEST_URI' ];
2016-03-25 01:18:05 -07:00
2021-06-10 13:15:52 -07:00
$start_settings [ 'url_valid' ] = ( url ( '/' ) . '/setup' === $pageURL );
2016-03-25 01:18:05 -07:00
2021-06-10 13:15:52 -07:00
$start_settings [ 'url_config' ] = url ( '/' );
$start_settings [ 'real_url' ] = $pageURL ;
2018-08-02 21:36:18 -07:00
$start_settings [ 'php_version_min' ] = true ;
2018-01-17 10:58:03 -08:00
2017-06-01 20:41:23 -07:00
// Curl the .env file to make sure it's not accessible via a browser
2021-06-10 13:15:52 -07:00
$ch = curl_init ( $protocol . $host . '/.env' );
2017-06-01 20:41:23 -07:00
curl_setopt ( $ch , CURLOPT_HEADER , true ); // we want headers
curl_setopt ( $ch , CURLOPT_NOBODY , true ); // we don't need body
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_TIMEOUT , 10 );
2021-06-10 13:15:52 -07:00
$output = curl_exec ( $ch );
2017-06-01 20:41:23 -07:00
$httpcode = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
curl_close ( $ch );
2016-03-25 01:18:05 -07:00
2018-10-03 10:06:24 -07:00
if ( 404 == $httpcode || 403 == $httpcode || 0 == $httpcode ) {
2016-03-25 01:18:05 -07:00
$start_settings [ 'env_exposed' ] = false ;
2017-06-01 20:41:23 -07:00
} else {
$start_settings [ 'env_exposed' ] = true ;
2016-03-25 01:18:05 -07:00
}
2018-10-03 10:06:24 -07:00
if ( \App :: Environment ( 'production' ) && ( true == config ( 'app.debug' ))) {
2016-03-25 01:18:05 -07:00
$start_settings [ 'debug_exposed' ] = true ;
} else {
$start_settings [ 'debug_exposed' ] = false ;
}
$environment = app () -> environment ();
2018-10-03 10:06:24 -07:00
if ( 'production' != $environment ) {
2021-06-10 13:15:52 -07:00
$start_settings [ 'env' ] = $environment ;
2016-03-25 01:18:05 -07:00
$start_settings [ 'prod' ] = false ;
} else {
2021-06-10 13:15:52 -07:00
$start_settings [ 'env' ] = $environment ;
2016-03-25 01:18:05 -07:00
$start_settings [ 'prod' ] = true ;
}
2016-06-22 12:27:41 -07:00
if ( function_exists ( 'posix_getpwuid' )) { // Probably Linux
2021-06-10 13:15:52 -07:00
$owner = posix_getpwuid ( fileowner ( $_SERVER [ 'SCRIPT_FILENAME' ]));
2016-06-06 05:37:45 -07:00
$start_settings [ 'owner' ] = $owner [ 'name' ];
} else { // Windows
// TODO: Is there a way of knowing if a windows user has elevated permissions
// This just gets the user name, which likely isn't 'root'
// $start_settings['owner'] = getenv('USERNAME');
$start_settings [ 'owner' ] = '' ;
}
2016-03-25 01:18:05 -07:00
2018-10-03 10:06:24 -07:00
if (( 'root' === $start_settings [ 'owner' ]) || ( '0' === $start_settings [ 'owner' ])) {
2016-03-25 01:18:05 -07:00
$start_settings [ 'owner_is_admin' ] = true ;
} else {
$start_settings [ 'owner_is_admin' ] = false ;
}
if (( is_writable ( storage_path ()))
2021-06-10 13:15:52 -07:00
&& ( is_writable ( storage_path () . '/framework' ))
&& ( is_writable ( storage_path () . '/framework/cache' ))
&& ( is_writable ( storage_path () . '/framework/sessions' ))
&& ( is_writable ( storage_path () . '/framework/views' ))
&& ( is_writable ( storage_path () . '/logs' ))
2016-03-25 01:18:05 -07:00
) {
$start_settings [ 'writable' ] = true ;
} else {
$start_settings [ 'writable' ] = false ;
}
$start_settings [ 'gd' ] = extension_loaded ( 'gd' );
2018-10-03 10:06:24 -07:00
2017-06-09 16:44:03 -07:00
return view ( 'setup/index' )
2020-04-21 04:08:25 -07:00
-> with ( 'step' , 1 )
-> with ( 'start_settings' , $start_settings )
-> with ( 'section' , 'Pre-Flight Check' );
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Save the first admin user from Setup .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v3 . 0 ]
*
* @ return Redirect
*/
2016-03-25 01:18:05 -07:00
public function postSaveFirstAdmin ( SetupUserRequest $request )
{
2021-06-10 13:15:52 -07:00
$user = new User ();
$user -> first_name = $data [ 'first_name' ] = $request -> input ( 'first_name' );
$user -> last_name = $request -> input ( 'last_name' );
$user -> email = $data [ 'email' ] = $request -> input ( 'email' );
$user -> activated = 1 ;
$permissions = [ 'superuser' => 1 ];
2016-05-14 15:04:59 -07:00
$user -> permissions = json_encode ( $permissions );
2021-06-10 13:15:52 -07:00
$user -> username = $data [ 'username' ] = $request -> input ( 'username' );
$user -> password = bcrypt ( $request -> input ( 'password' ));
$data [ 'password' ] = $request -> input ( 'password' );
2016-03-25 01:18:05 -07:00
2021-06-10 13:15:52 -07:00
$settings = new Setting ();
2018-01-17 10:58:03 -08:00
$settings -> full_multiple_companies_support = $request -> input ( 'full_multiple_companies_support' , 0 );
2021-06-10 13:15:52 -07:00
$settings -> site_name = $request -> input ( 'site_name' );
$settings -> alert_email = $request -> input ( 'email' );
$settings -> alerts_enabled = 1 ;
$settings -> pwd_secure_min = 10 ;
$settings -> brand = 1 ;
$settings -> locale = $request -> input ( 'locale' , 'en' );
$settings -> default_currency = $request -> input ( 'default_currency' , 'USD' );
$settings -> user_id = 1 ;
$settings -> email_domain = $request -> input ( 'email_domain' );
$settings -> email_format = $request -> input ( 'email_format' );
$settings -> next_auto_tag_base = 1 ;
$settings -> auto_increment_assets = $request -> input ( 'auto_increment_assets' , 0 );
$settings -> auto_increment_prefix = $request -> input ( 'auto_increment_prefix' );
2020-04-20 23:20:34 -07:00
2020-04-21 04:08:25 -07:00
if (( ! $user -> isValid ()) || ( ! $settings -> isValid ())) {
2016-04-28 21:06:41 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $user -> getErrors ()) -> withErrors ( $settings -> getErrors ());
2016-03-25 01:18:05 -07:00
} else {
2016-06-02 17:22:23 -07:00
$user -> save ();
2016-11-29 01:19:25 -08:00
Auth :: login ( $user , true );
2016-06-02 17:22:23 -07:00
$settings -> save ();
2016-09-17 00:00:39 -07:00
2020-09-15 01:51:10 -07:00
if ( $request -> input ( 'email_creds' ) == '1' ) {
2021-06-10 13:15:52 -07:00
$data = [];
$data [ 'email' ] = $user -> email ;
$data [ 'username' ] = $user -> username ;
2018-03-03 14:37:42 -08:00
$data [ 'first_name' ] = $user -> first_name ;
2021-06-10 13:15:52 -07:00
$data [ 'last_name' ] = $user -> last_name ;
$data [ 'password' ] = $request -> input ( 'password' );
2018-03-03 14:37:42 -08:00
$user -> notify ( new FirstAdminNotification ( $data ));
2016-03-25 01:18:05 -07:00
}
return redirect () -> route ( 'setup.done' );
}
}
/**
2018-10-03 10:06:24 -07:00
* Return the admin user creation form in Setup .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v3 . 0 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function getSetupUser ()
{
2017-06-09 16:44:03 -07:00
return view ( 'setup/user' )
2020-04-21 04:08:25 -07:00
-> with ( 'step' , 3 )
-> with ( 'section' , 'Create a User' );
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Return the view that tells the user that the Setup is done .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v3 . 0 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function getSetupDone ()
{
2017-06-09 16:44:03 -07:00
return view ( 'setup/done' )
2020-04-21 04:08:25 -07:00
-> with ( 'step' , 4 )
-> with ( 'section' , 'Done!' );
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Migrate the database tables , and return the output
* to a view for Setup .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v3 . 0 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function getSetupMigrate ()
{
Artisan :: call ( 'migrate' , [ '--force' => true ]);
2021-06-10 13:15:52 -07:00
if (( ! file_exists ( storage_path () . '/oauth-private.key' )) || ( ! file_exists ( storage_path () . '/oauth-public.key' ))) {
2019-01-30 14:45:36 -08:00
Artisan :: call ( 'migrate' , [ '--path' => 'vendor/laravel/passport/database/migrations' , '--force' => true ]);
2017-10-11 12:42:31 -07:00
Artisan :: call ( 'passport:install' );
2017-08-22 22:46:02 -07:00
}
2017-06-09 16:44:03 -07:00
return view ( 'setup/migrate' )
2020-04-21 04:08:25 -07:00
-> with ( 'output' , 'Databases installed!' )
-> with ( 'step' , 2 )
-> with ( 'section' , 'Create Database Tables' );
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Return a view that shows some of the key settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v1 . 0 ]
*
* @ return View
*/
2017-07-07 23:44:48 -07:00
public function index ()
2016-03-25 01:18:05 -07:00
{
2018-11-01 19:59:50 -07:00
$settings = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-06-09 16:44:03 -07:00
return view ( 'settings/index' , compact ( 'settings' ));
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Return the admin settings page .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v1 . 0 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function getEdit ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings/general' , compact ( 'setting' ));
}
2016-03-25 01:18:05 -07:00
2017-07-07 23:44:48 -07:00
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getSettings ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings/general' , compact ( 'setting' ));
2016-03-25 01:18:05 -07:00
}
/**
2017-07-07 23:44:48 -07:00
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postSettings ( Request $request )
2016-03-25 01:18:05 -07:00
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2016-04-28 21:06:41 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
2016-03-25 01:18:05 -07:00
}
2018-01-24 10:43:46 -08:00
$setting -> modellist_displays = '' ;
2021-06-10 13:15:52 -07:00
if (( $request -> filled ( 'show_in_model_list' )) && ( count ( $request -> input ( 'show_in_model_list' )) > 0 )) {
2018-01-24 10:43:46 -08:00
$setting -> modellist_displays = implode ( ',' , $request -> input ( 'show_in_model_list' ));
}
2017-07-07 23:44:48 -07:00
$setting -> full_multiple_companies_support = $request -> input ( 'full_multiple_companies_support' , '0' );
2021-06-10 13:15:52 -07:00
$setting -> unique_serial = $request -> input ( 'unique_serial' , '0' );
$setting -> show_images_in_email = $request -> input ( 'show_images_in_email' , '0' );
$setting -> show_archived_in_list = $request -> input ( 'show_archived_in_list' , '0' );
$setting -> dashboard_message = $request -> input ( 'dashboard_message' );
$setting -> email_domain = $request -> input ( 'email_domain' );
$setting -> email_format = $request -> input ( 'email_format' );
$setting -> username_format = $request -> input ( 'username_format' );
$setting -> require_accept_signature = $request -> input ( 'require_accept_signature' );
$setting -> show_assigned_assets = $request -> input ( 'show_assigned_assets' , '0' );
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2017-09-22 17:23:22 -07:00
$setting -> login_note = $request -> input ( 'login_note' );
}
2021-06-10 13:15:52 -07:00
$setting -> default_eula_text = $request -> input ( 'default_eula_text' );
$setting -> thumbnail_max_h = $request -> input ( 'thumbnail_max_h' );
2018-05-08 00:50:13 -07:00
$setting -> privacy_policy_link = $request -> input ( 'privacy_policy_link' );
2017-07-07 23:44:48 -07:00
2018-08-28 12:32:46 -07:00
$setting -> depreciation_method = $request -> input ( 'depreciation_method' );
2020-09-15 01:51:10 -07:00
if ( $request -> input ( 'per_page' ) != '' ) {
2017-07-07 23:44:48 -07:00
$setting -> per_page = $request -> input ( 'per_page' );
} else {
$setting -> per_page = 200 ;
}
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
2016-03-25 01:18:05 -07:00
2017-07-07 23:44:48 -07:00
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getBranding ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.branding' , compact ( 'setting' ));
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postBranding ( ImageUploadRequest $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2021-06-10 13:15:52 -07:00
$setting -> brand = $request -> input ( 'brand' , '1' );
$setting -> header_color = $request -> input ( 'header_color' );
$setting -> support_footer = $request -> input ( 'support_footer' );
$setting -> version_footer = $request -> input ( 'version_footer' );
$setting -> footer_text = $request -> input ( 'footer_text' );
$setting -> skin = $request -> input ( 'skin' );
$setting -> allow_user_skin = $request -> input ( 'allow_user_skin' );
2017-10-17 13:54:03 -07:00
$setting -> show_url_in_emails = $request -> input ( 'show_url_in_emails' , '0' );
2021-06-10 13:15:52 -07:00
$setting -> logo_print_assets = $request -> input ( 'logo_print_assets' , '0' );
2018-07-24 13:37:02 -07:00
2017-07-07 23:44:48 -07:00
// Only allow the site name and CSS to be changed if lock_passwords is false
// Because public demos make people act like dicks
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2021-06-10 13:15:52 -07:00
$setting -> site_name = $request -> input ( 'site_name' );
2017-07-07 18:06:31 -07:00
$setting -> custom_css = $request -> input ( 'custom_css' );
2017-07-07 23:44:48 -07:00
}
2021-06-10 13:15:52 -07:00
$setting = $request -> handleImages ( $setting , 600 , 'logo' , '' , 'logo' );
2017-07-07 23:44:48 -07:00
2020-08-26 11:53:36 -07:00
if ( '1' == $request -> input ( 'clear_logo' )) {
2020-04-27 23:22:52 -07:00
Storage :: disk ( 'public' ) -> delete ( $setting -> logo );
2021-06-10 13:15:52 -07:00
$setting -> logo = null ;
2020-04-27 23:22:52 -07:00
$setting -> brand = 1 ;
2017-07-07 23:44:48 -07:00
}
2018-12-05 19:56:12 -08:00
2021-06-10 13:15:52 -07:00
$setting = $request -> handleImages ( $setting , 600 , 'email_logo' , '' , 'email_logo' );
2018-12-05 19:56:12 -08:00
2020-08-26 12:17:50 -07:00
if ( '1' == $request -> input ( 'clear_email_logo' )) {
2020-04-27 23:22:52 -07:00
Storage :: disk ( 'public' ) -> delete ( $setting -> email_logo );
2021-06-10 13:15:52 -07:00
$setting -> email_logo = null ;
2020-04-27 23:22:52 -07:00
// If they are uploading an image, validate it and upload it
2018-12-05 19:56:12 -08:00
}
2019-03-01 15:25:42 -08:00
2021-06-10 13:15:52 -07:00
$setting = $request -> handleImages ( $setting , 600 , 'label_logo' , '' , 'label_logo' );
2019-03-01 15:25:42 -08:00
2020-08-26 12:17:50 -07:00
if ( '1' == $request -> input ( 'clear_label_logo' )) {
2020-04-27 23:22:52 -07:00
Storage :: disk ( 'public' ) -> delete ( $setting -> label_logo );
2021-06-10 13:15:52 -07:00
$setting -> label_logo = null ;
2019-03-01 15:25:42 -08:00
}
2019-01-18 14:05:52 -08:00
2020-08-26 12:17:50 -07:00
2018-12-05 19:56:12 -08:00
// If the user wants to clear the favicon...
2020-04-27 23:22:52 -07:00
if ( $request -> hasFile ( 'favicon' )) {
2021-06-10 13:15:52 -07:00
$favicon_image = $favicon_upload = $request -> file ( 'favicon' );
$favicon_ext = $favicon_image -> getClientOriginalExtension ();
$setting -> favicon = $favicon_file_name = 'favicon-uploaded.' . $favicon_ext ;
2018-12-05 19:56:12 -08:00
2021-06-10 13:15:52 -07:00
if (( $favicon_image -> getClientOriginalExtension () != 'ico' ) && ( $favicon_image -> getClientOriginalExtension () != 'svg' )) {
2019-03-01 15:25:42 -08:00
$favicon_upload = Image :: make ( $favicon_image -> getRealPath ()) -> resize ( null , 36 , function ( $constraint ) {
2018-12-05 19:56:12 -08:00
$constraint -> aspectRatio ();
$constraint -> upsize ();
});
2019-01-18 14:05:52 -08:00
// This requires a string instead of an object, so we use ($string)
Storage :: disk ( 'public' ) -> put ( $favicon_file_name , ( string ) $favicon_upload -> encode ());
} else {
Storage :: disk ( 'public' ) -> put ( $favicon_file_name , file_get_contents ( $request -> file ( 'favicon' )));
2018-12-05 19:56:12 -08:00
}
2019-01-18 14:05:52 -08:00
2020-04-21 04:08:25 -07:00
// Remove Current image if exists
if (( $setting -> favicon ) && ( file_exists ( $favicon_file_name ))) {
Storage :: disk ( 'public' ) -> delete ( $favicon_file_name );
2017-07-07 23:44:48 -07:00
}
2020-04-27 23:22:52 -07:00
} elseif ( '1' == $request -> input ( 'clear_favicon' )) {
Storage :: disk ( 'public' ) -> delete ( $setting -> clear_favicon );
2021-06-10 13:15:52 -07:00
$setting -> favicon = null ;
2020-04-27 23:22:52 -07:00
// If they are uploading an image, validate it and upload it
}
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getSecurity ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.security' , compact ( 'setting' ));
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postSecurity ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
if ( '' == $request -> input ( 'two_factor_enabled' )) {
2016-10-31 13:50:00 -07:00
$setting -> two_factor_enabled = null ;
} else {
2017-07-07 18:06:31 -07:00
$setting -> two_factor_enabled = $request -> input ( 'two_factor_enabled' );
2016-10-31 13:50:00 -07:00
}
2019-01-15 14:02:10 -08:00
// remote user login
2021-06-10 13:15:52 -07:00
$setting -> login_remote_user_enabled = ( int ) $request -> input ( 'login_remote_user_enabled' );
$setting -> login_common_disabled = ( int ) $request -> input ( 'login_common_disabled' );
2019-01-15 13:59:36 -08:00
$setting -> login_remote_user_custom_logout_url = $request -> input ( 'login_remote_user_custom_logout_url' );
2019-09-03 11:07:26 -07:00
$setting -> login_remote_user_header_name = $request -> input ( 'login_remote_user_header_name' );
2016-03-25 01:18:05 -07:00
}
2021-06-10 13:15:52 -07:00
$setting -> pwd_secure_uncommon = ( int ) $request -> input ( 'pwd_secure_uncommon' );
$setting -> pwd_secure_min = ( int ) $request -> input ( 'pwd_secure_min' );
2017-08-22 20:32:39 -07:00
$setting -> pwd_secure_complexity = '' ;
2018-03-14 12:48:07 -07:00
2019-05-23 17:39:50 -07:00
if ( $request -> filled ( 'pwd_secure_complexity' )) {
2021-06-10 13:15:52 -07:00
$setting -> pwd_secure_complexity = implode ( '|' , $request -> input ( 'pwd_secure_complexity' ));
2017-08-22 20:32:39 -07:00
}
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getLocalization ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.localization' , compact ( 'setting' ));
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postLocalization ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
2016-03-25 01:18:05 -07:00
}
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2018-07-24 13:37:02 -07:00
$setting -> locale = $request -> input ( 'locale' , 'en' );
}
2021-06-10 13:15:52 -07:00
$setting -> default_currency = $request -> input ( 'default_currency' , '$' );
2017-07-07 23:44:48 -07:00
$setting -> date_display_format = $request -> input ( 'date_display_format' );
$setting -> time_display_format = $request -> input ( 'time_display_format' );
2020-12-15 11:49:13 -08:00
$setting -> digit_separator = $request -> input ( 'digit_separator' );
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getAlerts ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.alerts' , compact ( 'setting' ));
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postAlerts ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2022-02-16 20:19:38 -08:00
// Check if the audit interval has changed - if it has, we want to update ALL of the assets audit dates
if ( $request -> input ( 'audit_interval' ) != $setting -> audit_interval ) {
// Be careful - this could be a negative number
2022-02-17 14:34:33 -08:00
$audit_diff_months = (( int ) $request -> input ( 'audit_interval' ) - ( int )( $setting -> audit_interval ));
2022-02-17 14:50:07 -08:00
// Grab all of the assets that have an existing next_audit_date
2022-02-17 14:34:33 -08:00
$assets = Asset :: whereNotNull ( 'next_audit_date' ) -> get ();
2022-02-16 20:19:38 -08:00
2022-02-17 14:50:07 -08:00
// Update all of the assets' next_audit_date values
2022-02-16 20:19:38 -08:00
foreach ( $assets as $asset ) {
if ( $asset -> next_audit_date != '' ) {
2022-02-17 14:34:33 -08:00
$old_next_audit = new \DateTime ( $asset -> next_audit_date );
$asset -> next_audit_date = $old_next_audit -> modify ( $audit_diff_months . ' month' ) -> format ( 'Y-m-d' );
2022-02-16 20:19:38 -08:00
$asset -> forceSave ();
}
}
2022-02-20 13:29:12 -08:00
}
2022-02-16 20:19:38 -08:00
2021-06-10 13:15:52 -07:00
$alert_email = rtrim ( $request -> input ( 'alert_email' ), ',' );
$alert_email = trim ( $alert_email );
2018-03-25 13:46:57 -07:00
$admin_cc_email = rtrim ( $request -> input ( 'admin_cc_email' ), ',' );
$admin_cc_email = trim ( $admin_cc_email );
2017-07-07 23:44:48 -07:00
2021-06-10 13:15:52 -07:00
$setting -> alert_email = $alert_email ;
$setting -> admin_cc_email = $admin_cc_email ;
$setting -> alerts_enabled = $request -> input ( 'alerts_enabled' , '0' );
$setting -> alert_interval = $request -> input ( 'alert_interval' );
$setting -> alert_threshold = $request -> input ( 'alert_threshold' );
$setting -> audit_interval = $request -> input ( 'audit_interval' );
$setting -> audit_warning_days = $request -> input ( 'audit_warning_days' );
2017-11-08 03:08:17 -08:00
$setting -> show_alerts_in_menu = $request -> input ( 'show_alerts_in_menu' , '0' );
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getSlack ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.slack' , compact ( 'setting' ));
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
2021-12-08 17:54:15 -08:00
public function postSlack ( SlackSettingsRequest $request )
2017-07-07 23:44:48 -07:00
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2021-12-15 07:38:51 -08:00
$setting -> slack_endpoint = $request -> input ( 'slack_endpoint' );
$setting -> slack_channel = $request -> input ( 'slack_channel' );
$setting -> slack_botname = $request -> input ( 'slack_botname' );
2021-12-16 14:26:24 -08:00
2020-04-21 04:08:25 -07:00
if ( $setting -> save ()) {
2017-07-07 23:44:48 -07:00
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2020-04-08 15:07:02 -07:00
2017-07-07 23:44:48 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getAssetTags ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.asset_tags' , compact ( 'setting' ));
}
/**
2018-10-03 10:06:24 -07:00
* Saves settings from form .
2017-07-07 23:44:48 -07:00
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postAssetTags ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
$setting -> auto_increment_prefix = $request -> input ( 'auto_increment_prefix' );
$setting -> auto_increment_assets = $request -> input ( 'auto_increment_assets' , '0' );
2021-06-10 13:15:52 -07:00
$setting -> zerofill_count = $request -> input ( 'zerofill_count' );
$setting -> next_auto_tag_base = $request -> input ( 'next_auto_tag_base' );
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getBarcodes ()
{
2021-06-10 13:15:52 -07:00
$setting = Setting :: getSettings ();
2017-07-07 23:44:48 -07:00
$is_gd_installed = extension_loaded ( 'gd' );
2018-10-03 10:06:24 -07:00
return view ( 'settings.barcodes' , compact ( 'setting' )) -> with ( 'is_gd_installed' , $is_gd_installed );
2017-07-07 23:44:48 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Saves settings from form .
2017-07-07 23:44:48 -07:00
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v1 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postBarcodes ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2021-06-10 13:15:52 -07:00
$setting -> qr_code = $request -> input ( 'qr_code' , '0' );
$setting -> alt_barcode = $request -> input ( 'alt_barcode' );
2017-07-07 18:06:31 -07:00
$setting -> alt_barcode_enabled = $request -> input ( 'alt_barcode_enabled' , '0' );
2021-06-10 13:15:52 -07:00
$setting -> barcode_type = $request -> input ( 'barcode_type' );
$setting -> qr_text = $request -> input ( 'qr_text' );
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
2017-07-08 00:09:39 -07:00
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-08 00:09:39 -07:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-08 00:09:39 -07:00
* @ return View
*/
public function getPhpInfo ()
{
2018-10-03 10:06:24 -07:00
if ( true === config ( 'app.debug' )) {
2017-07-08 00:22:30 -07:00
return view ( 'settings.phpinfo' );
}
2018-10-03 10:06:24 -07:00
2017-07-08 00:22:30 -07:00
return redirect () -> route ( 'settings.index' )
-> with ( 'error' , 'PHP syetem debugging information is only available when debug is enabled in your .env file.' );
2017-07-08 00:09:39 -07:00
}
2017-07-07 23:44:48 -07:00
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getLabels ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.labels' , compact ( 'setting' ));
}
/**
2018-10-03 10:06:24 -07:00
* Saves settings from form .
2017-07-07 23:44:48 -07:00
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postLabels ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2021-06-10 13:15:52 -07:00
$setting -> labels_per_page = $request -> input ( 'labels_per_page' );
$setting -> labels_width = $request -> input ( 'labels_width' );
$setting -> labels_height = $request -> input ( 'labels_height' );
$setting -> labels_pmargin_left = $request -> input ( 'labels_pmargin_left' );
$setting -> labels_pmargin_right = $request -> input ( 'labels_pmargin_right' );
$setting -> labels_pmargin_top = $request -> input ( 'labels_pmargin_top' );
$setting -> labels_pmargin_bottom = $request -> input ( 'labels_pmargin_bottom' );
$setting -> labels_display_bgutter = $request -> input ( 'labels_display_bgutter' );
$setting -> labels_display_sgutter = $request -> input ( 'labels_display_sgutter' );
$setting -> labels_fontsize = $request -> input ( 'labels_fontsize' );
$setting -> labels_pagewidth = $request -> input ( 'labels_pagewidth' );
$setting -> labels_pageheight = $request -> input ( 'labels_pageheight' );
2017-11-08 20:05:39 -08:00
$setting -> labels_display_company_name = $request -> input ( 'labels_display_company_name' , '0' );
2020-04-27 23:22:52 -07:00
$setting -> labels_display_company_name = $request -> input ( 'labels_display_company_name' , '0' );
2017-07-07 23:44:48 -07:00
2016-03-25 01:18:05 -07:00
2016-10-31 13:50:00 -07:00
2019-05-23 17:39:50 -07:00
if ( $request -> filled ( 'labels_display_name' )) {
2016-03-25 01:18:05 -07:00
$setting -> labels_display_name = 1 ;
} else {
$setting -> labels_display_name = 0 ;
}
2019-05-23 17:39:50 -07:00
if ( $request -> filled ( 'labels_display_serial' )) {
2016-03-25 01:18:05 -07:00
$setting -> labels_display_serial = 1 ;
} else {
$setting -> labels_display_serial = 0 ;
}
2019-05-23 17:39:50 -07:00
if ( $request -> filled ( 'labels_display_tag' )) {
2016-03-25 01:18:05 -07:00
$setting -> labels_display_tag = 1 ;
} else {
$setting -> labels_display_tag = 0 ;
2020-04-21 04:08:25 -07:00
}
2018-07-12 18:23:12 -07:00
2020-04-21 04:08:25 -07:00
if ( $request -> filled ( 'labels_display_tag' )) {
$setting -> labels_display_tag = 1 ;
} else {
$setting -> labels_display_tag = 0 ;
}
2016-03-25 01:18:05 -07:00
2019-05-23 17:39:50 -07:00
if ( $request -> filled ( 'labels_display_model' )) {
2018-07-24 12:09:30 -07:00
$setting -> labels_display_model = 1 ;
} else {
$setting -> labels_display_model = 0 ;
}
2017-07-07 23:44:48 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2017-07-07 23:44:48 -07:00
}
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getLdapSettings ()
{
2018-11-01 19:59:50 -07:00
$setting = Setting :: getSettings ();
2018-10-03 10:06:24 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.ldap' , compact ( 'setting' ));
}
/**
2018-10-03 10:06:24 -07:00
* Saves settings from form .
2017-07-07 23:44:48 -07:00
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function postLdapSettings ( Request $request )
{
2018-11-01 19:59:50 -07:00
if ( is_null ( $setting = Setting :: getSettings ())) {
2017-07-07 23:44:48 -07:00
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2016-03-25 01:18:05 -07:00
2021-06-10 13:15:52 -07:00
if ( ! config ( 'app.lock_passwords' ) === true ) {
$setting -> ldap_enabled = $request -> input ( 'ldap_enabled' , '0' );
$setting -> ldap_server = $request -> input ( 'ldap_server' );
2020-09-25 18:38:26 -07:00
$setting -> ldap_server_cert_ignore = $request -> input ( 'ldap_server_cert_ignore' , false );
2021-06-10 13:15:52 -07:00
$setting -> ldap_uname = $request -> input ( 'ldap_uname' );
2020-10-09 13:08:51 -07:00
if ( $request -> filled ( 'ldap_pword' )) {
2020-09-25 18:38:26 -07:00
$setting -> ldap_pword = Crypt :: encrypt ( $request -> input ( 'ldap_pword' ));
}
2021-06-10 13:15:52 -07:00
$setting -> ldap_basedn = $request -> input ( 'ldap_basedn' );
$setting -> ldap_filter = $request -> input ( 'ldap_filter' );
$setting -> ldap_username_field = $request -> input ( 'ldap_username_field' );
$setting -> ldap_lname_field = $request -> input ( 'ldap_lname_field' );
$setting -> ldap_fname_field = $request -> input ( 'ldap_fname_field' );
2020-09-25 18:38:26 -07:00
$setting -> ldap_auth_filter_query = $request -> input ( 'ldap_auth_filter_query' );
2021-06-10 13:15:52 -07:00
$setting -> ldap_version = $request -> input ( 'ldap_version' );
$setting -> ldap_active_flag = $request -> input ( 'ldap_active_flag' );
$setting -> ldap_emp_num = $request -> input ( 'ldap_emp_num' );
$setting -> ldap_email = $request -> input ( 'ldap_email' );
2022-03-21 11:15:39 -07:00
$setting -> ldap_manager = $request -> input ( 'ldap_manager' );
2021-06-10 13:15:52 -07:00
$setting -> ad_domain = $request -> input ( 'ad_domain' );
$setting -> is_ad = $request -> input ( 'is_ad' , '0' );
$setting -> ad_append_domain = $request -> input ( 'ad_append_domain' , '0' );
$setting -> ldap_tls = $request -> input ( 'ldap_tls' , '0' );
$setting -> ldap_pw_sync = $request -> input ( 'ldap_pw_sync' , '0' );
2020-09-25 18:38:26 -07:00
$setting -> custom_forgot_pass_url = $request -> input ( 'custom_forgot_pass_url' );
2021-06-10 13:15:52 -07:00
$setting -> ldap_phone_field = $request -> input ( 'ldap_phone' );
$setting -> ldap_jobtitle = $request -> input ( 'ldap_jobtitle' );
$setting -> ldap_country = $request -> input ( 'ldap_country' );
$setting -> ldap_dept = $request -> input ( 'ldap_dept' );
2021-08-17 14:43:36 -07:00
$setting -> ldap_client_tls_cert = $request -> input ( 'ldap_client_tls_cert' );
$setting -> ldap_client_tls_key = $request -> input ( 'ldap_client_tls_key' );
2020-09-25 18:38:26 -07:00
}
2017-07-07 18:06:31 -07:00
2016-03-25 01:18:05 -07:00
if ( $setting -> save ()) {
2021-08-17 14:43:36 -07:00
$setting -> update_client_side_cert_files ();
2018-12-06 14:05:43 -08:00
return redirect () -> route ( 'settings.ldap.index' )
2017-07-07 23:44:48 -07:00
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
2016-03-25 01:18:05 -07:00
}
2018-10-03 10:06:24 -07:00
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
2016-03-25 01:18:05 -07:00
}
2020-05-05 07:06:19 -07:00
/**
* Return a form to allow a super admin to update settings .
*
* @ author Johnson Yi < jyi . dev @ outlook . com >
*
* @ since v5 . 0.0
*
* @ return View
*/
public function getSamlSettings ()
{
$setting = Setting :: getSettings ();
return view ( 'settings.saml' , compact ( 'setting' ));
}
/**
* Saves settings from form .
*
* @ author Johnson Yi < jyi . dev @ outlook . com >
*
* @ since v5 . 0.0
*
* @ return View
*/
public function postSamlSettings ( SettingsSamlRequest $request )
{
if ( is_null ( $setting = Setting :: getSettings ())) {
return redirect () -> to ( 'admin' ) -> with ( 'error' , trans ( 'admin/settings/message.update.error' ));
}
2021-06-10 13:15:52 -07:00
$setting -> saml_enabled = $request -> input ( 'saml_enabled' , '0' );
$setting -> saml_idp_metadata = $request -> input ( 'saml_idp_metadata' );
$setting -> saml_attr_mapping_username = $request -> input ( 'saml_attr_mapping_username' );
$setting -> saml_forcelogin = $request -> input ( 'saml_forcelogin' , '0' );
$setting -> saml_slo = $request -> input ( 'saml_slo' , '0' );
if ( ! empty ( $request -> input ( 'saml_sp_privatekey' ))) {
$setting -> saml_sp_x509cert = $request -> input ( 'saml_sp_x509cert' );
$setting -> saml_sp_privatekey = $request -> input ( 'saml_sp_privatekey' );
2020-05-05 07:06:19 -07:00
}
2021-06-10 13:15:52 -07:00
if ( ! empty ( $request -> input ( 'saml_sp_x509certNew' ))) {
$setting -> saml_sp_x509certNew = $request -> input ( 'saml_sp_x509certNew' );
2020-08-14 02:10:19 -07:00
} else {
2021-06-10 13:15:52 -07:00
$setting -> saml_sp_x509certNew = '' ;
2020-08-14 02:10:19 -07:00
}
2021-06-10 13:15:52 -07:00
$setting -> saml_custom_settings = $request -> input ( 'saml_custom_settings' );
2020-05-05 07:06:19 -07:00
if ( $setting -> save ()) {
return redirect () -> route ( 'settings.saml.index' )
-> with ( 'success' , trans ( 'admin/settings/message.update.success' ));
}
return redirect () -> back () -> withInput () -> withErrors ( $setting -> getErrors ());
}
2022-03-16 15:53:32 -07:00
public static function getPDFBranding ()
{
$pdf_branding = Setting :: getSettings ();
return $pdf_branding ;
}
2020-05-05 07:06:19 -07:00
2016-03-25 01:18:05 -07:00
/**
2018-10-03 10:06:24 -07:00
* Show the listing of backups .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v1 . 8 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function getBackups ()
{
2022-05-17 14:36:05 -07:00
$settings = Setting :: getSettings ();
2021-06-10 13:15:52 -07:00
$path = 'app/backups' ;
2018-09-29 21:33:52 -07:00
$backup_files = Storage :: files ( $path );
2021-06-10 13:15:52 -07:00
$files_raw = [];
2016-03-25 15:50:08 -07:00
2018-09-29 21:33:52 -07:00
if ( count ( $backup_files ) > 0 ) {
2021-06-10 13:15:52 -07:00
for ( $f = 0 ; $f < count ( $backup_files ); $f ++ ) {
2020-08-28 14:10:43 -07:00
// Skip dotfiles like .gitignore and .DS_STORE
if (( substr ( basename ( $backup_files [ $f ]), 0 , 1 ) != '.' )) {
2021-11-09 22:37:49 -08:00
//$lastmodified = Carbon::parse(Storage::lastModified($backup_files[$f]))->toDatetimeString();
$file_timestamp = Storage :: lastModified ( $backup_files [ $f ]);
2020-11-30 14:46:10 -08:00
$files_raw [] = [
2020-08-28 14:10:43 -07:00
'filename' => basename ( $backup_files [ $f ]),
'filesize' => Setting :: fileSizeConvert ( Storage :: size ( $backup_files [ $f ])),
2021-11-09 22:37:49 -08:00
'modified_value' => $file_timestamp ,
2022-05-17 14:36:05 -07:00
'modified_display' => date ( $settings -> date_display_format . ' ' . $settings -> time_display_format , $file_timestamp ),
2021-11-09 22:37:49 -08:00
2020-08-28 14:10:43 -07:00
];
}
2021-11-09 22:37:49 -08:00
2016-03-25 01:18:05 -07:00
}
}
2020-11-30 14:46:10 -08:00
// Reverse the array so it lists oldest first
$files = array_reverse ( $files_raw );
2017-06-09 16:44:03 -07:00
return view ( 'settings/backups' , compact ( 'path' , 'files' ));
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Process the backup .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v1 . 8 ]
*
* @ return Redirect
*/
2016-03-25 01:18:05 -07:00
public function postBackups ()
{
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2016-03-25 01:18:05 -07:00
Artisan :: call ( 'backup:run' );
2017-11-01 14:12:18 -07:00
$output = Artisan :: output ();
// Backup completed
2018-10-03 10:06:24 -07:00
if ( ! preg_match ( '/failed/' , $output )) {
2017-11-01 14:12:18 -07:00
return redirect () -> route ( 'settings.backups.index' )
-> with ( 'success' , trans ( 'admin/settings/message.backup.generated' ));
}
$formatted_output = str_replace ( 'Backup completed!' , '' , $output );
2021-06-10 13:15:52 -07:00
$output_split = explode ( '...' , $formatted_output );
2017-11-01 14:12:18 -07:00
if ( array_key_exists ( 2 , $output_split )) {
2018-10-03 10:06:24 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , $output_split [ 2 ]);
2017-11-01 14:12:18 -07:00
}
2018-10-03 10:06:24 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , $formatted_output );
}
2017-11-01 14:12:18 -07:00
2018-10-03 10:06:24 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
2016-03-25 01:18:05 -07:00
}
/**
2018-10-03 10:06:24 -07:00
* Download the backup file .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v1 . 8 ]
*
2020-08-28 18:22:57 -07:00
* @ return Storage
2018-10-03 10:06:24 -07:00
*/
2016-03-25 01:18:05 -07:00
public function downloadFile ( $filename = null )
{
2020-08-28 18:22:37 -07:00
$path = 'app/backups' ;
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2021-06-10 13:15:52 -07:00
if ( Storage :: exists ( $path . '/' . $filename )) {
return StorageHelper :: downloader ( $path . '/' . $filename );
2016-03-25 01:18:05 -07:00
} else {
// Redirect to the backup page
2017-07-08 13:42:05 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'admin/settings/message.backup.file_not_found' ));
2016-03-25 01:18:05 -07:00
}
} else {
// Redirect to the backup page
2017-07-08 13:42:05 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
2016-03-25 01:18:05 -07:00
}
}
/**
2018-10-03 10:06:24 -07:00
* Delete the backup file .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v1 . 8 ]
*
* @ return View
*/
2016-03-25 01:18:05 -07:00
public function deleteFile ( $filename = null )
{
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2020-08-28 18:22:37 -07:00
$path = 'app/backups' ;
2016-03-25 01:18:05 -07:00
2021-06-10 13:15:52 -07:00
if ( Storage :: exists ( $path . '/' . $filename )) {
2018-10-03 10:06:24 -07:00
try {
2021-06-10 13:15:52 -07:00
Storage :: delete ( $path . '/' . $filename );
2018-09-29 21:33:52 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'success' , trans ( 'admin/settings/message.backup.file_deleted' ));
} catch ( \Exception $e ) {
\Log :: debug ( $e );
}
2016-03-25 01:18:05 -07:00
} else {
2017-07-08 13:42:05 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'admin/settings/message.backup.file_not_found' ));
2016-03-25 01:18:05 -07:00
}
} else {
2017-07-08 13:42:05 -07:00
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
2016-03-25 01:18:05 -07:00
}
}
2016-04-19 04:36:07 -07:00
2021-11-10 00:07:17 -08:00
/**
* Uploads a backup file
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v6 . 0 ]
*
* @ return Redirect
*/
public function postUploadBackup ( Request $request ) {
2021-11-15 19:42:02 -08:00
if ( ! config ( 'app.lock_passwords' )) {
if ( ! $request -> hasFile ( 'file' )) {
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , 'No file uploaded' );
} else {
$max_file_size = Helper :: file_upload_max_size ();
2021-11-10 00:07:17 -08:00
2021-11-15 19:42:02 -08:00
$rules = [
'file' => 'required|mimes:zip|max:' . $max_file_size ,
];
2021-11-10 00:07:17 -08:00
2021-11-15 19:42:02 -08:00
$validator = \Validator :: make ( $request -> all (), $rules );
2021-11-10 00:07:17 -08:00
2021-11-15 19:42:02 -08:00
if ( $validator -> passes ()) {
2021-11-10 00:07:17 -08:00
2021-11-15 19:42:02 -08:00
$upload_filename = 'uploaded-' . date ( 'U' ) . '-' . Str :: slug ( pathinfo ( $request -> file ( 'file' ) -> getClientOriginalName (), PATHINFO_FILENAME )) . '.zip' ;
2021-11-10 00:07:17 -08:00
2021-11-15 19:42:02 -08:00
Storage :: putFileAs ( 'app/backups' , $request -> file ( 'file' ), $upload_filename );
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'success' , 'File uploaded' );
} else {
return redirect () -> route ( 'settings.backups.index' ) -> withErrors ( $request -> getErrors ());
}
2021-11-10 00:07:17 -08:00
}
2021-11-15 19:42:02 -08:00
} else {
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
}
2021-11-10 01:43:45 -08:00
2021-11-10 00:07:17 -08:00
}
/**
* Restore the backup file .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v6 . 0 ]
*
* @ return View
*/
public function postRestore ( $filename = null )
{
if ( ! config ( 'app.lock_passwords' )) {
$path = 'app/backups' ;
if ( Storage :: exists ( $path . '/' . $filename )) {
// grab the user's info so we can make sure they exist in the system
$user = User :: find ( Auth :: user () -> id );
2022-02-17 14:59:44 -08:00
// TODO: run a backup
2021-11-10 01:43:45 -08:00
2022-05-17 04:27:48 -07:00
Artisan :: call ( 'db:wipe' , [
'--force' => true ,
]);
2021-11-10 01:43:45 -08:00
2022-05-17 09:41:35 -07:00
\Log :: debug ( 'Attempting to restore from: ' . storage_path ( $path ) . '/' . $filename );
2021-11-10 00:07:17 -08:00
// run the restore command
Artisan :: call ( 'snipeit:restore' ,
2021-11-10 01:43:45 -08:00
[
'--force' => true ,
'--no-progress' => true ,
'filename' => storage_path ( $path ) . '/' . $filename
]);
2021-11-10 00:07:17 -08:00
// If it's greater than 300, it probably worked
2022-02-17 14:59:44 -08:00
$output = Artisan :: output ();
2021-11-10 00:07:17 -08:00
if ( strlen ( $output ) > 300 ) {
2022-02-17 15:42:06 -08:00
$find_user = DB :: table ( 'users' ) -> where ( 'first_name' , $user -> first_name ) -> where ( 'last_name' , $user -> last_name ) -> exists ();
if ( ! $find_user ){
\Log :: warning ( 'Attempting to restore user: ' . $user -> first_name . ' ' . $user -> last_name );
$new_user = $user -> replicate ();
$new_user -> push ();
}
2022-02-17 16:00:24 -08:00
$session_files = glob ( storage_path ( " framework/sessions/* " ));
foreach ( $session_files as $file ) {
if ( is_file ( $file ))
unlink ( $file );
}
2022-02-17 16:03:00 -08:00
DB :: table ( 'users' ) -> update ([ 'remember_token' => null ]);
2021-11-15 19:40:01 -08:00
\Auth :: logout ();
2022-02-17 16:00:24 -08:00
2021-11-15 19:40:01 -08:00
return redirect () -> route ( 'login' ) -> with ( 'success' , 'Your system has been restored. Please login again.' );
2021-11-10 00:07:17 -08:00
} else {
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , $output );
}
2021-11-10 01:43:45 -08:00
2021-11-10 00:07:17 -08:00
} else {
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'admin/settings/message.backup.file_not_found' ));
}
} else {
return redirect () -> route ( 'settings.backups.index' ) -> with ( 'error' , trans ( 'general.feature_disabled' ));
}
}
2017-07-07 23:44:48 -07:00
/**
* Return a form to allow a super admin to update settings .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-07-07 23:44:48 -07:00
* @ return View
*/
public function getPurge ()
{
2021-02-02 02:20:30 -08:00
\Log :: warning ( 'User ID ' . Auth :: user () -> id . ' is attempting a PURGE' );
2021-06-10 13:15:52 -07:00
2017-07-07 23:44:48 -07:00
return view ( 'settings.purge-form' );
}
2016-04-19 04:36:07 -07:00
/**
2018-10-03 10:06:24 -07:00
* Purges soft - deletes .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
*
* @ since [ v3 . 0 ]
*
* @ return View
*/
2020-09-03 11:42:33 -07:00
public function postPurge ( Request $request )
2016-04-19 04:36:07 -07:00
{
2018-10-03 10:06:24 -07:00
if ( ! config ( 'app.lock_passwords' )) {
2020-09-15 01:51:10 -07:00
if ( 'DELETE' == $request -> input ( 'confirm_purge' )) {
2021-02-02 01:58:50 -08:00
\Log :: warning ( 'User ID ' . Auth :: user () -> id . ' initiated a PURGE!' );
2017-09-25 15:00:23 -07:00
// Run a backup immediately before processing
Artisan :: call ( 'backup:run' );
2018-10-03 10:06:24 -07:00
Artisan :: call ( 'snipeit:purge' , [ '--force' => 'true' , '--no-interaction' => true ]);
2016-04-19 04:36:07 -07:00
$output = Artisan :: output ();
2018-10-03 10:06:24 -07:00
2017-06-09 16:44:03 -07:00
return view ( 'settings/purge' )
2020-04-21 04:08:25 -07:00
-> with ( 'output' , $output ) -> with ( 'success' , trans ( 'admin/settings/message.purge.success' ));
2016-04-19 04:36:07 -07:00
} else {
2016-04-28 21:06:41 -07:00
return redirect () -> back () -> with ( 'error' , trans ( 'admin/settings/message.purge.validation_failed' ));
2016-04-19 04:36:07 -07:00
}
} else {
2016-04-28 21:06:41 -07:00
return redirect () -> back () -> with ( 'error' , trans ( 'general.feature_disabled' ));
2016-04-19 04:36:07 -07:00
}
}
2017-01-24 17:37:07 -08:00
/**
* Returns a page with the API token generation interface .
*
* We created a controller method for this because closures aren ' t allowed
* in the routes file if you want to be able to cache the routes .
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-01-24 17:37:07 -08:00
* @ since [ v4 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-01-24 17:37:07 -08:00
* @ return View
*/
2018-10-03 10:06:24 -07:00
public function api ()
{
2017-07-07 23:44:48 -07:00
return view ( 'settings.api' );
2017-01-24 17:37:07 -08:00
}
2017-10-19 06:16:03 -07:00
/**
2018-10-03 10:06:24 -07:00
* Test the email configuration .
2017-10-19 06:16:03 -07:00
*
* @ author [ A . Gianotto ] [ < snipe @ snipe . net > ]
2018-10-03 10:06:24 -07:00
*
2017-10-19 06:16:03 -07:00
* @ since [ v3 . 0 ]
2018-10-03 10:06:24 -07:00
*
2017-10-19 06:16:03 -07:00
* @ return Redirect
*/
public function ajaxTestEmail ()
{
try {
2018-10-03 10:06:24 -07:00
( new User ()) -> forceFill ([
'name' => config ( 'mail.from.name' ),
'email' => config ( 'mail.from.address' ),
2018-08-02 21:36:18 -07:00
]) -> notify ( new MailTest ());
2017-10-19 08:18:56 -07:00
return response () -> json ( Helper :: formatStandardApiResponse ( 'success' , null , 'Maiol sent!' ));
2017-10-19 06:16:03 -07:00
} catch ( Exception $e ) {
2017-10-19 08:18:56 -07:00
return response () -> json ( Helper :: formatStandardApiResponse ( 'success' , null , $e -> getMessage ()));
2017-10-19 06:16:03 -07:00
}
}
2018-10-03 10:06:24 -07:00
public function getLoginAttempts ()
{
2018-08-01 03:51:59 -07:00
return view ( 'settings.logins' );
2017-10-19 06:16:03 -07:00
}
2020-08-14 02:10:19 -07:00
}