diff --git a/backend/src/graphql/arg/UpdateUserInfosArgs.ts b/backend/src/graphql/arg/UpdateUserInfosArgs.ts index d3e3dc744..b9617f6df 100644 --- a/backend/src/graphql/arg/UpdateUserInfosArgs.ts +++ b/backend/src/graphql/arg/UpdateUserInfosArgs.ts @@ -3,6 +3,7 @@ import { ArgsType, Field, InputType, Int } from 'type-graphql' import { GmsPublishLocationType } from '@enum/GmsPublishLocationType' import { GmsPublishNameType } from '@enum/GmsPublishNameType' +import { PublishNameType } from '@enum/PublishNameType' import { Location } from '@model/Location' import { isValidLocation } from '@/graphql/validator/Location' @@ -58,9 +59,9 @@ export class UpdateUserInfosArgs { @IsEnum(GmsPublishNameType) gmsPublishName?: GmsPublishNameType | null - @Field(() => GmsPublishNameType, { nullable: true }) - @IsEnum(GmsPublishNameType) - humhubPublishName?: GmsPublishNameType | null + @Field(() => PublishNameType, { nullable: true }) + @IsEnum(PublishNameType) + humhubPublishName?: PublishNameType | null @Field(() => Location, { nullable: true }) @isValidLocation() diff --git a/backend/src/graphql/enum/PublishNameType.ts b/backend/src/graphql/enum/PublishNameType.ts new file mode 100644 index 000000000..5fa86ee9f --- /dev/null +++ b/backend/src/graphql/enum/PublishNameType.ts @@ -0,0 +1,19 @@ +import { registerEnumType } from 'type-graphql' + +/** + * Enum for decide which parts from first- and last-name are allowed to be published in an extern service + */ +export enum PublishNameType { + PUBLISH_NAME_NONE = 0, + PUBLISH_NAME_INITIALS = 1, + PUBLISH_NAME_FIRST = 2, + PUBLISH_NAME_FIRST_INITIAL = 3, + PUBLISH_NAME_LAST = 4, + PUBLISH_NAME_INITIAL_LAST = 5, + PUBLISH_NAME_FULL = 6, +} + +registerEnumType(PublishNameType, { + name: 'PublishNameType', // this one is mandatory + description: 'Type of first- and last-name publishing for extern service', // this one is optional +}) diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index a6a5ad199..aa4baaac0 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -3,6 +3,7 @@ import { ObjectType, Field, Int } from 'type-graphql' import { GmsPublishLocationType } from '@enum/GmsPublishLocationType' import { GmsPublishNameType } from '@enum/GmsPublishNameType' +import { PublishNameType } from '@enum/PublishNameType' import { KlickTipp } from './KlickTipp' @@ -91,8 +92,8 @@ export class User { @Field(() => GmsPublishNameType, { nullable: true }) gmsPublishName: GmsPublishNameType | null - @Field(() => GmsPublishNameType, { nullable: true }) - humhubPublishName: GmsPublishNameType | null + @Field(() => PublishNameType, { nullable: true }) + humhubPublishName: PublishNameType | null @Field(() => GmsPublishLocationType, { nullable: true }) gmsPublishLocation: GmsPublishLocationType | null diff --git a/frontend/src/components/UserSettings/UserGMSNamingFormat.spec.js b/frontend/src/components/UserSettings/UserGMSNamingFormat.spec.js new file mode 100644 index 000000000..e48f6baba --- /dev/null +++ b/frontend/src/components/UserSettings/UserGMSNamingFormat.spec.js @@ -0,0 +1,84 @@ +import { mount } from '@vue/test-utils' +import UserGMSNamingFormat from './UserGMSNamingFormat.vue' +import { toastErrorSpy } from '@test/testSetup' + +const mockAPIcall = jest.fn() + +const storeCommitMock = jest.fn() + +const localVue = global.localVue + +describe('UserNamingFormat', () => { + let wrapper + beforeEach(() => { + wrapper = mount(UserGMSNamingFormat, { + mocks: { + $t: (key) => key, // Mocking the translation function + $store: { + state: { + gmsPublishName: null, + }, + commit: storeCommitMock, + }, + $apollo: { + mutate: mockAPIcall, + }, + }, + localVue, + propsData: { + selectedOption: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS', + initialValue: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS', + attrName: 'gmsPublishName', + successMessage: 'success message', + }, + }) + }) + + afterEach(() => { + wrapper.destroy() + }) + + it('renders the correct dropdown options', () => { + const dropdownItems = wrapper.findAll('.dropdown-item') + expect(dropdownItems.length).toBe(5) + + const labels = dropdownItems.wrappers.map((item) => item.text()) + expect(labels).toEqual([ + 'settings.GMS.publish-name.alias-or-initials', + 'settings.GMS.publish-name.initials', + 'settings.GMS.publish-name.first', + 'settings.GMS.publish-name.first-initial', + 'settings.GMS.publish-name.name-full', + ]) + }) + + it('updates selected option on click', async () => { + const dropdownItem = wrapper.findAll('.dropdown-item').at(3) // Click the fourth item + await dropdownItem.trigger('click') + + expect(wrapper.emitted().valueChanged).toBeTruthy() + expect(wrapper.emitted().valueChanged.length).toBe(1) + expect(wrapper.emitted().valueChanged[0]).toEqual(['GMS_PUBLISH_NAME_FIRST_INITIAL']) + }) + + it('does not update when clicking on already selected option', async () => { + const dropdownItem = wrapper.findAll('.dropdown-item').at(0) // Click the first item (which is already selected) + await dropdownItem.trigger('click') + + expect(wrapper.emitted().valueChanged).toBeFalsy() + }) + + describe('update with error', () => { + beforeEach(async () => { + mockAPIcall.mockRejectedValue({ + message: 'Ouch', + }) + const dropdownItem = wrapper.findAll('.dropdown-item').at(2) // Click the third item + await dropdownItem.trigger('click') + }) + + it('toasts an error message', () => { + expect(toastErrorSpy).toBeCalledWith('Ouch') + }) + }) +}) diff --git a/frontend/src/components/UserSettings/UserGMSNamingFormat.vue b/frontend/src/components/UserSettings/UserGMSNamingFormat.vue new file mode 100644 index 000000000..98e0911ed --- /dev/null +++ b/frontend/src/components/UserSettings/UserGMSNamingFormat.vue @@ -0,0 +1,92 @@ + + + + {{ selectedOptionLabel }} + + {{ option.label }} + + + + + + diff --git a/frontend/src/components/UserSettings/UserNamingFormat.spec.js b/frontend/src/components/UserSettings/UserNamingFormat.spec.js index f07f5e3f2..8ded29ca7 100644 --- a/frontend/src/components/UserSettings/UserNamingFormat.spec.js +++ b/frontend/src/components/UserSettings/UserNamingFormat.spec.js @@ -26,9 +26,9 @@ describe('UserNamingFormat', () => { }, localVue, propsData: { - selectedOption: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS', - initialValue: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS', - attrName: 'gmsPublishName', + selectedOption: 'PUBLISH_NAME_NONE', + initialValue: 'PUBLISH_NAME_NONE', + attrName: 'publishName', successMessage: 'success message', }, }) @@ -40,15 +40,17 @@ describe('UserNamingFormat', () => { it('renders the correct dropdown options', () => { const dropdownItems = wrapper.findAll('.dropdown-item') - expect(dropdownItems.length).toBe(5) + expect(dropdownItems.length).toBe(7) const labels = dropdownItems.wrappers.map((item) => item.text()) expect(labels).toEqual([ - 'settings.GMS.publish-name.alias-or-initials', - 'settings.GMS.publish-name.initials', - 'settings.GMS.publish-name.first', - 'settings.GMS.publish-name.first-initial', - 'settings.GMS.publish-name.name-full', + 'settings.publish-name.none', + 'settings.publish-name.initials', + 'settings.publish-name.first', + 'settings.publish-name.first-initial', + 'settings.publish-name.last', + 'settings.publish-name.last-initial', + 'settings.publish-name.full', ]) }) @@ -58,7 +60,7 @@ describe('UserNamingFormat', () => { expect(wrapper.emitted().valueChanged).toBeTruthy() expect(wrapper.emitted().valueChanged.length).toBe(1) - expect(wrapper.emitted().valueChanged[0]).toEqual(['GMS_PUBLISH_NAME_FIRST_INITIAL']) + expect(wrapper.emitted().valueChanged[0]).toEqual(['PUBLISH_NAME_FIRST_INITIAL']) }) it('does not update when clicking on already selected option', async () => { diff --git a/frontend/src/components/UserSettings/UserNamingFormat.vue b/frontend/src/components/UserSettings/UserNamingFormat.vue index 510541219..658f276ca 100644 --- a/frontend/src/components/UserSettings/UserNamingFormat.vue +++ b/frontend/src/components/UserSettings/UserNamingFormat.vue @@ -20,7 +20,7 @@ import { updateUserInfos } from '@/graphql/mutations' export default { name: 'UserNamingFormat', props: { - initialValue: { type: String, default: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS' }, + initialValue: { type: String, default: 'PUBLISH_NAME_NONE' }, attrName: { type: String }, successMessage: { type: String }, }, @@ -29,29 +29,39 @@ export default { selectedOption: this.initialValue, dropdownOptions: [ { - label: this.$t('settings.GMS.publish-name.alias-or-initials'), - title: this.$t('settings.GMS.publish-name.alias-or-initials-tooltip'), - value: 'GMS_PUBLISH_NAME_ALIAS_OR_INITALS', + label: this.$t('settings.publish-name.none'), + title: this.$t('settings.publish-name.none-tooltip'), + value: 'PUBLISH_NAME_NONE', }, { - label: this.$t('settings.GMS.publish-name.initials'), - title: this.$t('settings.GMS.publish-name.initials-tooltip'), - value: 'GMS_PUBLISH_NAME_INITIALS', + label: this.$t('settings.publish-name.initials'), + title: this.$t('settings.publish-name.initials-tooltip'), + value: 'PUBLISH_NAME_INITIALS', }, { - label: this.$t('settings.GMS.publish-name.first'), - title: this.$t('settings.GMS.publish-name.first-tooltip'), - value: 'GMS_PUBLISH_NAME_FIRST', + label: this.$t('settings.publish-name.first'), + title: this.$t('settings.publish-name.first-tooltip'), + value: 'PUBLISH_NAME_FIRST', }, { - label: this.$t('settings.GMS.publish-name.first-initial'), - title: this.$t('settings.GMS.publish-name.first-initial-tooltip'), - value: 'GMS_PUBLISH_NAME_FIRST_INITIAL', + label: this.$t('settings.publish-name.first-initial'), + title: this.$t('settings.publish-name.first-initial-tooltip'), + value: 'PUBLISH_NAME_FIRST_INITIAL', }, { - label: this.$t('settings.GMS.publish-name.name-full'), - title: this.$t('settings.GMS.publish-name.name-full-tooltip'), - value: 'GMS_PUBLISH_NAME_FULL', + label: this.$t('settings.publish-name.last'), + title: this.$t('settings.publish-name.last-tooltip'), + value: 'PUBLISH_NAME_LAST', + }, + { + label: this.$t('settings.publish-name.last-initial'), + title: this.$t('settings.publish-name.last-initial-tooltip'), + value: 'PUBLISH_NAME_INITIAL_LAST', + }, + { + label: this.$t('settings.publish-name.full'), + title: this.$t('settings.publish-name.full-tooltip'), + value: 'PUBLISH_NAME_FULL', }, ], } diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index ab78ca03b..efcbcffb3 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -37,7 +37,7 @@ export const updateUserInfos = gql` $gmsAllowed: Boolean $humhubAllowed: Boolean $gmsPublishName: GmsPublishNameType - $humhubPublishName: GmsPublishNameType + $humhubPublishName: PublishNameType $gmsLocation: Location $gmsPublishLocation: GmsPublishLocationType ) { diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index df59f05b2..da212d379 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -330,7 +330,6 @@ "humhub": { "disabled": "Daten werden nicht in die Gradido Community exportiert", "enabled": "Daten werden in die Gradido Community exportiert", - "export-consequences": "In der Gradido Community können dich alle Benutzer mit deinem Vor- und Nachnamen finden.", "naming-format": "Namensformat in der Gradido Community", "publish-name": { "updated": "Namensformat für die Gradido Community aktualisiert." @@ -374,6 +373,22 @@ }, "subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen." }, + "publish-name": { + "none": "Keine", + "none-tooltip": "Vorname und Nachname bleiben leer", + "first": "Vorname", + "first-tooltip": "Nur der Vornamen, z.B. Max", + "first-initial": "Vorname und Initiale", + "first-initial-tooltip": "Vornamen plus Anfangsbuchstabe des Nachnamens, z.B. Max M.", + "last": "Nachname", + "last-tooltip": "Nur der Nachname, z.B. Mustermann", + "last-initial": "Initiale und Nachname", + "last-initial-tooltip": "Anfangsbuchstabe des Vornamen plus Nachname, z.B. M. Mustermann", + "initials": "Initialen", + "initials-tooltip": "Nur die Initialen von Vor- und Nachname, z.B. M. M.", + "full": "Ganzer Name", + "full-tooltip": "Vollständiger Name: Vorname plus Nachname, z.B. Max Mustermann" + }, "showAmountGDD": "Dein GDD Betrag ist sichtbar.", "showAmountGDT": "Dein GDT Betrag ist sichtbar.", "username": { diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 0377a3eec..7bba0d5eb 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -330,7 +330,6 @@ "humhub": { "disabled": "Data not exported into the Gradido Community", "enabled": "Data exported into the Gradido Community", - "export-consequences": "In the Gradido Community, all users can find you by your first and last name.", "naming-format": "Format of name in the Gradido Community", "publish-name": { "updated": "Format of name for the Gradido Community updated." @@ -374,6 +373,22 @@ }, "subtitle": "If you have forgotten your password, you can reset it here." }, + "publish-name": { + "none": "None", + "none-tooltip": "first name and last name are empty", + "first": "first name", + "first-tooltip": "the first name only", + "first-initial": "first name and initial", + "first-initial-tooltip": "first name plus initial of last name", + "last": "last name", + "last-tooltip": "last name only", + "last-initial": "initial and last name", + "last-initial-tooltip": "First letter of the first name plus last name", + "initials": "initials", + "initials-tooltip": "Initials of first name and last name", + "full": "full name", + "full-tooltip": "full name: firstname plus lastname" + }, "showAmountGDD": "Your GDD amount is visible.", "showAmountGDT": "Your GDT amount is visible.", "username": { diff --git a/frontend/src/pages/Settings.vue b/frontend/src/pages/Settings.vue index 1fb84318e..57fb9dc11 100644 --- a/frontend/src/pages/Settings.vue +++ b/frontend/src/pages/Settings.vue @@ -107,7 +107,7 @@ {{ $t('settings.GMS.naming-format') }} - {{ $t('Humhub') }} - {{ $t('settings.humhub.export-consequences') }} {{ $t('settings.humhub.switch') }} @@ -181,6 +180,7 @@