From c39373e974ed16ae9c21d2a2ae01afb91b1a1be2 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Thu, 15 Aug 2024 17:04:02 +0200 Subject: [PATCH 01/15] N21-2119 show external role in migration assistant match dialog --- .../molecules/vImportUsersMatchSearch.vue | 51 ++++++++++++++++++- src/locales/de.ts | 8 +++ src/locales/en.ts | 8 +++ src/locales/es.ts | 8 +++ src/locales/uk.ts | 8 +++ src/store/env-config-defaults.ts | 2 +- 6 files changed, 83 insertions(+), 2 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.vue b/src/components/molecules/vImportUsersMatchSearch.vue index 94a8656d39..0bd7248b28 100644 --- a/src/components/molecules/vImportUsersMatchSearch.vue +++ b/src/components/molecules/vImportUsersMatchSearch.vue @@ -43,7 +43,9 @@ {{ `${editedItem.firstName} ${editedItem.lastName}` }} - {{ mapRoleNames(editedItem.roleNames) }} + {{ + `${mapRoleNames(editedItem.roleNames)} ${externalRoleLabel}` + }} { return props.editedItem.match && selectedItem.value === null; }); +const externalRoleLabel = computed(() => { + if ( + props.editedItem.externalRoleNames && + props.editedItem.externalRoleNames.length + ) { + return `(${props.ldapSource}: ${mapExternalRoleNames(props.editedItem.externalRoleNames)})`; + } + return ""; +}); + const getDataFromApi = async (append = false) => { loading.value = true; @@ -417,6 +430,42 @@ const mapRoleNames = (roleNames: unknown[]) => { .join(", "); }; +const mapExternalRoleNames = (externalRoleNames: string[]) => { + return externalRoleNames + .map((role) => { + switch (props.ldapSource) { + case "moin.schule": + return mapSchulconnexExternalRoleNames(role); + default: + return role; + } + }) + .join(", "); +}; + +const mapSchulconnexExternalRoleNames = (externalRoleName: string) => { + switch (externalRoleName) { + case "Lehr": + return t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher" + ); + case "Lern": + return t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student" + ); + case "Leit": + return t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager" + ); + case "OrgAdmin": + return t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin" + ); + default: + return externalRoleName; + } +}; + onMounted(async () => { flagged.value = props.editedItem.flagged; diff --git a/src/locales/de.ts b/src/locales/de.ts index 1b234023bf..93d35544fe 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -601,6 +601,14 @@ export default { "Keiner. Benutzer wird neu erstellt.", "components.molecules.importUsersMatch.write": "Vornamen oder Nachnamen eingeben", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": + "Lehrende/r", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": + "Lernende/r", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin": + "Organisationsadministrator", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager": + "Organisationsleitung", "components.molecules.MintEcFooter.chapters": "Kapitelübersicht", "components.molecules.share.columnBoard.options.infoText": "Mit dem folgenden Link kann der Bereich als Kopie von anderen Lehrkräften importiert werden. Personenbezogene Daten werden dabei nicht importiert.", diff --git a/src/locales/en.ts b/src/locales/en.ts index 6f8b9bae9c..a36c776299 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -589,6 +589,14 @@ export default { "components.molecules.importUsersMatch.unMatched": "None. Account will be newly created.", "components.molecules.importUsersMatch.write": "Input first and last name", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": + "Teacher", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": + "Student", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin": + "Organizational Administrator", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager": + "Organizational Management", "components.molecules.MintEcFooter.chapters": "Chapter overview", "components.molecules.share.courses.mail.body": "Link to the course:", "components.molecules.share.courses.mail.subject": "Course you can import", diff --git a/src/locales/es.ts b/src/locales/es.ts index 12e22dd717..d74c8897a1 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -601,6 +601,14 @@ export default { "components.molecules.importUsersMatch.unMatched": "Ninguno. El usuario es recién creado.", "components.molecules.importUsersMatch.write": "Introduzca nombre o apellido", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": + "Profesor", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": + "Estudiante", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin": + "Administrador de organización", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager": + "Gestión organizativa", "components.molecules.MintEcFooter.chapters": "Resumen del capítulo", "components.molecules.share.columnBoard.options.infoText": "Con el siguiente enlace, el tablero puede ser importado como copia por otros profesores. Los datos personales no se importarán.", diff --git a/src/locales/uk.ts b/src/locales/uk.ts index 585a932f39..046ce3422e 100644 --- a/src/locales/uk.ts +++ b/src/locales/uk.ts @@ -598,6 +598,14 @@ export default { "components.molecules.importUsersMatch.unMatched": "немає. Обліковий запис буде створено знову.", "components.molecules.importUsersMatch.write": "Введіть ім'я та прізвище", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": + "Учитель", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": + "Студент", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin": + "Організаційний адміністратор", + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager": + "Організаційний менеджмент", "components.molecules.MintEcFooter.chapters": "Огляд розділу", "components.molecules.share.columnBoard.options.infoText": "За наступним посиланням завдання можуть імпортувати як копію інші вчителі. Особисті дані не будуть імпортовані.", diff --git a/src/store/env-config-defaults.ts b/src/store/env-config-defaults.ts index cd5d655e24..a7de7c8ed5 100644 --- a/src/store/env-config-defaults.ts +++ b/src/store/env-config-defaults.ts @@ -60,7 +60,7 @@ export const defaultConfigEnvs: ConfigResponse = { FEATURE_LOGIN_LINK_ENABLED: false, FEATURE_LESSON_SHARE: false, FEATURE_TASK_SHARE: false, - FEATURE_USER_MIGRATION_ENABLED: false, + FEATURE_USER_MIGRATION_ENABLED: true, FEATURE_COPY_SERVICE_ENABLED: false, FEATURE_COMMON_CARTRIDGE_COURSE_EXPORT_ENABLED: false, FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_ENABLED: false, From 8b4058bee352e5dd3894ca9769628d05e7fb44ac Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Thu, 15 Aug 2024 17:09:17 +0200 Subject: [PATCH 02/15] N21-2119 update api.ts --- src/serverApi/v3/api.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts index 772f298bac..b472c8b26b 100644 --- a/src/serverApi/v3/api.ts +++ b/src/serverApi/v3/api.ts @@ -3352,6 +3352,12 @@ export interface ImportUserResponse { * @memberof ImportUserResponse */ flagged: boolean; + /** + * exact user roles from the external system + * @type {Array} + * @memberof ImportUserResponse + */ + externalRoleNames: Array; } /** From 94a4f3506246724db95a60d10ef879c96c60c436 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Thu, 15 Aug 2024 17:45:36 +0200 Subject: [PATCH 03/15] N21-2119 wip fix tests --- src/components/molecules/vImportUsersMatchSearch.unit.ts | 5 ++++- src/store/import-users.unit.ts | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.unit.ts b/src/components/molecules/vImportUsersMatchSearch.unit.ts index 5fc85e8dd4..b45ae4877d 100644 --- a/src/components/molecules/vImportUsersMatchSearch.unit.ts +++ b/src/components/molecules/vImportUsersMatchSearch.unit.ts @@ -17,6 +17,7 @@ import { } from "vuetify/lib/components/index.mjs"; import vImportUsersMatchSearch from "./vImportUsersMatchSearch.vue"; +// TODO: moin.schule test case const testProps = { editedItem: { flagged: false, @@ -26,6 +27,7 @@ const testProps = { lastName: "Mustermann", roleNames: ["student"], classNames: ["6a"], + externalRoleNames: ["student-a"], }, isDialog: true, ldapSource: "LDAP", @@ -63,6 +65,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("common.roleName.student"); expect(editedItemElement).toContain("max_mus"); expect(editedItemElement).toContain("6a"); + expect(editedItemElement).toContain("(LDAP: student-a)"); }); it("should set 'flagged' property true when flag-button clicked", async () => { @@ -192,7 +195,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(deleteMatchButton.props("disabled")).toBe(true); }); - it("should disable save button when no no item was selected", () => { + it("should disable save button when no item was selected", () => { const wrapper = getWrapper(testProps); const saveMatchButton = wrapper diff --git a/src/store/import-users.unit.ts b/src/store/import-users.unit.ts index 02fd31ebaf..266465f918 100644 --- a/src/store/import-users.unit.ts +++ b/src/store/import-users.unit.ts @@ -573,6 +573,7 @@ describe("import-users store actions", () => { importUserId: "abc", loginName: "asdf.asdf", roleNames: [], + externalRoleNames: [], }, { firstName: "qwer", @@ -582,6 +583,7 @@ describe("import-users store actions", () => { importUserId: "qwer", loginName: "qwer.qwer", roleNames: [], + externalRoleNames: [], }, ], }); @@ -750,6 +752,7 @@ describe("import-users store actions", () => { importUserId: "extern.1234", loginName: "samuel.vimes", roleNames: [ImportUserResponseRoleNamesEnum.Teacher], + externalRoleNames: ["teacher"], match: { firstName: "Samuel", lastName: "Vimes", @@ -767,6 +770,7 @@ describe("import-users store actions", () => { importUserId: "extern.5678", loginName: "samuel.vimes", roleNames: [ImportUserResponseRoleNamesEnum.Teacher], + externalRoleNames: ["teacher"], match: { firstName: "Samuel", lastName: "Vimes", From 2ac3b9ba736ca048063918cb3a7182668892b5d3 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Fri, 16 Aug 2024 13:59:07 +0200 Subject: [PATCH 04/15] N21-2119 adapted external role text --- .../molecules/vImportUsersMatchSearch.vue | 14 +++++++++----- src/locales/de.ts | 2 ++ src/locales/en.ts | 2 ++ src/locales/es.ts | 2 ++ src/locales/uk.ts | 2 ++ 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.vue b/src/components/molecules/vImportUsersMatchSearch.vue index 0bd7248b28..4fce5f7df5 100644 --- a/src/components/molecules/vImportUsersMatchSearch.vue +++ b/src/components/molecules/vImportUsersMatchSearch.vue @@ -43,9 +43,8 @@ {{ `${editedItem.firstName} ${editedItem.lastName}` }} - {{ - `${mapRoleNames(editedItem.roleNames)} ${externalRoleLabel}` - }} + {{ mapRoleNames(editedItem.roleNames) }} + {{ externalRoleText }} { return props.editedItem.match && selectedItem.value === null; }); -const externalRoleLabel = computed(() => { +const externalRoleText = computed(() => { if ( props.editedItem.externalRoleNames && props.editedItem.externalRoleNames.length ) { - return `(${props.ldapSource}: ${mapExternalRoleNames(props.editedItem.externalRoleNames)})`; + return `(${t( + "components.molecules.importUsersMatch.externalRoleName.label", + { + source: props.ldapSource, + } + )}: ${mapExternalRoleNames(props.editedItem.externalRoleNames)})`; } return ""; }); diff --git a/src/locales/de.ts b/src/locales/de.ts index 93d35544fe..92dcb288ea 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -601,6 +601,8 @@ export default { "Keiner. Benutzer wird neu erstellt.", "components.molecules.importUsersMatch.write": "Vornamen oder Nachnamen eingeben", + "components.molecules.importUsersMatch.externalRoleName.label": + "{source} Rolle", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Lehrende/r", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": diff --git a/src/locales/en.ts b/src/locales/en.ts index a36c776299..45820d326d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -589,6 +589,8 @@ export default { "components.molecules.importUsersMatch.unMatched": "None. Account will be newly created.", "components.molecules.importUsersMatch.write": "Input first and last name", + "components.molecules.importUsersMatch.externalRoleName.label": + "{source} role", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Teacher", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": diff --git a/src/locales/es.ts b/src/locales/es.ts index d74c8897a1..4cb140b2f5 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -601,6 +601,8 @@ export default { "components.molecules.importUsersMatch.unMatched": "Ninguno. El usuario es recién creado.", "components.molecules.importUsersMatch.write": "Introduzca nombre o apellido", + "components.molecules.importUsersMatch.externalRoleName.label": + "{source} papel", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Profesor", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": diff --git a/src/locales/uk.ts b/src/locales/uk.ts index 046ce3422e..02bbf6344e 100644 --- a/src/locales/uk.ts +++ b/src/locales/uk.ts @@ -598,6 +598,8 @@ export default { "components.molecules.importUsersMatch.unMatched": "немає. Обліковий запис буде створено знову.", "components.molecules.importUsersMatch.write": "Введіть ім'я та прізвище", + "components.molecules.importUsersMatch.externalRoleName.label": + "{source} роль", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Учитель", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": From 3e67ad5d8c5aeb5cd433b8eed2f47cb478fa5fd0 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Fri, 16 Aug 2024 15:34:47 +0200 Subject: [PATCH 05/15] N21-2119 new tests & fixed failing test --- .../molecules/vImportUsersMatchSearch.unit.ts | 95 +++++++++++++++++-- .../administration/ImportUsers.unit.ts | 3 + 2 files changed, 90 insertions(+), 8 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.unit.ts b/src/components/molecules/vImportUsersMatchSearch.unit.ts index b45ae4877d..18409e7a9b 100644 --- a/src/components/molecules/vImportUsersMatchSearch.unit.ts +++ b/src/components/molecules/vImportUsersMatchSearch.unit.ts @@ -1,5 +1,6 @@ import { importUsersModule } from "@/store"; import ImportUsersModule from "@/store/import-users"; +import { ImportUserResponseRoleNamesEnum } from "@/serverApi/v3"; import { THEME_KEY } from "@/utils/inject"; import { createTestingI18n, @@ -17,7 +18,6 @@ import { } from "vuetify/lib/components/index.mjs"; import vImportUsersMatchSearch from "./vImportUsersMatchSearch.vue"; -// TODO: moin.schule test case const testProps = { editedItem: { flagged: false, @@ -25,9 +25,9 @@ const testProps = { loginName: "max_mus", firstName: "Max", lastName: "Mustermann", - roleNames: ["student"], + roleNames: [ImportUserResponseRoleNamesEnum.Student], classNames: ["6a"], - externalRoleNames: ["student-a"], + externalRoleNames: ["student-ext"], }, isDialog: true, ldapSource: "LDAP", @@ -65,7 +65,9 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("common.roleName.student"); expect(editedItemElement).toContain("max_mus"); expect(editedItemElement).toContain("6a"); - expect(editedItemElement).toContain("(LDAP: student-a)"); + expect(editedItemElement).toContain( + "(components.molecules.importUsersMatch.externalRoleName.label: student-ext)" + ); }); it("should set 'flagged' property true when flag-button clicked", async () => { @@ -96,7 +98,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { loginName: "lehrer@schul-cloud.org", firstName: "Cord", lastName: "Carl", - roleNames: ["teacher"], + roleNames: [ImportUserResponseRoleNamesEnum.Teacher], text: "Cord Carl", }; const wrapper = getWrapper(testProps); @@ -118,7 +120,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { loginName: "lehrer@schul-cloud.org", firstName: "Cord", lastName: "Carl", - roleNames: ["teacher"], + roleNames: [ImportUserResponseRoleNamesEnum.Teacher], text: "Cord Carl", }; @@ -153,7 +155,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { loginName: "max_mus", firstName: "Max", lastName: "Mustermann", - roleNames: ["student"], + roleNames: [ImportUserResponseRoleNamesEnum.Student], classNames: ["6a"], }; const match = { @@ -161,7 +163,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { loginName: "admin@schul-cloud.org", firstName: "Thorsten", lastName: "Test", - roleNames: ["admin"], + roleNames: [ImportUserResponseRoleNamesEnum.Admin], matchedBy: "admin", }; const wrapper = getWrapper({ @@ -216,4 +218,81 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemUsername.exists()).toBe(false); }); + + describe("when the source is from moin.schule", () => { + const setup = () => { + const adminTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Student], + classNames: ["6a"], + externalRoleNames: ["Lern"], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + adminTestProps, + }; + }; + + it("should correctly show the external role of the user", () => { + const { adminTestProps } = setup(); + const wrapper = getWrapper(adminTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.student"); + expect(editedItemElement).toContain( + "(components.molecules.importUsersMatch.externalRoleName.label: " + + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student)" + ); + }); + }); + + describe("when externalRoleNames prop is empty", () => { + const setup = () => { + const setupTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Student], + classNames: ["6a"], + externalRoleNames: [], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + setupTestProps, + }; + }; + + it("should not show the external role label", () => { + const { setupTestProps } = setup(); + const wrapper = getWrapper(setupTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.student"); + expect(editedItemElement).not.toContain( + "components.molecules.importUsersMatch.externalRoleName.label" + ); + }); + }); }); diff --git a/src/components/organisms/administration/ImportUsers.unit.ts b/src/components/organisms/administration/ImportUsers.unit.ts index 87d49d93b9..be5a7cb13e 100644 --- a/src/components/organisms/administration/ImportUsers.unit.ts +++ b/src/components/organisms/administration/ImportUsers.unit.ts @@ -31,6 +31,7 @@ const mockImportUsers: ImportUserListResponse = { lastName: "Bruns", roleNames: [ImportUserResponseRoleNamesEnum.Student], classNames: ["6a"], + externalRoleNames: [], }, { flagged: false, @@ -40,6 +41,7 @@ const mockImportUsers: ImportUserListResponse = { lastName: "Cordes", roleNames: [ImportUserResponseRoleNamesEnum.Teacher], classNames: [], + externalRoleNames: [], }, { flagged: false, @@ -52,6 +54,7 @@ const mockImportUsers: ImportUserListResponse = { ImportUserResponseRoleNamesEnum.Teacher, ], classNames: ["1c"], + externalRoleNames: [], }, ], }; From 00317f0b0e9d536eb449f19ed159025b2c3eb26e Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Fri, 16 Aug 2024 16:06:34 +0200 Subject: [PATCH 06/15] N21-2119 added more tests --- .../molecules/vImportUsersMatchSearch.unit.ts | 176 +++++++++++++++--- 1 file changed, 146 insertions(+), 30 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.unit.ts b/src/components/molecules/vImportUsersMatchSearch.unit.ts index 18409e7a9b..4a702cb5cb 100644 --- a/src/components/molecules/vImportUsersMatchSearch.unit.ts +++ b/src/components/molecules/vImportUsersMatchSearch.unit.ts @@ -220,41 +220,157 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }); describe("when the source is from moin.schule", () => { - const setup = () => { - const adminTestProps = { - editedItem: { - flagged: false, - importUserId: "123", - loginName: "max_mus", - firstName: "Max", - lastName: "Mustermann", - roleNames: [ImportUserResponseRoleNamesEnum.Student], - classNames: ["6a"], - externalRoleNames: ["Lern"], - }, - isDialog: true, - ldapSource: "moin.schule", + describe("when the external role is 'Lern' (Student)", () => { + const setup = () => { + const adminTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Student], + classNames: ["6a"], + externalRoleNames: ["Lern"], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + adminTestProps, + }; }; - return { - adminTestProps, + + it("should correctly show the external role of the user", () => { + const { adminTestProps } = setup(); + const wrapper = getWrapper(adminTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.student"); + expect(editedItemElement).toContain( + "(components.molecules.importUsersMatch.externalRoleName.label: " + + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student)" + ); + }); + }); + describe("when the external role is 'Lehr' (Teacher)", () => { + const setup = () => { + const adminTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Teacher], + classNames: ["6a"], + externalRoleNames: ["Lehr"], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + adminTestProps, + }; }; - }; - it("should correctly show the external role of the user", () => { - const { adminTestProps } = setup(); - const wrapper = getWrapper(adminTestProps); + it("should correctly show the external role of the user", () => { + const { adminTestProps } = setup(); + const wrapper = getWrapper(adminTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.teacher"); + expect(editedItemElement).toContain( + "(components.molecules.importUsersMatch.externalRoleName.label: " + + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher)" + ); + }); + }); + describe("when the external role is 'Leit' (Management)", () => { + const setup = () => { + const adminTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Admin], + classNames: ["6a"], + externalRoleNames: ["Leit"], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + adminTestProps, + }; + }; - const editedItemElement = wrapper - .find("[data-testid=edited-item]") - .html(); + it("should correctly show the external role of the user", () => { + const { adminTestProps } = setup(); + const wrapper = getWrapper(adminTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.administrator"); + expect(editedItemElement).toContain( + "(components.molecules.importUsersMatch.externalRoleName.label: " + + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager)" + ); + }); + }); + describe("when the external role is 'OrgAdmin' (Admin)", () => { + const setup = () => { + const adminTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Admin], + classNames: ["6a"], + externalRoleNames: ["OrgAdmin"], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + adminTestProps, + }; + }; - expect(editedItemElement).toContain("Max"); - expect(editedItemElement).toContain("Mustermann"); - expect(editedItemElement).toContain("common.roleName.student"); - expect(editedItemElement).toContain( - "(components.molecules.importUsersMatch.externalRoleName.label: " + - "components.molecules.importUsersMatch.externalRoleName.schulconnex.student)" - ); + it("should correctly show the external role of the user", () => { + const { adminTestProps } = setup(); + const wrapper = getWrapper(adminTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.administrator"); + expect(editedItemElement).toContain( + "(components.molecules.importUsersMatch.externalRoleName.label: " + + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin)" + ); + }); }); }); From b6b67168adf409869be9313811e1da72496bcdba Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Fri, 16 Aug 2024 16:42:27 +0200 Subject: [PATCH 07/15] N21-2119 changed switch-case -> if --- src/components/molecules/vImportUsersMatchSearch.vue | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.vue b/src/components/molecules/vImportUsersMatchSearch.vue index 4fce5f7df5..ffd6fbd2dd 100644 --- a/src/components/molecules/vImportUsersMatchSearch.vue +++ b/src/components/molecules/vImportUsersMatchSearch.vue @@ -437,12 +437,10 @@ const mapRoleNames = (roleNames: unknown[]) => { const mapExternalRoleNames = (externalRoleNames: string[]) => { return externalRoleNames .map((role) => { - switch (props.ldapSource) { - case "moin.schule": - return mapSchulconnexExternalRoleNames(role); - default: - return role; + if (props.ldapSource === "moin.schule") { + return mapSchulconnexExternalRoleNames(role); } + return role; }) .join(", "); }; From 3e06c6f0fb1848ce9addef6cbfbca4867af1a4eb Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Fri, 16 Aug 2024 16:51:30 +0200 Subject: [PATCH 08/15] N21-2119 revert accidental changes --- src/store/env-config-defaults.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/env-config-defaults.ts b/src/store/env-config-defaults.ts index a7de7c8ed5..cd5d655e24 100644 --- a/src/store/env-config-defaults.ts +++ b/src/store/env-config-defaults.ts @@ -60,7 +60,7 @@ export const defaultConfigEnvs: ConfigResponse = { FEATURE_LOGIN_LINK_ENABLED: false, FEATURE_LESSON_SHARE: false, FEATURE_TASK_SHARE: false, - FEATURE_USER_MIGRATION_ENABLED: true, + FEATURE_USER_MIGRATION_ENABLED: false, FEATURE_COPY_SERVICE_ENABLED: false, FEATURE_COMMON_CARTRIDGE_COURSE_EXPORT_ENABLED: false, FEATURE_COMMON_CARTRIDGE_COURSE_IMPORT_ENABLED: false, From 5c31ae6bfa58e17f6790fc61f528e0445c72e5d4 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Mon, 19 Aug 2024 10:10:48 +0200 Subject: [PATCH 09/15] N21-2119 n/a for when there is no external roles --- .../molecules/vImportUsersMatchSearch.unit.ts | 105 ++++++++++++------ .../molecules/vImportUsersMatchSearch.vue | 16 +-- src/locales/de.ts | 4 +- src/locales/en.ts | 4 +- src/locales/es.ts | 4 +- src/locales/uk.ts | 4 +- 6 files changed, 88 insertions(+), 49 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.unit.ts b/src/components/molecules/vImportUsersMatchSearch.unit.ts index 4a702cb5cb..7fcfb6be17 100644 --- a/src/components/molecules/vImportUsersMatchSearch.unit.ts +++ b/src/components/molecules/vImportUsersMatchSearch.unit.ts @@ -27,7 +27,7 @@ const testProps = { lastName: "Mustermann", roleNames: [ImportUserResponseRoleNamesEnum.Student], classNames: ["6a"], - externalRoleNames: ["student-ext"], + externalRoleNames: [], }, isDialog: true, ldapSource: "LDAP", @@ -65,9 +65,6 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("common.roleName.student"); expect(editedItemElement).toContain("max_mus"); expect(editedItemElement).toContain("6a"); - expect(editedItemElement).toContain( - "(components.molecules.importUsersMatch.externalRoleName.label: student-ext)" - ); }); it("should set 'flagged' property true when flag-button clicked", async () => { @@ -219,6 +216,41 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemUsername.exists()).toBe(false); }); + describe("when the source is not from moin.schule", () => { + const setup = () => { + const setupTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Student], + classNames: ["6a"], + externalRoleNames: ["student-external"], + }, + isDialog: true, + ldapSource: "ldap-external", + }; + return { + setupTestProps, + }; + }; + + it("should not contain any text for external role", () => { + const { setupTestProps } = setup(); + const wrapper = getWrapper(setupTestProps); + + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); + + expect(editedItemElement).not.toContain( + "components.molecules.importUsersMatch.externalRoleName.label" + ); + }); + }); + describe("when the source is from moin.schule", () => { describe("when the external role is 'Lern' (Student)", () => { const setup = () => { @@ -372,43 +404,42 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { ); }); }); - }); - - describe("when externalRoleNames prop is empty", () => { - const setup = () => { - const setupTestProps = { - editedItem: { - flagged: false, - importUserId: "123", - loginName: "max_mus", - firstName: "Max", - lastName: "Mustermann", - roleNames: [ImportUserResponseRoleNamesEnum.Student], - classNames: ["6a"], - externalRoleNames: [], - }, - isDialog: true, - ldapSource: "moin.schule", - }; - return { - setupTestProps, + describe("when externalRoleNames prop is empty", () => { + const setup = () => { + const setupTestProps = { + editedItem: { + flagged: false, + importUserId: "123", + loginName: "max_mus", + firstName: "Max", + lastName: "Mustermann", + roleNames: [ImportUserResponseRoleNamesEnum.Student], + classNames: ["6a"], + externalRoleNames: [], + }, + isDialog: true, + ldapSource: "moin.schule", + }; + return { + setupTestProps, + }; }; - }; - it("should not show the external role label", () => { - const { setupTestProps } = setup(); - const wrapper = getWrapper(setupTestProps); + it("should show that the role is not available", () => { + const { setupTestProps } = setup(); + const wrapper = getWrapper(setupTestProps); - const editedItemElement = wrapper - .find("[data-testid=edited-item]") - .html(); + const editedItemElement = wrapper + .find("[data-testid=edited-item]") + .html(); - expect(editedItemElement).toContain("Max"); - expect(editedItemElement).toContain("Mustermann"); - expect(editedItemElement).toContain("common.roleName.student"); - expect(editedItemElement).not.toContain( - "components.molecules.importUsersMatch.externalRoleName.label" - ); + expect(editedItemElement).toContain("Max"); + expect(editedItemElement).toContain("Mustermann"); + expect(editedItemElement).toContain("common.roleName.student"); + expect(editedItemElement).toContain( + "components.molecules.importUsersMatch.externalRoleName.none" + ); + }); }); }); }); diff --git a/src/components/molecules/vImportUsersMatchSearch.vue b/src/components/molecules/vImportUsersMatchSearch.vue index ffd6fbd2dd..816a40f9fb 100644 --- a/src/components/molecules/vImportUsersMatchSearch.vue +++ b/src/components/molecules/vImportUsersMatchSearch.vue @@ -44,7 +44,9 @@ {{ mapRoleNames(editedItem.roleNames) }} - {{ externalRoleText }} + {{ + props.ldapSource === "moin.schule" ? externalRoleText : "" + }} { }); const externalRoleText = computed(() => { + let role = t("components.molecules.importUsersMatch.externalRoleName.none"); if ( props.editedItem.externalRoleNames && props.editedItem.externalRoleNames.length ) { - return `(${t( - "components.molecules.importUsersMatch.externalRoleName.label", - { - source: props.ldapSource, - } - )}: ${mapExternalRoleNames(props.editedItem.externalRoleNames)})`; + role = mapExternalRoleNames(props.editedItem.externalRoleNames); } - return ""; + + const text = `(${t("components.molecules.importUsersMatch.externalRoleName.label", { source: props.ldapSource })}: ${role})`; + return text; }); const getDataFromApi = async (append = false) => { diff --git a/src/locales/de.ts b/src/locales/de.ts index 92dcb288ea..29d1faaddd 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -602,7 +602,9 @@ export default { "components.molecules.importUsersMatch.write": "Vornamen oder Nachnamen eingeben", "components.molecules.importUsersMatch.externalRoleName.label": - "{source} Rolle", + "Rolle {source}", + "components.molecules.importUsersMatch.externalRoleName.none": + "Nicht verfügbar", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Lehrende/r", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": diff --git a/src/locales/en.ts b/src/locales/en.ts index 45820d326d..317ca7c59d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -590,7 +590,9 @@ export default { "None. Account will be newly created.", "components.molecules.importUsersMatch.write": "Input first and last name", "components.molecules.importUsersMatch.externalRoleName.label": - "{source} role", + "Role {source}", + "components.molecules.importUsersMatch.externalRoleName.none": + "Not available", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Teacher", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": diff --git a/src/locales/es.ts b/src/locales/es.ts index 4cb140b2f5..f4c5c93b6e 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -602,7 +602,9 @@ export default { "Ninguno. El usuario es recién creado.", "components.molecules.importUsersMatch.write": "Introduzca nombre o apellido", "components.molecules.importUsersMatch.externalRoleName.label": - "{source} papel", + "Papel {source}", + "components.molecules.importUsersMatch.externalRoleName.none": + "No disponible", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Profesor", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": diff --git a/src/locales/uk.ts b/src/locales/uk.ts index 02bbf6344e..c2df0b50fe 100644 --- a/src/locales/uk.ts +++ b/src/locales/uk.ts @@ -599,7 +599,9 @@ export default { "немає. Обліковий запис буде створено знову.", "components.molecules.importUsersMatch.write": "Введіть ім'я та прізвище", "components.molecules.importUsersMatch.externalRoleName.label": - "{source} роль", + "роль {source}", + "components.molecules.importUsersMatch.externalRoleName.none": + "Немає в наявності", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": "Учитель", "components.molecules.importUsersMatch.externalRoleName.schulconnex.student": From 070ebe2e416e2b86bbc6bc021303d1294c8f7980 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Mon, 19 Aug 2024 10:16:00 +0200 Subject: [PATCH 10/15] N21-2119 update api.ts --- src/serverApi/v3/api.ts | 112 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts index b472c8b26b..e74d39d296 100644 --- a/src/serverApi/v3/api.ts +++ b/src/serverApi/v3/api.ts @@ -1735,6 +1735,37 @@ export interface CountyResponse { */ antaresKey: string; } +/** + * + * @export + * @interface CourseCommonCartridgeMetadataResponse + */ +export interface CourseCommonCartridgeMetadataResponse { + /** + * The id of the course + * @type {string} + * @memberof CourseCommonCartridgeMetadataResponse + */ + id: string; + /** + * Title of the course + * @type {string} + * @memberof CourseCommonCartridgeMetadataResponse + */ + title: string; + /** + * Creation date of the course + * @type {string} + * @memberof CourseCommonCartridgeMetadataResponse + */ + creationDate: string; + /** + * Copy right owners of the course + * @type {Array} + * @memberof CourseCommonCartridgeMetadataResponse + */ + copyRightOwners: Array; +} /** * * @export @@ -13008,6 +13039,44 @@ export const CoursesApiAxiosParamCreator = function (configuration?: Configurati + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + courseControllerGetCourseById: async (courseId: string, options: any = {}): Promise => { + // verify required parameter 'courseId' is not null or undefined + assertParamExists('courseControllerGetCourseById', 'courseId', courseId) + const localVarPath = `/courses/{courseId}` + .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -13171,6 +13240,17 @@ export const CoursesApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerFindForUser(skip, limit, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async courseControllerGetCourseById(courseId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerGetCourseById(courseId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary Get permissions for a user in a course. @@ -13235,6 +13315,16 @@ export const CoursesApiFactory = function (configuration?: Configuration, basePa courseControllerFindForUser(skip?: number, limit?: number, options?: any): AxiosPromise { return localVarFp.courseControllerFindForUser(skip, limit, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + courseControllerGetCourseById(courseId: string, options?: any): AxiosPromise { + return localVarFp.courseControllerGetCourseById(courseId, options).then((request) => request(axios, basePath)); + }, /** * * @summary Get permissions for a user in a course. @@ -13295,6 +13385,16 @@ export interface CoursesApiInterface { */ courseControllerFindForUser(skip?: number, limit?: number, options?: any): AxiosPromise; + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof CoursesApiInterface + */ + courseControllerGetCourseById(courseId: string, options?: any): AxiosPromise; + /** * * @summary Get permissions for a user in a course. @@ -13359,6 +13459,18 @@ export class CoursesApi extends BaseAPI implements CoursesApiInterface { return CoursesApiFp(this.configuration).courseControllerFindForUser(skip, limit, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get common cartridge metadata of a course by Id. + * @param {string} courseId The id of the course + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof CoursesApi + */ + public courseControllerGetCourseById(courseId: string, options?: any) { + return CoursesApiFp(this.configuration).courseControllerGetCourseById(courseId, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Get permissions for a user in a course. From 53d885021c8ebf7afbc6fb6b2fbfd90b1815ec70 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Tue, 20 Aug 2024 15:09:11 +0200 Subject: [PATCH 11/15] N21-2119 update tests & api.ts for optional external role --- .../administration/ImportUsers.unit.ts | 3 --- src/serverApi/v3/api.ts | 22 +++++++++---------- src/store/import-users.unit.ts | 4 ---- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/components/organisms/administration/ImportUsers.unit.ts b/src/components/organisms/administration/ImportUsers.unit.ts index be5a7cb13e..87d49d93b9 100644 --- a/src/components/organisms/administration/ImportUsers.unit.ts +++ b/src/components/organisms/administration/ImportUsers.unit.ts @@ -31,7 +31,6 @@ const mockImportUsers: ImportUserListResponse = { lastName: "Bruns", roleNames: [ImportUserResponseRoleNamesEnum.Student], classNames: ["6a"], - externalRoleNames: [], }, { flagged: false, @@ -41,7 +40,6 @@ const mockImportUsers: ImportUserListResponse = { lastName: "Cordes", roleNames: [ImportUserResponseRoleNamesEnum.Teacher], classNames: [], - externalRoleNames: [], }, { flagged: false, @@ -54,7 +52,6 @@ const mockImportUsers: ImportUserListResponse = { ImportUserResponseRoleNamesEnum.Teacher, ], classNames: ["1c"], - externalRoleNames: [], }, ], }; diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts index e74d39d296..e1ef1b70b6 100644 --- a/src/serverApi/v3/api.ts +++ b/src/serverApi/v3/api.ts @@ -3388,7 +3388,7 @@ export interface ImportUserResponse { * @type {Array} * @memberof ImportUserResponse */ - externalRoleNames: Array; + externalRoleNames?: Array; } /** @@ -13055,10 +13055,10 @@ export const CoursesApiAxiosParamCreator = function (configuration?: Configurati * @param {*} [options] Override http request option. * @throws {RequiredError} */ - courseControllerGetCourseById: async (courseId: string, options: any = {}): Promise => { + courseControllerGetCourseCcMetadataById: async (courseId: string, options: any = {}): Promise => { // verify required parameter 'courseId' is not null or undefined - assertParamExists('courseControllerGetCourseById', 'courseId', courseId) - const localVarPath = `/courses/{courseId}` + assertParamExists('courseControllerGetCourseCcMetadataById', 'courseId', courseId) + const localVarPath = `/courses/{courseId}/cc-metadata` .replace(`{${"courseId"}}`, encodeURIComponent(String(courseId))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -13247,8 +13247,8 @@ export const CoursesApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async courseControllerGetCourseById(courseId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerGetCourseById(courseId, options); + async courseControllerGetCourseCcMetadataById(courseId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.courseControllerGetCourseCcMetadataById(courseId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, /** @@ -13322,8 +13322,8 @@ export const CoursesApiFactory = function (configuration?: Configuration, basePa * @param {*} [options] Override http request option. * @throws {RequiredError} */ - courseControllerGetCourseById(courseId: string, options?: any): AxiosPromise { - return localVarFp.courseControllerGetCourseById(courseId, options).then((request) => request(axios, basePath)); + courseControllerGetCourseCcMetadataById(courseId: string, options?: any): AxiosPromise { + return localVarFp.courseControllerGetCourseCcMetadataById(courseId, options).then((request) => request(axios, basePath)); }, /** * @@ -13393,7 +13393,7 @@ export interface CoursesApiInterface { * @throws {RequiredError} * @memberof CoursesApiInterface */ - courseControllerGetCourseById(courseId: string, options?: any): AxiosPromise; + courseControllerGetCourseCcMetadataById(courseId: string, options?: any): AxiosPromise; /** * @@ -13467,8 +13467,8 @@ export class CoursesApi extends BaseAPI implements CoursesApiInterface { * @throws {RequiredError} * @memberof CoursesApi */ - public courseControllerGetCourseById(courseId: string, options?: any) { - return CoursesApiFp(this.configuration).courseControllerGetCourseById(courseId, options).then((request) => request(this.axios, this.basePath)); + public courseControllerGetCourseCcMetadataById(courseId: string, options?: any) { + return CoursesApiFp(this.configuration).courseControllerGetCourseCcMetadataById(courseId, options).then((request) => request(this.axios, this.basePath)); } /** diff --git a/src/store/import-users.unit.ts b/src/store/import-users.unit.ts index 266465f918..02fd31ebaf 100644 --- a/src/store/import-users.unit.ts +++ b/src/store/import-users.unit.ts @@ -573,7 +573,6 @@ describe("import-users store actions", () => { importUserId: "abc", loginName: "asdf.asdf", roleNames: [], - externalRoleNames: [], }, { firstName: "qwer", @@ -583,7 +582,6 @@ describe("import-users store actions", () => { importUserId: "qwer", loginName: "qwer.qwer", roleNames: [], - externalRoleNames: [], }, ], }); @@ -752,7 +750,6 @@ describe("import-users store actions", () => { importUserId: "extern.1234", loginName: "samuel.vimes", roleNames: [ImportUserResponseRoleNamesEnum.Teacher], - externalRoleNames: ["teacher"], match: { firstName: "Samuel", lastName: "Vimes", @@ -770,7 +767,6 @@ describe("import-users store actions", () => { importUserId: "extern.5678", loginName: "samuel.vimes", roleNames: [ImportUserResponseRoleNamesEnum.Teacher], - externalRoleNames: ["teacher"], match: { firstName: "Samuel", lastName: "Vimes", From 8f26733a694a95b7f97b690ac8f0ae1de9f8cb44 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Tue, 20 Aug 2024 15:10:20 +0200 Subject: [PATCH 12/15] N21-2119 use isNbc, record for role name mapping & adjust role label --- .../molecules/vImportUsersMatchSearch.unit.ts | 21 ++++--- .../molecules/vImportUsersMatchSearch.vue | 63 +++++++++---------- src/locales/de.ts | 2 - src/locales/en.ts | 2 - src/locales/es.ts | 2 - src/locales/uk.ts | 2 - 6 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.unit.ts b/src/components/molecules/vImportUsersMatchSearch.unit.ts index 7fcfb6be17..038981a81a 100644 --- a/src/components/molecules/vImportUsersMatchSearch.unit.ts +++ b/src/components/molecules/vImportUsersMatchSearch.unit.ts @@ -216,7 +216,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemUsername.exists()).toBe(false); }); - describe("when the source is not from moin.schule", () => { + describe("when the theme is not NBC", () => { const setup = () => { const setupTestProps = { editedItem: { @@ -231,6 +231,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }, isDialog: true, ldapSource: "ldap-external", + isNbc: false, }; return { setupTestProps, @@ -246,12 +247,12 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { .html(); expect(editedItemElement).not.toContain( - "components.molecules.importUsersMatch.externalRoleName.label" + `common.labels.role ${setupTestProps.ldapSource}` ); }); }); - describe("when the source is from moin.schule", () => { + describe("when the theme is NBC", () => { describe("when the external role is 'Lern' (Student)", () => { const setup = () => { const adminTestProps = { @@ -267,6 +268,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }, isDialog: true, ldapSource: "moin.schule", + isNbc: true, }; return { adminTestProps, @@ -285,7 +287,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("Mustermann"); expect(editedItemElement).toContain("common.roleName.student"); expect(editedItemElement).toContain( - "(components.molecules.importUsersMatch.externalRoleName.label: " + + `common.labels.role ${adminTestProps.ldapSource}: ` + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student)" ); }); @@ -305,6 +307,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }, isDialog: true, ldapSource: "moin.schule", + isNbc: true, }; return { adminTestProps, @@ -323,7 +326,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("Mustermann"); expect(editedItemElement).toContain("common.roleName.teacher"); expect(editedItemElement).toContain( - "(components.molecules.importUsersMatch.externalRoleName.label: " + + `common.labels.role ${adminTestProps.ldapSource}: ` + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher)" ); }); @@ -343,6 +346,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }, isDialog: true, ldapSource: "moin.schule", + isNbc: true, }; return { adminTestProps, @@ -361,7 +365,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("Mustermann"); expect(editedItemElement).toContain("common.roleName.administrator"); expect(editedItemElement).toContain( - "(components.molecules.importUsersMatch.externalRoleName.label: " + + `common.labels.role ${adminTestProps.ldapSource}: ` + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager)" ); }); @@ -381,6 +385,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }, isDialog: true, ldapSource: "moin.schule", + isNbc: true, }; return { adminTestProps, @@ -399,11 +404,12 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { expect(editedItemElement).toContain("Mustermann"); expect(editedItemElement).toContain("common.roleName.administrator"); expect(editedItemElement).toContain( - "(components.molecules.importUsersMatch.externalRoleName.label: " + + `common.labels.role ${adminTestProps.ldapSource}: ` + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin)" ); }); }); + describe("when externalRoleNames prop is empty", () => { const setup = () => { const setupTestProps = { @@ -419,6 +425,7 @@ describe("@/components/molecules/vImportUsersMatchSearch", () => { }, isDialog: true, ldapSource: "moin.schule", + isNbc: true, }; return { setupTestProps, diff --git a/src/components/molecules/vImportUsersMatchSearch.vue b/src/components/molecules/vImportUsersMatchSearch.vue index 816a40f9fb..e648628a8c 100644 --- a/src/components/molecules/vImportUsersMatchSearch.vue +++ b/src/components/molecules/vImportUsersMatchSearch.vue @@ -44,9 +44,7 @@ {{ mapRoleNames(editedItem.roleNames) }} - {{ - props.ldapSource === "moin.schule" ? externalRoleText : "" - }} + {{ isNbc ? externalRoleText : "" }} = computed(() => { return true; }); -const canDelete = computed(() => { +const canDelete: ComputedRef = computed(() => { return props.editedItem.match && selectedItem.value === null; }); -const externalRoleText = computed(() => { +const externalRoleText: ComputedRef = computed(() => { let role = t("components.molecules.importUsersMatch.externalRoleName.none"); - if ( - props.editedItem.externalRoleNames && - props.editedItem.externalRoleNames.length - ) { + if (props.editedItem.externalRoleNames?.length) { role = mapExternalRoleNames(props.editedItem.externalRoleNames); } - const text = `(${t("components.molecules.importUsersMatch.externalRoleName.label", { source: props.ldapSource })}: ${role})`; + const text = `(${t("common.labels.role")} ${props.ldapSource}: ${role})`; return text; }); +const schulconnexExternalRoleNamesMapping: ComputedRef> = + computed(() => { + const roleMapping = { + ["Lehr"]: t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher" + ), + ["Lern"]: t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.student" + ), + ["Leit"]: t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager" + ), + ["OrgAdmin"]: t( + "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin" + ), + }; + return roleMapping; + }); + const getDataFromApi = async (append = false) => { loading.value = true; @@ -437,37 +451,16 @@ const mapRoleNames = (roleNames: unknown[]) => { const mapExternalRoleNames = (externalRoleNames: string[]) => { return externalRoleNames .map((role) => { - if (props.ldapSource === "moin.schule") { - return mapSchulconnexExternalRoleNames(role); + if (props.isNbc) { + const userFriendlyRoleName = + schulconnexExternalRoleNamesMapping.value[role]; + return userFriendlyRoleName; } return role; }) .join(", "); }; -const mapSchulconnexExternalRoleNames = (externalRoleName: string) => { - switch (externalRoleName) { - case "Lehr": - return t( - "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher" - ); - case "Lern": - return t( - "components.molecules.importUsersMatch.externalRoleName.schulconnex.student" - ); - case "Leit": - return t( - "components.molecules.importUsersMatch.externalRoleName.schulconnex.manager" - ); - case "OrgAdmin": - return t( - "components.molecules.importUsersMatch.externalRoleName.schulconnex.orgAdmin" - ); - default: - return externalRoleName; - } -}; - onMounted(async () => { flagged.value = props.editedItem.flagged; diff --git a/src/locales/de.ts b/src/locales/de.ts index 29d1faaddd..beafbc839d 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -601,8 +601,6 @@ export default { "Keiner. Benutzer wird neu erstellt.", "components.molecules.importUsersMatch.write": "Vornamen oder Nachnamen eingeben", - "components.molecules.importUsersMatch.externalRoleName.label": - "Rolle {source}", "components.molecules.importUsersMatch.externalRoleName.none": "Nicht verfügbar", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": diff --git a/src/locales/en.ts b/src/locales/en.ts index 317ca7c59d..c49b8c0fcd 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -589,8 +589,6 @@ export default { "components.molecules.importUsersMatch.unMatched": "None. Account will be newly created.", "components.molecules.importUsersMatch.write": "Input first and last name", - "components.molecules.importUsersMatch.externalRoleName.label": - "Role {source}", "components.molecules.importUsersMatch.externalRoleName.none": "Not available", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": diff --git a/src/locales/es.ts b/src/locales/es.ts index f4c5c93b6e..99e547585a 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -601,8 +601,6 @@ export default { "components.molecules.importUsersMatch.unMatched": "Ninguno. El usuario es recién creado.", "components.molecules.importUsersMatch.write": "Introduzca nombre o apellido", - "components.molecules.importUsersMatch.externalRoleName.label": - "Papel {source}", "components.molecules.importUsersMatch.externalRoleName.none": "No disponible", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": diff --git a/src/locales/uk.ts b/src/locales/uk.ts index c2df0b50fe..10b53f7bcc 100644 --- a/src/locales/uk.ts +++ b/src/locales/uk.ts @@ -598,8 +598,6 @@ export default { "components.molecules.importUsersMatch.unMatched": "немає. Обліковий запис буде створено знову.", "components.molecules.importUsersMatch.write": "Введіть ім'я та прізвище", - "components.molecules.importUsersMatch.externalRoleName.label": - "роль {source}", "components.molecules.importUsersMatch.externalRoleName.none": "Немає в наявності", "components.molecules.importUsersMatch.externalRoleName.schulconnex.teacher": From 687c73050da36667c430474c016f5fb9566bc217 Mon Sep 17 00:00:00 2001 From: Gordon Nicholas Date: Tue, 20 Aug 2024 15:54:02 +0200 Subject: [PATCH 13/15] N21-2119 minor adjustments --- .../molecules/vImportUsersMatchSearch.vue | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/components/molecules/vImportUsersMatchSearch.vue b/src/components/molecules/vImportUsersMatchSearch.vue index e648628a8c..a8269aeebc 100644 --- a/src/components/molecules/vImportUsersMatchSearch.vue +++ b/src/components/molecules/vImportUsersMatchSearch.vue @@ -201,7 +201,7 @@