From 9f9f021fea958dc816794436d25a64cd55df4bfe Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Fri, 8 Mar 2024 15:23:39 +0100 Subject: [PATCH 1/8] style: format scope validation error --- backend/core/base_models.py | 7 +------ backend/core/serializers.py | 7 ++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/core/base_models.py b/backend/core/base_models.py index 82c7984a7..f744d66eb 100644 --- a/backend/core/base_models.py +++ b/backend/core/base_models.py @@ -92,12 +92,7 @@ def clean(self) -> None: if not self.is_unique_in_scope(scope=scope, fields_to_check=_fields_to_check): for field in _fields_to_check: if not self.is_unique_in_scope(scope=scope, fields_to_check=[field]): - field_errors[field] = ValidationError( - _( - f"{getattr(self, field)} is already in use in this scope. Please choose another value." - ), - code="unique", - ) + field_errors[field] = f"{getattr(self, field)} is already in use in this scope. Please choose another value." super().clean() if field_errors: raise ValidationError(field_errors) diff --git a/backend/core/serializers.py b/backend/core/serializers.py index ab6444bcc..94720f115 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -42,7 +42,12 @@ def create(self, validated_data: Any): "folder": "You do not have permission to create objects in this folder" } ) - return super().create(validated_data) + try: + object_created = super().create(validated_data) + return object_created + except Exception as e: + logger.error(e) + raise serializers.ValidationError(e.args[0]) class Meta: model: models.Model From ffdba499e2660e402b3166b9273c8448f7d10fac Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Mon, 11 Mar 2024 10:08:41 +0100 Subject: [PATCH 2/8] fix: display errors in update form --- backend/core/base_models.py | 2 +- backend/core/serializers.py | 7 ++++++- .../(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts | 3 +++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/core/base_models.py b/backend/core/base_models.py index f744d66eb..4f11da487 100644 --- a/backend/core/base_models.py +++ b/backend/core/base_models.py @@ -92,7 +92,7 @@ def clean(self) -> None: if not self.is_unique_in_scope(scope=scope, fields_to_check=_fields_to_check): for field in _fields_to_check: if not self.is_unique_in_scope(scope=scope, fields_to_check=[field]): - field_errors[field] = f"{getattr(self, field)} is already in use in this scope. Please choose another value." + field_errors[field] = f"{getattr(self, field)} is already used in this scope. Please choose another value." super().clean() if field_errors: raise ValidationError(field_errors) diff --git a/backend/core/serializers.py b/backend/core/serializers.py index 94720f115..92de37ec0 100644 --- a/backend/core/serializers.py +++ b/backend/core/serializers.py @@ -23,7 +23,12 @@ def update(self, instance: models.Model, validated_data: Any) -> models.Model: raise serializers.ValidationError( {"urn": "Imported objects cannot be modified"} ) - return super().update(instance, validated_data) + try: + object_updated = super().update(instance, validated_data) + return object_updated + except Exception as e: + logger.error(e) + raise serializers.ValidationError(e.args[0]) def create(self, validated_data: Any): logger.debug("validated data", **validated_data) diff --git a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts index 279de22dc..217c160cb 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/[model=urlmodel]/[id=uuid]/edit/+page.server.ts @@ -34,6 +34,9 @@ export const actions: Actions = { if (response.non_field_errors) { setError(form, 'non_field_errors', response.non_field_errors); } + Object.entries(response).forEach(([key, value]) => { + setError(form, key, value); + }); return fail(400, { form: form }); } const createdObject = await res.json(); From 1971b6beeb8ec7733cff9759909be2350454ac6b Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 12 Mar 2024 08:47:47 +0100 Subject: [PATCH 3/8] feat: display field errors in risk scenario update view --- .../routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts index 6aef14d87..c54708e40 100644 --- a/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts +++ b/frontend/src/routes/(app)/risk-scenarios/[id=uuid]/edit/+page.server.ts @@ -212,6 +212,9 @@ export const actions: Actions = { if (response.non_field_errors) { setError(form, 'non_field_errors', response.non_field_errors); } + Object.entries(response).forEach(([key, value]) => { + setError(form, key, value); + }); return fail(400, { form: form }); } const model: string = urlParamModelVerboseName(URLModel); From 251c0c2c137eaae7789c481364744d598ca16aa9 Mon Sep 17 00:00:00 2001 From: Mohamed-Hacene Date: Tue, 12 Mar 2024 10:24:39 +0100 Subject: [PATCH 4/8] fix: error message for same name in a scope --- frontend/src/lib/components/Forms/Form.svelte | 21 +++++++- .../src/lib/components/Forms/ModelForm.svelte | 2 - .../(app)/[model=urlmodel]/+page.server.ts | 16 +++--- .../(app)/[model=urlmodel]/+page.svelte | 52 +------------------ .../[id=uuid]/+page.svelte | 6 ++- .../risk-assessments/[id=uuid]/+page.svelte | 3 +- 6 files changed, 37 insertions(+), 63 deletions(-) diff --git a/frontend/src/lib/components/Forms/Form.svelte b/frontend/src/lib/components/Forms/Form.svelte index 107d16d9a..910cf5465 100644 --- a/frontend/src/lib/components/Forms/Form.svelte +++ b/frontend/src/lib/components/Forms/Form.svelte @@ -4,6 +4,11 @@ import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte'; import type { AnyZodObject } from 'zod'; + import type { ModalStore } from '@skeletonlabs/skeleton'; + import { getModalStore } from '@skeletonlabs/skeleton'; + + const modalStore: ModalStore = getModalStore(); + export let data: SuperValidated; export let dataType: 'form' | 'json'; export let invalidateAll = true; // set to false to keep form data using muliple forms on a page @@ -13,12 +18,26 @@ export let debug = false; // set to true to enable SuperDebug component + function handleFormUpdated({ + form, + closeModal + }: { + form: any; + closeModal: boolean; + }) { + if (closeModal && form.valid) { + $modalStore[0] ? modalStore.close() : null; + } + } + export const _form = superForm(data, { dataType: dataType, invalidateAll: invalidateAll, applyAction: applyAction, resetForm: resetForm, - validators: validators + validators: validators, + onUpdated: ({ form }) => handleFormUpdated({ form, closeModal: true }) + }); const { form, message /*, tainted*/, delayed, errors, allErrors, enhance } = _form; diff --git a/frontend/src/lib/components/Forms/ModelForm.svelte b/frontend/src/lib/components/Forms/ModelForm.svelte index aeb577f33..01a2ed047 100644 --- a/frontend/src/lib/components/Forms/ModelForm.svelte +++ b/frontend/src/lib/components/Forms/ModelForm.svelte @@ -17,8 +17,6 @@ import { browser } from '$app/environment'; import { page } from '$app/stores'; import * as m from '$paraglide/messages.js'; - import { localItems, toCamelCase } from '$lib/utils/locales'; - import { languageTag } from '$paraglide/runtime'; export let form: SuperValidated; export let model: ModelInfo; diff --git a/frontend/src/routes/(app)/[model=urlmodel]/+page.server.ts b/frontend/src/routes/(app)/[model=urlmodel]/+page.server.ts index 01a0a7f36..174de2c3e 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/+page.server.ts +++ b/frontend/src/routes/(app)/[model=urlmodel]/+page.server.ts @@ -128,19 +128,19 @@ export const actions: Actions = { const model: string = urlParamModelVerboseName(event.params.model!); // TODO: reference newly created object if (model === 'User') { - return message(createForm, m.successfullyCreatedObject({object: localItems(languageTag())[model.toLowerCase()].toLowerCase()})); + setFlash({ type: 'success', message: m.successfullyCreatedObject({object: localItems(languageTag())[model.toLowerCase()].toLowerCase()}) }, event); } - return message(createForm, m.successfullyCreatedObject({object: localItems(languageTag())[toCamelCase(model.toLowerCase())].toLowerCase()})); + setFlash({ type: 'success', message: m.successfullyCreatedObject({object: localItems(languageTag())[model.toLowerCase()].toLowerCase()}) }, event); } return { createForm }; }, - delete: async ({ request, fetch, params }) => { - const formData = await request.formData(); + delete: async (event) => { + const formData = await event.request.formData(); const schema = z.object({ id: z.string().uuid() }); const deleteForm = await superValidate(formData, schema); const id = deleteForm.data.id; - const endpoint = `${BASE_API_URL}/${params.model}/${id}/`; + const endpoint = `${BASE_API_URL}/${event.params.model}/${id}/`; if (!deleteForm.valid) { console.log(deleteForm.errors); @@ -151,7 +151,7 @@ export const actions: Actions = { const requestInitOptions: RequestInit = { method: 'DELETE' }; - const res = await fetch(endpoint, requestInitOptions); + const res = await event.fetch(endpoint, requestInitOptions); if (!res.ok) { const response = await res.json(); console.log(response); @@ -160,9 +160,9 @@ export const actions: Actions = { } return fail(400, { form: deleteForm }); } - const model: string = urlParamModelVerboseName(params.model!); + const model: string = urlParamModelVerboseName(event.params.model!); // TODO: reference object by name instead of id - return message(deleteForm, m.successfullyDeletedObject({object: localItems(languageTag())[toCamelCase(model.toLowerCase())].toLowerCase(), id: id})); + setFlash({ type: 'success', message: m.successfullyDeletedObject({object: localItems(languageTag())[toCamelCase(model.toLowerCase())].toLowerCase()}) }, event); } return { deleteForm }; } diff --git a/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte b/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte index cf46c91a0..21d2e4c71 100644 --- a/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte +++ b/frontend/src/routes/(app)/[model=urlmodel]/+page.svelte @@ -1,15 +1,12 @@