diff --git a/admin/src/components/ContributionMessages/ContributionMessagesList.vue b/admin/src/components/ContributionMessages/ContributionMessagesList.vue index 8f06d841e..837f2ade1 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesList.vue @@ -12,7 +12,7 @@ {{ $t('filter.byEmail') }}   - {{ contribution.user.humhubUsername }} + {{ contribution.user.publicName }}   { if (url.endsWith('/')) { url = url.slice(0, -1) } - return `${url}/u/${props.contribution.humhubUsername}` + return `${url}/u/${props.contribution.user.uniqueUsername}` }) const messages = ref([]) diff --git a/admin/src/graphql/adminListContributions.graphql b/admin/src/graphql/adminListContributions.graphql index cb696a51b..f98c9083f 100644 --- a/admin/src/graphql/adminListContributions.graphql +++ b/admin/src/graphql/adminListContributions.graphql @@ -13,7 +13,8 @@ query adminListContributions( email } ...UserCommonFields - humhubUsername + publicName + uniqueUsername createdAt } amount diff --git a/backend/src/apis/gms/model/GmsUser.ts b/backend/src/apis/gms/model/GmsUser.ts index 7dc81432f..92c2b67a6 100644 --- a/backend/src/apis/gms/model/GmsUser.ts +++ b/backend/src/apis/gms/model/GmsUser.ts @@ -15,11 +15,11 @@ export class GmsUser { this.email = this.getGmsEmail(user) this.countryCode = this.getGmsCountryCode(user) this.mobile = this.getGmsPhone(user) - const fn = pnLogic.getFirstName(user.gmsPublishName) + const fn = pnLogic.getFirstName(user.gmsPublishName as PublishNameType) this.firstName = fn !== '' ? fn : null // getGmsFirstName(user) - const ln = pnLogic.getLastName(user.gmsPublishName) + const ln = pnLogic.getLastName(user.gmsPublishName as PublishNameType) this.lastName = ln !== '' ? ln : null // getGmsLastName(user) - this.alias = this.getGmsAlias(user) + this.alias = pnLogic.getPublicName(user.gmsPublishName as PublishNameType) this.type = user.gmsPublishLocation // GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM this.location = user.location } diff --git a/backend/src/apis/humhub/model/AbstractUser.ts b/backend/src/apis/humhub/model/AbstractUser.ts index 8f876f053..abcf9dcda 100644 --- a/backend/src/apis/humhub/model/AbstractUser.ts +++ b/backend/src/apis/humhub/model/AbstractUser.ts @@ -1,8 +1,5 @@ import { User } from '@entity/User' -import { PublishNameLogic } from '@/data/PublishName.logic' -import { PublishNameType } from '@/graphql/enum/PublishNameType' - import { Account } from './Account' import { Profile } from './Profile' @@ -10,12 +7,6 @@ export abstract class AbstractUser { public constructor(user: User) { this.account = new Account(user) this.profile = new Profile(user) - // temp fix for prevent double usernames in humhub, if the username ist created from initials - const publishNameLogic = new PublishNameLogic(user) - if (publishNameLogic.isUsernameFromInitials(user.humhubPublishName as PublishNameType)) { - this.profile.firstname = this.account.username - this.account.username = user.gradidoID - } } account: Account diff --git a/backend/src/apis/humhub/model/Account.ts b/backend/src/apis/humhub/model/Account.ts index 1eb3e37be..1ccc911ad 100644 --- a/backend/src/apis/humhub/model/Account.ts +++ b/backend/src/apis/humhub/model/Account.ts @@ -8,7 +8,7 @@ import { PublishNameType } from '@/graphql/enum/PublishNameType' export class Account { public constructor(user: User) { const publishNameLogic = new PublishNameLogic(user) - this.username = publishNameLogic.getUsername(user.humhubPublishName as PublishNameType) + this.username = publishNameLogic.getUniqueUsername(user.humhubPublishName as PublishNameType) this.email = user.emailContact.email this.language = convertGradidoLanguageToHumhub(user.language) this.status = 1 diff --git a/backend/src/data/PublishName.logic.test.ts b/backend/src/data/PublishName.logic.test.ts index 280836c5e..6356444f0 100644 --- a/backend/src/data/PublishName.logic.test.ts +++ b/backend/src/data/PublishName.logic.test.ts @@ -1,23 +1,87 @@ import { User } from '@entity/User' +import { v4 as uuidv4 } from 'uuid' import { PublishNameType } from '@/graphql/enum/PublishNameType' import { PublishNameLogic } from './PublishName.logic' +const gradidoUuid = uuidv4() +let user: User +let logic: PublishNameLogic + +/* +export enum PublishNameType { + PUBLISH_NAME_ALIAS_OR_INITALS = 0, + PUBLISH_NAME_INITIALS = 1, + PUBLISH_NAME_FIRST = 2, + PUBLISH_NAME_FIRST_INITIAL = 3, + PUBLISH_NAME_FULL = 4, +} +*/ + describe('test publish name logic', () => { - describe('test username', () => { - it('alias or initials with alias set', () => { - const user = new User() - user.alias = 'alias' - const logic = new PublishNameLogic(user) - expect(logic.getUsername(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe(user.alias) + beforeEach(() => { + user = new User() + user.alias = 'alias' + user.firstName = 'John' + user.lastName = 'Smith' + user.gradidoID = gradidoUuid + logic = new PublishNameLogic(user) + }) + describe('test unique username', () => { + it('for alias or initials with alias set', () => { + expect(logic.getUniqueUsername(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('alias') }) - it('alias or initials with empty alias', () => { - const user = new User() - user.firstName = 'John' - user.lastName = 'Smith' - const logic = new PublishNameLogic(user) - expect(logic.getUsername(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('JoSm') + it('for alias or initials with empty alias', () => { + user.alias = '' + expect(logic.getUniqueUsername(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe( + gradidoUuid, + ) + }) + it('for publish name initials', () => { + expect(logic.getUniqueUsername(PublishNameType.PUBLISH_NAME_INITIALS)).toBe(gradidoUuid) + }) + it('for publish name first', () => { + expect(logic.getUniqueUsername(PublishNameType.PUBLISH_NAME_FIRST)).toBe(gradidoUuid) + }) + it('for publish name first initial', () => { + expect(logic.getUniqueUsername(PublishNameType.PUBLISH_NAME_FIRST_INITIAL)).toBe(gradidoUuid) + }) + it('for publish name full', () => { + expect(logic.getUniqueUsername(PublishNameType.PUBLISH_NAME_FULL)).toBe(gradidoUuid) + }) + }) + + describe('test public name', () => { + it('for alias or initials with alias set', () => { + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('alias') + }) + it('for alias or initials with empty alias', () => { + user.alias = '' + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('JoSm') + }) + it('for alias or initials with empty alias and lower case written names', () => { + user.alias = '' + user.firstName = 'john' + user.lastName = 'smith' + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_ALIAS_OR_INITALS)).toBe('JoSm') + }) + it('for publish name initials', () => { + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_INITIALS)).toBe('JoSm') + }) + it('for publish name initials with lower case written names', () => { + user.firstName = 'john' + user.lastName = 'smith' + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_INITIALS)).toBe('JoSm') + }) + it('for publish name first', () => { + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_FIRST)).toBe('John') + }) + it('for publish name first initial', () => { + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_FIRST_INITIAL)).toBe('John S') + }) + it('for publish name full', () => { + expect(logic.getPublicName(PublishNameType.PUBLISH_NAME_FULL)).toBe('John Smith') }) }) }) diff --git a/backend/src/data/PublishName.logic.ts b/backend/src/data/PublishName.logic.ts index 4e092cfe4..70fab21cd 100644 --- a/backend/src/data/PublishName.logic.ts +++ b/backend/src/data/PublishName.logic.ts @@ -59,23 +59,34 @@ export class PublishNameLogic { } /** - * get username from user.alias for PUBLISH_NAME_ALIAS_OR_INITALS and if user has alias - * get first name first two characters and last name first two characters for PUBLISH_NAME_ALIAS_OR_INITALS - * if no alias or PUBLISH_NAME_INITIALS + * get unique username * @param publishNameType - * @returns user.alias for publishNameType = PUBLISH_NAME_ALIAS_OR_INITALS and user has alias - * else return user.firstName[0,2] + user.lastName[0,2] for publishNameType = [PUBLISH_NAME_ALIAS_OR_INITALS, PUBLISH_NAME_INITIALS] + * @return when alias if exist and publishNameType = [PUBLISH_NAME_ALIAS_OR_INITALS, PUBLISH_NAME_INITIALS] + * return alias + * else return gradido id */ - public getUsername(publishNameType: PublishNameType): string { - if (this.isUsernameFromInitials(publishNameType)) { - return ( - this.firstUpperCaseSecondLowerCase(this.filterOutInvalidChar(this.user.firstName)) + - this.firstUpperCaseSecondLowerCase(this.filterOutInvalidChar(this.user.lastName)) - ) - } else if (this.isUsernameFromAlias(publishNameType)) { - return this.filterOutInvalidChar(this.user.alias) - } - return this.user.gradidoID + public getUniqueUsername(publishNameType: PublishNameType): string { + return this.isUsernameFromAlias(publishNameType) + ? this.filterOutInvalidChar(this.user.alias) + : this.user.gradidoID + } + + /** + * get public name based on publishNameType: PublishNameType value + * @param publishNameType: PublishNameType + * @return alias if exist and type = PUBLISH_NAME_ALIAS_OR_INITALS + * initials if type = PUBLISH_NAME_INITIALS + * full first name if type = PUBLISH_NAME_FIRST + * full first name and last name initial if type = PUBLISH_NAME_FIRST_INITIAL + * full first name and full last name if type = PUBLISH_NAME_FULL + */ + public getPublicName(publishNameType: PublishNameType): string { + return this.isUsernameFromAlias(publishNameType) + ? this.filterOutInvalidChar(this.user.alias) + : this.isUsernameFromInitials(publishNameType) + ? this.firstUpperCaseSecondLowerCase(this.user.firstName) + + this.firstUpperCaseSecondLowerCase(this.user.lastName) + : (this.getFirstName(publishNameType) + ' ' + this.getLastName(publishNameType)).trim() } public isUsernameFromInitials(publishNameType: PublishNameType): boolean { diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index b665bde98..970ff28b3 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -26,7 +26,9 @@ export class User { this.alias = user.alias const publishNameLogic = new PublishNameLogic(user) - this.humhubUsername = publishNameLogic.getUsername(user.humhubPublishName as PublishNameType) + const publishNameType = user.humhubPublishName as PublishNameType + this.publicName = publishNameLogic.getPublicName(publishNameType) + this.uniqueUsername = publishNameLogic.getUniqueUsername(publishNameType) if (user.emailContact) { this.emailChecked = user.emailContact.emailChecked @@ -71,7 +73,10 @@ export class User { alias: string | null @Field(() => String, { nullable: true }) - humhubUsername: string | null + publicName: string | null + + @Field(() => String, { nullable: true }) + uniqueUsername: string | null @Field(() => String, { nullable: true }) firstName: string | null diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 5e8843650..bbac91597 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -8,6 +8,7 @@ import { ProjectBranding } from '@entity/ProjectBranding' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' +import { UserLoggingView } from '@logging/UserLogging.view' import { GraphQLResolveInfo } from 'graphql' import i18n from 'i18n' import { @@ -738,7 +739,7 @@ export class UserResolver { }) await queryRunner.commitTransaction() - logger.debug('writing User data successful...', user) + logger.debug('writing User data successful...', new UserLoggingView(user)) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Error on writing updated user data', e) @@ -832,7 +833,7 @@ export class UserResolver { throw new LogError('cannot create humhub client') } const userNameLogic = new PublishNameLogic(dbUser) - const username = userNameLogic.getUsername(dbUser.humhubPublishName as PublishNameType) + const username = userNameLogic.getUniqueUsername(dbUser.humhubPublishName as PublishNameType) let humhubUser = await humhubClient.userByUsername(username) if (!humhubUser) { humhubUser = await humhubClient.userByEmail(dbUser.emailContact.email) diff --git a/backend/src/graphql/resolver/util/compareGmsRelevantUserSettings.ts b/backend/src/graphql/resolver/util/compareGmsRelevantUserSettings.ts index 2144c9833..edfba7457 100644 --- a/backend/src/graphql/resolver/util/compareGmsRelevantUserSettings.ts +++ b/backend/src/graphql/resolver/util/compareGmsRelevantUserSettings.ts @@ -1,5 +1,6 @@ import { Point } from '@dbTools/typeorm' import { User as DbUser } from '@entity/User' +import { UserLoggingView } from '@logging/UserLogging.view' import { UpdateUserInfosArgs } from '@/graphql/arg/UpdateUserInfosArgs' import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType' @@ -16,7 +17,7 @@ export function compareGmsRelevantUserSettings( if (!orgUser) { throw new LogError('comparison without any user is impossible') } - logger.debug('compareGmsRelevantUserSettings:', orgUser, updateUserInfosArgs) + logger.debug('compareGmsRelevantUserSettings:', new UserLoggingView(orgUser), updateUserInfosArgs) // nach GMS updaten, wenn alias gesetzt wird oder ist und PublishLevel die alias-Übermittlung erlaubt if ( updateUserInfosArgs.alias && diff --git a/database/logging/UserLogging.view.ts b/database/logging/UserLogging.view.ts index 19b3ca911..839b0ad8b 100644 --- a/database/logging/UserLogging.view.ts +++ b/database/logging/UserLogging.view.ts @@ -32,7 +32,7 @@ export class UserLoggingView extends AbstractLoggingView { lastName: this.self.lastName?.substring(0, 3) + '...', createdAt: this.dateToString(this.self.createdAt), deletedAt: this.dateToString(this.self.deletedAt), - passwordEncryptionType: this.self.passwordEncryptionType as PasswordEncryptionType, + passwordEncryptionType: PasswordEncryptionType[this.self.passwordEncryptionType], language: this.self.language, hideAmountGDD: this.self.hideAmountGDD, hideAmountGDT: this.self.hideAmountGDT,