diff --git a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts index f9b19d82c3bd9ca6b91cf8e723026f42de8d9d52..ee8961051481fb0a1f020559d4d2f5d80eefda82 100644 --- a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts +++ b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.spec.ts @@ -14,8 +14,9 @@ import { KeycloakResourceService } from './keycloak.resource.service'; describe('KeycloakResourceService', () => { let service: KeycloakResourceService<unknown>; - const dummyObject = createDummy(); const id = faker.random.word(); + const emptyStateResource = createEmptyStateResource<unknown[]>(); + const dummyObject = createDummy(); const dummyAction = of(dummyObject); beforeEach(() => { @@ -42,24 +43,12 @@ describe('KeycloakResourceService', () => { }); describe('handleChanges', () => { - beforeEach(() => { - service.loadResource = jest.fn(); - }); - - it('should call loadResource when loading is required', () => { - jest.spyOn(resourceUtil, 'isLoadingRequired').mockReturnValue(true); - - service.handleChanges(createEmptyStateResource()); - - expect(service.loadResource).toHaveBeenCalled(); - }); + it('should call doIfLoadingRequired', () => { + const doIfLoadingRequired = jest.spyOn(resourceUtil, 'doIfLoadingRequired'); - it('should not call loadResource when loading is required', () => { - jest.spyOn(resourceUtil, 'isLoadingRequired').mockReturnValue(false); + service.handleChanges(emptyStateResource); - service.handleChanges(createEmptyStateResource()); - - expect(service.loadResource).not.toHaveBeenCalled(); + expect(doIfLoadingRequired).toHaveBeenCalled(); }); }); @@ -163,16 +152,15 @@ describe('KeycloakResourceService', () => { }); }); - // warum funktioniert hier fakeAsync nicht? describe('refreshAfterFirstEmit', () => { - it('should call refresh after first emit', (done) => { + it('should call refresh after first emit', fakeAsync(() => { service.refresh = jest.fn(); - service.refreshAfterFirstEmit(dummyAction).subscribe(() => { - expect(service.refresh).toHaveBeenCalled(); - done(); - }); - }); + service.refreshAfterFirstEmit(dummyAction).subscribe(); + tick(); + + expect(service.refresh).toHaveBeenCalled(); + })); }); describe('progress', () => { @@ -225,7 +213,7 @@ describe('KeycloakResourceService', () => { class TestResourceService extends KeycloakResourceService<unknown> { getItemsFromKeycloak(): Observable<unknown[]> { - return of([null]); + return of(null); } saveInKeycloak(): Observable<void> { diff --git a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts index 7ed82d400b566d68ba97b19d902bd446b1d9e12d..914d547f4a1e962860d65437709c35bf6787c7cc 100644 --- a/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts +++ b/alfa-client/libs/admin/settings/src/lib/user/keycloak.resource.service.ts @@ -1,12 +1,11 @@ import { createEmptyStateResource, createStateResource, - isLoadingRequired, + doIfLoadingRequired, StateResource, } from '@alfa-client/tech-shared'; import { BehaviorSubject, first, map, Observable, startWith, tap } from 'rxjs'; -// KeycloakListResourceService? export abstract class KeycloakResourceService<T> { readonly stateResource: BehaviorSubject<StateResource<T[]>> = new BehaviorSubject( createEmptyStateResource(), @@ -19,9 +18,7 @@ export abstract class KeycloakResourceService<T> { } handleChanges(stateResource: StateResource<T[]>) { - if (isLoadingRequired(stateResource)) { - this.loadResource(); - } + doIfLoadingRequired(stateResource, () => this.loadResource()); } loadResource(): void { @@ -33,7 +30,7 @@ export abstract class KeycloakResourceService<T> { abstract getItemsFromKeycloak(): Observable<T[]>; - private updateResource(items: T[]) { + private updateResource(items: T[]): void { this.stateResource.next(createStateResource(items)); } diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.model.ts b/alfa-client/libs/admin/settings/src/lib/user/user.model.ts index ec046fa088c5099386abc746eecc857a8360008a..308e945aa9b0f900ccfc135eeb98f713efc7e5e7 100644 --- a/alfa-client/libs/admin/settings/src/lib/user/user.model.ts +++ b/alfa-client/libs/admin/settings/src/lib/user/user.model.ts @@ -1,10 +1,3 @@ -import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; -import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; - -export type User = UserRepresentation & { - groupReps: GroupRepresentation[]; -}; - export interface Organisationseinheit { id: string; name: string; diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts b/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts index bca73c460b000f7480db5bba114929d034c7d67b..0c14ace06e992c49e1b96c5a6b92fc5d79437eea 100644 --- a/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts +++ b/alfa-client/libs/admin/settings/src/lib/user/user.repository.service.ts @@ -2,6 +2,7 @@ import { Injectable } from '@angular/core'; import KcAdminClient, { NetworkError } from '@keycloak/keycloak-admin-client'; import { TokenProvider } from '@keycloak/keycloak-admin-client/lib/client'; import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; +import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation'; import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { OAuthService } from 'angular-oauth2-oidc'; import { @@ -14,7 +15,7 @@ import { mergeMap, throwError, } from 'rxjs'; -import { Organisationseinheit, OrganisationseinheitError, User } from './user.model'; +import { Organisationseinheit, OrganisationseinheitError } from './user.model'; import { KEYCLOAK_CREATE_GROUPS_ERROR_STATUS } from './user.util'; @Injectable({ @@ -103,18 +104,43 @@ export class UserRepository { }; } - public getUsers(): Observable<User[]> { + public getUsers(): Observable<UserRepresentation[]> { return from(this.kcAdminClient.users.find()).pipe( - mergeMap((users) => forkJoin(users.map((users) => this.addGroupsToUser(users)))), + mergeMap((users) => forkJoin(users.map((users) => this.addInformationToUser(users)))), ); } - private addGroupsToUser(user: UserRepresentation) { - return from(this.kcAdminClient.users.listGroups({ id: user.id })).pipe( - map((groups) => ({ + private addInformationToUser(user: UserRepresentation) { + return forkJoin({ + groups: this.getUserGroups(user), + roles: this.getAlfaClientRoles(user), + }).pipe( + map(({ groups, roles }) => ({ ...user, - groupReps: groups, + groups, + roles, })), ); } + + private getUserGroups(user: UserRepresentation): Observable<string[]> { + return from(this.kcAdminClient.users.listGroups({ id: user.id })).pipe( + map((groups: GroupRepresentation[]) => groups.map((group) => group.name)), + ); + } + + private getAlfaClientRoles(user: UserRepresentation): Observable<string[]> { + return from(this.kcAdminClient.users.listRoleMappings({ id: user.id })).pipe( + map((clientMappings) => this.mapToAlfaClientRoleNames(clientMappings)), + ); + } + + private mapToAlfaClientRoleNames(roleMappings: MappingsRepresentation): string[] { + const clientMappings = + roleMappings.clientMappings ? roleMappings.clientMappings['alfa'] : undefined; + if (clientMappings && clientMappings.mappings) { + return clientMappings.mappings.map((role: any) => role.name); + } + return []; + } } diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts index a56add9681e158fd1a48f96647b3fbeacbfa1376..23d0951d8bcc60689206e83320a407e93e118ea7 100644 --- a/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts +++ b/alfa-client/libs/admin/settings/src/lib/user/user.repository.spec.ts @@ -192,10 +192,10 @@ describe('UserRepository', () => { mockGroupsFunc('create', createMock); await firstValueFrom( - repository.createOrganisationseinheit( - newOrganisationseinheit.name, - newOrganisationseinheit.organisationseinheitIds, - ), + repository.createOrganisationseinheit({ + name: newOrganisationseinheit.name, + organisationseinheitIds: newOrganisationseinheit.organisationseinheitIds, + }), ); expect(createMock).toHaveBeenCalledWith({ @@ -213,10 +213,10 @@ describe('UserRepository', () => { mockGroupsFunc('create', createMock); const newGroupResult: Organisationseinheit = await firstValueFrom( - repository.createOrganisationseinheit( - newOrganisationseinheit.name, - newOrganisationseinheit.organisationseinheitIds, - ), + repository.createOrganisationseinheit({ + name: newOrganisationseinheit.name, + organisationseinheitIds: newOrganisationseinheit.organisationseinheitIds, + }), ); expect(newGroupResult).toEqual(newOrganisationseinheit); @@ -230,10 +230,10 @@ describe('UserRepository', () => { .mockReturnValue(catchError(() => throwError(() => error))); repository - .createOrganisationseinheit( - newOrganisationseinheit.name, - newOrganisationseinheit.organisationseinheitIds, - ) + .createOrganisationseinheit({ + name: newOrganisationseinheit.name, + organisationseinheitIds: newOrganisationseinheit.organisationseinheitIds, + }) .subscribe({ error: (err) => { expect(err).toBe(error); diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.service.spec.ts b/alfa-client/libs/admin/settings/src/lib/user/user.service.spec.ts deleted file mode 100644 index 23b4daf728e04840d285ac8a4a9f4415c5815f0d..0000000000000000000000000000000000000000 --- a/alfa-client/libs/admin/settings/src/lib/user/user.service.spec.ts +++ /dev/null @@ -1,342 +0,0 @@ -import { mock, Mock, useFromMock } from '@alfa-client/test-utils'; -import { fakeAsync, tick } from '@angular/core/testing'; -import { cold } from 'jest-marbles'; -import { singleCold } from 'libs/tech-shared/test/marbles'; -import { firstValueFrom, lastValueFrom, Observable, of } from 'rxjs'; -import { - createOrganisationseinheit, - createOrganisationseinheitState, -} from '../../../test/user/user'; -import { Organisationseinheit } from './user.model'; -import { UserRepository } from './user.repository.service'; -import { UserService } from './user.service'; - -describe('UserService', () => { - let service: UserService; - let repository: Mock<UserRepository>; - const sortedNames: string[] = ['BBBB', 'CCCC', 'XXXX']; - const sortedOrganisationseinheitItems: Organisationseinheit[] = sortedNames.map((name) => ({ - ...createOrganisationseinheit(), - name, - })); - const unsortedOrganisationseinheitItems: Organisationseinheit[] = [ - sortedOrganisationseinheitItems[2], - sortedOrganisationseinheitItems[0], - sortedOrganisationseinheitItems[1], - ]; - let setOrganisationseinheitItemsSpy: jest.SpyInstance; - let setLoadingUntilFirstSpy: jest.SpyInstance; - - beforeEach(() => { - repository = mock(UserRepository); - service = new UserService(useFromMock(repository)); - setOrganisationseinheitItemsSpy = jest.spyOn(service, 'setOrganisationseinheit'); - setLoadingUntilFirstSpy = jest.spyOn(service, 'setLoadingUntilFirst'); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('initial state', () => { - it('should have empty group list', () => { - expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual([]); - }); - it('should not be loading', () => { - expect(service.organisationseinheitState$.value.loading).toEqual(false); - }); - it('should be requiring a reload', () => { - expect(service.organisationseinheitState$.value.updateRequired).toEqual(true); - }); - }); - - describe('get group state', () => { - it('should update if required', async () => { - service.updateIfRequired = jest.fn(); - - await firstValueFrom(service.getOrganisationseinheitState()); - - expect(service.updateIfRequired).toHaveBeenCalled(); - }); - - it('should call find groups', fakeAsync(() => { - repository.findOrganisationseinheitItems.mockReturnValue( - of(unsortedOrganisationseinheitItems), - ); - - service.getOrganisationseinheitState().subscribe(); - tick(); - - expect(repository.findOrganisationseinheitItems).toHaveBeenCalled(); - })); - }); - - describe('update if required', () => { - beforeEach(() => { - service.updateOrganisationseinheitItems = jest.fn(() => of([])); - }); - - it('should call update groups with initial values', () => { - service.updateIfRequired(); - - expect(service.updateOrganisationseinheitItems).toHaveBeenCalled(); - }); - - it('should not call update groups if loading', () => { - service.setLoading(); - - service.updateIfRequired(); - - expect(service.updateOrganisationseinheitItems).not.toHaveBeenCalled(); - }); - - it('should not call update groups if not requiring update', () => { - service.setUpdateRequired(false); - - service.updateIfRequired(); - - expect(service.updateOrganisationseinheitItems).not.toHaveBeenCalled(); - }); - }); - - describe('update groups', () => { - beforeEach(() => { - repository.findOrganisationseinheitItems.mockReturnValue( - of(unsortedOrganisationseinheitItems), - ); - }); - - it('should set loading', () => { - service.updateOrganisationseinheitItems(); - - expect(service.organisationseinheitState$.value.loading).toBeTruthy(); - }); - - it('should set sorted groups', async () => { - await lastValueFrom(service.updateOrganisationseinheitItems()); - - expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual( - sortedOrganisationseinheitItems, - ); - }); - - it('should not require update afterward', async () => { - await lastValueFrom(service.updateOrganisationseinheitItems()); - - expect(service.organisationseinheitState$.value.updateRequired).toBeFalsy(); - }); - }); - - describe('save organisationseinheit', () => { - const saveGroup: Organisationseinheit = { - ...createOrganisationseinheit(), - id: sortedOrganisationseinheitItems[0].id, - }; - - beforeEach(() => { - repository.saveOrganisationseinheit.mockReturnValue(of(null)); - }); - - it('should use set loading until first', fakeAsync(() => { - service.saveOrganisationseinheit(saveGroup).subscribe(); - tick(); - - expect(setLoadingUntilFirstSpy).toHaveBeenCalled(); - })); - - it('should call repository for save', fakeAsync(() => { - service.saveOrganisationseinheit(saveGroup).subscribe(); - tick(); - - expect(repository.saveOrganisationseinheit).toHaveBeenCalledWith(saveGroup); - })); - - it('should set organisationseinheit items with updated organisationseinheit', fakeAsync(() => { - service.setOrganisationseinheit(sortedOrganisationseinheitItems); - setOrganisationseinheitItemsSpy.mockClear(); - - service.saveOrganisationseinheit(saveGroup).subscribe(); - tick(); - - expect(setOrganisationseinheitItemsSpy).toHaveBeenCalledWith([ - saveGroup, - ...sortedOrganisationseinheitItems.slice(1), - ]); - })); - }); - - describe('create organisationseinheit', () => { - const organisationseinheit: Organisationseinheit = createOrganisationseinheit(); - - beforeEach(() => { - repository.createOrganisationseinheit.mockReturnValue(of(organisationseinheit)); - }); - - it('should use set loading until first', () => { - service.createOrganisationseinheit( - organisationseinheit.name, - organisationseinheit.organisationseinheitIds, - ); - - expect(setLoadingUntilFirstSpy).toHaveBeenCalled(); - }); - - it('should call repository for save', () => { - service.createOrganisationseinheit( - organisationseinheit.name, - organisationseinheit.organisationseinheitIds, - ); - - expect(repository.createOrganisationseinheit).toHaveBeenCalledWith( - organisationseinheit.name, - organisationseinheit.organisationseinheitIds, - ); - }); - - it('should set organisationseinheit items with new group', fakeAsync(() => { - service.setOrganisationseinheit(sortedOrganisationseinheitItems); - setOrganisationseinheitItemsSpy.mockClear(); - - service - .createOrganisationseinheit( - organisationseinheit.name, - organisationseinheit.organisationseinheitIds, - ) - .subscribe(); - tick(); - - expect(setOrganisationseinheitItemsSpy).toHaveBeenCalledWith([ - ...sortedOrganisationseinheitItems, - organisationseinheit, - ]); - })); - }); - - describe('set organisationseinheit items', () => { - it('should sort groups by name', async () => { - service.setOrganisationseinheit(unsortedOrganisationseinheitItems); - - expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual( - sortedOrganisationseinheitItems, - ); - }); - }); - - describe('delete group', () => { - const deleteGroup: Organisationseinheit = unsortedOrganisationseinheitItems[1]; - - beforeEach(async () => { - repository.deleteOrganisationseinheit.mockReturnValue(of(null)); - service.organisationseinheitState$.next({ - ...service.organisationseinheitState$.value, - organisationseinheitItems: sortedOrganisationseinheitItems, - }); - }); - - it('should use set loading until first', () => { - const setLoadingUntilFirstSpy: jest.SpyInstance = jest.spyOn(service, 'setLoadingUntilFirst'); - service.deleteOrganisationseinheit(deleteGroup.id); - - expect(setLoadingUntilFirstSpy).toHaveBeenCalled(); - }); - - it('should call repository', () => { - service.deleteOrganisationseinheit(deleteGroup.id); - - expect(repository.deleteOrganisationseinheit).toHaveBeenCalledWith(deleteGroup.id); - }); - - describe('which exists', () => { - it('should not have group in list after delete', fakeAsync(() => { - service.deleteOrganisationseinheit(deleteGroup.id).subscribe(); - tick(); - - expect(service.organisationseinheitState$.value.organisationseinheitItems).not.toContain( - deleteGroup, - ); - })); - }); - - describe('which does not exist', () => { - it('should have no effect', fakeAsync(() => { - service.deleteOrganisationseinheit('unknown-id').subscribe(); - tick(); - - expect(service.organisationseinheitState$.value.organisationseinheitItems).toEqual( - sortedOrganisationseinheitItems, - ); - })); - }); - }); - - describe('set loading until first', () => { - it('should set loading', () => { - service.setLoadingUntilFirst(of(null), () => {}); - - expect(service.organisationseinheitState$.value.loading).toBe(true); - }); - - it('should unset loading', fakeAsync(() => { - service.setLoadingUntilFirst(of(null), () => {}).subscribe(); - tick(); - - expect(service.organisationseinheitState$.value.loading).toBe(false); - })); - - it('should emit loading before first and emit loading after first', () => { - const delayedNull = cold('-a|', { a: null }); - - const progressObservable = service.setLoadingUntilFirst(delayedNull, () => {}); - - expect(progressObservable).toBeObservable(cold('a(b|)', { a: true, b: false })); - }); - - it('should call tap function', fakeAsync(() => { - const tapFunction: jest.Mock = jest.fn(); - const value: string = 'abc'; - const delayedNull: Observable<string> = of(value); - - service.setLoadingUntilFirst(delayedNull, tapFunction).subscribe(); - tick(); - - expect(tapFunction).toHaveBeenCalledWith(value); - })); - }); - - describe('get organisationseinheit items', () => { - it('should return items of state', () => { - const organisationseinheitItems: Organisationseinheit[] = [ - createOrganisationseinheit(), - createOrganisationseinheit(), - ]; - service.getOrganisationseinheitState = jest - .fn() - .mockReturnValue(singleCold(createOrganisationseinheitState(organisationseinheitItems))); - - const itemsObservable: Observable<Organisationseinheit[]> = - service.getOrganisationseinheitItems(); - expect(itemsObservable).toBeObservable(singleCold(organisationseinheitItems)); - }); - }); - - describe('getUsers', () => { - const users = [{ id: 'userId' }]; - - beforeEach(() => { - repository.getUsers.mockReturnValue(of(users)); - }); - - it('should call repository getUsers', () => { - service.getUsers(); - - expect(repository.getUsers).toHaveBeenCalled(); - }); - - it('should set userState on subscription subscribed', fakeAsync(() => { - service.getUsers().subscribe(); - tick(); - - expect(service.usersState$.value).toEqual(users); - })); - }); -}); diff --git a/alfa-client/libs/admin/settings/src/lib/user/user.service.ts b/alfa-client/libs/admin/settings/src/lib/user/user.service.ts deleted file mode 100644 index 4dd8938c040e2f5dcc53b1f3cf8cc41e609dd61f..0000000000000000000000000000000000000000 --- a/alfa-client/libs/admin/settings/src/lib/user/user.service.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject, first, map, Observable, startWith, tap } from 'rxjs'; -import { Organisationseinheit, OrganisationseinheitState, User } from './user.model'; -import { UserRepository } from './user.repository.service'; - -@Injectable({ - providedIn: 'root', -}) -export class UserService { - readonly organisationseinheitState$: BehaviorSubject<OrganisationseinheitState> = - new BehaviorSubject({ - organisationseinheitItems: [], - loading: false, - updateRequired: true, - }); - - readonly usersState$: BehaviorSubject<any> = new BehaviorSubject({}); - - constructor(private userRepository: UserRepository) {} - - public saveOrganisationseinheit(organisationseinheit: Organisationseinheit): Observable<boolean> { - return this.setLoadingUntilFirst( - this.userRepository.saveOrganisationseinheit(organisationseinheit), - () => { - this.updateExistingOrganisationseinheit(organisationseinheit); - }, - ); - } - - private updateExistingOrganisationseinheit(organisationseinheit: Organisationseinheit): void { - this.setOrganisationseinheit([ - organisationseinheit, - ...this.organisationseinheitState$.value.organisationseinheitItems.filter( - (otherOrganisationseinheit: Organisationseinheit) => - otherOrganisationseinheit.id !== organisationseinheit.id, - ), - ]); - } - - public createOrganisationseinheit( - name: string, - organisationseinheitIds: string[], - ): Observable<boolean> { - return this.setLoadingUntilFirst( - this.userRepository.createOrganisationseinheit({ name, organisationseinheitIds }), - (organisationseinheit: Organisationseinheit) => { - this.addOrganisationseinheit(organisationseinheit); - }, - ); - } - - public deleteOrganisationseinheit(id: string): Observable<boolean> { - return this.setLoadingUntilFirst(this.userRepository.deleteOrganisationseinheit(id), () => - this.removeOrganisationseinheit(id), - ); - } - - private removeOrganisationseinheit(id: string): void { - this.setOrganisationseinheit( - this.organisationseinheitState$.value.organisationseinheitItems.filter( - (organisationseinheit: Organisationseinheit) => organisationseinheit.id !== id, - ), - ); - } - - setLoadingUntilFirst<T>( - action: Observable<T>, - tapFunction: (value: T) => void, - ): Observable<boolean> { - this.setLoading(); - - return action.pipe( - first(), - tap(tapFunction), - tap(() => this.setLoading(false)), - map(() => this.organisationseinheitState$.value.loading), - startWith(this.organisationseinheitState$.value.loading), - ); - } - - private addOrganisationseinheit(organisationseinheit: Organisationseinheit): void { - this.setOrganisationseinheit([ - ...this.organisationseinheitState$.value.organisationseinheitItems, - organisationseinheit, - ]); - } - - setOrganisationseinheit(organisationseinheitItems: Organisationseinheit[]): void { - this.organisationseinheitState$.next({ - ...this.organisationseinheitState$.value, - organisationseinheitItems: this.sortedOrganisationseinheitItems(organisationseinheitItems), - }); - } - - private sortedOrganisationseinheitItems( - organisationseinheitItems: Organisationseinheit[], - ): Organisationseinheit[] { - return [...organisationseinheitItems].sort((a, b) => a.name.localeCompare(b.name)); - } - - public getOrganisationseinheitState(): Observable<OrganisationseinheitState> { - return this.organisationseinheitState$.pipe(tap(() => this.updateIfRequired())); - } - - updateIfRequired(): void { - if (this.isUpdateRequired(this.organisationseinheitState$.value)) { - this.updateOrganisationseinheitItems().pipe(first()).subscribe(); - } - } - - private isUpdateRequired(state: OrganisationseinheitState): boolean { - return state.updateRequired && !state.loading; - } - - updateOrganisationseinheitItems(): Observable<Organisationseinheit[]> { - this.setLoading(); - - return this.userRepository.findOrganisationseinheitItems().pipe( - tap(() => this.setUpdateRequired(false)), - tap((organisationseinheitItems: Organisationseinheit[]) => - this.setOrganisationseinheit(organisationseinheitItems), - ), - ); - } - - setUpdateRequired(updateRequired: boolean = true) { - this.organisationseinheitState$.next({ - ...this.organisationseinheitState$.value, - updateRequired, - }); - } - - setLoading(loading: boolean = true): void { - this.organisationseinheitState$.next({ - ...this.organisationseinheitState$.value, - loading, - }); - } - - public getOrganisationseinheitItems(): Observable<Organisationseinheit[]> { - return this.getOrganisationseinheitState().pipe( - map((state: OrganisationseinheitState) => state.organisationseinheitItems), - ); - } - - public getUsers() { - return this.userRepository.getUsers().pipe(tap((users) => this.saveUsers(users))); - } - - private saveUsers(users: User[]) { - this.usersState$.next(users); - } -} diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts index 33cea0dc83abbd108ebc19e6d19c41772c99de14..2cf249cd158242f28cd719ec6c26db9b984d74dc 100644 --- a/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts +++ b/alfa-client/libs/admin/settings/src/lib/users-roles/userAndRolesService.ts @@ -1,26 +1,26 @@ import { Injectable } from '@angular/core'; +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { Observable } from 'rxjs'; import { KeycloakResourceService } from '../user/keycloak.resource.service'; -import { User } from '../user/user.model'; import { UserRepository } from '../user/user.repository.service'; @Injectable({ providedIn: 'root', }) -export class UserAndRolesService extends KeycloakResourceService<User> { +export class UserAndRolesService extends KeycloakResourceService<UserRepresentation> { constructor(private userRepository: UserRepository) { super(); } - getItemsFromKeycloak(): Observable<User[]> { + getItemsFromKeycloak(): Observable<UserRepresentation[]> { return this.userRepository.getUsers(); } - createInKeycloak(item: Partial<User>): Observable<User> { + createInKeycloak(item: Partial<UserRepresentation>): Observable<UserRepresentation> { throw new Error('Method not implemented.'); } - saveInKeycloak(item: User): Observable<void> { + saveInKeycloak(item: UserRepresentation): Observable<void> { throw new Error('Method not implemented.'); } diff --git a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts index f7adf7487c55c682370c0146fc52ff3daeb65be6..76c08323aa090b333d240aa51ef22786daf121ae 100644 --- a/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts +++ b/alfa-client/libs/admin/settings/src/lib/users-roles/users-roles.component.ts @@ -1,7 +1,7 @@ -import { Component } from '@angular/core'; import { StateResource } from '@alfa-client/tech-shared'; +import { Component } from '@angular/core'; +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { Observable } from 'rxjs'; -import { User } from '../user/user.model'; import { UserAndRolesService } from './userAndRolesService'; @Component({ @@ -10,7 +10,7 @@ import { UserAndRolesService } from './userAndRolesService'; styleUrl: './users-roles.component.scss', }) export class UsersRolesComponent { - users$: Observable<StateResource<User[]>>; + users$: Observable<StateResource<UserRepresentation[]>>; constructor(private userAndRolesService: UserAndRolesService) { this.users$ = this.userAndRolesService.get(); diff --git a/alfa-client/libs/admin/settings/test/user/user.ts b/alfa-client/libs/admin/settings/test/user/user.ts index 090c729b48a5a0bea9f37ea4ec790793bf49b1f5..3cb4f55fd1da44fb1ef3741bf2cb6958c159ffb4 100644 --- a/alfa-client/libs/admin/settings/test/user/user.ts +++ b/alfa-client/libs/admin/settings/test/user/user.ts @@ -5,7 +5,6 @@ import { Organisationseinheit, OrganisationseinheitError, OrganisationseinheitErrorType, - OrganisationseinheitState, } from '../../src/lib/user/user.model'; export function createOrganisationseinheit(): Organisationseinheit {