mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-11-04 05:15:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			363 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			363 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
/**
 | 
						|
 * PreferencesController.php
 | 
						|
 * Copyright (c) 2019 james@firefly-iii.org
 | 
						|
 *
 | 
						|
 * This file is part of Firefly III (https://github.com/firefly-iii).
 | 
						|
 *
 | 
						|
 * This program is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU Affero General Public License as
 | 
						|
 * published by the Free Software Foundation, either version 3 of the
 | 
						|
 * License, or (at your option) any later version.
 | 
						|
 *
 | 
						|
 * This program is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU Affero General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU Affero General Public License
 | 
						|
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
declare(strict_types=1);
 | 
						|
 | 
						|
namespace FireflyIII\Http\Controllers;
 | 
						|
 | 
						|
use FireflyIII\Enums\AccountTypeEnum;
 | 
						|
use FireflyIII\Events\Preferences\UserGroupChangedDefaultCurrency;
 | 
						|
use FireflyIII\Events\Test\UserTestNotificationChannel;
 | 
						|
use FireflyIII\Exceptions\FireflyException;
 | 
						|
use FireflyIII\Http\Requests\PreferencesRequest;
 | 
						|
use FireflyIII\Models\Account;
 | 
						|
use FireflyIII\Models\Preference;
 | 
						|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
 | 
						|
use FireflyIII\Support\Facades\Preferences;
 | 
						|
use FireflyIII\User;
 | 
						|
use Illuminate\Contracts\View\Factory;
 | 
						|
use Illuminate\Http\RedirectResponse;
 | 
						|
use Illuminate\Http\Request;
 | 
						|
use Illuminate\Routing\Redirector;
 | 
						|
use Illuminate\Support\Facades\Log;
 | 
						|
use Illuminate\View\View;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class PreferencesController.
 | 
						|
 */
 | 
						|
class PreferencesController extends Controller
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * PreferencesController constructor.
 | 
						|
     */
 | 
						|
    public function __construct()
 | 
						|
    {
 | 
						|
        parent::__construct();
 | 
						|
 | 
						|
        $this->middleware(
 | 
						|
            static function ($request, $next) {
 | 
						|
                app('view')->share('title', (string) trans('firefly.preferences'));
 | 
						|
                app('view')->share('mainTitleIcon', 'fa-gear');
 | 
						|
 | 
						|
                return $next($request);
 | 
						|
            }
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Show overview of preferences.
 | 
						|
     *
 | 
						|
     * @return Factory|View
 | 
						|
     *
 | 
						|
     * @throws FireflyException
 | 
						|
     */
 | 
						|
    public function index(AccountRepositoryInterface $repository)
 | 
						|
    {
 | 
						|
        $accounts                       = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::MORTGAGE->value]);
 | 
						|
        $isDocker                       = env('IS_DOCKER', false); // @phpstan-ignore-line
 | 
						|
        $groupedAccounts                = [];
 | 
						|
 | 
						|
        /** @var Account $account */
 | 
						|
        foreach ($accounts as $account) {
 | 
						|
            $type                                                                        = $account->accountType->type;
 | 
						|
            $role                                                                        = sprintf('opt_group_%s', $repository->getMetaValue($account, 'account_role'));
 | 
						|
 | 
						|
            if (in_array($type, [AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value], true)) {
 | 
						|
                $role = sprintf('opt_group_l_%s', $type);
 | 
						|
            }
 | 
						|
 | 
						|
            if ('opt_group_' === $role) {
 | 
						|
                $role = 'opt_group_defaultAsset';
 | 
						|
            }
 | 
						|
            $groupedAccounts[(string) trans(sprintf('firefly.%s', $role))][$account->id] = $account->name;
 | 
						|
        }
 | 
						|
        ksort($groupedAccounts);
 | 
						|
 | 
						|
        /** @var array<int, int> $accountIds */
 | 
						|
        $accountIds                     = $accounts->pluck('id')->toArray();
 | 
						|
        $viewRange                      = app('navigation')->getViewRange(false);
 | 
						|
        $frontpageAccountsPref          = Preferences::get('frontpageAccounts', $accountIds);
 | 
						|
        $frontpageAccounts              = $frontpageAccountsPref->data;
 | 
						|
        if (!is_array($frontpageAccounts)) {
 | 
						|
            $frontpageAccounts = $accountIds;
 | 
						|
        }
 | 
						|
        $language                       = app('steam')->getLanguage();
 | 
						|
        $languages                      = config('firefly.languages');
 | 
						|
        $locale                         = Preferences::get('locale', config('firefly.default_locale', 'equal'))->data;
 | 
						|
        $listPageSize                   = Preferences::get('listPageSize', 50)->data;
 | 
						|
        $darkMode                       = Preferences::get('darkMode', 'browser')->data;
 | 
						|
        $customFiscalYear               = Preferences::get('customFiscalYear', 0)->data;
 | 
						|
        $fiscalYearStartStr             = Preferences::get('fiscalYearStart', '01-01')->data;
 | 
						|
        $convertToNative                = $this->convertToNative;
 | 
						|
        if (is_array($fiscalYearStartStr)) {
 | 
						|
            $fiscalYearStartStr = '01-01';
 | 
						|
        }
 | 
						|
        $fiscalYearStart                = sprintf('%s-%s', date('Y'), (string) $fiscalYearStartStr);
 | 
						|
        $tjOptionalFields               = Preferences::get('transaction_journal_optional_fields', [])->data;
 | 
						|
        $availableDarkModes             = config('firefly.available_dark_modes');
 | 
						|
 | 
						|
        // notifications settings
 | 
						|
        $slackUrl                       = Preferences::getEncrypted('slack_webhook_url', '')->data;
 | 
						|
        $pushoverAppToken               = (string) Preferences::getEncrypted('pushover_app_token', '')->data;
 | 
						|
        $pushoverUserToken              = (string) Preferences::getEncrypted('pushover_user_token', '')->data;
 | 
						|
        $ntfyServer                     = Preferences::getEncrypted('ntfy_server', 'https://ntfy.sh')->data;
 | 
						|
        $ntfyTopic                      = (string) Preferences::getEncrypted('ntfy_topic', '')->data;
 | 
						|
        $ntfyAuth                       = '1' === Preferences::get('ntfy_auth', false)->data;
 | 
						|
        $ntfyUser                       = Preferences::getEncrypted('ntfy_user', '')->data;
 | 
						|
        $ntfyPass                       = (string) Preferences::getEncrypted('ntfy_pass', '')->data;
 | 
						|
        $channels                       = config('notifications.channels');
 | 
						|
        $forcedAvailability             = [];
 | 
						|
 | 
						|
        // notification preferences
 | 
						|
        $notifications                  = [];
 | 
						|
        foreach (config('notifications.notifications.user') as $key => $info) {
 | 
						|
            if (true === $info['enabled']) {
 | 
						|
                $notifications[$key]
 | 
						|
                    = [
 | 
						|
                        'enabled'      => true === Preferences::get(sprintf('notification_%s', $key), true)->data,
 | 
						|
                        'configurable' => $info['configurable'],
 | 
						|
                    ];
 | 
						|
            }
 | 
						|
        }
 | 
						|
        // loop all channels to see if they are available.
 | 
						|
        foreach ($channels as $channel => $info) {
 | 
						|
            $forcedAvailability[$channel] = true;
 | 
						|
        }
 | 
						|
        $forcedAvailability['ntfy']     = '' !== $ntfyTopic;
 | 
						|
        $forcedAvailability['pushover'] = '' !== $pushoverAppToken && '' !== $pushoverUserToken;
 | 
						|
 | 
						|
        ksort($languages);
 | 
						|
 | 
						|
        // list of locales also has "equal" which makes it equal to whatever the language is.
 | 
						|
 | 
						|
        try {
 | 
						|
            $locales = json_decode((string) file_get_contents(resource_path(sprintf('locales/%s/locales.json', $language))), true, 512, JSON_THROW_ON_ERROR);
 | 
						|
        } catch (\JsonException $e) {
 | 
						|
            app('log')->error($e->getMessage());
 | 
						|
            $locales = [];
 | 
						|
        }
 | 
						|
        $locales                        = ['equal' => (string) trans('firefly.equal_to_language')] + $locales;
 | 
						|
        // an important fallback is that the frontPageAccount array gets refilled automatically
 | 
						|
        // when it turns up empty.
 | 
						|
        if (0 === count($frontpageAccounts)) {
 | 
						|
            $frontpageAccounts = $accountIds;
 | 
						|
        }
 | 
						|
 | 
						|
        // for the demo user, the notification settings are automatically emptied.
 | 
						|
        // this isn't really secure, but it means that the demo site has semi-secret notification settings.
 | 
						|
        if (auth()->user()->hasRole('demo')) {
 | 
						|
            $slackUrl          = '';
 | 
						|
            $pushoverAppToken  = '';
 | 
						|
            $pushoverUserToken = '';
 | 
						|
            $ntfyServer        = '';
 | 
						|
            $ntfyTopic         = '';
 | 
						|
            $ntfyAuth          = false;
 | 
						|
            $ntfyUser          = '';
 | 
						|
            $ntfyPass          = '';
 | 
						|
        }
 | 
						|
 | 
						|
        return view('preferences.index', compact(
 | 
						|
            'language',
 | 
						|
            'pushoverAppToken',
 | 
						|
            'pushoverUserToken',
 | 
						|
            'ntfyServer',
 | 
						|
            'ntfyTopic',
 | 
						|
            'ntfyAuth',
 | 
						|
            'channels',
 | 
						|
            'ntfyUser',
 | 
						|
            'forcedAvailability',
 | 
						|
            'ntfyPass',
 | 
						|
            'groupedAccounts',
 | 
						|
            'isDocker',
 | 
						|
            'frontpageAccounts',
 | 
						|
            'languages',
 | 
						|
            'darkMode',
 | 
						|
            'availableDarkModes',
 | 
						|
            'notifications',
 | 
						|
            'convertToNative',
 | 
						|
            'slackUrl',
 | 
						|
            'locales',
 | 
						|
            'locale',
 | 
						|
            'tjOptionalFields',
 | 
						|
            'viewRange',
 | 
						|
            'customFiscalYear',
 | 
						|
            'listPageSize',
 | 
						|
            'fiscalYearStart'
 | 
						|
        ));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Store new preferences.
 | 
						|
     *
 | 
						|
     * @return Redirector|RedirectResponse
 | 
						|
     *
 | 
						|
     * @throws FireflyException
 | 
						|
     *
 | 
						|
     * @SuppressWarnings("PHPMD.ExcessiveMethodLength")
 | 
						|
     * @SuppressWarnings("PHPMD.NPathComplexity")
 | 
						|
     */
 | 
						|
    public function postIndex(PreferencesRequest $request)
 | 
						|
    {
 | 
						|
        // front page accounts
 | 
						|
        $frontpageAccounts = [];
 | 
						|
        if (is_array($request->get('frontpageAccounts')) && count($request->get('frontpageAccounts')) > 0) {
 | 
						|
            foreach ($request->get('frontpageAccounts') as $id) {
 | 
						|
                $frontpageAccounts[] = (int) $id;
 | 
						|
            }
 | 
						|
            Preferences::set('frontpageAccounts', $frontpageAccounts);
 | 
						|
        }
 | 
						|
 | 
						|
        // extract notifications:
 | 
						|
        $all               = $request->all();
 | 
						|
        foreach (config('notifications.notifications.user') as $key => $info) {
 | 
						|
            $key = sprintf('notification_%s', $key);
 | 
						|
            if (array_key_exists($key, $all)) {
 | 
						|
                Preferences::set($key, true);
 | 
						|
            }
 | 
						|
            if (!array_key_exists($key, $all)) {
 | 
						|
                Preferences::set($key, false);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // view range:
 | 
						|
        Preferences::set('viewRange', $request->get('viewRange'));
 | 
						|
        // forget session values:
 | 
						|
        session()->forget('start');
 | 
						|
        session()->forget('end');
 | 
						|
        session()->forget('range');
 | 
						|
 | 
						|
        // notification settings, cannot be set by the demo user.
 | 
						|
        if (!auth()->user()->hasRole('demo')) {
 | 
						|
 | 
						|
            $variables = ['slack_webhook_url', 'pushover_app_token', 'pushover_user_token', 'ntfy_server', 'ntfy_topic', 'ntfy_user', 'ntfy_pass'];
 | 
						|
            foreach ($variables as $variable) {
 | 
						|
                if ('' === $all[$variable]) {
 | 
						|
                    Preferences::delete($variable);
 | 
						|
                }
 | 
						|
                if ('' !== $all[$variable]) {
 | 
						|
                    Preferences::setEncrypted($variable, $all[$variable]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            Preferences::set('ntfy_auth', $all['ntfy_auth'] ?? false);
 | 
						|
        }
 | 
						|
 | 
						|
        // convert native
 | 
						|
        $convertToNative   = 1 === (int) $request->get('convertToNative');
 | 
						|
        if ($convertToNative && !$this->convertToNative) {
 | 
						|
            // set to true!
 | 
						|
            Log::debug('User sets convertToNative to true.');
 | 
						|
            Preferences::set('convert_to_native', $convertToNative);
 | 
						|
            event(new UserGroupChangedDefaultCurrency(auth()->user()->userGroup));
 | 
						|
        }
 | 
						|
        Preferences::set('convert_to_native', $convertToNative);
 | 
						|
 | 
						|
        // custom fiscal year
 | 
						|
        $customFiscalYear  = 1 === (int) $request->get('customFiscalYear');
 | 
						|
        $string            = strtotime((string) $request->get('fiscalYearStart'));
 | 
						|
        if (false !== $string) {
 | 
						|
            $fiscalYearStart = date('m-d', $string);
 | 
						|
            Preferences::set('customFiscalYear', $customFiscalYear);
 | 
						|
            Preferences::set('fiscalYearStart', $fiscalYearStart);
 | 
						|
        }
 | 
						|
 | 
						|
        // save page size:
 | 
						|
        Preferences::set('listPageSize', 50);
 | 
						|
        $listPageSize      = (int) $request->get('listPageSize');
 | 
						|
        if ($listPageSize > 0 && $listPageSize < 1337) {
 | 
						|
            Preferences::set('listPageSize', $listPageSize);
 | 
						|
        }
 | 
						|
 | 
						|
        // language:
 | 
						|
        /** @var Preference $currentLang */
 | 
						|
        $currentLang       = Preferences::get('language', 'en_US');
 | 
						|
        $lang              = $request->get('language');
 | 
						|
        if (array_key_exists($lang, config('firefly.languages'))) {
 | 
						|
            Preferences::set('language', $lang);
 | 
						|
        }
 | 
						|
        if ($currentLang->data !== $lang) {
 | 
						|
            // this string is untranslated on purpose.
 | 
						|
            session()->flash('info', 'All translations are supplied by volunteers. There might be errors and mistakes. I appreciate your feedback.');
 | 
						|
        }
 | 
						|
 | 
						|
        // same for locale:
 | 
						|
        if (!auth()->user()->hasRole('demo')) {
 | 
						|
            $locale = (string) $request->get('locale');
 | 
						|
            $locale = '' === $locale ? null : $locale;
 | 
						|
            Preferences::set('locale', $locale);
 | 
						|
        }
 | 
						|
 | 
						|
        // optional fields for transactions:
 | 
						|
        $setOptions        = $request->get('tj') ?? [];
 | 
						|
        $optionalTj        = [
 | 
						|
            'interest_date'      => array_key_exists('interest_date', $setOptions),
 | 
						|
            'book_date'          => array_key_exists('book_date', $setOptions),
 | 
						|
            'process_date'       => array_key_exists('process_date', $setOptions),
 | 
						|
            'due_date'           => array_key_exists('due_date', $setOptions),
 | 
						|
            'payment_date'       => array_key_exists('payment_date', $setOptions),
 | 
						|
            'invoice_date'       => array_key_exists('invoice_date', $setOptions),
 | 
						|
            'internal_reference' => array_key_exists('internal_reference', $setOptions),
 | 
						|
            'notes'              => array_key_exists('notes', $setOptions),
 | 
						|
            'attachments'        => array_key_exists('attachments', $setOptions),
 | 
						|
            'external_url'       => array_key_exists('external_url', $setOptions),
 | 
						|
            'location'           => array_key_exists('location', $setOptions),
 | 
						|
            'links'              => array_key_exists('links', $setOptions),
 | 
						|
        ];
 | 
						|
        Preferences::set('transaction_journal_optional_fields', $optionalTj);
 | 
						|
 | 
						|
        // dark mode
 | 
						|
        $darkMode          = $request->get('darkMode') ?? 'browser';
 | 
						|
        if (in_array($darkMode, config('firefly.available_dark_modes'), true)) {
 | 
						|
            Preferences::set('darkMode', $darkMode);
 | 
						|
        }
 | 
						|
 | 
						|
        session()->flash('success', (string) trans('firefly.saved_preferences'));
 | 
						|
        Preferences::mark();
 | 
						|
 | 
						|
        return redirect(route('preferences.index'));
 | 
						|
    }
 | 
						|
 | 
						|
    public function testNotification(Request $request): mixed
 | 
						|
    {
 | 
						|
 | 
						|
        $all     = $request->all();
 | 
						|
        $channel = $all['channel'] ?? '';
 | 
						|
 | 
						|
        switch ($channel) {
 | 
						|
            default:
 | 
						|
                session()->flash('error', (string) trans('firefly.notification_test_failed', ['channel' => $channel]));
 | 
						|
 | 
						|
                break;
 | 
						|
 | 
						|
            case 'email':
 | 
						|
            case 'slack':
 | 
						|
            case 'pushover':
 | 
						|
            case 'ntfy':
 | 
						|
                /** @var User $user */
 | 
						|
                $user = auth()->user();
 | 
						|
                app('log')->debug(sprintf('Now in testNotification("%s") controller.', $channel));
 | 
						|
                event(new UserTestNotificationChannel($channel, $user));
 | 
						|
                session()->flash('success', (string) trans('firefly.notification_test_executed', ['channel' => $channel]));
 | 
						|
        }
 | 
						|
 | 
						|
        return '';
 | 
						|
    }
 | 
						|
}
 |