diff --git a/app/Api/v1/Requests/SettingUpdateRequest.php b/app/Api/v1/Requests/SettingUpdateRequest.php index a4f618f1..5f5b6d5c 100644 --- a/app/Api/v1/Requests/SettingUpdateRequest.php +++ b/app/Api/v1/Requests/SettingUpdateRequest.php @@ -2,6 +2,7 @@ namespace App\Api\v1\Requests; +use App\Rules\IsValideEmailList; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Auth; @@ -24,8 +25,16 @@ public function authorize() */ public function rules() { - return [ - 'value' => 'required', + $rule = [ + 'value' => [ + 'required', + ] ]; + + if ($this->route()->parameter('settingName') == 'restrictList') { + $rule['value'][] = new IsValideEmailList; + } + + return $rule; } } diff --git a/app/Http/Requests/UserStoreRequest.php b/app/Http/Requests/UserStoreRequest.php index 16d6969f..5f6a09dd 100644 --- a/app/Http/Requests/UserStoreRequest.php +++ b/app/Http/Requests/UserStoreRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Rules\ComplyWithEmailRestrictionPolicy; use Illuminate\Foundation\Http\FormRequest; class UserStoreRequest extends FormRequest @@ -24,8 +25,15 @@ public function authorize() public function rules() { return [ - 'name' => 'unique:App\Models\User,name|required|string|max:191', - 'email' => 'unique:App\Models\User,email|required|string|email|max:191', + 'name' => 'unique:App\Models\User,name|required|string|max:191', + 'email' => [ + 'unique:App\Models\User,email', + 'required', + 'string', + 'email', + 'max:191', + new ComplyWithEmailRestrictionPolicy, + ], 'password' => 'required|string|min:8|confirmed', ]; } diff --git a/app/Http/Requests/UserUpdateRequest.php b/app/Http/Requests/UserUpdateRequest.php index 6aa8da26..dc9e92c5 100644 --- a/app/Http/Requests/UserUpdateRequest.php +++ b/app/Http/Requests/UserUpdateRequest.php @@ -2,6 +2,7 @@ namespace App\Http\Requests; +use App\Rules\ComplyWithEmailRestrictionPolicy; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Auth; use Illuminate\Validation\Rule; @@ -37,6 +38,7 @@ public function rules() 'email', 'max:191', Rule::unique('users')->ignore($this->user()->id), + new ComplyWithEmailRestrictionPolicy, ], 'password' => 'required', ]; diff --git a/app/Rules/ComplyWithEmailRestrictionPolicy.php b/app/Rules/ComplyWithEmailRestrictionPolicy.php new file mode 100644 index 00000000..12bb8ee6 --- /dev/null +++ b/app/Rules/ComplyWithEmailRestrictionPolicy.php @@ -0,0 +1,42 @@ +translate(); + } + } + else { + if (! $validatesFilter || ! $validatesRegex) { + $fail('validation.custom.email.ComplyWithEmailRestrictionPolicy')->translate(); + } + } + } + } +} diff --git a/app/Rules/IsValideEmailList.php b/app/Rules/IsValideEmailList.php new file mode 100644 index 00000000..55ae6050 --- /dev/null +++ b/app/Rules/IsValideEmailList.php @@ -0,0 +1,29 @@ + 'email', + ] + )->passes(); + + if (! $pass) { + $fail('validation.custom.email.IsValidEmailList')->translate(); + } + } +} diff --git a/config/2fauth.php b/config/2fauth.php index 9afb9bd0..2b84131e 100644 --- a/config/2fauth.php +++ b/config/2fauth.php @@ -74,6 +74,7 @@ 'latestRelease' => false, 'disableRegistration' => false, 'enableSso' => true, + 'restrictRegistration' => false, ], /* diff --git a/resources/js/icons.js b/resources/js/icons.js index 7711642c..4a1fa8d0 100644 --- a/resources/js/icons.js +++ b/resources/js/icons.js @@ -46,6 +46,7 @@ import { faFileLines, faVideoSlash, faChevronRight, + faSlash, } from '@fortawesome/free-solid-svg-icons' import { @@ -107,6 +108,7 @@ library.add( faChevronRight, faOpenid, faPaperPlane, + faSlash, ); export default FontAwesomeIcon \ No newline at end of file diff --git a/resources/js/services/appSettingService.js b/resources/js/services/appSettingService.js index 2905554d..e7743a98 100644 --- a/resources/js/services/appSettingService.js +++ b/resources/js/services/appSettingService.js @@ -3,6 +3,14 @@ import { httpClientFactory } from '@/services/httpClientFactory' const apiClient = httpClientFactory('api') export default { + /** + * + * @returns + */ + get(config = {}) { + return apiClient.get('/settings', { ...config }) + }, + /** * * @returns @@ -11,4 +19,11 @@ export default { return apiClient.put('/settings/' + name, { value: value }) }, + /** + * + * @returns + */ + delete(name, config = {}) { + return apiClient.delete('/settings/' + name, { ...config }) + }, } \ No newline at end of file diff --git a/resources/js/views/admin/AppSetup.vue b/resources/js/views/admin/AppSetup.vue index 3d9187a0..16ca23d3 100644 --- a/resources/js/views/admin/AppSetup.vue +++ b/resources/js/views/admin/AppSetup.vue @@ -17,6 +17,19 @@ const infos = ref() const listInfos = ref(null) const isSendingTestEmail = ref(false) + const fieldErrors = ref({ + restrictList: null, + restrictRule: null, + }) + const _settings = ref({ + checkForUpdate: appSettings.checkForUpdate, + useEncryption: appSettings.useEncryption, + restrictRegistration: appSettings.restrictRegistration, + restrictList: appSettings.restrictList, + restrictRule: appSettings.restrictRule, + disableRegistration: appSettings.disableRegistration, + enableSso: appSettings.enableSso, + }) /** * Saves a setting on the backend @@ -24,9 +37,46 @@ * @param {any} value */ function saveSetting(setting, value) { + fieldErrors.value[setting] = null + appSettingService.update(setting, value).then(response => { + appSettings[setting] = value useNotifyStore().success({ type: 'is-success', text: trans('settings.forms.setting_saved') }) }) + .catch(error => { + if( error.response.status === 422 ) { + fieldErrors.value[setting] = error.response.data.message + } + else { + notify.error(error); + } + }) + } + + /** + * Saves a setting on the backend + * @param {string} preference + * @param {any} value + */ + function saveOrDeleteSetting(setting, value) { + if (value == '') { + fieldErrors.value[setting] = null + + appSettingService.delete(setting, { returnError: true }).then(response => { + appSettings[setting] = '' + useNotifyStore().success({ type: 'is-success', text: trans('settings.forms.setting_saved') }) + }) + .catch(error => { + // appSettings[setting] = oldValue + + if( error.response.status !== 404 ) { + notify.error(error); + } + }) + } + else { + saveSetting(setting, value) + } } /** @@ -47,7 +97,23 @@ } }) - onMounted(() => { + onMounted(async () => { + appSettingService.get({ returnError: true }) + .then(response => { + // we reset those two because they are not registered on server side + // in order to be able to set them to blank + _settings.value.restrictList = '' + _settings.value.restrictRule = '' + + response.data.forEach(setting => { + appSettings[setting.key] = setting.value + _settings.value[setting.key] = setting.value + }) + }) + .catch(error => { + notify.alert({ text: trans('errors.data_cannot_be_refreshed_from_server') }) + }) + systemService.getSystemInfos({returnError: true}).then(response => { infos.value = response.data.common }) @@ -66,7 +132,7 @@