From ef93cf2a3486135b3826d096a4da24c101f9ef7a Mon Sep 17 00:00:00 2001 From: davwas Date: Fri, 6 Oct 2023 23:35:01 +0200 Subject: [PATCH 01/16] add delete action to terms of use and privacy policy modules --- src/store/privacy-policy.ts | 18 ++++++++++++++++++ src/store/terms-of-use.ts | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/store/privacy-policy.ts b/src/store/privacy-policy.ts index 00744deb87..d41c883adf 100644 --- a/src/store/privacy-policy.ts +++ b/src/store/privacy-policy.ts @@ -106,4 +106,22 @@ export default class PrivacyPolicyModule extends VuexModule { this.setStatus("error"); } } + + @Action + async deletePrivacyPolicy(): Promise { + try { + this.resetBusinessError(); + this.setStatus("pending"); + + if (this.privacyPolicy) { + await $axios.delete(`/v1/consentVersions/${this.privacyPolicy._id}`); + } + + this.setPrivacyPolicy(null); + this.setStatus("completed"); + } catch (error) { + this.setBusinessError(error as BusinessError); + this.setStatus("error"); + } + } } diff --git a/src/store/terms-of-use.ts b/src/store/terms-of-use.ts index 50fe43bf90..2a02873736 100644 --- a/src/store/terms-of-use.ts +++ b/src/store/terms-of-use.ts @@ -104,4 +104,22 @@ export default class TermsOfUseModule extends VuexModule { this.setStatus("error"); } } + + @Action + async deleteTermsOfUse(): Promise { + try { + this.resetBusinessError(); + this.setStatus("pending"); + + if (this.termsOfUse) { + await $axios.delete(`/v1/consentVersions/${this.termsOfUse._id}`); + } + + this.setTermsOfUse(null); + this.setStatus("completed"); + } catch (error) { + this.setBusinessError(error as BusinessError); + this.setStatus("error"); + } + } } From c4801cd5f9a9093f88daffe483c20452a31e8061 Mon Sep 17 00:00:00 2001 From: davwas Date: Fri, 6 Oct 2023 23:35:09 +0200 Subject: [PATCH 02/16] add tests --- src/store/privacy-policy.unit.ts | 41 ++++++++++++++++++++++++++++++++ src/store/terms-of-use.unit.ts | 38 +++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/store/privacy-policy.unit.ts b/src/store/privacy-policy.unit.ts index 1536dc93cc..fa8e227722 100644 --- a/src/store/privacy-policy.unit.ts +++ b/src/store/privacy-policy.unit.ts @@ -149,6 +149,47 @@ describe("privacy policy module", () => { expect(policyModule.privacyPolicy).toBe(getRequestReturn.data); }); }); + + describe("deletePrivacyPolicy", () => { + it("should call backend and set correct state", async () => { + const policyModule = new PrivacyPolicyModule({}); + + policyModule.privacyPolicy = { + _id: "123", + schoolId: "333", + title: "sometitle", + consentText: "", + publishedAt: "somedate", + createdAt: "somedate", + updatedAt: "somedate", + consentTypes: ["privacy"], + consentData: { + _id: "999", + schoolId: "333", + createdAt: "someotherdate", + updatedAt: "someotherdate", + fileType: "pdf", + fileName: "somefilename", + data: "data:application/pdf;base64,SOMEFILEDATA", + }, + }; + + const setPrivacyPolicySpy = jest.spyOn( + policyModule, + "setPrivacyPolicy" + ); + const setStatusSpy = jest.spyOn(policyModule, "setStatus"); + + await policyModule.deletePrivacyPolicy(); + + expect(receivedRequests.length).toBe(1); + expect(receivedRequests[0].path).toBe("/v1/consentVersions/123"); + expect(setStatusSpy).toHaveBeenCalledWith("pending"); + expect(setStatusSpy).toHaveBeenCalledWith("completed"); + expect(setPrivacyPolicySpy).toHaveBeenCalledWith(null); + expect(policyModule.privacyPolicy).toBe(null); + }); + }); }); describe("mutations", () => { diff --git a/src/store/terms-of-use.unit.ts b/src/store/terms-of-use.unit.ts index b302fabf1f..b7c950c72e 100644 --- a/src/store/terms-of-use.unit.ts +++ b/src/store/terms-of-use.unit.ts @@ -143,6 +143,44 @@ describe("terms of use module", () => { expect(termsOfUseModule.termsOfUse).toBe(getRequestReturn.data); }); }); + + describe("deleteTermsOfUse", () => { + it("should call backend and set correct state", async () => { + const termsOfUseModule = new TermsOfUseModule({}); + + termsOfUseModule.termsOfUse = { + _id: "123", + schoolId: "333", + title: "sometitle", + consentText: "", + publishedAt: "somedate", + createdAt: "somedate", + updatedAt: "somedate", + consentTypes: ["termsOfUse"], + consentData: { + _id: "999", + schoolId: "333", + createdAt: "someotherdate", + updatedAt: "someotherdate", + fileType: "pdf", + fileName: "somefilename", + data: "data:application/pdf;base64,SOMEFILEDATA", + }, + }; + + const setTermsOfUseSpy = jest.spyOn(termsOfUseModule, "setTermsOfUse"); + const setStatusSpy = jest.spyOn(termsOfUseModule, "setStatus"); + + await termsOfUseModule.deleteTermsOfUse(); + + expect(receivedRequests.length).toBe(1); + expect(receivedRequests[0].path).toBe("/v1/consentVersions/123"); + expect(setStatusSpy).toHaveBeenCalledWith("pending"); + expect(setStatusSpy).toHaveBeenCalledWith("completed"); + expect(setTermsOfUseSpy).toHaveBeenCalledWith(null); + expect(termsOfUseModule.termsOfUse).toBe(null); + }); + }); }); describe("mutations", () => { From 80dfb2d1609fd4349b82b416d1134761e4b6e5c2 Mon Sep 17 00:00:00 2001 From: davwas Date: Mon, 9 Oct 2023 09:39:32 +0200 Subject: [PATCH 03/16] add translations --- src/locales/de.json | 9 ++++++++- src/locales/en.json | 7 +++++++ src/locales/es.json | 7 +++++++ src/locales/uk.json | 7 +++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/locales/de.json b/src/locales/de.json index 68461258e3..1c1818f617 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -14,6 +14,7 @@ "common.actions.ok": "OK", "common.action.publish": "Veröffentlichen", "common.actions.remove": "Löschen", + "common.actions.delete": "Löschen", "common.actions.save": "Speichern", "common.actions.share": "Teilen", "common.actions.shareCourse": "Kurskopie teilen", @@ -700,7 +701,10 @@ "pages.administration.school.index.schoolPolicy.validation.fileTooBig": "Die Datei ist größer als 4MB. Bitte reduzieren sie die Dateigröße", "pages.administration.school.index.schoolPolicy.validation.notPdf": "Dieses Dateiformat wird nicht unterstützt. Verwenden Sie bitte PDF", "pages.administration.school.index.schoolPolicy.error": "Beim Laden der Datenschutzerklärung ist ein Fehler aufgetreten", - "pages.administration.school.index.schoolPolicy.success": "Neue Datei wurde erfolgreich hochgeladen.", + "pages.administration.school.index.schoolPolicy.delete.title": "Datenschutzerklärung löschen", + "pages.administration.school.index.schoolPolicy.delete.text": "Wenn Sie diese Datei löschen, wird automatisch die Standard-Datenschutzerklärung verwendet.", + "pages.administration.school.index.schoolPolicy.delete.success": "Privacy Policy file was successfully deleted.", + "pages.administration.school.index.schoolPolicy.success": "Die Datei mit den Datenschutzerklärung wurde erfolgreich gelöscht.", "pages.administration.school.index.schoolPolicy.replace": "Ersetzen", "pages.administration.school.index.schoolPolicy.cancel": "Abbrechen", "pages.administration.school.index.schoolPolicy.uploadedOn": "Hochgeladen am {date}", @@ -714,6 +718,9 @@ "pages.administration.school.index.termsOfUse.validation.fileTooBig": "Die Datei ist größer als 4MB. Bitte reduzieren sie die Dateigröße", "pages.administration.school.index.termsOfUse.validation.notPdf": "Dieses Dateiformat wird nicht unterstützt. Verwenden Sie bitte PDF", "pages.administration.school.index.termsOfUse.error": "Beim Laden der Nutzungsordnung ist ein Fehler aufgetreten", + "pages.administration.school.index.termsOfUse.delete.title": "Nutzungsordnung löschen", + "pages.administration.school.index.termsOfUse.delete.text": "Wenn Sie diese Datei löschen, wird automatisch die Standard-Nutzungsordnung verwendet.", + "pages.administration.school.index.termsOfUse.delete.success": "Die Datei mit den Nutzungsordnung wurde erfolgreich gelöscht.", "pages.administration.school.index.termsOfUse.success": "Neue Datei wurde erfolgreich hochgeladen.", "pages.administration.school.index.termsOfUse.replace": "Ersetzen", "pages.administration.school.index.termsOfUse.cancel": "Abbrechen", diff --git a/src/locales/en.json b/src/locales/en.json index 22191139ef..2c7a481ce6 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -15,6 +15,7 @@ "common.actions.ok": "OK", "common.action.publish": "Publish", "common.actions.remove": "Remove", + "common.actions.delete": "Delete", "common.actions.save": "Save", "common.actions.share": "Share", "common.actions.shareCourse": "Share course copy", @@ -698,6 +699,9 @@ "pages.administration.school.index.schoolPolicy.validation.fileTooBig": "The file is larger than 4MB. Please reduce the file size", "pages.administration.school.index.schoolPolicy.validation.notPdf": "This file format is not supported. Please use PDF only", "pages.administration.school.index.schoolPolicy.error": "An error occurred while loading the privacy policy", + "pages.administration.school.index.schoolPolicy.delete.title": "Delete Privacy Policy", + "pages.administration.school.index.schoolPolicy.delete.text": "If you delete this file, the default Privacy Policy will be automatically used.", + "pages.administration.school.index.schoolPolicy.delete.success": "Privacy Policy file was successfully deleted.", "pages.administration.school.index.schoolPolicy.success": "New file was successfully uploaded.", "pages.administration.school.index.schoolPolicy.replace": "Replace", "pages.administration.school.index.schoolPolicy.cancel": "Cancel", @@ -712,6 +716,9 @@ "pages.administration.school.index.termsOfUse.validation.fileTooBig": "The file is larger than 4MB. Please reduce the file size", "pages.administration.school.index.termsOfUse.validation.notPdf": "This file format is not supported. Please use PDF only", "pages.administration.school.index.termsOfUse.error": "An error occurred while loading the terms of use", + "pages.administration.school.index.termsOfUse.delete.title": "Delete Terms of Use", + "pages.administration.school.index.termsOfUse.delete.text": "If you delete this file, the default Terms of Use will be automatically used.", + "pages.administration.school.index.termsOfUse.delete.success": "Terms of Use file was successfully deleted.", "pages.administration.school.index.termsOfUse.success": "New file was successfully uploaded.", "pages.administration.school.index.termsOfUse.replace": "Replace", "pages.administration.school.index.termsOfUse.cancel": "Cancel", diff --git a/src/locales/es.json b/src/locales/es.json index 63e6bd8d61..574dea3d1c 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -19,6 +19,7 @@ "common.actions.logout": "Desconectar", "common.action.publish": "Publicar", "common.actions.remove": "Eliminar", + "common.actions.delete": "Borrar", "common.actions.save": "Guardar", "common.actions.share": "Compartir", "common.actions.shareCourse": "Compartir copia de la cotización", @@ -687,6 +688,9 @@ "pages.administration.school.index.schoolPolicy.validation.fileTooBig": "El archivo pesa más de 4 MB. Por favor, reduzca el tamaño del archivo", "pages.administration.school.index.schoolPolicy.validation.notPdf": "Este formato de archivo no es compatible. Utilice sólo PDF", "pages.administration.school.index.schoolPolicy.error": "Se ha producido un error al cargar la Política de Privacidad", + "pages.administration.school.index.schoolPolicy.delete.title": "Borrar la Política de Privacidad", + "pages.administration.school.index.schoolPolicy.delete.text": "Si borra este archivo, se utilizará automáticamente la Política de Privacidad por defecto.", + "pages.administration.school.index.schoolPolicy.delete.success": "El archivo de Política de Privacidad se ha eliminado correctamente.", "pages.administration.school.index.schoolPolicy.success": "El nuevo archivo se ha cargado correctamente.", "pages.administration.school.index.schoolPolicy.replace": "Sustituir", "pages.administration.school.index.schoolPolicy.cancel": "Cancelar", @@ -701,6 +705,9 @@ "pages.administration.school.index.termsOfUse.validation.fileTooBig": "El archivo pesa más de 4 MB. Por favor, reduzca el tamaño del archivo", "pages.administration.school.index.termsOfUse.validation.notPdf": "Este formato de archivo no es compatible. Utilice sólo PDF", "pages.administration.school.index.termsOfUse.error": "Se ha producido un error al cargar la Condiciones de Uso", + "pages.administration.school.index.termsOfUse.delete.title": "Borrar las Condiciones de Uso", + "pages.administration.school.index.termsOfUse.delete.text": "Si borra este archivo, se utilizarán automáticamente las Condiciones de Uso por defecto.", + "pages.administration.school.index.termsOfUse.delete.success": "El archivo de condiciones de uso se ha eliminado correctamente.", "pages.administration.school.index.termsOfUse.success": "El nuevo archivo se ha cargado correctamente.", "pages.administration.school.index.termsOfUse.replace": "Sustituir", "pages.administration.school.index.termsOfUse.cancel": "Cancelar", diff --git a/src/locales/uk.json b/src/locales/uk.json index a50c7184b4..a7df82485c 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -15,6 +15,7 @@ "common.actions.ok": "ОК", "common.action.publish": "Опублікувати", "common.actions.remove": "Вилучити", + "common.actions.delete": "Видалити", "common.actions.save": "Зберегти", "common.actions.share": "Поділіться", "common.actions.shareCourse": "Копія котирування акцій", @@ -674,6 +675,9 @@ "pages.administration.school.index.schoolPolicy.validation.fileTooBig": "Розмір файлу перевищує 4 МБ. Будь ласка, зменшіть розмір файлу", "pages.administration.school.index.schoolPolicy.validation.notPdf": "Цей формат файлу не підтримується. Будь ласка, використовуйте тільки PDF", "pages.administration.school.index.schoolPolicy.error": "Виникла помилка під час завантаження політики конфіденційності", + "pages.administration.school.index.schoolPolicy.delete.title": "Видалити політику конфіденційності", + "pages.administration.school.index.schoolPolicy.delete.text": "Якщо ви видалите цей файл, буде автоматично застосована Політика конфіденційності за замовчуванням.", + "pages.administration.school.index.schoolPolicy.delete.success": "Файл Політики конфіденційності успішно видалено.", "pages.administration.school.index.schoolPolicy.success": "Новий файл успішно завантажено.", "pages.administration.school.index.schoolPolicy.replace": "Замінити", "pages.administration.school.index.schoolPolicy.cancel": "Скасувати", @@ -688,6 +692,9 @@ "pages.administration.school.index.termsOfUse.validation.fileTooBig": "Розмір файлу перевищує 4 МБ. Будь ласка, зменшіть розмір файлу", "pages.administration.school.index.termsOfUse.validation.notPdf": "Цей формат файлу не підтримується. Будь ласка, використовуйте тільки PDF", "pages.administration.school.index.termsOfUse.error": "Виникла помилка під час завантаження Умови використання", + "pages.administration.school.index.termsOfUse.delete.title": "Видалити Умови використання", + "pages.administration.school.index.termsOfUse.delete.text": "Якщо ви видалите цей файл, будуть автоматично застосовані Умови використання за замовчуванням.", + "pages.administration.school.index.termsOfUse.delete.success": "Файл Умов використання успішно видалено.", "pages.administration.school.index.termsOfUse.success": "Новий файл успішно завантажено.", "pages.administration.school.index.termsOfUse.replace": "Замінити", "pages.administration.school.index.termsOfUse.cancel": "Скасувати", From 87f31a5862acc233eea288cce01fb83463aee9f6 Mon Sep 17 00:00:00 2001 From: davwas Date: Mon, 9 Oct 2023 09:40:05 +0200 Subject: [PATCH 04/16] add optional icon prop to vCustomDialog --- src/components/organisms/vCustomDialog.vue | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/organisms/vCustomDialog.vue b/src/components/organisms/vCustomDialog.vue index 085153130f..5a95416923 100644 --- a/src/components/organisms/vCustomDialog.vue +++ b/src/components/organisms/vCustomDialog.vue @@ -54,7 +54,11 @@ depressed :disabled="confirmBtnDisabled" @click="confirmDialog" - >{{ $t(confirmBtnTitleKey) }} + > + + {{ confirmBtnIcon }} + + {{ $t(confirmBtnTitleKey) }} Date: Mon, 9 Oct 2023 09:42:48 +0200 Subject: [PATCH 05/16] add views and actions to remove terms of use and privacy policy --- .../organisms/administration/SchoolPolicy.vue | 63 ++++++++++++++----- .../administration/SchoolPolicyFormDialog.vue | 2 +- .../organisms/administration/SchoolTerms.vue | 63 +++++++++++++------ .../administration/SchoolTermsFormDialog.vue | 2 +- 4 files changed, 92 insertions(+), 38 deletions(-) diff --git a/src/components/organisms/administration/SchoolPolicy.vue b/src/components/organisms/administration/SchoolPolicy.vue index d54e0c35e7..d7cd0a2ffa 100644 --- a/src/components/organisms/administration/SchoolPolicy.vue +++ b/src/components/organisms/administration/SchoolPolicy.vue @@ -22,7 +22,7 @@ data-testid="progress-bar" /> - + $file_pdf_outline @@ -34,7 +34,7 @@ {{ t("pages.administration.school.index.schoolPolicy.uploadedOn", { date: dayjs(privacyPolicy.publishedAt).format( - t("format.dateTime") + t("format.date") ), }) }} @@ -50,7 +50,6 @@ @@ -60,22 +59,21 @@ t('pages.administration.school.index.schoolPolicy.edit') " > - $mdiPencilOutline + $mdiTrayArrowUp - $mdiTrayArrowDown + $mdiTrashCanOutline @@ -85,6 +83,28 @@ @close="closeDialog" data-testid="form-dialog" /> + +

+ {{ t("pages.administration.school.index.schoolPolicy.delete.title") }} +

+ +
@@ -102,11 +122,14 @@ import { PRIVACY_POLICY_MODULE_KEY, injectStrict, SCHOOLS_MODULE_KEY, + NOTIFIER_MODULE_KEY, } from "@/utils/inject"; +import vCustomDialog from "@/components/organisms/vCustomDialog.vue"; export default defineComponent({ name: "SchoolPolicy", components: { + vCustomDialog, SchoolPolicyFormDialog, }, setup() { @@ -114,8 +137,10 @@ export default defineComponent({ const authModule = injectStrict(AUTH_MODULE_KEY); const privacyPolicyModule = injectStrict(PRIVACY_POLICY_MODULE_KEY); const schoolsModule = injectStrict(SCHOOLS_MODULE_KEY); + const notifierModule = injectStrict(NOTIFIER_MODULE_KEY); const isSchoolPolicyFormDialogOpen: Ref = ref(false); + const isDeletePolicyDialogOpen: Ref = ref(false); const school: ComputedRef = computed(() => schoolsModule.getSchool); watch( @@ -139,13 +164,16 @@ export default defineComponent({ () => privacyPolicyModule.getBusinessError ); - const downloadFile = () => { - const link = document.createElement("a"); - link.href = privacyPolicy.value?.consentData.data as string; - link.download = t( - "pages.administration.school.index.schoolPolicy.fileName" - ); - link.click(); + const deleteFile = async () => { + await privacyPolicyModule.deletePrivacyPolicy(); + + notifierModule.show({ + text: t( + "pages.administration.school.index.schoolPolicy.delete.success" + ), + status: "success", + timeout: 10000, + }); }; const closeDialog = () => { @@ -155,11 +183,12 @@ export default defineComponent({ return { t, isSchoolPolicyFormDialogOpen, + isDeletePolicyDialogOpen, hasSchoolEditPermission, privacyPolicy, status, error, - downloadFile, + deleteFile, dayjs, closeDialog, }; diff --git a/src/components/organisms/administration/SchoolPolicyFormDialog.vue b/src/components/organisms/administration/SchoolPolicyFormDialog.vue index 71bc4acab1..da7636249d 100644 --- a/src/components/organisms/administration/SchoolPolicyFormDialog.vue +++ b/src/components/organisms/administration/SchoolPolicyFormDialog.vue @@ -1,5 +1,5 @@ @@ -98,11 +116,14 @@ import { AUTH_MODULE_KEY, TERMS_OF_USE_MODULE_KEY, SCHOOLS_MODULE_KEY, + NOTIFIER_MODULE_KEY, } from "@/utils/inject"; +import vCustomDialog from "@/components/organisms/vCustomDialog.vue"; export default defineComponent({ name: "SchoolTerms", components: { + vCustomDialog, SchoolTermsFormDialog, }, setup() { @@ -110,8 +131,10 @@ export default defineComponent({ const authModule = injectStrict(AUTH_MODULE_KEY); const termsOfUseModule = injectStrict(TERMS_OF_USE_MODULE_KEY); const schoolsModule = injectStrict(SCHOOLS_MODULE_KEY); + const notifierModule = injectStrict(NOTIFIER_MODULE_KEY); const isSchoolTermsFormDialogOpen: Ref = ref(false); + const isDeleteTermsDialogOpen: Ref = ref(false); const school: ComputedRef = computed(() => schoolsModule.getSchool); watch( @@ -135,13 +158,14 @@ export default defineComponent({ () => termsOfUseModule.getBusinessError ); - const downloadFile = () => { - const link = document.createElement("a"); - link.href = termsOfUse.value?.consentData.data as string; - link.download = t( - "pages.administration.school.index.termsOfUse.fileName" - ); - link.click(); + const deleteFile = async () => { + await termsOfUseModule.deleteTermsOfUse(); + + notifierModule.show({ + text: t("pages.administration.school.index.termsOfUse.delete.success"), + status: "success", + timeout: 10000, + }); }; const closeDialog = () => { @@ -151,11 +175,12 @@ export default defineComponent({ return { t, isSchoolTermsFormDialogOpen, + isDeleteTermsDialogOpen, hasSchoolEditPermission, termsOfUse, status, error, - downloadFile, + deleteFile, dayjs, closeDialog, }; diff --git a/src/components/organisms/administration/SchoolTermsFormDialog.vue b/src/components/organisms/administration/SchoolTermsFormDialog.vue index eac46ceec6..b9e17c3f83 100644 --- a/src/components/organisms/administration/SchoolTermsFormDialog.vue +++ b/src/components/organisms/administration/SchoolTermsFormDialog.vue @@ -1,5 +1,5 @@ @@ -56,7 +56,7 @@ Date: Wed, 11 Oct 2023 14:14:52 +0200 Subject: [PATCH 11/16] fix custom dialog usage --- .../administration/SchoolPolicyFormDialog.vue | 43 ++++++------------- .../administration/SchoolTermsFormDialog.vue | 43 ++++++------------- src/components/organisms/vCustomDialog.vue | 2 +- 3 files changed, 27 insertions(+), 61 deletions(-) diff --git a/src/components/organisms/administration/SchoolPolicyFormDialog.vue b/src/components/organisms/administration/SchoolPolicyFormDialog.vue index da7636249d..37a83e4a2b 100644 --- a/src/components/organisms/administration/SchoolPolicyFormDialog.vue +++ b/src/components/organisms/administration/SchoolPolicyFormDialog.vue @@ -1,12 +1,21 @@