diff --git a/app/Api/v1/Controllers/SettingController.php b/app/Api/v1/Controllers/SettingController.php index f6b435bd..a0c8b9dc 100644 --- a/app/Api/v1/Controllers/SettingController.php +++ b/app/Api/v1/Controllers/SettingController.php @@ -6,6 +6,7 @@ use App\Api\v1\Requests\SettingStoreRequest; use App\Api\v1\Requests\SettingUpdateRequest; use App\Facades\Settings; use App\Http\Controllers\Controller; +use Illuminate\Validation\ValidationException; class SettingController extends Controller { @@ -95,8 +96,18 @@ class SettingController extends Controller abort(404); } - $appSettings = config('2fauth.settings'); - if (array_key_exists($settingName, $appSettings)) { + $defaultAppSettings = config('2fauth.settings'); + + // When deleting a setting, it may be an original or an additional one: + // - Additional settings are created by administrators to extend 2FAuth, they are not registered in the laravel config object. + // They are not nullable so empty string is not allowed.They only exist in the Options table, so it is possible to delete them. + // - Original settings are part of 2FAuth, they are registered in the laravel config object with their default value. + // When set by an admin, their custom value is stored in the Options table too. Deleting a custom value in the Options table from here + // won't delete the setting at all, so we reject all requests that ask for. + // But there is an exception with the restrictRule and restrictList settings: + // Unlike other settings, these two have to support empty strings. Because the Options table does not allow empty strings, + // the only way to set them like so is to restore their original value, an empty string. + if (array_key_exists($settingName, $defaultAppSettings) && $defaultAppSettings[$settingName] !== '') { return response()->json( ['message' => 'bad request', 'reason' => [__('errors.delete_user_setting_only')], diff --git a/config/2fauth.php b/config/2fauth.php index db25deb4..87e40472 100644 --- a/config/2fauth.php +++ b/config/2fauth.php @@ -89,6 +89,8 @@ return [ 'disableRegistration' => false, 'enableSso' => true, 'restrictRegistration' => false, + 'restrictList' => '', + 'restrictRule' => '', 'keepSsoRegistrationEnabled' => false, ], diff --git a/resources/js/composables/appSettingsUpdater.js b/resources/js/composables/appSettingsUpdater.js new file mode 100644 index 00000000..66381197 --- /dev/null +++ b/resources/js/composables/appSettingsUpdater.js @@ -0,0 +1,32 @@ +import appSettingService from '@/services/appSettingService' +import { useAppSettingsStore } from '@/stores/appSettings' +import { useNotifyStore } from '@/stores/notify' + +/** + * Saves a setting on the backend + * @param {string} preference + * @param {any} value + */ +export async function useAppSettingsUpdater(setting, value, returnValidationError = false) { + + // const appSettings = useAppSettingsStore() + let data = null + let error = null + + await appSettingService.update(setting, value, { returnError: true }) + .then(response => { + // appSettings[setting] = value + data = value + useNotifyStore().success({ type: 'is-success', text: trans('settings.forms.setting_saved') }) + }) + .catch(err => { + if( returnValidationError && err.response.status === 422 ) { + error = err + } + else { + useNotifyStore().error(err); + } + }) + + return { data, error } +} \ No newline at end of file diff --git a/resources/js/services/appSettingService.js b/resources/js/services/appSettingService.js index e7743a98..03dcea5c 100644 --- a/resources/js/services/appSettingService.js +++ b/resources/js/services/appSettingService.js @@ -7,7 +7,7 @@ export default { * * @returns */ - get(config = {}) { + getAll(config = {}) { return apiClient.get('/settings', { ...config }) }, @@ -15,8 +15,8 @@ export default { * * @returns */ - update(name, value) { - return apiClient.put('/settings/' + name, { value: value }) + update(name, value, config = {}) { + return apiClient.put('/settings/' + name, { value: value }, { ...config }) }, /** diff --git a/resources/js/stores/appSettings.js b/resources/js/stores/appSettings.js index 351464f8..f553f6c9 100644 --- a/resources/js/stores/appSettings.js +++ b/resources/js/stores/appSettings.js @@ -1,4 +1,6 @@ +import appSettingService from '@/services/appSettingService' import { defineStore } from 'pinia' +import { useNotifyStore } from '@/stores/notify' export const useAppSettingsStore = defineStore({ id: 'appSettings', @@ -8,6 +10,20 @@ export const useAppSettingsStore = defineStore({ }, actions: { - + + /** + * Fetches the appSetting collection from the backend + */ + async fetch() { + appSettingService.getAll({ returnError: true }) + .then(response => { + response.data.forEach(setting => { + this[setting.key] = setting.value + }) + }) + .catch(error => { + useNotifyStore().alert({ text: trans('errors.data_cannot_be_refreshed_from_server') }) + }) + }, }, }) diff --git a/resources/js/views/admin/AppSetup.vue b/resources/js/views/admin/AppSetup.vue index a8d49671..8635f02c 100644 --- a/resources/js/views/admin/AppSetup.vue +++ b/resources/js/views/admin/AppSetup.vue @@ -1,7 +1,7 @@ diff --git a/resources/lang/en/admin.php b/resources/lang/en/admin.php index 762175ec..9cad331d 100644 --- a/resources/lang/en/admin.php +++ b/resources/lang/en/admin.php @@ -15,6 +15,7 @@ return [ 'admin' => 'Admin', 'app_setup' => 'App setup', + 'auth' => 'Auth', 'registrations' => 'Registrations', 'users' => 'Users', 'users_legend' => 'Manage users registered on your instance or create new ones.', @@ -83,6 +84,7 @@ return [ 'show_one_year_log' => 'Show entries from the last year', 'sort_by_date_asc' => 'Show least recent first', 'sort_by_date_desc' => 'Show most recent first', + 'single_sign_on' => 'Single Sign-On (SSO)', 'forms' => [ 'use_encryption' => [ 'label' => 'Protect sensitive data', @@ -105,7 +107,7 @@ return [ 'help' => 'Prevent new user registration. Unless overridden (see below), this affects SSO as well, so new users won\'t be able to sign in via SSO', ], 'enable_sso' => [ - 'label' => 'Enable Single Sign-On (SSO)', + 'label' => 'Enable SSO', 'help' => 'Allow visitors to authenticate using an external ID via the Single Sign-On scheme', ], 'keep_sso_registration_enabled' => [