diff --git a/.env.example b/.env.example index ae71e78e69..95607b2e37 100644 --- a/.env.example +++ b/.env.example @@ -4,7 +4,6 @@ APP_KEY= APP_TIMEZONE=UTC APP_URL=http://panel.test APP_LOCALE=en -APP_ENVIRONMENT_ONLY=true LOG_CHANNEL=daily LOG_STACK=single diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 92fea58bda..5e2ee88471 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,7 +32,6 @@ jobs: APP_KEY: ThisIsARandomStringForTests12345 APP_TIMEZONE: UTC APP_URL: http://localhost/ - APP_ENVIRONMENT_ONLY: "true" CACHE_DRIVER: array MAIL_MAILER: array SESSION_DRIVER: array @@ -106,7 +105,6 @@ jobs: APP_KEY: ThisIsARandomStringForTests12345 APP_TIMEZONE: UTC APP_URL: http://localhost/ - APP_ENVIRONMENT_ONLY: "true" CACHE_DRIVER: array MAIL_MAILER: array SESSION_DRIVER: array @@ -170,7 +168,6 @@ jobs: APP_KEY: ThisIsARandomStringForTests12345 APP_TIMEZONE: UTC APP_URL: http://localhost/ - APP_ENVIRONMENT_ONLY: "true" CACHE_DRIVER: array MAIL_MAILER: array SESSION_DRIVER: array diff --git a/app/Console/Commands/Environment/AppSettingsCommand.php b/app/Console/Commands/Environment/AppSettingsCommand.php index 4f2e931196..a480e9b6f5 100644 --- a/app/Console/Commands/Environment/AppSettingsCommand.php +++ b/app/Console/Commands/Environment/AppSettingsCommand.php @@ -38,8 +38,7 @@ class AppSettingsCommand extends Command {--queue= : The queue driver backend to use.} {--redis-host= : Redis host to use for connections.} {--redis-pass= : Password used to connect to redis.} - {--redis-port= : Port to connect to redis over.} - {--settings-ui= : Enable or disable the settings UI.}'; + {--redis-port= : Port to connect to redis over.}'; protected array $variables = []; @@ -87,12 +86,6 @@ public function handle(): int array_key_exists($selected, self::QUEUE_DRIVERS) ? $selected : null ); - if (!is_null($this->option('settings-ui'))) { - $this->variables['APP_ENVIRONMENT_ONLY'] = $this->option('settings-ui') == 'true' ? 'false' : 'true'; - } else { - $this->variables['APP_ENVIRONMENT_ONLY'] = $this->confirm(__('commands.appsettings.comment.settings_ui'), true) ? 'false' : 'true'; - } - // Make sure session cookies are set as "secure" when using HTTPS if (str_starts_with($this->variables['APP_URL'], 'https://')) { $this->variables['SESSION_SECURE_COOKIE'] = 'true'; diff --git a/app/Filament/Clusters/Settings.php b/app/Filament/Clusters/Settings.php deleted file mode 100644 index 0ac8254c82..0000000000 --- a/app/Filament/Clusters/Settings.php +++ /dev/null @@ -1,10 +0,0 @@ -form->fill(); + } + + protected function getFormSchema(): array + { + return [ + Tabs::make('Tabs') + ->columns() + ->persistTabInQueryString() + ->tabs([ + Tab::make('general') + ->label('General') + ->icon('tabler-home') + ->schema($this->generalSettings()), + Tab::make('recaptcha') + ->label('reCAPTCHA') + ->icon('tabler-shield') + ->schema($this->recaptchaSettings()), + Tab::make('mail') + ->label('Mail') + ->icon('tabler-mail') + ->schema($this->mailSettings()), + Tab::make('backup') + ->label('Backup') + ->icon('tabler-box') + ->schema($this->backupSettings()), + Tab::make('misc') + ->label('Misc') + ->icon('tabler-tool') + ->schema($this->miscSettings()), + ]), + ]; + } + + private function generalSettings(): array + { + return [ + TextInput::make('APP_NAME') + ->label('App Name') + ->required() + ->default(env('APP_NAME', 'Pelican')), + TextInput::make('APP_FAVICON') + ->label('App Favicon') + ->hintIcon('tabler-question-mark') + ->hintIconTooltip('Favicons should be placed in the public folder, located in the root panel directory.') + ->required() + ->default(env('APP_FAVICON', './pelican.ico')), + Toggle::make('APP_DEBUG') + ->label('Enable Debug Mode?') + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('APP_DEBUG', (bool) $state)) + ->default(env('RECAPTCHA_ENABLED', config('recaptcha.enabled'))), + ToggleButtons::make('FILAMENT_TOP_NAVIGATION') + ->label('Navigation') + ->grouped() + ->options([ + false => 'Sidebar', + true => 'Topbar', + ]) + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('FILAMENT_TOP_NAVIGATION', (bool) $state)) + ->default(env('FILAMENT_TOP_NAVIGATION', config('panel.filament.top-navigation'))), + ToggleButtons::make('PANEL_USE_BINARY_PREFIX') + ->label('Unit prefix') + ->grouped() + ->options([ + false => 'Decimal Prefix (MB/ GB)', + true => 'Binary Prefix (MiB/ GiB)', + ]) + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_USE_BINARY_PREFIX', (bool) $state)) + ->default(env('PANEL_USE_BINARY_PREFIX', config('panel.use_binary_prefix'))), + ToggleButtons::make('APP_2FA_REQUIRED') + ->label('2FA Requirement') + ->grouped() + ->options([ + 0 => 'Not required', + 1 => 'Required for only Admins', + 2 => 'Required for all Users', + ]) + ->formatStateUsing(fn ($state): int => (int) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('APP_2FA_REQUIRED', (int) $state)) + ->default(env('APP_2FA_REQUIRED', config('panel.auth.2fa_required'))), + TagsInput::make('TRUSTED_PROXIES') + ->label('Trusted Proxies') + ->separator() + ->splitKeys(['Tab', ' ']) + ->placeholder('New IP or IP Range') + ->default(env('TRUSTED_PROXIES', config('trustedproxy.proxies'))) + ->hintActions([ + FormAction::make('clear') + ->label('Clear') + ->color('danger') + ->icon('tabler-trash') + ->requiresConfirmation() + ->action(fn (Set $set) => $set('TRUSTED_PROXIES', [])), + FormAction::make('cloudflare') + ->label('Set to Cloudflare IPs') + ->icon('tabler-brand-cloudflare') + ->action(fn (Set $set) => $set('TRUSTED_PROXIES', [ + '173.245.48.0/20', + '103.21.244.0/22', + '103.22.200.0/22', + '103.31.4.0/22', + '141.101.64.0/18', + '108.162.192.0/18', + '190.93.240.0/20', + '188.114.96.0/20', + '197.234.240.0/22', + '198.41.128.0/17', + '162.158.0.0/15', + '104.16.0.0/13', + '104.24.0.0/14', + '172.64.0.0/13', + '131.0.72.0/22', + ])), + ]), + ]; + } + + private function recaptchaSettings(): array + { + return [ + Toggle::make('RECAPTCHA_ENABLED') + ->label('Enable reCAPTCHA?') + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->live() + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('RECAPTCHA_ENABLED', (bool) $state)) + ->default(env('RECAPTCHA_ENABLED', config('recaptcha.enabled'))), + TextInput::make('RECAPTCHA_DOMAIN') + ->label('Domain') + ->required() + ->visible(fn (Get $get) => $get('RECAPTCHA_ENABLED')) + ->default(env('RECAPTCHA_DOMAIN', config('recaptcha.domain'))), + TextInput::make('RECAPTCHA_WEBSITE_KEY') + ->label('Website Key') + ->required() + ->visible(fn (Get $get) => $get('RECAPTCHA_ENABLED')) + ->default(env('RECAPTCHA_WEBSITE_KEY', config('recaptcha.website_key'))), + TextInput::make('RECAPTCHA_SECRET_KEY') + ->label('Secret Key') + ->required() + ->visible(fn (Get $get) => $get('RECAPTCHA_ENABLED')) + ->default(env('RECAPTCHA_SECRET_KEY', config('recaptcha.secret_key'))), + ]; + } + + private function mailSettings(): array + { + return [ + ToggleButtons::make('MAIL_MAILER') + ->label('Mail Driver') + ->columnSpanFull() + ->grouped() + ->options([ + 'log' => 'Print mails to Log', + 'smtp' => 'SMTP Server', + 'sendmail' => 'sendmail Binary', + 'mailgun' => 'Mailgun', + 'mandrill' => 'Mandrill', + 'postmark' => 'Postmark', + ]) + ->live() + ->default(env('MAIL_MAILER', config('mail.default'))) + ->hintAction( + FormAction::make('test') + ->label('Send Test Mail') + ->icon('tabler-send') + ->hidden(fn (Get $get) => $get('MAIL_MAILER') === 'log') + ->action(function () { + try { + MailNotification::route('mail', auth()->user()->email) + ->notify(new MailTested(auth()->user())); + + Notification::make() + ->title('Test Mail sent') + ->success() + ->send(); + } catch (Exception $exception) { + Notification::make() + ->title('Test Mail failed') + ->body($exception->getMessage()) + ->danger() + ->send(); + } + }) + ), + Section::make('"From" Settings') + ->description('Set the Address and Name used as "From" in mails.') + ->columns() + ->schema([ + TextInput::make('MAIL_FROM_ADDRESS') + ->label('From Address') + ->required() + ->email() + ->default(env('MAIL_FROM_ADDRESS', config('mail.from.address'))), + TextInput::make('MAIL_FROM_NAME') + ->label('From Name') + ->required() + ->default(env('MAIL_FROM_NAME', config('mail.from.name'))), + ]), + Section::make('SMTP Configuration') + ->columns() + ->visible(fn (Get $get) => $get('MAIL_MAILER') === 'smtp') + ->schema([ + TextInput::make('MAIL_HOST') + ->label('SMTP Host') + ->required() + ->default(env('MAIL_HOST', config('mail.mailers.smtp.host'))), + TextInput::make('MAIL_PORT') + ->label('SMTP Port') + ->required() + ->numeric() + ->minValue(1) + ->maxValue(65535) + ->default(env('MAIL_PORT', config('mail.mailers.smtp.port'))), + TextInput::make('MAIL_USERNAME') + ->label('SMTP Username') + ->required() + ->default(env('MAIL_USERNAME', config('mail.mailers.smtp.username'))), + TextInput::make('MAIL_PASSWORD') + ->label('SMTP Password') + ->password() + ->revealable() + ->default(env('MAIL_PASSWORD')), + ToggleButtons::make('MAIL_ENCRYPTION') + ->label('SMTP encryption') + ->required() + ->grouped() + ->options(['tls' => 'TLS', 'ssl' => 'SSL', '' => 'None']) + ->default(env('MAIL_ENCRYPTION', config('mail.mailers.smtp.encryption', 'tls'))), + ]), + Section::make('Mailgun Configuration') + ->columns() + ->visible(fn (Get $get) => $get('MAIL_MAILER') === 'mailgun') + ->schema([ + TextInput::make('MAILGUN_DOMAIN') + ->label('Mailgun Domain') + ->required() + ->default(env('MAILGUN_DOMAIN', config('services.mailgun.domain'))), + TextInput::make('MAILGUN_SECRET') + ->label('Mailgun Secret') + ->required() + ->default(env('MAIL_USERNAME', config('services.mailgun.secret'))), + TextInput::make('MAILGUN_ENDPOINT') + ->label('Mailgun Endpoint') + ->required() + ->default(env('MAILGUN_ENDPOINT', config('services.mailgun.endpoint'))), + ]), + ]; + } + + private function backupSettings(): array + { + return [ + ToggleButtons::make('APP_BACKUP_DRIVER') + ->label('Backup Driver') + ->columnSpanFull() + ->grouped() + ->options([ + Backup::ADAPTER_DAEMON => 'Wings', + Backup::ADAPTER_AWS_S3 => 'S3', + ]) + ->live() + ->default(env('APP_BACKUP_DRIVER', config('backups.default'))), + Section::make('Throttles') + ->description('Configure how many backups can be created in a period. Set period to 0 to disable this throttle.') + ->columns() + ->schema([ + TextInput::make('BACKUP_THROTTLE_LIMIT') + ->label('Limit') + ->required() + ->numeric() + ->minValue(1) + ->default(config('backups.throttles.limit')), + TextInput::make('BACKUP_THROTTLE_PERIOD') + ->label('Period') + ->required() + ->numeric() + ->minValue(0) + ->suffix('Seconds') + ->default(config('backups.throttles.period')), + ]), + Section::make('S3 Configuration') + ->columns() + ->visible(fn (Get $get) => $get('APP_BACKUP_DRIVER') === Backup::ADAPTER_AWS_S3) + ->schema([ + TextInput::make('AWS_DEFAULT_REGION') + ->label('Default Region') + ->required() + ->default(config('backups.disks.s3.region')), + TextInput::make('AWS_ACCESS_KEY_ID') + ->label('Access Key ID') + ->required() + ->default(config('backups.disks.s3.key')), + TextInput::make('AWS_SECRET_ACCESS_KEY') + ->label('Secret Access Key') + ->required() + ->default(config('backups.disks.s3.secret')), + TextInput::make('AWS_BACKUPS_BUCKET') + ->label('Bucket') + ->required() + ->default(config('backups.disks.s3.bucket')), + TextInput::make('AWS_ENDPOINT') + ->label('Endpoint') + ->required() + ->default(config('backups.disks.s3.endpoint')), + Toggle::make('AWS_USE_PATH_STYLE_ENDPOINT') + ->label('Use path style endpoint?') + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->live() + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('AWS_USE_PATH_STYLE_ENDPOINT', (bool) $state)) + ->default(env('AWS_USE_PATH_STYLE_ENDPOINT', config('backups.disks.s3.use_path_style_endpoint'))), + ]), + ]; + } + + private function miscSettings(): array + { + return [ + Section::make('Automatic Allocation Creation') + ->description('Toggle if Users can create allocations via the client area.') + ->columns() + ->collapsible() + ->collapsed() + ->schema([ + Toggle::make('PANEL_CLIENT_ALLOCATIONS_ENABLED') + ->label('Allow Users to create allocations?') + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->live() + ->columnSpanFull() + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_CLIENT_ALLOCATIONS_ENABLED', (bool) $state)) + ->default(env('PANEL_CLIENT_ALLOCATIONS_ENABLED', config('panel.client_features.allocations.enabled'))), + TextInput::make('PANEL_CLIENT_ALLOCATIONS_RANGE_START') + ->label('Starting Port') + ->required() + ->numeric() + ->minValue(1024) + ->maxValue(65535) + ->visible(fn (Get $get) => $get('PANEL_CLIENT_ALLOCATIONS_ENABLED')) + ->default(env('PANEL_CLIENT_ALLOCATIONS_RANGE_START')), + TextInput::make('PANEL_CLIENT_ALLOCATIONS_RANGE_END') + ->label('Ending Port') + ->required() + ->numeric() + ->minValue(1024) + ->maxValue(65535) + ->visible(fn (Get $get) => $get('PANEL_CLIENT_ALLOCATIONS_ENABLED')) + ->default(env('PANEL_CLIENT_ALLOCATIONS_RANGE_END')), + ]), + Section::make('Mail Notifications') + ->description('Toggle which mail notifications should be sent to Users.') + ->columns() + ->collapsible() + ->collapsed() + ->schema([ + Toggle::make('PANEL_SEND_INSTALL_NOTIFICATION') + ->label('Server Installed') + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->live() + ->columnSpanFull() + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_SEND_INSTALL_NOTIFICATION', (bool) $state)) + ->default(env('PANEL_SEND_INSTALL_NOTIFICATION', config('panel.email.send_install_notification'))), + Toggle::make('PANEL_SEND_REINSTALL_NOTIFICATION') + ->label('Server Reinstalled') + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->live() + ->columnSpanFull() + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('PANEL_SEND_REINSTALL_NOTIFICATION', (bool) $state)) + ->default(env('PANEL_SEND_REINSTALL_NOTIFICATION', config('panel.email.send_reinstall_notification'))), + ]), + Section::make('Connections') + ->description('Timeouts used when making requests.') + ->columns() + ->collapsible() + ->collapsed() + ->schema([ + TextInput::make('GUZZLE_TIMEOUT') + ->label('Request Timeout') + ->required() + ->numeric() + ->minValue(15) + ->maxValue(60) + ->suffix('Seconds') + ->default(env('GUZZLE_TIMEOUT', config('panel.guzzle.timeout'))), + TextInput::make('GUZZLE_CONNECT_TIMEOUT') + ->label('Connect Timeout') + ->required() + ->numeric() + ->minValue(5) + ->maxValue(60) + ->suffix('Seconds') + ->default(env('GUZZLE_CONNECT_TIMEOUT', config('panel.guzzle.connect_timeout'))), + ]), + Section::make('Activity Logs') + ->description('Configure how often old activity logs should be pruned and whether admin activities should be logged.') + ->columns() + ->collapsible() + ->collapsed() + ->schema([ + TextInput::make('APP_ACTIVITY_PRUNE_DAYS') + ->label('Prune age') + ->required() + ->numeric() + ->minValue(1) + ->maxValue(365) + ->suffix('Days') + ->default(env('APP_ACTIVITY_PRUNE_DAYS', config('activity.prune_days'))), + Toggle::make('APP_ACTIVITY_HIDE_ADMIN') + ->label('Hide admin activities?') + ->inline(false) + ->onIcon('tabler-check') + ->offIcon('tabler-x') + ->onColor('success') + ->offColor('danger') + ->live() + ->formatStateUsing(fn ($state): bool => (bool) $state) + ->afterStateUpdated(fn ($state, Set $set) => $set('APP_ACTIVITY_HIDE_ADMIN', (bool) $state)) + ->default(env('APP_ACTIVITY_HIDE_ADMIN', config('activity.hide_admin_activity'))), + ]), + Section::make('API') + ->description('Defines the rate limit for the number of requests per minute that can be executed.') + ->columns() + ->collapsible() + ->collapsed() + ->schema([ + TextInput::make('APP_API_CLIENT_RATELIMIT') + ->label('Client API Rate Limit') + ->required() + ->numeric() + ->minValue(1) + ->suffix('Requests Per Minute') + ->default(env('APP_API_CLIENT_RATELIMIT', config('http.rate_limit.client'))), + TextInput::make('APP_API_APPLICATION_RATELIMIT') + ->label('Application API Rate Limit') + ->required() + ->numeric() + ->minValue(1) + ->suffix('Requests Per Minute') + ->default(env('APP_API_APPLICATION_RATELIMIT', config('http.rate_limit.application'))), + ]), + ]; + } + + protected function getFormStatePath(): ?string + { + return 'data'; + } + + protected function hasUnsavedDataChangesAlert(): bool + { + return true; + } + + public function save(): void + { + try { + $data = $this->form->getState(); + + $this->writeToEnvironment($data); + + Artisan::call('config:clear'); + Artisan::call('queue:restart'); + + $this->rememberData(); + + $this->redirect($this->getUrl()); + + Notification::make() + ->title('Settings saved') + ->success() + ->send(); + } catch (Exception $exception) { + Notification::make() + ->title('Save failed') + ->body($exception->getMessage()) + ->danger() + ->send(); + } + } + + protected function getHeaderActions(): array + { + return [ + Action::make('save') + ->action('save') + ->keyBindings(['mod+s']), + ]; + + } + protected function getFormActions(): array + { + return []; + } +} diff --git a/app/Http/Controllers/Admin/Settings/AdvancedController.php b/app/Http/Controllers/Admin/Settings/AdvancedController.php deleted file mode 100644 index def9124a8b..0000000000 --- a/app/Http/Controllers/Admin/Settings/AdvancedController.php +++ /dev/null @@ -1,56 +0,0 @@ - $showRecaptchaWarning, - ]); - } - - /** - * @throws \App\Exceptions\Model\DataValidationException - */ - public function update(AdvancedSettingsFormRequest $request): RedirectResponse - { - foreach ($request->normalize() as $key => $value) { - Setting::set('settings::' . $key, $value); - } - - $this->kernel->call('queue:restart'); - $this->alert->success('Advanced settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash(); - - return redirect()->route('admin.settings.advanced'); - } -} diff --git a/app/Http/Controllers/Admin/Settings/IndexController.php b/app/Http/Controllers/Admin/Settings/IndexController.php deleted file mode 100644 index 47c5674582..0000000000 --- a/app/Http/Controllers/Admin/Settings/IndexController.php +++ /dev/null @@ -1,56 +0,0 @@ - $this->versionService, - 'languages' => $this->getAvailableLanguages(), - ]); - } - - /** - * Handle settings update. - * - * @throws \App\Exceptions\Model\DataValidationException - */ - public function update(BaseSettingsFormRequest $request): RedirectResponse - { - foreach ($request->normalize() as $key => $value) { - Setting::set('settings::' . $key, $value); - } - - $this->kernel->call('queue:restart'); - $this->alert->success('Panel settings have been updated successfully and the queue worker was restarted to apply these changes.')->flash(); - - return redirect()->route('admin.settings'); - } -} diff --git a/app/Http/Controllers/Admin/Settings/MailController.php b/app/Http/Controllers/Admin/Settings/MailController.php deleted file mode 100644 index 33aa5c31f2..0000000000 --- a/app/Http/Controllers/Admin/Settings/MailController.php +++ /dev/null @@ -1,82 +0,0 @@ - config('mail.default') !== 'smtp', - ]); - } - - /** - * Handle request to update SMTP mail settings. - * - * @throws DisplayException - * @throws \App\Exceptions\Model\DataValidationException - */ - public function update(MailSettingsFormRequest $request): Response - { - if (config('mail.default') !== 'smtp') { - throw new DisplayException('This feature is only available if SMTP is the selected email driver for the Panel.'); - } - - $values = $request->normalize(); - if (array_get($values, 'mail:mailers:smtp:password') === '!e') { - $values['mail:mailers:smtp:password'] = ''; - } - - foreach ($values as $key => $value) { - if (in_array($key, SettingsServiceProvider::getEncryptedKeys()) && !empty($value)) { - $value = encrypt($value); - } - - Setting::set('settings::' . $key, $value); - } - - $this->kernel->call('queue:restart'); - - return response('', 204); - } - - /** - * Submit a request to send a test mail message. - */ - public function test(Request $request): Response - { - try { - Notification::route('mail', $request->user()->email) - ->notify(new MailTested($request->user())); - } catch (\Exception $exception) { - return response($exception->getMessage(), 500); - } - - return response('', 204); - } -} diff --git a/app/Models/Setting.php b/app/Models/Setting.php index d25bd1b5d8..9efad2b080 100644 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -24,62 +24,4 @@ class Setting extends Model 'key' => 'required|string|between:1,255', 'value' => 'string', ]; - - private static array $cache = []; - - private static array $databaseMiss = []; - - /** - * Store a new persistent setting in the database. - */ - public static function set(string $key, string $value = null): void - { - // Clear item from the cache. - self::clearCache($key); - - self::query()->updateOrCreate(['key' => $key], ['value' => $value ?? '']); - - self::$cache[$key] = $value; - } - - /** - * Retrieve a persistent setting from the database. - */ - public static function get(string $key, mixed $default = null): mixed - { - // If item has already been requested return it from the cache. If - // we already know it is missing, immediately return the default value. - if (array_key_exists($key, self::$cache)) { - return self::$cache[$key]; - } elseif (array_key_exists($key, self::$databaseMiss)) { - return value($default); - } - - $instance = self::query()->where('key', $key)->first(); - if (is_null($instance)) { - self::$databaseMiss[$key] = true; - - return value($default); - } - - return self::$cache[$key] = $instance->value; - } - - /** - * Remove a key from the database cache. - */ - public static function forget(string $key) - { - self::clearCache($key); - - return self::query()->where('key', $key)->delete(); - } - - /** - * Remove a key from the cache. - */ - private static function clearCache(string $key): void - { - unset(self::$cache[$key], self::$databaseMiss[$key]); - } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 7d5ba0c44b..384e4501d1 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -87,11 +87,6 @@ public function boot(): void */ public function register(): void { - // Only load the settings service provider if the environment is configured to allow it. - if (!config('panel.load_environment_only', false) && $this->app->environment() !== 'testing') { - $this->app->register(SettingsServiceProvider::class); - } - $this->app->singleton('extensions.themes', function () { return new Theme(); }); diff --git a/app/Providers/SettingsServiceProvider.php b/app/Providers/SettingsServiceProvider.php deleted file mode 100644 index 5c74124559..0000000000 --- a/app/Providers/SettingsServiceProvider.php +++ /dev/null @@ -1,112 +0,0 @@ -keys = array_merge($this->keys, $this->emailKeys); - } - - try { - $values = Setting::all()->mapWithKeys(function ($setting) { - return [$setting->key => $setting->value]; - })->toArray(); - } catch (QueryException $exception) { - $log->notice('A query exception was encountered while trying to load settings from the database: ' . $exception->getMessage()); - - return; - } - - foreach ($this->keys as $key) { - $value = array_get($values, 'settings::' . $key, config(str_replace(':', '.', $key))); - if (in_array($key, self::$encrypted)) { - try { - $value = decrypt($value); - } catch (Exception) { - // ignore - } - } - - switch (strtolower($value)) { - case 'true': - case '(true)': - $value = true; - break; - case 'false': - case '(false)': - $value = false; - break; - case 'empty': - case '(empty)': - $value = ''; - break; - case 'null': - case '(null)': - $value = null; - } - - config()->set(str_replace(':', '.', $key), $value); - } - } - - public static function getEncryptedKeys(): array - { - return self::$encrypted; - } -} diff --git a/config/app.php b/config/app.php index e8d4deb301..f9a4acc850 100644 --- a/config/app.php +++ b/config/app.php @@ -5,6 +5,7 @@ return [ 'name' => env('APP_NAME', 'Pelican'), + 'favicon' => env('APP_FAVICON', './pelican.ico'), 'version' => 'canary', diff --git a/config/panel.php b/config/panel.php index 7b049f1459..32b11bc3a2 100644 --- a/config/panel.php +++ b/config/panel.php @@ -1,18 +1,6 @@ (bool) env('APP_ENVIRONMENT_ONLY', false), - /* |-------------------------------------------------------------------------- | Authentication diff --git a/lang/en/commands.php b/lang/en/commands.php index a42ca228b4..3b9ab9f452 100644 --- a/lang/en/commands.php +++ b/lang/en/commands.php @@ -6,7 +6,6 @@ 'author' => 'Provide the email address that eggs exported by this Panel should be from. This should be a valid email address.', 'url' => 'The application URL MUST begin with https:// or http:// depending on if you are using SSL or not. If you do not include the scheme your emails and other content will link to the wrong location.', 'timezone' => "The timezone should match one of PHP\'s supported timezones. If you are unsure, please reference https://php.net/manual/en/timezones.php.", - 'settings_ui' => 'Enable UI based settings editor?', ], 'redis' => [ 'note' => 'You\'ve selected the Redis driver for one or more options, please provide valid connection information below. In most cases you can use the defaults provided unless you have modified your setup.', diff --git a/resources/views/admin/settings/advanced.blade.php b/resources/views/admin/settings/advanced.blade.php deleted file mode 100644 index dc5543ca9c..0000000000 --- a/resources/views/admin/settings/advanced.blade.php +++ /dev/null @@ -1,127 +0,0 @@ -@extends('layouts.admin') -@include('partials/admin.settings.nav', ['activeTab' => 'advanced']) - -@section('title') - Advanced Settings -@endsection - -@section('content-header') -
php artisan p:environment:mail
command to update your email settings, or set MAIL_DRIVER=smtp
in your environment file.
- APP_ENVIRONMENT_ONLY=false
in your environment file in order to load settings dynamically.
-