. */ declare(strict_types=1); namespace FireflyIII\Http\Controllers; use FireflyIII\Exceptions\FireflyException; use FireflyIII\Models\Account; use FireflyIII\Models\AccountType; use FireflyIII\Models\Preference; use FireflyIII\Repositories\Account\AccountRepositoryInterface; use Illuminate\Contracts\View\Factory; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Redirector; use Illuminate\View\View; use JsonException; use Log; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; /** * Class PreferencesController. */ class PreferencesController extends Controller { /** * PreferencesController constructor. * * @codeCoverageIgnore */ public function __construct() { parent::__construct(); $this->middleware( function ($request, $next) { app('view')->share('title', (string)trans('firefly.preferences')); app('view')->share('mainTitleIcon', 'fa-gear'); return $next($request); } ); } /** * Show overview of preferences. * * @param AccountRepositoryInterface $repository * * @return Factory|View * @throws FireflyException * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function index(AccountRepositoryInterface $repository) { $accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]); $isDocker = env('IS_DOCKER', false); // group accounts $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, [AccountType::MORTGAGE, AccountType::DEBT, AccountType::LOAN], true)) { $role = sprintf('opt_group_l_%s', $type); } if ('opt_group_' === $role) { $role = 'opt_group_defaultAsset'; } $groupedAccounts[trans(sprintf('firefly.%s', $role))][$account->id] = $account->name; } ksort($groupedAccounts); $accountIds = $accounts->pluck('id')->toArray(); $viewRangePref = app('navigation')->getViewRange(false); $viewRange = $viewRangePref->data; $frontPageAccounts = app('preferences')->get('frontPageAccounts', $accountIds); $language = app('steam')->getLanguage(); $languages = config('firefly.languages'); $locale = app('preferences')->get('locale', config('firefly.default_locale', 'equal'))->data; $listPageSize = app('preferences')->get('listPageSize', 50)->data; $slackUrl = app('preferences')->get('slack_webhook_url', '')->data; $customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data; $fiscalYearStartStr = app('preferences')->get('fiscalYearStart', '01-01')->data; $fiscalYearStart = date('Y').'-'.$fiscalYearStartStr; $tjOptionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data; // notification preferences (single value for each): $notifications = []; foreach (config('firefly.available_notifications') as $notification) { $notifications[$notification] = app('preferences')->get(sprintf('notification_%s', $notification), true)->data; } ksort($languages); // list of locales also has "equal" which makes it equal to whatever the language is. try { $locales = json_decode(file_get_contents(resource_path(sprintf('lang/%s/locales.json', $language))), true, 512, JSON_THROW_ON_ERROR); } catch (JsonException $e) { 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->data)) { $frontPageAccounts = $accountIds; } return view( 'preferences.index', compact( 'language', 'groupedAccounts', 'isDocker', 'frontPageAccounts', 'languages', 'notifications', 'slackUrl', 'locales', 'locale', 'tjOptionalFields', 'viewRange', 'customFiscalYear', 'listPageSize', 'fiscalYearStart' ) ); } /** * Store new preferences. * * @param Request $request * * @return RedirectResponse|Redirector * @throws FireflyException * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ public function postIndex(Request $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; } app('preferences')->set('frontPageAccounts', $frontPageAccounts); } // extract notifications: $all = $request->all(); foreach (config('firefly.available_notifications') as $option) { $key = sprintf('notification_%s', $option); if (array_key_exists($key, $all)) { app('preferences')->set($key, true); } if (!array_key_exists($key, $all)) { app('preferences')->set($key, false); } } // view range: app('preferences')->set('viewRange', $request->get('viewRange')); // forget session values: session()->forget('start'); session()->forget('end'); session()->forget('range'); // slack URL: $url = (string)$request->get('slackUrl'); if (str_starts_with($url, 'https://hooks.slack.com/services/')) { app('preferences')->set('slack_webhook_url', $url); } if ('' === $url) { app('preferences')->delete('slack_webhook_url'); } // custom fiscal year $customFiscalYear = 1 === (int)$request->get('customFiscalYear'); $string = strtotime((string)$request->get('fiscalYearStart')); if (false !== $string) { $fiscalYearStart = date('m-d', $string); app('preferences')->set('customFiscalYear', $customFiscalYear); app('preferences')->set('fiscalYearStart', $fiscalYearStart); } // save page size: app('preferences')->set('listPageSize', 50); $listPageSize = (int)$request->get('listPageSize'); if ($listPageSize > 0 && $listPageSize < 1337) { app('preferences')->set('listPageSize', $listPageSize); } // language: /** @var Preference $currentLang */ $currentLang = app('preferences')->get('language', 'en_US'); $lang = $request->get('language'); if (array_key_exists($lang, config('firefly.languages'))) { app('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')) { /** @var Preference $locale */ $locale = $request->get('locale'); app('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), ]; app('preferences')->set('transaction_journal_optional_fields', $optionalTj); session()->flash('success', (string)trans('firefly.saved_preferences')); app('preferences')->mark(); return redirect(route('preferences.index')); } }