diff --git a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts index e2cbf35c6a1488905f98fa26df189a6fe1425ccd..6869eafd381b1d9df0dde4b213466d4c8db8b4db 100644 --- a/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts +++ b/alfa-client/apps/admin-e2e/src/e2e/main-tests/benutzer_rollen/benutzer-anlegen.cy.ts @@ -1,10 +1,11 @@ +import { faker } from '@faker-js/faker'; import { E2EBenutzerHelper } from 'apps/admin-e2e/src/helper/benutzer/benutzer.helper'; import { E2EBenutzerVerifier } from 'apps/admin-e2e/src/helper/benutzer/benutzer.verifier'; import { getCypressEnv, interceptWithResponse, waitOfInterceptor } from 'apps/admin-e2e/src/support/cypress-helper'; import { SnackBarE2EComponent } from '../../../components/ui/snackbar.e2e.component'; import { AdminUserE2E, HttpMethodE2E, SnackbarMessagesE2E } from '../../../model/util'; import { contains, notExist } from '../../../support/cypress.util'; -import { loginAsAriane } from '../../../support/user-util'; +import { loginAsAriane, loginByUsernameAndPassword } from '../../../support/user-util'; describe('Benutzer anlegen', () => { const benutzerHelper: E2EBenutzerHelper = new E2EBenutzerHelper(); @@ -12,7 +13,8 @@ describe('Benutzer anlegen', () => { const snackBar: SnackBarE2EComponent = new SnackBarE2EComponent(); - const newUser: AdminUserE2E = { + const newUserPassword: string = 'TestTestTest'; + const newAdminUser: AdminUserE2E = { vorname: 'Theo', nachname: 'Testuser', username: 'testtheo', @@ -22,6 +24,15 @@ describe('Benutzer anlegen', () => { organisationseinheiten: [], }; + const newRegularUser: AdminUserE2E = { + vorname: 'Max', + nachname: 'Mustermann', + username: 'maxmust', + email: 'max.mustermann@ozg-sh.de', + isUser: true, + organisationseinheiten: [], + }; + before(() => { loginAsAriane(); }); @@ -34,7 +45,7 @@ describe('Benutzer anlegen', () => { interceptWithResponse(HttpMethodE2E.POST, url, { errorCode, errorBody }).as(interceptor); benutzerHelper.openNewBenutzerPage(); - benutzerHelper.addBenutzer(newUser); + benutzerHelper.addBenutzer(newAdminUser); benutzerHelper.saveBenutzer(); waitOfInterceptor(interceptor).then(() => { @@ -47,7 +58,7 @@ describe('Benutzer anlegen', () => { it('should show snackbar after save', () => { benutzerHelper.openNewBenutzerPage(); - benutzerHelper.addBenutzer(newUser); + benutzerHelper.addBenutzer(newAdminUser); benutzerHelper.saveBenutzer(); contains(snackBar.getMessage(), SnackbarMessagesE2E.NUTZER_ANGELEGT); @@ -55,11 +66,60 @@ describe('Benutzer anlegen', () => { }); it('should show created user in list', () => { - benutzerVerifier.verifyUserInList(newUser); + benutzerVerifier.verifyUserInList(newAdminUser); }); it('should remove benutzer', () => { - benutzerHelper.deleteBenutzer(newUser.username); - benutzerVerifier.verifyUserNotInList(newUser.username); + benutzerHelper.deleteBenutzer(newAdminUser.username); + benutzerVerifier.verifyUserNotInList(newAdminUser.username); + }); + + describe('newly created admin user', () => { + it('should create new admin user', () => { + benutzerHelper.openNewBenutzerPage(); + + benutzerHelper.addBenutzer(newAdminUser); + benutzerHelper.saveBenutzer(); + + benutzerVerifier.verifyUserInList(newAdminUser); + }); + + it('should create new regular user', () => { + benutzerHelper.openNewBenutzerPage(); + + benutzerHelper.addBenutzer(newRegularUser); + benutzerHelper.saveBenutzer(); + + benutzerVerifier.verifyUserInList(newRegularUser); + }); + + it('should modify user', () => { + const userWithChangedFirstName = { ...newRegularUser, vorname: faker.person.firstName() }; + + benutzerHelper.activateUser(newAdminUser.username, newUserPassword).then(() => { + loginByUsernameAndPassword(newAdminUser.username, newUserPassword); + benutzerHelper.openBenutzerPage(newRegularUser.username); + + benutzerHelper.editBenutzer(userWithChangedFirstName); + benutzerHelper.saveBenutzer(); + + benutzerVerifier.verifyUserInList(userWithChangedFirstName); + }); + }); + + it('should have rights to delete user', () => { + loginByUsernameAndPassword(newAdminUser.username, newUserPassword); + benutzerHelper.openBenutzerListPage(); + + benutzerHelper.deleteBenutzer(newRegularUser.username); + + benutzerVerifier.verifyUserNotInList(newRegularUser.username); + }); + + it('should delete user', () => { + loginAsAriane(); + + benutzerHelper.deleteBenutzer(newAdminUser.username); + }); }); }); diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts index b9d17f8d68a5ba002c09da8d39fd3309d8e1bee4..ec1bbb05e560d3c45de062711da3da9ed8cf39c1 100644 --- a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.executor.ts @@ -1,3 +1,4 @@ +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { BenutzerDeleteDialogE2EComponent, BenutzerE2EComponent, @@ -7,6 +8,7 @@ import { SnackBarE2EComponent } from '../../components/ui/snackbar.e2e.component import { OrganisationsEinheitE2E } from '../../model/organisations-einheit'; import { AdminUserE2E } from '../../model/util'; import { exist, notExist } from '../../support/cypress.util'; +import Chainable = Cypress.Chainable; export class E2EBenutzerExecutor { private benutzerPage: BenutzerE2EComponent = new BenutzerE2EComponent(); @@ -54,4 +56,16 @@ export class E2EBenutzerExecutor { this.benutzerDeleteDialog.getDeleteButton().click(); exist(this.benutzerListPage.getList()); } + + public verifyEmail(userId: string): Chainable<Cypress.Response<void>> { + return cy.verifyEmail(userId); + } + + public resetPassword(userId: string, newPassword: string): Chainable<Cypress.Response<void>> { + return cy.resetPassword(userId, newPassword); + } + + public findUser(username: string): Chainable<UserRepresentation> { + return cy.findUser(username); + } } diff --git a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts index e7ec4228940b8ce3b78ca5543cec2587fa163819..0c0ad0c26492851788cb31352522ac0244f4217f 100644 --- a/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts +++ b/alfa-client/apps/admin-e2e/src/helper/benutzer/benutzer.helper.ts @@ -1,3 +1,4 @@ +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; import { OrganisationsEinheitE2E } from '../../model/organisations-einheit'; import { AdminUserE2E } from '../../model/util'; import { E2EBenutzerExecutor } from './benutzer.executor'; @@ -5,7 +6,7 @@ import { E2EBenutzerNavigator } from './benutzer.navigator'; export class E2EBenutzerHelper { private navigator: E2EBenutzerNavigator = new E2EBenutzerNavigator(); - private executer: E2EBenutzerExecutor = new E2EBenutzerExecutor(); + private executor: E2EBenutzerExecutor = new E2EBenutzerExecutor(); public openBenutzerListPage(): void { this.navigator.openBenutzerListPage(); @@ -34,32 +35,41 @@ export class E2EBenutzerHelper { } private modifyBenutzer(user: AdminUserE2E): void { - this.executer.modifyBenutzer(user); + this.executor.modifyBenutzer(user); } private createBenutzer(user: AdminUserE2E): void { - this.executer.createBenutzer(user); + this.executor.createBenutzer(user); } public editOrganisationsEinheitenAndSave(organisationsEinheiten: OrganisationsEinheitE2E[]): void { - this.executer.modifyOrganisationsEinheiten(organisationsEinheiten); + this.executor.modifyOrganisationsEinheiten(organisationsEinheiten); this.saveAndCloseSnackbar(); } private saveAndCloseSnackbar(): void { - this.executer.saveAndCloseSnackbar(); + this.executor.saveAndCloseSnackbar(); } public saveBenutzer(): void { - this.executer.saveBenutzer(); + this.executor.saveBenutzer(); } public deleteBenutzer(userName: string): void { this.openBenutzerPage(userName); - this.executer.deleteBenutzer(); + this.executor.deleteBenutzer(); } public openBenutzerPage(userName: string): void { this.navigator.openBenutzerPage(userName); } + + public activateUser(username: string, newPassword: string): Cypress.Chainable<UserRepresentation> { + return cy + .findUser(username) + .then((userRepresentation: UserRepresentation) => cy.verifyEmail(userRepresentation.id!).then(() => userRepresentation)) + .then((userRepresentation: UserRepresentation) => + cy.resetPassword(userRepresentation.id!, newPassword).then(() => userRepresentation), + ); + } } diff --git a/alfa-client/apps/admin-e2e/src/support/commands.ts b/alfa-client/apps/admin-e2e/src/support/commands.ts index 15e9839f02fc0b236bc23a554de9caa710947cf1..5442317e9972045e9b6be4644c4bbd5621377682 100644 --- a/alfa-client/apps/admin-e2e/src/support/commands.ts +++ b/alfa-client/apps/admin-e2e/src/support/commands.ts @@ -24,8 +24,12 @@ /// <reference types="cypress" /> +import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; +import { getCypressEnv } from './cypress-helper'; + enum HttpMethod { POST = 'POST', + PUT = 'PUT', GET = 'GET', } @@ -81,12 +85,57 @@ Cypress.Commands.add('getUserInfo', () => { return cy.request({ method: HttpMethod.GET, url: `${getKeycloakBaseRealmUrl()}/userinfo`, - headers: { - [Header.AUTHORIZATION]: `bearer ${window.sessionStorage.getItem(ACCES_TOKEN)}`, - }, + headers: { ...buildBearerTokenAuthorizationHeader() }, }); }); +Cypress.Commands.add('findUser', (username: string) => + cy + .request<UserRepresentation[]>({ + method: HttpMethod.GET, + url: getUsersApiUrl(), + headers: { ...buildBearerTokenAuthorizationHeader() }, + }) + .then<UserRepresentation>((response: Cypress.Response<UserRepresentation[]>) => { + const users: UserRepresentation[] = response.body; + const found: UserRepresentation | undefined = users.find((u: UserRepresentation) => u.username === username); + if (found) return found; + return Promise.reject(`User with username ${username} not found`); + }), +); + +Cypress.Commands.add('verifyEmail', (userId: string) => + cy.request<void>({ + method: HttpMethod.PUT, + url: getUsersApiUrl() + '/' + userId, + headers: { ...buildBearerTokenAuthorizationHeader() }, + body: { emailVerified: true }, + }), +); + +Cypress.Commands.add('resetPassword', (userId: string, newPassword: string) => + cy.request<void>({ + method: HttpMethod.PUT, + url: getUsersApiUrl() + '/' + userId + '/reset-password', + headers: { ...buildBearerTokenAuthorizationHeader() }, + body: { type: 'password', temporary: false, value: newPassword }, + }), +); + +function buildBearerTokenAuthorizationHeader(): object { + return { + [Header.AUTHORIZATION]: `Bearer ${getAccessToken()}`, + }; +} + +function getAccessToken(): string | null { + return window.sessionStorage.getItem(ACCES_TOKEN); +} + +function getUsersApiUrl(): string { + return getCypressEnv('keycloakUrl') + '/admin/realms/' + getCypressEnv('keycloakRealm') + '/users'; +} + function getKeycloakBaseRealmUrl(): string { return `${Cypress.env(CypressEnv.KEYCLOAK_URL)}realms/${Cypress.env(CypressEnv.KEYCLOAK_REALM)}/protocol/openid-connect`; } @@ -115,6 +164,12 @@ declare global { findElement(selector: string): Chainable<Element>; getUserInfo(): Chainable<void>; + + findUser(username: string): Chainable<UserRepresentation>; + + verifyEmail(userId: string): Chainable<Response<void>>; + + resetPassword(userId: string, password: string): Chainable<Response<void>>; } } } diff --git a/alfa-client/apps/admin-e2e/src/support/user-util.ts b/alfa-client/apps/admin-e2e/src/support/user-util.ts index 989e061babc526985e62ace05e516bdb2d058516..0b8f311d0e9cbb0e5f453ee3e7c1e72a80548529 100644 --- a/alfa-client/apps/admin-e2e/src/support/user-util.ts +++ b/alfa-client/apps/admin-e2e/src/support/user-util.ts @@ -50,15 +50,19 @@ function login(userJson: string): void { // Hinweis: cacheAcrossSpecs: true lässt Tests umfallen export function loginByUi(user: UserE2E): void { + loginByUsernameAndPassword(user.name, user.password); +} + +export function loginByUsernameAndPassword(username: string, password: string): void { cy.session( - user.name, + username, () => { cy.visit('/') .get('#kc-login') .should('exist') .then(() => { - cy.get('#username').type(user.name); - cy.get('#password').type(user.password); + cy.get('#username').type(username); + cy.get('#password').type(password); cy.get('#kc-login').click(); }); }, diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.model.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a2a5d7eabcfd524c1846a53c47f4d31d54f75a1 --- /dev/null +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/keycloak.model.ts @@ -0,0 +1,12 @@ +export const KeycloakDefaults = { + clients: { + realmManagement: { + clientName: 'realm-management', + roles: { + managerUsers: { roleName: 'manage-users' }, + queryGroups: { roleName: 'query-groups' }, + viewClients: { roleName: 'view-clients' }, + }, + }, + }, +}; diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts index afbb09bee049b4e79cda30ee0d97f3e4810799f9..c0ef6b387b57946efc4336573809b55582b7912e 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.spec.ts @@ -21,15 +21,17 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { RoleMappings, User } from '@admin-client/user-shared'; +import { AdminRoles, RoleMappings, User } from '@admin-client/user-shared'; import { UserRepository } from '@admin/keycloak-shared'; import { StateResource } from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; +import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { faker } from '@faker-js/faker'; +import { expect } from '@jest/globals'; import KcAdminClient from '@keycloak/keycloak-admin-client'; import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation'; +import { RequiredActionAlias } from '@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation'; import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation'; import { Users } from '@keycloak/keycloak-admin-client/lib/resources/users'; import { cold } from 'jest-marbles'; @@ -37,6 +39,7 @@ import { omit, times } from 'lodash-es'; import { throwError } from 'rxjs'; import { createUser } from '../../../user-shared/test/user'; import { UserFormService } from '../../../user/src/lib/user-form/user.formservice'; +import { KeycloakDefaults } from './keycloak.model'; describe('UserRepository', () => { let repository: UserRepository; @@ -530,6 +533,50 @@ describe('UserRepository', () => { }); }); + describe('update user roles for admin', () => { + const clientId: string = faker.string.uuid(); + + beforeEach(() => { + repository._updateUserRolesForClient = jest.fn(); + repository._getClientId = jest.fn().mockReturnValue(new Promise((resolve) => resolve(clientId))); + }); + + it('should get client id', async () => { + await repository._updateUserRolesForAdmin(user.id, { + admin: [AdminRoles.ADMIN], + alfa: [], + }); + + expect(repository._getClientId).toHaveBeenCalledWith(KeycloakDefaults.clients.realmManagement.clientName); + }); + + it('should update user roles', async () => { + await repository._updateUserRolesForAdmin(user.id, { + admin: [AdminRoles.ADMIN], + alfa: [], + }); + + expect(repository._updateUserRolesForClient).toHaveBeenCalledWith( + user.id, + [ + KeycloakDefaults.clients.realmManagement.roles.managerUsers.roleName, + KeycloakDefaults.clients.realmManagement.roles.queryGroups.roleName, + KeycloakDefaults.clients.realmManagement.roles.viewClients.roleName, + ], + clientId, + ); + }); + + it('should NOT update user roles for no ADMIN_ADMIN role', async () => { + await repository._updateUserRolesForAdmin(user.id, { + admin: [faker.word.noun()], + alfa: [], + }); + + expect(repository._updateUserRolesForClient).not.toHaveBeenCalled(); + }); + }); + describe('sendActivationMail', () => { it('should call kcAdminClient users executeActionsEmail', () => { const userId: string = faker.string.uuid(); @@ -538,7 +585,7 @@ describe('UserRepository', () => { expect(kcAdminClientUsers.executeActionsEmail).toHaveBeenCalledWith({ id: userId, - actions: ['VERIFY_EMAIL'], + actions: [RequiredActionAlias.VERIFY_EMAIL, RequiredActionAlias.UPDATE_PASSWORD], lifespan: 3600 * 24 * 7, }); }); diff --git a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts index e5eca5be54120f7fdf51b66d130053a330ced543..c510b595f5b6157f20093328d23fa31bcc11e242 100644 --- a/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts +++ b/alfa-client/libs/admin/keycloak-shared/src/lib/user.repository.ts @@ -21,19 +21,20 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { ClientMapping, ClientRoles, RoleMappings, User } from '@admin-client/user-shared'; +import { AdminRoles, ClientMapping, ClientRoles, RoleMappings, User } from '@admin-client/user-shared'; import { createStateResource, StateResource } from '@alfa-client/tech-shared'; import { inject, Injectable } from '@angular/core'; import KcAdminClient from '@keycloak/keycloak-admin-client'; import ClientRepresentation from '@keycloak/keycloak-admin-client/lib/defs/clientRepresentation'; import GroupRepresentation from '@keycloak/keycloak-admin-client/lib/defs/groupRepresentation'; import MappingsRepresentation from '@keycloak/keycloak-admin-client/lib/defs/mappingsRepresentation'; +import { RequiredActionAlias } from '@keycloak/keycloak-admin-client/lib/defs/requiredActionProviderRepresentation'; import { RoleMappingPayload } from '@keycloak/keycloak-admin-client/lib/defs/roleRepresentation'; import UserRepresentation from '@keycloak/keycloak-admin-client/lib/defs/userRepresentation'; +import * as _ from 'lodash-es'; import { isNil, omit } from 'lodash-es'; import { catchError, concatMap, forkJoin, from, map, mergeMap, Observable, tap, throwError } from 'rxjs'; - -import * as _ from 'lodash-es'; +import { KeycloakDefaults } from './keycloak.model'; @Injectable({ providedIn: 'root', @@ -104,6 +105,7 @@ export class UserRepository { async _updateUserRoles(userId: string, clientRoles: ClientRoles): Promise<void> { await this._updateUserRolesForClient(userId, clientRoles.admin, await this._getClientId(UserRepository.ADMIN_CLIENT_NAME)); await this._updateUserRolesForClient(userId, clientRoles.alfa, await this._getClientId(UserRepository.ALFA_CLIENT_NAME)); + await this._updateUserRolesForAdmin(userId, clientRoles); } async _updateUserRolesForClient(userId: string, clientRoles: string[], clientId: string): Promise<void> { @@ -177,10 +179,24 @@ export class UserRepository { }); } + async _updateUserRolesForAdmin(userId: string, clientRoles: ClientRoles): Promise<void> { + if (clientRoles.admin.includes(AdminRoles.ADMIN)) { + await this._updateUserRolesForClient( + userId, + [ + KeycloakDefaults.clients.realmManagement.roles.managerUsers.roleName, + KeycloakDefaults.clients.realmManagement.roles.queryGroups.roleName, + KeycloakDefaults.clients.realmManagement.roles.viewClients.roleName, + ], + await this._getClientId(KeycloakDefaults.clients.realmManagement.clientName), + ); + } + } + _sendActivationMail(userId: string): void { this.kcAdminClient.users.executeActionsEmail({ id: userId, - actions: ['VERIFY_EMAIL'], + actions: [RequiredActionAlias.VERIFY_EMAIL, RequiredActionAlias.UPDATE_PASSWORD], lifespan: 3600 * 24 * 7, }); } diff --git a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts index f496e42b8734907ab060fe4872fc91cb29b14c42..45d8e171c2c2b1cde1e96e25d76cac23bcf6e5e2 100644 --- a/alfa-client/libs/admin/user-shared/src/lib/user.model.ts +++ b/alfa-client/libs/admin/user-shared/src/lib/user.model.ts @@ -48,3 +48,7 @@ export interface RoleMappings { newClientRoleMappings: RoleMappingPayload[]; oldClientRoleMappings: RoleMappingPayload[]; } + +export enum AdminRoles { + ADMIN = 'ADMIN_ADMIN', +} diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts index abb31e6062eba1eb79af8f741f3edb624be19bfc..99e28aabc946516a2076a89eb850c1df7b5594cd 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.spec.ts @@ -26,18 +26,14 @@ import { ROUTES } from '@admin-client/shared'; import { User, UserService } from '@admin-client/user-shared'; import { PatchConfig } from '@admin/keycloak-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; -import { - createEmptyStateResource, - createLoadingStateResource, - createStateResource, - StateResource, -} from '@alfa-client/tech-shared'; +import { createEmptyStateResource, createLoadingStateResource, createStateResource, StateResource, } from '@alfa-client/tech-shared'; import { Mock, mock, mockWindowError } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; import { fakeAsync, TestBed, tick } from '@angular/core/testing'; import { AbstractControl, FormControl, FormGroup, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { ActivatedRoute, UrlSegment } from '@angular/router'; import { faker } from '@faker-js/faker/locale/de'; +import { expect } from '@jest/globals'; import { cold } from 'jest-marbles'; import { createUser } from 'libs/admin/user-shared/test/user'; import { Observable, of, throwError } from 'rxjs'; @@ -45,7 +41,6 @@ import { createUrlSegment } from '../../../../../navigation-shared/test/navigati import { singleCold, singleColdCompleted, singleHot } from '../../../../../tech-shared/test/marbles'; import { createAdminOrganisationsEinheit } from '../../../../organisations-einheit-shared/src/test/organisations-einheit'; import { UserFormService } from './user.formservice'; - import SpyInstance = jest.SpyInstance; describe('UserFormService', () => { diff --git a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts index cfccff6fbc249d1eb8174bee7fb25ac9e1cf8b56..666d4d192605be0c6e14cca6008225b86570e1d5 100644 --- a/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts +++ b/alfa-client/libs/admin/user/src/lib/user-form/user.formservice.ts @@ -23,21 +23,13 @@ */ import { AdminOrganisationsEinheit, AdminOrganisationsEinheitService } from '@admin-client/organisations-einheit-shared'; import { ROUTES } from '@admin-client/shared'; -import { User, UserService } from '@admin-client/user-shared'; +import { AdminRoles, User, UserService } from '@admin-client/user-shared'; import { KeycloakFormService, PatchConfig } from '@admin/keycloak-shared'; import { NavigationService } from '@alfa-client/navigation-shared'; import { createEmptyStateResource, EMPTY_STRING, isLoaded, mapToResource, StateResource } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; import { Injectable, OnDestroy } from '@angular/core'; -import { - AbstractControl, - FormControl, - UntypedFormBuilder, - UntypedFormGroup, - ValidationErrors, - ValidatorFn, - Validators, -} from '@angular/forms'; +import { AbstractControl, FormControl, UntypedFormBuilder, UntypedFormGroup, ValidationErrors, ValidatorFn, Validators, } from '@angular/forms'; import { UrlSegment } from '@angular/router'; import { catchError, filter, Observable, of, Subscription, tap } from 'rxjs'; @@ -51,7 +43,7 @@ export class UserFormService extends KeycloakFormService<User> implements OnDest public static readonly CLIENT_ROLES: string = 'clientRoles'; public static readonly GROUPS: string = 'groups'; public static readonly ADMINISTRATION_GROUP: string = 'admin'; - public static readonly ADMIN: string = 'ADMIN_ADMIN'; + public static readonly ADMIN: string = AdminRoles.ADMIN; public static readonly DATENBEAUFTRAGUNG: string = 'DATENBEAUFTRAGUNG'; public static readonly ALFA_GROUP: string = 'alfa'; public static readonly LOESCHEN: string = 'VERWALTUNG_LOESCHEN';