mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
Merge pull request #3310 from gradido/humhub_sync_active_user
feat(backend): sync user change with humhub
This commit is contained in:
commit
9722a38982
@ -24,7 +24,7 @@ function getUsersPage(page: number, limit: number): Promise<[User[], number]> {
|
||||
|
||||
/**
|
||||
* @param client
|
||||
* @returns user map indiced with email
|
||||
* @returns user map indices with email
|
||||
*/
|
||||
async function loadUsersFromHumHub(client: HumHubClient): Promise<Map<string, GetUser>> {
|
||||
const start = new Date().getTime()
|
||||
|
||||
50
backend/src/apis/humhub/__mocks__/HumHubClient.ts
Normal file
50
backend/src/apis/humhub/__mocks__/HumHubClient.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { User } from '@entity/User'
|
||||
import { UserContact } from '@entity/UserContact'
|
||||
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { PostUser } from '@/apis/humhub/model/PostUser'
|
||||
import { UsersResponse } from '@/apis/humhub/model/UsersResponse'
|
||||
|
||||
/**
|
||||
* HumHubClient as singleton class
|
||||
*/
|
||||
export class HumHubClient {
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
private static instance: HumHubClient
|
||||
|
||||
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
||||
private constructor() {}
|
||||
|
||||
public static getInstance(): HumHubClient {
|
||||
if (!HumHubClient.instance) {
|
||||
HumHubClient.instance = new HumHubClient()
|
||||
}
|
||||
return HumHubClient.instance
|
||||
}
|
||||
|
||||
public async users(): Promise<UsersResponse | null> {
|
||||
return Promise.resolve(new UsersResponse())
|
||||
}
|
||||
|
||||
public async userByEmail(email: string): Promise<GetUser | null> {
|
||||
const user = new User()
|
||||
user.emailContact = new UserContact()
|
||||
user.emailContact.email = email
|
||||
return Promise.resolve(new GetUser(user, 1))
|
||||
}
|
||||
|
||||
public async createUser(): Promise<void> {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
public async updateUser(inputUser: PostUser, humhubUserId: number): Promise<GetUser | null> {
|
||||
const user = new User()
|
||||
user.emailContact = new UserContact()
|
||||
user.emailContact.email = inputUser.account.email
|
||||
return Promise.resolve(new GetUser(user, humhubUserId))
|
||||
}
|
||||
|
||||
public async deleteUser(): Promise<void> {
|
||||
return Promise.resolve()
|
||||
}
|
||||
}
|
||||
44
backend/src/apis/humhub/__mocks__/syncUser.ts
Normal file
44
backend/src/apis/humhub/__mocks__/syncUser.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { isHumhubUserIdenticalToDbUser } from '@/apis/humhub/compareHumhubUserDbUser'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
|
||||
export enum ExecutedHumhubAction {
|
||||
UPDATE,
|
||||
CREATE,
|
||||
SKIP,
|
||||
DELETE,
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* @param user
|
||||
* @param humHubClient
|
||||
* @param humhubUsers
|
||||
* @returns
|
||||
*/
|
||||
export async function syncUser(
|
||||
user: User,
|
||||
humhubUsers: Map<string, GetUser>,
|
||||
): Promise<ExecutedHumhubAction> {
|
||||
const humhubUser = humhubUsers.get(user.emailContact.email.trim())
|
||||
if (humhubUser) {
|
||||
if (!user.humhubAllowed) {
|
||||
return Promise.resolve(ExecutedHumhubAction.DELETE)
|
||||
}
|
||||
if (!isHumhubUserIdenticalToDbUser(humhubUser, user)) {
|
||||
// if humhub allowed
|
||||
return Promise.resolve(ExecutedHumhubAction.UPDATE)
|
||||
}
|
||||
} else {
|
||||
if (user.humhubAllowed) {
|
||||
return Promise.resolve(ExecutedHumhubAction.CREATE)
|
||||
}
|
||||
}
|
||||
return Promise.resolve(ExecutedHumhubAction.SKIP)
|
||||
}
|
||||
@ -2,47 +2,16 @@
|
||||
import { User } from '@entity/User'
|
||||
import { UserContact } from '@entity/UserContact'
|
||||
|
||||
import { CONFIG } from '@/config'
|
||||
|
||||
import { HumHubClient } from './HumHubClient'
|
||||
import { GetUser } from './model/GetUser'
|
||||
import { syncUser, ExecutedHumhubAction } from './syncUser'
|
||||
|
||||
jest.mock('@/apis/humhub/HumHubClient')
|
||||
|
||||
const defaultUser = new User()
|
||||
defaultUser.emailContact = new UserContact()
|
||||
defaultUser.emailContact.email = 'email@gmail.com'
|
||||
|
||||
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', () => {
|
||||
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()
|
||||
})
|
||||
|
||||
@ -79,6 +79,7 @@ import { getKlicktippState } from './util/getKlicktippState'
|
||||
import { Location2Point } from './util/Location2Point'
|
||||
import { setUserRole, deleteUserRole } from './util/modifyUserRole'
|
||||
import { sendUserToGms } from './util/sendUserToGms'
|
||||
import { syncHumhub } from './util/syncHumhub'
|
||||
import { validateAlias } from './util/validateAlias'
|
||||
|
||||
const LANGUAGES = ['de', 'en', 'es', 'fr', 'nl']
|
||||
@ -670,6 +671,9 @@ export class UserResolver {
|
||||
logger.debug(`gms-user update successfully.`)
|
||||
}
|
||||
}
|
||||
if (CONFIG.HUMHUB_ACTIVE) {
|
||||
await syncHumhub(updateUserInfosArgs, user)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
63
backend/src/graphql/resolver/util/syncHumhub.test.ts
Normal file
63
backend/src/graphql/resolver/util/syncHumhub.test.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import { User } from '@entity/User'
|
||||
import { UserContact } from '@entity/UserContact'
|
||||
|
||||
import { HumHubClient } from '@/apis/humhub/HumHubClient'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { ExecutedHumhubAction } from '@/apis/humhub/syncUser'
|
||||
import { UpdateUserInfosArgs } from '@/graphql/arg/UpdateUserInfosArgs'
|
||||
import { PublishNameType } from '@/graphql/enum/PublishNameType'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
import { syncHumhub } from './syncHumhub'
|
||||
|
||||
jest.mock('@/apis/humhub/HumHubClient')
|
||||
jest.mock('@/apis/humhub/syncUser')
|
||||
|
||||
const mockUser = new User()
|
||||
mockUser.humhubAllowed = true
|
||||
mockUser.emailContact = new UserContact()
|
||||
mockUser.emailContact.email = 'email@gmail.com'
|
||||
mockUser.humhubPublishName = PublishNameType.PUBLISH_NAME_FULL
|
||||
const mockUpdateUserInfosArg = new UpdateUserInfosArgs()
|
||||
const mockHumHubUser = new GetUser(mockUser, 1)
|
||||
|
||||
describe('syncHumhub', () => {
|
||||
beforeAll(() => {
|
||||
// humhubClientMockbBeforeAll()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
jest.spyOn(logger, 'debug').mockImplementation()
|
||||
jest.spyOn(logger, 'info').mockImplementation()
|
||||
jest.spyOn(HumHubClient, 'getInstance')
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
// humhubClientMockbAfterEach()
|
||||
})
|
||||
afterAll(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
||||
it('Should not sync if no relevant changes', async () => {
|
||||
await syncHumhub(mockUpdateUserInfosArg, new User())
|
||||
expect(HumHubClient.getInstance).not.toBeCalled()
|
||||
// language logging from some other place
|
||||
expect(logger.debug).toBeCalledTimes(4)
|
||||
expect(logger.info).toBeCalledTimes(0)
|
||||
})
|
||||
|
||||
it('Should retrieve user from humhub and sync if relevant changes', async () => {
|
||||
mockUpdateUserInfosArg.firstName = 'New' // Relevant changes
|
||||
mockUser.firstName = 'New'
|
||||
await syncHumhub(mockUpdateUserInfosArg, mockUser)
|
||||
expect(logger.debug).toHaveBeenCalledTimes(7) // Four language logging calls, two debug calls in function, one for not syncing
|
||||
expect(logger.info).toHaveBeenLastCalledWith('finished sync user with humhub', {
|
||||
localId: mockUser.id,
|
||||
externId: mockHumHubUser.id,
|
||||
result: ExecutedHumhubAction.UPDATE,
|
||||
})
|
||||
})
|
||||
|
||||
// Add more test cases as needed...
|
||||
})
|
||||
42
backend/src/graphql/resolver/util/syncHumhub.ts
Normal file
42
backend/src/graphql/resolver/util/syncHumhub.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { HumHubClient } from '@/apis/humhub/HumHubClient'
|
||||
import { GetUser } from '@/apis/humhub/model/GetUser'
|
||||
import { syncUser } from '@/apis/humhub/syncUser'
|
||||
import { UpdateUserInfosArgs } from '@/graphql/arg/UpdateUserInfosArgs'
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
|
||||
export async function syncHumhub(
|
||||
updateUserInfosArg: UpdateUserInfosArgs,
|
||||
user: User,
|
||||
): Promise<void> {
|
||||
// check for humhub relevant changes
|
||||
if (
|
||||
!updateUserInfosArg.alias &&
|
||||
!updateUserInfosArg.firstName &&
|
||||
!updateUserInfosArg.lastName &&
|
||||
!updateUserInfosArg.humhubAllowed &&
|
||||
!updateUserInfosArg.humhubPublishName &&
|
||||
!updateUserInfosArg.language
|
||||
) {
|
||||
return
|
||||
}
|
||||
logger.debug('changed user-settings relevant for humhub-user update...')
|
||||
const humhubClient = HumHubClient.getInstance()
|
||||
if (!humhubClient) {
|
||||
return
|
||||
}
|
||||
logger.debug('retrieve user from humhub')
|
||||
const humhubUser = await humhubClient.userByEmail(user.emailContact.email)
|
||||
const humhubUsers = new Map<string, GetUser>()
|
||||
if (humhubUser) {
|
||||
humhubUsers.set(user.emailContact.email, humhubUser)
|
||||
}
|
||||
logger.debug('update user at humhub')
|
||||
const result = await syncUser(user, humhubUsers)
|
||||
logger.info('finished sync user with humhub', {
|
||||
localId: user.id,
|
||||
externId: humhubUser?.id,
|
||||
result,
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user