From f1ae304bbdad13910984651565d97f0aad93cb5e Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Fri, 19 Apr 2024 11:14:03 +0200 Subject: [PATCH] refactor and test --- backend/jest.config.js | 2 +- backend/src/apis/humhub/ImportUsers.ts | 2 +- .../humhub/compareHumhubUserDbUser.test.ts | 64 ++++++++++ .../src/apis/humhub/convertLanguage.test.ts | 31 +++++ backend/src/apis/humhub/model/Account.ts | 1 - backend/src/apis/humhub/model/GetUser.ts | 8 ++ backend/src/apis/humhub/model/Profile.ts | 8 +- backend/src/apis/humhub/syncUser.test.ts | 111 +++++++++++++++--- backend/src/apis/humhub/syncUser.ts | 7 +- backend/src/data/PublishName.logic.ts | 14 ++- 10 files changed, 218 insertions(+), 30 deletions(-) create mode 100644 backend/src/apis/humhub/compareHumhubUserDbUser.test.ts create mode 100644 backend/src/apis/humhub/convertLanguage.test.ts diff --git a/backend/jest.config.js b/backend/jest.config.js index 6140da0aa..867aeea5e 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -7,7 +7,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 83, + lines: 82, }, }, setupFiles: ['/test/testSetup.ts'], diff --git a/backend/src/apis/humhub/ImportUsers.ts b/backend/src/apis/humhub/ImportUsers.ts index b57350abc..de33ba779 100644 --- a/backend/src/apis/humhub/ImportUsers.ts +++ b/backend/src/apis/humhub/ImportUsers.ts @@ -89,7 +89,7 @@ async function main() { userCount = users.length page++ const promises: Promise[] = [] - users.forEach((user: User) => promises.push(syncUser(user, humHubClient, humhubUsers))) + users.forEach((user: User) => promises.push(syncUser(user, humhubUsers))) const executedActions = await Promise.all(promises) executedActions.forEach((executedAction: ExecutedHumhubAction) => { executedHumhubActionsCount[executedAction as number]++ diff --git a/backend/src/apis/humhub/compareHumhubUserDbUser.test.ts b/backend/src/apis/humhub/compareHumhubUserDbUser.test.ts new file mode 100644 index 000000000..cc636d17a --- /dev/null +++ b/backend/src/apis/humhub/compareHumhubUserDbUser.test.ts @@ -0,0 +1,64 @@ +/* eslint-disable prettier/prettier */ +import { communityDbUser } from '@/util/communityUser' + +import { isHumhubUserIdenticalToDbUser } from './compareHumhubUserDbUser' +import { GetUser } from './model/GetUser' + +const defaultUser = communityDbUser + +describe('isHumhubUserIdenticalToDbUser', () => { + beforeEach(() => { + defaultUser.firstName = 'first name' + defaultUser.lastName = 'last name' + defaultUser.alias = 'alias' + defaultUser.emailContact.email = 'email@gmail.com' + defaultUser.language = 'en' + }) + + it('Should return true because humhubUser was created from entity user', () => { + const humhubUser = new GetUser(defaultUser, 1) + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(true) + }) + + it('Should return false because first name differ', () => { + const humhubUser = new GetUser(defaultUser, 1) + humhubUser.profile.firstname = 'changed first name' + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(false) + }) + it('Should return false because last name differ', () => { + const humhubUser = new GetUser(defaultUser, 1) + humhubUser.profile.lastname = 'changed last name' + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(false) + }) + it('Should return false because username differ', () => { + const humhubUser = new GetUser(defaultUser, 1) + humhubUser.account.username = 'changed username' + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(false) + }) + + it('Should return false because email differ', () => { + const humhubUser = new GetUser(defaultUser, 1) + humhubUser.account.email = 'new@gmail.com' + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(false) + }) + + it('Should return false because language differ', () => { + const humhubUser = new GetUser(defaultUser, 1) + humhubUser.account.language = 'de' + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(false) + }) + + it('Should return false because gradido_address differ', () => { + const humhubUser = new GetUser(defaultUser, 1) + // eslint-disable-next-line camelcase + humhubUser.profile.gradido_address = 'changed gradido address' + const result = isHumhubUserIdenticalToDbUser(humhubUser, defaultUser) + expect(result).toBe(false) + }) +}) diff --git a/backend/src/apis/humhub/convertLanguage.test.ts b/backend/src/apis/humhub/convertLanguage.test.ts new file mode 100644 index 000000000..052e63075 --- /dev/null +++ b/backend/src/apis/humhub/convertLanguage.test.ts @@ -0,0 +1,31 @@ +import { convertGradidoLanguageToHumhub, convertHumhubLanguageToGradido } from './convertLanguage' + +describe('convertGradidoLanguageToHumhub', () => { + it('Should convert "en" to "en-US"', () => { + const result = convertGradidoLanguageToHumhub('en') + expect(result).toBe('en-US') + }) + + it('Should return the same language for other values', () => { + const languages = ['de', 'fr', 'es', 'pt'] + languages.forEach((lang) => { + const result = convertGradidoLanguageToHumhub(lang) + expect(result).toBe(lang) + }) + }) +}) + +describe('convertHumhubLanguageToGradido', () => { + it('Should convert "en-US" to "en"', () => { + const result = convertHumhubLanguageToGradido('en-US') + expect(result).toBe('en') + }) + + it('Should return the same language for other values', () => { + const languages = ['de', 'fr', 'es', 'pt'] + languages.forEach((lang) => { + const result = convertHumhubLanguageToGradido(lang) + expect(result).toBe(lang) + }) + }) +}) diff --git a/backend/src/apis/humhub/model/Account.ts b/backend/src/apis/humhub/model/Account.ts index 52777e8c8..0926af2c2 100644 --- a/backend/src/apis/humhub/model/Account.ts +++ b/backend/src/apis/humhub/model/Account.ts @@ -16,6 +16,5 @@ export class Account { username: string email: string - tags: string[] language: string } diff --git a/backend/src/apis/humhub/model/GetUser.ts b/backend/src/apis/humhub/model/GetUser.ts index 16231c224..7d9814fc3 100644 --- a/backend/src/apis/humhub/model/GetUser.ts +++ b/backend/src/apis/humhub/model/GetUser.ts @@ -1,7 +1,15 @@ +import { User } from '@entity/User' + import { Account } from './Account' import { Profile } from './Profile' export class GetUser { + public constructor(user: User, id: number) { + this.id = id + this.account = new Account(user) + this.profile = new Profile(user) + } + id: number guid: string // eslint-disable-next-line camelcase diff --git a/backend/src/apis/humhub/model/Profile.ts b/backend/src/apis/humhub/model/Profile.ts index eadf6cf65..424c48026 100644 --- a/backend/src/apis/humhub/model/Profile.ts +++ b/backend/src/apis/humhub/model/Profile.ts @@ -2,11 +2,14 @@ import { User } from '@entity/User' import { CONFIG } from '@/config' +import { PublishNameLogic } from '@/data/PublishName.logic' +import { PublishNameType } from '@/graphql/enum/PublishNameType' export class Profile { public constructor(user: User) { - this.firstname = user.firstName - this.lastname = user.lastName + const publishNameLogic = new PublishNameLogic(user) + this.firstname = publishNameLogic.getFirstName(user.humhubPublishName as PublishNameType) + this.lastname = publishNameLogic.getLastName(user.humhubPublishName as PublishNameType) if (user.alias && user.alias.length > 2) { this.gradido_address = CONFIG.COMMUNITY_NAME + '/' + user.alias } else { @@ -17,5 +20,4 @@ export class Profile { firstname: string lastname: string gradido_address: string - about: string } diff --git a/backend/src/apis/humhub/syncUser.test.ts b/backend/src/apis/humhub/syncUser.test.ts index aebacc4cf..141714854 100644 --- a/backend/src/apis/humhub/syncUser.test.ts +++ b/backend/src/apis/humhub/syncUser.test.ts @@ -1,34 +1,111 @@ /* eslint-disable @typescript-eslint/no-empty-function */ import { User } from '@entity/User' -import { mocked } from 'ts-jest/utils' +import { UserContact } from '@entity/UserContact' + +import { CONFIG } from '@/config' import { HumHubClient } from './HumHubClient' import { GetUser } from './model/GetUser' import { syncUser, ExecutedHumhubAction } from './syncUser' -const defaultUser = User.create() +const defaultUser = new User() +defaultUser.emailContact = new UserContact() +defaultUser.emailContact.email = 'email@gmail.com' -jest.mock('./HumHubClient', () => { - return { - HumHubClient: jest.fn().mockImplementation(() => { - return { - createUser: () => {}, - updateUser: () => {}, - deleteUser: () => {}, - getInstance: () => { return new HumHubClient() } - } - }), - } -}) +CONFIG.HUMHUB_ACTIVE = true +CONFIG.HUMHUB_API_URL = 'http://localhost' + +let humhubClient: HumHubClient | undefined +let humhubClientSpy: { + createUser: jest.SpyInstance + updateUser: jest.SpyInstance + deleteUser: jest.SpyInstance +} describe('syncUser function', () => { - test('When humhubUser exists and user.humhubAllowed is false, should return DELETE action', async () => { - const mockedHumhubClient = mocked(HumHubClient) + beforeAll(() => { + humhubClient = HumHubClient.getInstance() + if (!humhubClient) { + throw new Error('error creating humhub client') + } + humhubClientSpy = { + createUser: jest.spyOn(humhubClient, 'createUser'), + updateUser: jest.spyOn(humhubClient, 'updateUser'), + deleteUser: jest.spyOn(humhubClient, 'deleteUser'), + } + humhubClientSpy.createUser.mockImplementation(() => Promise.resolve()) + humhubClientSpy.updateUser.mockImplementation(() => Promise.resolve()) + humhubClientSpy.deleteUser.mockImplementation(() => Promise.resolve()) + }) + + afterEach(() => { + humhubClientSpy.createUser.mockClear() + humhubClientSpy.updateUser.mockClear() + humhubClientSpy.deleteUser.mockClear() + }) + afterAll(() => { + jest.resetAllMocks() + }) + + /* + * Trigger action according to conditions + * | User exist on humhub | export to humhub allowed | changes in user data | ACTION + * | true | false | ignored | DELETE + * | true | true | true | UPDATE + * | true | true | false | SKIP + * | false | false | ignored | SKIP + * | false | true | ignored | CREATE + * */ + + it('When humhubUser exists and user.humhubAllowed is false, should return DELETE action', async () => { const humhubUsers = new Map() + humhubUsers.set(defaultUser.emailContact.email, new GetUser(defaultUser, 1)) defaultUser.humhubAllowed = false - const result = await syncUser(defaultUser, new HumHubClient(), humhubUsers) + const result = await syncUser(defaultUser, humhubUsers) expect(result).toBe(ExecutedHumhubAction.DELETE) }) + + it('When humhubUser exists and user.humhubAllowed is true and there are changes in user data, should return UPDATE action', async () => { + const humhubUsers = new Map() + const humhubUser = new GetUser(defaultUser, 1) + humhubUser.account.username = 'test username' + humhubUsers.set(defaultUser.emailContact.email, humhubUser) + + defaultUser.humhubAllowed = true + const result = await syncUser(defaultUser, humhubUsers) + + expect(result).toBe(ExecutedHumhubAction.UPDATE) + }) + + it('When humhubUser exists and user.humhubAllowed is true and there are no changes in user data, should return SKIP action', async () => { + const humhubUsers = new Map() + const humhubUser = new GetUser(defaultUser, 1) + humhubUsers.set(defaultUser.emailContact.email, humhubUser) + + defaultUser.humhubAllowed = true + const result = await syncUser(defaultUser, humhubUsers) + + expect(result).toBe(ExecutedHumhubAction.SKIP) + }) + + it('When humhubUser not exists and user.humhubAllowed is false, should return SKIP action', async () => { + const humhubUsers = new Map() + + defaultUser.humhubAllowed = false + const result = await syncUser(defaultUser, humhubUsers) + + expect(result).toBe(ExecutedHumhubAction.SKIP) + }) + + it('When humhubUser not exists and user.humhubAllowed is true, should return CREATE action', async () => { + const humhubUsers = new Map() + + defaultUser.humhubAllowed = true + const result = await syncUser(defaultUser, humhubUsers) + + expect(result).toBe(ExecutedHumhubAction.CREATE) + }) + }) diff --git a/backend/src/apis/humhub/syncUser.ts b/backend/src/apis/humhub/syncUser.ts index 33b04b6c0..fc6fcc99b 100644 --- a/backend/src/apis/humhub/syncUser.ts +++ b/backend/src/apis/humhub/syncUser.ts @@ -1,5 +1,7 @@ import { User } from '@entity/User' +import { LogError } from '@/server/LogError' + import { isHumhubUserIdenticalToDbUser } from './compareHumhubUserDbUser' import { HumHubClient } from './HumHubClient' import { GetUser } from './model/GetUser' @@ -26,11 +28,14 @@ export enum ExecutedHumhubAction { */ export async function syncUser( user: User, - humHubClient: HumHubClient, humhubUsers: Map, ): Promise { const postUser = new PostUser(user) const humhubUser = humhubUsers.get(user.emailContact.email.trim()) + const humHubClient = HumHubClient.getInstance() + if (!humHubClient) { + throw new LogError('Error creating humhub client') + } if (humhubUser) { if (!user.humhubAllowed) { diff --git a/backend/src/data/PublishName.logic.ts b/backend/src/data/PublishName.logic.ts index e17708ceb..831c27e0d 100644 --- a/backend/src/data/PublishName.logic.ts +++ b/backend/src/data/PublishName.logic.ts @@ -8,10 +8,10 @@ export class PublishNameLogic { /** * get first name based on publishNameType: PublishNameType value * @param publishNameType - * @returns user.firstName for GMS_PUBLISH_NAME_FIRST, GMS_PUBLISH_NAME_FIRST_INITIAL or GMS_PUBLISH_NAME_FULL - * first initial from user.firstName for GMS_PUBLISH_NAME_INITIALS or GMS_PUBLISH_NAME_ALIAS_OR_INITALS and empty alias + * @returns user.firstName for PUBLISH_NAME_FIRST, PUBLISH_NAME_FIRST_INITIAL or PUBLISH_NAME_FULL + * first initial from user.firstName for PUBLISH_NAME_INITIALS or PUBLISH_NAME_INITIAL_LAST */ - public getFirstName(publishNameType: PublishNameType): string | undefined { + public getFirstName(publishNameType: PublishNameType): string { if ( [ PublishNameType.PUBLISH_NAME_FIRST, @@ -28,15 +28,16 @@ export class PublishNameLogic { ) { return this.user.firstName.substring(0, 1) } + return '' } /** * get last name based on publishNameType: GmsPublishNameType value * @param publishNameType - * @returns user.lastName for GMS_PUBLISH_NAME_FULL - * first initial from user.lastName for GMS_PUBLISH_NAME_FIRST_INITIAL, GMS_PUBLISH_NAME_INITIALS or GMS_PUBLISH_NAME_ALIAS_OR_INITALS and empty alias + * @returns user.lastName for PUBLISH_NAME_LAST, PUBLISH_NAME_INITIAL_LAST, PUBLISH_NAME_FULL + * first initial from user.lastName for PUBLISH_NAME_FIRST_INITIAL, PUBLISH_NAME_INITIALS */ - public getLastName(publishNameType: PublishNameType): string | undefined { + public getLastName(publishNameType: PublishNameType): string { if ( [ PublishNameType.PUBLISH_NAME_LAST, @@ -53,5 +54,6 @@ export class PublishNameLogic { ) { return this.user.lastName.substring(0, 1) } + return '' } }