Files
cachet-docker/app/Http/Controllers/Dashboard/SettingsController.php
Anthony Bocci d4c1e145fa Redirect to setting page on image uploading error
In the settings we can upload an image as banner. There are some
verifications that are done on the file to check that it's a valid
image.
If the file is not valid, a redirection is done to the theme page with
an error message.

When redirecting to the theme page because of an error on the file, the
controller redirects to an URL set in a variable. The problem was this
variable '$redirectUrl' was undefined, so the controller thrown an
error. The problem occured only if there was an error on the file, but
it worked well if the file was a valid image.

In the controller's constructor a 'submenu' field is set with panel
items and url, so the variable '$redirectUrl' is set to the theme
page URL. Now if there is an error with the file, the user is well
redirected and the error is displayed.

See: CachetHQ/Cachet#2956
2018-03-24 00:05:20 +01:00

425 lines
13 KiB
PHP

<?php
/*
* This file is part of Cachet.
*
* (c) Alt Three Services Limited
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CachetHQ\Cachet\Http\Controllers\Dashboard;
use CachetHQ\Cachet\Bus\Commands\System\Config\UpdateConfigCommand;
use CachetHQ\Cachet\Integrations\Contracts\Credits;
use CachetHQ\Cachet\Models\User;
use CachetHQ\Cachet\Notifications\System\SystemTestNotification;
use CachetHQ\Cachet\Settings\Repository;
use Exception;
use GrahamCampbell\Binput\Facades\Binput;
use Illuminate\Log\Writer;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Lang;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Str;
use Monolog\Handler\SyslogHandler;
class SettingsController extends Controller
{
/**
* Array of sub-menu items.
*
* @var array
*/
protected $subMenu = [];
/**
* Creates a new settings controller instance.
*
* @return void
*/
public function __construct()
{
$this->subMenu = [
'setup' => [
'title' => trans('dashboard.settings.app-setup.app-setup'),
'url' => cachet_route('dashboard.settings.setup'),
'icon' => 'ion-gear-b',
'active' => false,
],
'theme' => [
'title' => trans('dashboard.settings.theme.theme'),
'url' => cachet_route('dashboard.settings.theme'),
'icon' => 'ion-paintbrush',
'active' => false,
],
'stylesheet' => [
'title' => trans('dashboard.settings.stylesheet.stylesheet'),
'url' => cachet_route('dashboard.settings.stylesheet'),
'icon' => 'ion-paintbucket',
'active' => false,
],
'customization' => [
'title' => trans('dashboard.settings.customization.customization'),
'url' => cachet_route('dashboard.settings.customization'),
'icon' => 'ion-wand',
'active' => false,
],
'localization' => [
'title' => trans('dashboard.settings.localization.localization'),
'url' => cachet_route('dashboard.settings.localization'),
'icon' => 'ion-earth',
'active' => false,
],
'security' => [
'title' => trans('dashboard.settings.security.security'),
'url' => cachet_route('dashboard.settings.security'),
'icon' => 'ion-lock-combination',
'active' => false,
],
'analytics' => [
'title' => trans('dashboard.settings.analytics.analytics'),
'url' => cachet_route('dashboard.settings.analytics'),
'icon' => 'ion-stats-bars',
'active' => false,
],
'log' => [
'title' => trans('dashboard.settings.log.log'),
'url' => cachet_route('dashboard.settings.log'),
'icon' => 'ion-document-text',
'active' => false,
],
'credits' => [
'title' => trans('dashboard.settings.credits.credits'),
'url' => cachet_route('dashboard.settings.credits'),
'icon' => 'ion-ios-list',
'active' => false,
],
'mail' => [
'title' => trans('dashboard.settings.mail.mail'),
'url' => cachet_route('dashboard.settings.mail'),
'icon' => 'ion-paper-airplane',
'active' => false,
],
'about' => [
'title' => CACHET_VERSION,
'url' => 'javascript: void(0);',
'icon' => 'ion-flag',
'active' => false,
],
];
View::share([
'sub_title' => trans('dashboard.settings.settings'),
'sub_menu' => $this->subMenu,
]);
}
/**
* Shows the settings setup view.
*
* @return \Illuminate\View\View
*/
public function showSetupView()
{
$this->subMenu['setup']['active'] = true;
Session::flash('redirect_to', $this->subMenu['setup']['url']);
return View::make('dashboard.settings.app-setup')
->withPageTitle(trans('dashboard.settings.app-setup.app-setup').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu)
->withRawAppAbout(Config::get('setting.app_about'));
}
/**
* Shows the settings analytics view.
*
* @return \Illuminate\View\View
*/
public function showAnalyticsView()
{
$this->subMenu['analytics']['active'] = true;
Session::flash('redirect_to', $this->subMenu['analytics']['url']);
return View::make('dashboard.settings.analytics')
->withPageTitle(trans('dashboard.settings.analytics.analytics').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu);
}
/**
* Shows the settings localization view.
*
* @return \Illuminate\View\View
*/
public function showLocalizationView()
{
$this->subMenu['localization']['active'] = true;
Session::flash('redirect_to', $this->subMenu['localization']['url']);
return View::make('dashboard.settings.localization')
->withPageTitle(trans('dashboard.settings.localization.localization').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu);
}
/**
* Shows the settings customization view.
*
* @return \Illuminate\View\View
*/
public function showCustomizationView()
{
$this->subMenu['customization']['active'] = true;
Session::flash('redirect_to', $this->subMenu['customization']['url']);
return View::make('dashboard.settings.customization')
->withPageTitle(trans('dashboard.settings.customization.customization').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu);
}
/**
* Shows the settings theme view.
*
* @return \Illuminate\View\View
*/
public function showThemeView()
{
$this->subMenu['theme']['active'] = true;
Session::flash('redirect_to', $this->subMenu['theme']['url']);
return View::make('dashboard.settings.theme')
->withPageTitle(trans('dashboard.settings.theme.theme').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu);
}
/**
* Shows the settings security view.
*
* @return \Illuminate\View\View
*/
public function showSecurityView()
{
$this->subMenu['security']['active'] = true;
$unsecureUsers = User::whereNull('google_2fa_secret')->orWhere('google_2fa_secret', '=', '')->get();
Session::flash('redirect_to', $this->subMenu['security']['url']);
return View::make('dashboard.settings.security')
->withPageTitle(trans('dashboard.settings.security.security').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu)
->withUnsecureUsers($unsecureUsers);
}
/**
* Shows the settings stylesheet view.
*
* @return \Illuminate\View\View
*/
public function showStylesheetView()
{
$this->subMenu['stylesheet']['active'] = true;
Session::flash('redirect_to', $this->subMenu['stylesheet']['url']);
return View::make('dashboard.settings.stylesheet')
->withPageTitle(trans('dashboard.settings.stylesheet.stylesheet').' - '.trans('dashboard.dashboard'))
->withSubMenu($this->subMenu);
}
/**
* Show the credits view.
*
* @return \Illuminate\View\View
*/
public function showCreditsView()
{
$this->subMenu['credits']['active'] = true;
$credits = app(Credits::class)->latest();
$backers = $credits['backers'];
$contributors = $credits['contributors'];
shuffle($backers);
shuffle($contributors);
return View::make('dashboard.settings.credits')
->withPageTitle(trans('dashboard.settings.credits.credits').' - '.trans('dashboard.dashboard'))
->withBackers($backers)
->withContributors($contributors)
->withSubMenu($this->subMenu);
}
/**
* Show the most recent log.
*
* @return \Illuminate\View\View
*/
public function showLogView()
{
$this->subMenu['log']['active'] = true;
$log = app(Writer::class)->getMonolog();
$logContents = '';
collect($log->getHandlers())->reject(function ($handler) {
return $handler instanceof SyslogHandler;
})->each(function ($handler) use (&$logContents, $log) {
if (file_exists($path = $log->getHandlers()[0]->getUrl())) {
$logContents = file_get_contents($path);
}
});
return View::make('dashboard.settings.log')->withLog($logContents)->withSubMenu($this->subMenu);
}
/**
* Show the mail settings view.
*
* @return \Illuminate\View\View
*/
public function showMailView()
{
$this->subMenu['mail']['active'] = true;
return View::make('dashboard.settings.mail')->withConfig(Config::get('mail'));
}
/**
* Test the mail config.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function testMail()
{
Auth::user()->notify(new SystemTestNotification());
return cachet_redirect('dashboard.settings.mail')
->withSuccess(trans('dashboard.notifications.awesome'));
}
/**
* Handle updating of the settings.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function postMail()
{
$config = Binput::get('config');
dispatch(new UpdateConfigCommand($config));
return cachet_redirect('dashboard.settings.mail')
->withInput(Binput::all())
->withSuccess(trans('dashboard.notifications.awesome'));
}
/**
* Updates the status page settings.
*
* @return \Illuminate\View\View
*/
public function postSettings()
{
$setting = app(Repository::class);
if (Binput::get('remove_banner') === '1') {
$setting->set('app_banner', null);
}
$parameters = Binput::all();
if (isset($parameters['header'])) {
if ($header = Binput::get('header', null, false, false)) {
$setting->set('header', $header);
} else {
$setting->delete('header');
}
}
if (isset($parameters['footer'])) {
if ($footer = Binput::get('footer', null, false, false)) {
$setting->set('footer', $footer);
} else {
$setting->delete('footer');
}
}
if (Binput::hasFile('app_banner')) {
$this->handleUpdateBanner($setting);
}
$excludedParams = [
'_token',
'app_banner',
'remove_banner',
'header',
'footer',
];
try {
foreach (Binput::except($excludedParams) as $settingName => $settingValue) {
if ($settingName === 'app_analytics_pi_url') {
$settingValue = rtrim($settingValue, '/');
}
$setting->set($settingName, $settingValue);
}
} catch (Exception $e) {
return Redirect::back()->withErrors(trans('dashboard.settings.edit.failure'));
}
if (Binput::has('app_locale')) {
Lang::setLocale(Binput::get('app_locale'));
}
return Redirect::back()->withSuccess(trans('dashboard.settings.edit.success'));
}
/**
* Handle updating of the banner image.
*
* @param \CachetHQ\Cachet\Settings\Repository $setting
*
* @return void
*/
protected function handleUpdateBanner(Repository $setting)
{
$file = Binput::file('app_banner');
$redirectUrl = $this->subMenu['theme']['url'];
// Image Validation.
// Image size in bytes.
$maxSize = $file->getMaxFilesize();
if ($file->getSize() > $maxSize) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.app-setup.too-big', ['size' => $maxSize]));
}
if (!$file->isValid() || $file->getError()) {
return Redirect::to($redirectUrl)->withErrors($file->getErrorMessage());
}
if (!Str::startsWith($file->getMimeType(), 'image/')) {
return Redirect::to($redirectUrl)->withErrors(trans('dashboard.settings.app-setup.images-only'));
}
// Store the banner.
$setting->set('app_banner', base64_encode(file_get_contents($file->getRealPath())));
// Store the banner type.
$setting->set('app_banner_type', $file->getMimeType());
}
}