From 531cb738ee1f8fdf1caf12e50d8f6c9aa103a5a4 Mon Sep 17 00:00:00 2001 From: Martin <git@mail.de> Date: Fri, 17 Jan 2025 17:43:21 +0100 Subject: [PATCH 1/5] OZG-6986 OZG-7509 adjust authentication service --- .../src/lib/authentication.service.spec.ts | 236 +++++++++++++++++- .../src/lib/authentication.service.ts | 56 ++++- .../authentication/test/authentication.ts | 7 +- 3 files changed, 283 insertions(+), 16 deletions(-) diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts index bd176bb914..1ef750f989 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts @@ -23,30 +23,39 @@ */ import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { UserProfileResource } from '@alfa-client/user-profile-shared'; +import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc'; +import { Environment } from 'libs/environment-shared/src/lib/environment.model'; import { createUserProfileResource } from 'libs/user-profile-shared/test/user-profile'; -import { AuthConfig, OAuthService } from 'angular-oauth2-oidc'; -import { AuthenticationService } from './authentication.service'; -import { createAuthConfig } from '../../test/authentication'; +import { Subject } from 'rxjs'; import { createEnvironment } from '../../../environment-shared/test/environment'; -import { Environment } from 'libs/environment-shared/src/lib/environment.model'; +import { createAuthConfig, createOAuthEvent } from '../../test/authentication'; +import { AuthenticationService } from './authentication.service'; describe('AuthenticationService', () => { let service: AuthenticationService; let oAuthService: Mock<OAuthService>; let environmentConfig: Environment; + let eventsSubject: Subject<OAuthEvent>; + beforeEach(() => { + eventsSubject = new Subject<OAuthEvent>(); + oAuthService = <any>{ ...mock(OAuthService), loadDiscoveryDocumentAndLogin: jest.fn().mockResolvedValue(() => Promise.resolve()), + hasValidAccessToken: jest.fn(), + hasValidIdToken: jest.fn(), }; + Object.defineProperty(oAuthService, 'events', { get: () => eventsSubject }); + environmentConfig = createEnvironment(); service = new AuthenticationService(useFromMock(oAuthService), environmentConfig); }); describe('login', () => { beforeEach(() => { - service.setCurrentUser = jest.fn(); + service.buildEventPromise = jest.fn(); }); it('should configure service with authConfig', async () => { @@ -72,16 +81,227 @@ describe('AuthenticationService', () => { expect(oAuthService.tokenValidationHandler).not.toBeNull(); }); + it('should build event promise', async () => { + service.buildEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve()); + + await service.login(); + + expect(service.buildEventPromise).toHaveBeenCalled(); + }); + it('should load discovery document and login', () => { service.login(); expect(oAuthService.loadDiscoveryDocumentAndLogin).toHaveBeenCalled(); }); - it('should set current user', async () => { - await service.login(); + it('should return eventPromise', async () => { + const promise: Promise<void> = Promise.resolve(); + service.buildEventPromise = jest.fn().mockResolvedValue(promise); + + const returnPromise: Promise<void> = service.login(); + + await expect(returnPromise).resolves.toBeUndefined(); + }); + }); + + describe('build event promise', () => { + const event: OAuthEvent = createOAuthEvent(); + + beforeEach(() => { + service.shouldProceed = jest.fn().mockReturnValue(true); + service.setCurrentUser = jest.fn(); + service.unsubscribeEvents = jest.fn(); + }); + + it('should call shouldProceed on event trigger', () => { + service.buildEventPromise(); + eventsSubject.next(event); + + expect(service.shouldProceed).toHaveBeenCalledWith(event); + }); + + describe('on next', () => { + it('should set current user', () => { + service.buildEventPromise(); + eventsSubject.next(event); + + expect(service.setCurrentUser).toHaveBeenCalled(); + }); + + it('should unsubscribe event', () => { + service.buildEventPromise(); + eventsSubject.next(event); + + expect(service.unsubscribeEvents).toHaveBeenCalled(); + }); + + it('should resolved promise with a valid event', async () => { + const promise: Promise<void> = service.buildEventPromise(); + eventsSubject.next(event); + + await expect(promise).resolves.toBeUndefined(); + }); + }); + + describe('on error', () => { + const errorMessage: string = 'Test Error'; + const error: Error = new Error(errorMessage); + + it('should unsubscribe event', () => { + service.buildEventPromise(); + eventsSubject.error(error); + + expect(service.unsubscribeEvents).toHaveBeenCalled(); + }); + + it('should reject the promise with an error', async () => { + const promise: Promise<void> = service.buildEventPromise(); + + eventsSubject.error(error); + + await expect(promise).rejects.toThrow(errorMessage); + }); + }); + }); + + describe('should proceed', () => { + const event: OAuthEvent = createOAuthEvent(); + + it('should call considered as login event', () => { + service.consideredAsLoginEvent = jest.fn(); + + service.shouldProceed(event); + + expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type); + }); + + it('should return true on login event', () => { + service.consideredAsLoginEvent = jest.fn().mockReturnValue(true); + + const proceed: boolean = service.shouldProceed(event); + + expect(proceed).toBeTruthy(); + }); + + it('should call considered as page reload event', () => { + service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); + service.consideredAsPageReloadEvent = jest.fn(); + + service.shouldProceed(event); + + expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type); + }); + + it('should return true on page reload event', () => { + service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); + service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true); + + const proceed: boolean = service.shouldProceed(event); + + expect(proceed).toBeTruthy(); + }); + + it('should return false on non login or page reload event', () => { + service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); + service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false); + + const proceed: boolean = service.shouldProceed(event); + + expect(proceed).toBeFalsy(); + }); + }); + + describe('consideredAsLoginEvent', () => { + it('should return true if event is "token_received"', () => { + const event: string = 'token_received'; + + const result: boolean = service.consideredAsLoginEvent(event); + + expect(result).toBeTruthy(); + }); + + it('should return false if event is not "token_received"', () => { + const event: string = 'something_else'; + + const result: boolean = service.consideredAsLoginEvent(event); + + expect(result).toBeFalsy(); + }); + }); + + describe('consideredAsPageReloadEvent', () => { + it('should return true if event is "discovery_document_loaded" and tokens are valid', () => { + service.hasValidToken = jest.fn().mockReturnValue(true); + const event: string = 'discovery_document_loaded'; + + const result: boolean = service.consideredAsPageReloadEvent(event); + + expect(result).toBeTruthy(); + }); + + it('should return false if event is "discovery_document_loaded" and tokens are invalid', () => { + service.hasValidToken = jest.fn().mockReturnValue(false); + const event: string = 'discovery_document_loaded'; + + const result: boolean = service.consideredAsPageReloadEvent(event); + + expect(result).toBeFalsy(); + }); + + it('should return false if event is not "discovery_document_loaded" and tokens are valid', () => { + service.hasValidToken = jest.fn().mockReturnValue(true); + const event: string = 'something_else'; + + const result: boolean = service.consideredAsPageReloadEvent(event); + + expect(result).toBeFalsy(); + }); + + it('should return false if event is not "discovery_document_loaded" and tokens are invalid', () => { + service.hasValidToken = jest.fn().mockReturnValue(false); + const event: string = 'something_else'; + + const result: boolean = service.consideredAsPageReloadEvent(event); + + expect(result).toBeFalsy(); + }); + }); + + describe('hasValidToken', () => { + it('should return true if both tokens are valid', () => { + oAuthService.hasValidAccessToken.mockReturnValue(true); + oAuthService.hasValidIdToken.mockReturnValue(true); + + const result: boolean = service.hasValidToken(); + + expect(result).toBeTruthy(); + }); + + it('should return false if access token is invalid', () => { + oAuthService.hasValidAccessToken.mockReturnValue(false); + + const result: boolean = service.hasValidToken(); + + expect(result).toBeFalsy(); + }); + + it('should return false if id token is invalid', () => { + oAuthService.hasValidAccessToken.mockReturnValue(true); + oAuthService.hasValidIdToken.mockReturnValue(false); + + const result: boolean = service.hasValidToken(); + + expect(result).toBeFalsy(); + }); + + it('should return false if both tokens are invalid', () => { + oAuthService.hasValidAccessToken.mockReturnValue(false); + oAuthService.hasValidIdToken.mockReturnValue(false); + + const result: boolean = service.hasValidToken(); - expect(service.setCurrentUser).toHaveBeenCalled(); + expect(result).toBeFalsy(); }); }); diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts index 9b094a2ba2..e6957194ff 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts @@ -22,16 +22,20 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared'; +import { isNotNull } from '@alfa-client/tech-shared'; import { Inject, Injectable } from '@angular/core'; -import { AuthConfig, OAuthService } from 'angular-oauth2-oidc'; +import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc'; import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks'; import { UserProfileResource } from 'libs/user-profile-shared/src/lib/user-profile.model'; import { getUserNameInitials } from 'libs/user-profile-shared/src/lib/user-profile.util'; +import { filter, Subscription } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthenticationService { currentUserResource: UserProfileResource; + private eventSubscription: Subscription; + constructor( private oAuthService: OAuthService, @Inject(ENVIRONMENT_CONFIG) private envConfig: Environment, @@ -41,18 +45,48 @@ export class AuthenticationService { this.oAuthService.configure(this.buildConfiguration()); this.oAuthService.setupAutomaticSilentRefresh(); this.oAuthService.tokenValidationHandler = new JwksValidationHandler(); + + const eventPromise: Promise<void> = this.buildEventPromise(); await this.oAuthService.loadDiscoveryDocumentAndLogin(); - this.setCurrentUser(); + return eventPromise; + } + + buildEventPromise(): Promise<void> { + return new Promise<void>((resolve, reject) => { + this.eventSubscription = this.oAuthService.events.pipe(filter((event: OAuthEvent) => this.shouldProceed(event))).subscribe({ + next: () => { + this.setCurrentUser(); + this.unsubscribeEvents(); + resolve(); + }, + error: (error: any) => { + this.unsubscribeEvents(); + reject(error); + }, + }); + }); + } + + shouldProceed(event: OAuthEvent): boolean { + return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type); + } + + consideredAsLoginEvent(eventType: string): boolean { + return eventType === 'token_received'; + } + + consideredAsPageReloadEvent(eventType: string): boolean { + return eventType === 'discovery_document_loaded' && this.hasValidToken(); + } + + hasValidToken(): boolean { + return this.oAuthService.hasValidAccessToken() && this.oAuthService.hasValidIdToken(); } buildConfiguration(): AuthConfig { return { issuer: this.envConfig.authServer + '/realms/' + this.envConfig.realm, - tokenEndpoint: - this.envConfig.authServer + - '/realms/' + - this.envConfig.realm + - '/protocol/openid-connect/token', + tokenEndpoint: this.envConfig.authServer + '/realms/' + this.envConfig.realm + '/protocol/openid-connect/token', redirectUri: window.location.origin + '/', clientId: this.envConfig.clientId, scope: 'openid profile', @@ -71,10 +105,18 @@ export class AuthenticationService { this.currentUserResource = userResource; } + unsubscribeEvents(): void { + this.eventSubscription.unsubscribe(); + } + public getCurrentUserInitials(): string { return getUserNameInitials(this.currentUserResource); } + public isLoggedIn(): boolean { + return isNotNull(this.oAuthService.getIdentityClaims()); + } + public logout(): void { this.oAuthService.revokeTokenAndLogout(); } diff --git a/alfa-client/libs/authentication/test/authentication.ts b/alfa-client/libs/authentication/test/authentication.ts index 3422390591..3cf143c030 100644 --- a/alfa-client/libs/authentication/test/authentication.ts +++ b/alfa-client/libs/authentication/test/authentication.ts @@ -21,8 +21,13 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { AuthConfig } from 'angular-oauth2-oidc'; +import { faker } from '@faker-js/faker'; +import { AuthConfig, OAuthEvent } from 'angular-oauth2-oidc'; export function createAuthConfig(): AuthConfig { return {}; } + +export function createOAuthEvent(): OAuthEvent { + return { type: <any>faker.lorem.word() }; +} -- GitLab From 8b4cda9cb430543759e2d62da8c0a249a04dee6b Mon Sep 17 00:00:00 2001 From: Martin <git@mail.de> Date: Fri, 17 Jan 2025 17:43:53 +0100 Subject: [PATCH 2/5] OZG-6986 OZG-7509 adjust initial navigation/routing --- .../apps/admin/src/app/app.component.spec.ts | 212 +++++++++++++++--- .../apps/admin/src/app/app.component.ts | 82 +++++-- alfa-client/apps/admin/src/app/app.routes.ts | 6 +- 3 files changed, 251 insertions(+), 49 deletions(-) diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts index 54c0b68df0..cb90801ee5 100644 --- a/alfa-client/apps/admin/src/app/app.component.spec.ts +++ b/alfa-client/apps/admin/src/app/app.component.spec.ts @@ -21,10 +21,11 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared'; import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared'; import { BuildInfoComponent } from '@alfa-client/common'; import { HasLinkPipe, createEmptyStateResource, createStateResource } from '@alfa-client/tech-shared'; -import { Mock, dispatchEventFromFixture, existsAsHtmlElement, mock, notExistsAsHtmlElement } from '@alfa-client/test-utils'; +import { Mock, existsAsHtmlElement, mock, notExistsAsHtmlElement } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ActivatedRoute, Router, RouterOutlet } from '@angular/router'; import { AuthenticationService } from '@authentication'; @@ -36,11 +37,12 @@ import { OrgaUnitIconComponent, UsersIconComponent, } from '@ods/system'; +import { createConfigurationResource } from 'libs/admin/configuration-shared/test/configuration'; import { MenuContainerComponent } from 'libs/admin/configuration/src/lib/menu-container/menu-container.component'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent, MockDirective } from 'ng-mocks'; -import { of } from 'rxjs'; +import { Subscription, of } from 'rxjs'; import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component'; import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component'; import { AppComponent } from './app.component'; @@ -55,7 +57,6 @@ describe('AppComponent', () => { const usersRolesNavigationSelector: string = getDataTestIdOf('users-roles-navigation'); const organisationsEinheitenNavigationSelector: string = getDataTestIdOf('organisations-einheiten-navigation'); - const logoLink: string = getDataTestIdOf('logo-link'); const routerOutletSelector: string = getDataTestIdOf('router-outlet'); const menuContainer: string = getDataTestIdOf('menu-container'); @@ -78,8 +79,11 @@ describe('AppComponent', () => { }; const apiRootService: Mock<ApiRootService> = mock(ApiRootService); + let configurationService: Mock<ConfigurationService>; beforeEach(async () => { + configurationService = mock(ConfigurationService); + await TestBed.configureTestingModule({ imports: [HasLinkPipe], declarations: [ @@ -105,6 +109,10 @@ describe('AppComponent', () => { provide: ApiRootService, useValue: apiRootService, }, + { + provide: ConfigurationService, + useValue: configurationService, + }, { provide: Router, useValue: router, @@ -147,26 +155,195 @@ describe('AppComponent', () => { }); describe('do after logged in', () => { + beforeEach(() => { + component.evaluateInitialNavigation = jest.fn(); + }); + it('should call apiRootService to getApiRoot', () => { component.doAfterLoggedIn(); expect(apiRootService.getApiRoot).toHaveBeenCalled(); }); - it('should call forwardWithoutAuthenticationParams', () => { - component.forwardWithoutAuthenticationParams = jest.fn(); + it('should call evaluateInitialNavigation', () => { + component.evaluateInitialNavigation = jest.fn(); component.doAfterLoggedIn(); - expect(component.forwardWithoutAuthenticationParams).toHaveBeenCalled(); + expect(component.evaluateInitialNavigation).toHaveBeenCalled(); + }); + }); + + describe('evaluate initial navigation', () => { + beforeEach(() => { + component.evaluateNavigationByApiRoot = jest.fn(); + }); + + it('should call evaluate navigation by apiRoot', () => { + const apiRootResource: ApiRootResource = createApiRootResource(); + component.apiRootStateResource$ = of(createStateResource(apiRootResource)); + + component.evaluateInitialNavigation(); + + expect(component.evaluateNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource); + }); + + it('should NOT call evaluate navigation by apiRoot if resource is loading', () => { + component.apiRootStateResource$ = of(createEmptyStateResource<ApiRootResource>(true)); + component.evaluateNavigationByApiRoot = jest.fn(); + + component.evaluateInitialNavigation(); + + expect(component.evaluateNavigationByApiRoot).not.toHaveBeenCalled(); + }); + }); + + describe('evaluate navigation api root', () => { + it('should evaluate navigation by configuration if link exists', () => { + component.evaluateNavigationByConfiguration = jest.fn(); + const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.CONFIGURATION]); + + component.evaluateNavigationByApiRoot(apiRootResource); + + expect(component.evaluateNavigationByConfiguration).toHaveBeenCalled(); + }); + + it('should do navigation by api root if link is missing', () => { + component.doNavigationByApiRoot = jest.fn(); + const apiRootResource: ApiRootResource = createApiRootResource(); + + component.evaluateNavigationByApiRoot(apiRootResource); + + expect(component.doNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource); + }); + }); + + describe('evaluate navigation by configuration', () => { + const configurationResource: ConfigurationResource = createConfigurationResource(); + + beforeEach(() => { + configurationService.get.mockReturnValue(of(createStateResource(configurationResource))); + component.doNavigationByConfiguration = jest.fn(); + }); + + it('should call configuration service to get resource', () => { + component.evaluateNavigationByConfiguration(); + + expect(configurationService.get).toHaveBeenCalled(); + }); + + it('should call do navigation by configuration', () => { + component.evaluateNavigationByConfiguration(); + + expect(component.doNavigationByConfiguration).toHaveBeenCalledWith(configurationResource); + }); + + it('should NOT call do navigation by configuration if resource is loading', () => { + configurationService.get.mockReturnValue(of(createEmptyStateResource<ConfigurationResource>(true))); + + component.evaluateNavigationByConfiguration(); + + expect(component.doNavigationByConfiguration).not.toHaveBeenCalled(); + }); + }); + + describe('do navigation by configuration', () => { + beforeEach(() => { + component.unsubscribe = jest.fn(); + }); + + it('should navigate to postfach if settings link exists', () => { + component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING])); + + expect(router.navigate).toHaveBeenCalledWith(['/postfach']); + }); + + it('should navigate to statistik if aggregation mapping link exists', () => { + component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS])); + + expect(router.navigate).toHaveBeenCalledWith(['/statistik']); + }); + + it('should navigate to unavailable page if no link exists', () => { + component.doNavigationByConfiguration(createConfigurationResource()); + + expect(router.navigate).toHaveBeenCalledWith(['/unavailable']); + }); + + it('should call unsubscribe', () => { + component.doNavigationByConfiguration(createConfigurationResource()); + + expect(component.unsubscribe).toHaveBeenCalled(); + }); + }); + + describe('do navigation by api root', () => { + beforeEach(() => { + component.unsubscribe = jest.fn(); + }); + + it('should navigate to benutzer und rollen if users link exists', () => { + const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.USERS]); + + component.doNavigationByApiRoot(apiRootResource); + + expect(router.navigate).toHaveBeenCalledWith(['/benutzer_und_rollen']); + }); + + it('should navigate to unavailable page if no link exists', () => { + component.doNavigationByApiRoot(createApiRootResource()); + + expect(router.navigate).toHaveBeenCalledWith(['/unavailable']); + }); + + it('should call unsubscribe', () => { + component.doNavigationByApiRoot(createApiRootResource()); + + expect(component.unsubscribe).toHaveBeenCalled(); }); }); - describe('forward without authentication params', () => { - it('should navigate to same route without authentication params', () => { - component.forwardWithoutAuthenticationParams(); + describe('unsubscribe', () => { + describe('apiRoot subscription', () => { + it('should unsubscribe if exists', () => { + component.apiRootSubscription = <any>mock(Subscription); + component.apiRootSubscription.unsubscribe = jest.fn(); - expect(router.navigate).toHaveBeenCalledWith([], { queryParams: {} }); + component.unsubscribe(); + + expect(component.apiRootSubscription.unsubscribe).toHaveBeenCalled(); + }); + + it('should do nothing if not exists', () => { + component.apiRootSubscription = undefined; + const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe'); + + component.unsubscribe(); + + expect(unsubscribeSpy).not.toHaveBeenCalled(); + unsubscribeSpy.mockRestore(); + }); + }); + + describe('configuration subscription', () => { + it('should unsubscribe if exists', () => { + component.configurationSubscription = <any>mock(Subscription); + component.configurationSubscription.unsubscribe = jest.fn(); + + component.unsubscribe(); + + expect(component.configurationSubscription.unsubscribe).toHaveBeenCalled(); + }); + + it('should do nothing if not exists', () => { + component.apiRootSubscription = undefined; + const unsubscribeSpy: jest.SpyInstance = jest.spyOn(Subscription.prototype, 'unsubscribe'); + + component.unsubscribe(); + + expect(unsubscribeSpy).not.toHaveBeenCalled(); + unsubscribeSpy.mockRestore(); + }); }); }); }); @@ -190,21 +367,6 @@ describe('AppComponent', () => { }); }); - describe('administration logo', () => { - const apiResource: ApiRootResource = createApiRootResource(); - - beforeEach(() => { - component.apiRootStateResource$ = of(createStateResource(apiResource)); - fixture.detectChanges(); - }); - - it('should navigate to start page on click', () => { - dispatchEventFromFixture(fixture, logoLink, 'click'); - - expect(router.navigate).toHaveBeenCalledWith([], { queryParams: {} }); - }); - }); - describe('navigation', () => { describe('user and roles', () => { it('should show if users link is present', () => { diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts index 77e7d9b5bb..979c8024a5 100644 --- a/alfa-client/apps/admin/src/app/app.component.ts +++ b/alfa-client/apps/admin/src/app/app.component.ts @@ -22,13 +22,16 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { MenuContainerComponent } from '@admin-client/configuration'; +import { ConfigurationLinkRel, ConfigurationResource, ConfigurationService } from '@admin-client/configuration-shared'; +import { ROUTES } from '@admin-client/shared'; import { ApiRootLinkRel, ApiRootResource, ApiRootService } from '@alfa-client/api-root-shared'; import { BuildInfoComponent } from '@alfa-client/common'; -import { StateResource, TechSharedModule } from '@alfa-client/tech-shared'; +import { isLoaded, isNotUndefined, mapToResource, StateResource, TechSharedModule } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; -import { Component, OnInit } from '@angular/core'; -import { ActivatedRoute, Params, Router, RouterLink, RouterOutlet } from '@angular/router'; +import { Component, inject, OnInit } from '@angular/core'; +import { Router, RouterLink, RouterOutlet } from '@angular/router'; import { AuthenticationService } from '@authentication'; +import { hasLink } from '@ngxp/rest'; import { AdminLogoIconComponent, NavbarComponent, @@ -36,7 +39,7 @@ import { OrgaUnitIconComponent, UsersIconComponent, } from '@ods/system'; -import { Observable } from 'rxjs'; +import { filter, Observable, Subscription } from 'rxjs'; import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component'; import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/unavailable-page.component'; @@ -62,18 +65,19 @@ import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/ ], }) export class AppComponent implements OnInit { - readonly title: string = 'admin'; + readonly title = 'admin'; + + private readonly authenticationService: AuthenticationService = inject(AuthenticationService); + private readonly apiRootService: ApiRootService = inject(ApiRootService); + private readonly router: Router = inject(Router); + private readonly configurationService: ConfigurationService = inject(ConfigurationService); public apiRootStateResource$: Observable<StateResource<ApiRootResource>>; - public readonly apiRootLinkRel = ApiRootLinkRel; + apiRootSubscription: Subscription; + configurationSubscription: Subscription; - constructor( - public authenticationService: AuthenticationService, - private apiRootService: ApiRootService, - private router: Router, - private route: ActivatedRoute, - ) {} + public readonly apiRootLinkRel = ApiRootLinkRel; ngOnInit(): void { this.authenticationService.login().then(() => this.doAfterLoggedIn()); @@ -81,16 +85,56 @@ export class AppComponent implements OnInit { doAfterLoggedIn(): void { this.apiRootStateResource$ = this.apiRootService.getApiRoot(); - this.forwardWithoutAuthenticationParams(); + this.evaluateInitialNavigation(); + } + + evaluateInitialNavigation(): void { + this.apiRootSubscription = this.apiRootStateResource$ + .pipe(filter(isLoaded), mapToResource<ApiRootResource>()) + .subscribe((apiRootResource: ApiRootResource) => this.evaluateNavigationByApiRoot(apiRootResource)); + } + + evaluateNavigationByApiRoot(apiRootResource: ApiRootResource): void { + if (hasLink(apiRootResource, ApiRootLinkRel.CONFIGURATION)) { + this.evaluateNavigationByConfiguration(); + } else { + this.doNavigationByApiRoot(apiRootResource); + } + } + + evaluateNavigationByConfiguration(): void { + this.configurationSubscription = this.configurationService + .get() + .pipe(filter(isLoaded), mapToResource<ApiRootResource>()) + .subscribe((configurationResource: ConfigurationResource) => this.doNavigationByConfiguration(configurationResource)); + } + + doNavigationByConfiguration(configurationResource: ConfigurationResource): void { + if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) { + this.doInitialNavigation(ROUTES.POSTFACH); + } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) { + this.doInitialNavigation(ROUTES.STATISTIK); + } else { + this.doInitialNavigation(ROUTES.UNAVAILABLE); + } + this.unsubscribe(); + } + + doNavigationByApiRoot(apiRootResource: ApiRootResource): void { + if (hasLink(apiRootResource, ApiRootLinkRel.USERS)) { + this.doInitialNavigation(ROUTES.BENUTZER_UND_ROLLEN); + } else { + this.doInitialNavigation(ROUTES.UNAVAILABLE); + } + this.unsubscribe(); } - forwardWithoutAuthenticationParams(): void { - const queryParams: Params = this.getQueryParamsWithoutAuthentication(); - this.router.navigate([], { queryParams }); + private doInitialNavigation(routePath: string): void { + this.router.navigate(['/' + routePath]); } - private getQueryParamsWithoutAuthentication(): Params { - const { iss, state, session_state, code, ...queryParams } = this.route.snapshot.queryParams; - return queryParams; + unsubscribe(): void { + if (isNotUndefined(this.apiRootSubscription)) this.apiRootSubscription.unsubscribe(); + if (isNotUndefined(this.configurationSubscription)) this.configurationSubscription.unsubscribe(); } } diff --git a/alfa-client/apps/admin/src/app/app.routes.ts b/alfa-client/apps/admin/src/app/app.routes.ts index e26615b6c1..a7ed852a61 100644 --- a/alfa-client/apps/admin/src/app/app.routes.ts +++ b/alfa-client/apps/admin/src/app/app.routes.ts @@ -37,12 +37,8 @@ import { apiRootGuard, configurationGuard } from './app.guard'; export interface GuardData { linkRelName: string; } + export const appRoutes: Route[] = [ - { - path: '', - redirectTo: ROUTES.POSTFACH, - pathMatch: 'full', - }, { path: ROUTES.POSTFACH, component: PostfachPageComponent, -- GitLab From 78b06a2e49bcbf250c030473baec556f36d54bf4 Mon Sep 17 00:00:00 2001 From: Martin <git@mail.de> Date: Fri, 17 Jan 2025 17:46:39 +0100 Subject: [PATCH 3/5] OZG-6986 OZG-7509 cleanup --- .../libs/authentication/src/lib/authentication.service.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts index e6957194ff..7dcfc4741a 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts @@ -22,7 +22,6 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ import { Environment, ENVIRONMENT_CONFIG } from '@alfa-client/environment-shared'; -import { isNotNull } from '@alfa-client/tech-shared'; import { Inject, Injectable } from '@angular/core'; import { AuthConfig, OAuthEvent, OAuthService } from 'angular-oauth2-oidc'; import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks'; @@ -113,10 +112,6 @@ export class AuthenticationService { return getUserNameInitials(this.currentUserResource); } - public isLoggedIn(): boolean { - return isNotNull(this.oAuthService.getIdentityClaims()); - } - public logout(): void { this.oAuthService.revokeTokenAndLogout(); } -- GitLab From 055eaa6ffe657a490e2be65587c1a6bd4e051d7f Mon Sep 17 00:00:00 2001 From: Martin <git@mail.de> Date: Mon, 20 Jan 2025 11:08:23 +0100 Subject: [PATCH 4/5] OZG-6986 impl MR comments --- .../apps/admin/src/app/app.component.spec.ts | 34 +++++++++---------- .../apps/admin/src/app/app.component.ts | 30 ++++++++-------- .../src/lib/authentication.service.spec.ts | 18 +++++----- .../src/lib/authentication.service.ts | 12 ++++--- 4 files changed, 49 insertions(+), 45 deletions(-) diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts index cb90801ee5..86fda2c791 100644 --- a/alfa-client/apps/admin/src/app/app.component.spec.ts +++ b/alfa-client/apps/admin/src/app/app.component.spec.ts @@ -208,13 +208,13 @@ describe('AppComponent', () => { expect(component.evaluateNavigationByConfiguration).toHaveBeenCalled(); }); - it('should do navigation by api root if link is missing', () => { - component.doNavigationByApiRoot = jest.fn(); + it('should navigate by api root if link is missing', () => { + component.navigateByApiRoot = jest.fn(); const apiRootResource: ApiRootResource = createApiRootResource(); component.evaluateNavigationByApiRoot(apiRootResource); - expect(component.doNavigationByApiRoot).toHaveBeenCalledWith(apiRootResource); + expect(component.navigateByApiRoot).toHaveBeenCalledWith(apiRootResource); }); }); @@ -223,7 +223,7 @@ describe('AppComponent', () => { beforeEach(() => { configurationService.get.mockReturnValue(of(createStateResource(configurationResource))); - component.doNavigationByConfiguration = jest.fn(); + component.navigateByConfiguration = jest.fn(); }); it('should call configuration service to get resource', () => { @@ -232,52 +232,52 @@ describe('AppComponent', () => { expect(configurationService.get).toHaveBeenCalled(); }); - it('should call do navigation by configuration', () => { + it('should call navigate by configuration', () => { component.evaluateNavigationByConfiguration(); - expect(component.doNavigationByConfiguration).toHaveBeenCalledWith(configurationResource); + expect(component.navigateByConfiguration).toHaveBeenCalledWith(configurationResource); }); - it('should NOT call do navigation by configuration if resource is loading', () => { + it('should NOT call navigate by configuration if resource is loading', () => { configurationService.get.mockReturnValue(of(createEmptyStateResource<ConfigurationResource>(true))); component.evaluateNavigationByConfiguration(); - expect(component.doNavigationByConfiguration).not.toHaveBeenCalled(); + expect(component.navigateByConfiguration).not.toHaveBeenCalled(); }); }); - describe('do navigation by configuration', () => { + describe('navigate by configuration', () => { beforeEach(() => { component.unsubscribe = jest.fn(); }); it('should navigate to postfach if settings link exists', () => { - component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING])); + component.navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.SETTING])); expect(router.navigate).toHaveBeenCalledWith(['/postfach']); }); it('should navigate to statistik if aggregation mapping link exists', () => { - component.doNavigationByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS])); + component.navigateByConfiguration(createConfigurationResource([ConfigurationLinkRel.AGGREGATION_MAPPINGS])); expect(router.navigate).toHaveBeenCalledWith(['/statistik']); }); it('should navigate to unavailable page if no link exists', () => { - component.doNavigationByConfiguration(createConfigurationResource()); + component.navigateByConfiguration(createConfigurationResource()); expect(router.navigate).toHaveBeenCalledWith(['/unavailable']); }); it('should call unsubscribe', () => { - component.doNavigationByConfiguration(createConfigurationResource()); + component.navigateByConfiguration(createConfigurationResource()); expect(component.unsubscribe).toHaveBeenCalled(); }); }); - describe('do navigation by api root', () => { + describe('navigate by api root', () => { beforeEach(() => { component.unsubscribe = jest.fn(); }); @@ -285,19 +285,19 @@ describe('AppComponent', () => { it('should navigate to benutzer und rollen if users link exists', () => { const apiRootResource: ApiRootResource = createApiRootResource([ApiRootLinkRel.USERS]); - component.doNavigationByApiRoot(apiRootResource); + component.navigateByApiRoot(apiRootResource); expect(router.navigate).toHaveBeenCalledWith(['/benutzer_und_rollen']); }); it('should navigate to unavailable page if no link exists', () => { - component.doNavigationByApiRoot(createApiRootResource()); + component.navigateByApiRoot(createApiRootResource()); expect(router.navigate).toHaveBeenCalledWith(['/unavailable']); }); it('should call unsubscribe', () => { - component.doNavigationByApiRoot(createApiRootResource()); + component.navigateByApiRoot(createApiRootResource()); expect(component.unsubscribe).toHaveBeenCalled(); }); diff --git a/alfa-client/apps/admin/src/app/app.component.ts b/alfa-client/apps/admin/src/app/app.component.ts index 979c8024a5..c9d3c4f536 100644 --- a/alfa-client/apps/admin/src/app/app.component.ts +++ b/alfa-client/apps/admin/src/app/app.component.ts @@ -65,12 +65,12 @@ import { UnavailablePageComponent } from '../pages/unavailable/unavailable-page/ ], }) export class AppComponent implements OnInit { - readonly title = 'admin'; + readonly title: string = 'admin'; - private readonly authenticationService: AuthenticationService = inject(AuthenticationService); - private readonly apiRootService: ApiRootService = inject(ApiRootService); - private readonly router: Router = inject(Router); - private readonly configurationService: ConfigurationService = inject(ConfigurationService); + private readonly authenticationService = inject(AuthenticationService); + private readonly apiRootService = inject(ApiRootService); + private readonly router = inject(Router); + private readonly configurationService = inject(ConfigurationService); public apiRootStateResource$: Observable<StateResource<ApiRootResource>>; @@ -98,7 +98,7 @@ export class AppComponent implements OnInit { if (hasLink(apiRootResource, ApiRootLinkRel.CONFIGURATION)) { this.evaluateNavigationByConfiguration(); } else { - this.doNavigationByApiRoot(apiRootResource); + this.navigateByApiRoot(apiRootResource); } } @@ -106,30 +106,30 @@ export class AppComponent implements OnInit { this.configurationSubscription = this.configurationService .get() .pipe(filter(isLoaded), mapToResource<ApiRootResource>()) - .subscribe((configurationResource: ConfigurationResource) => this.doNavigationByConfiguration(configurationResource)); + .subscribe((configurationResource: ConfigurationResource) => this.navigateByConfiguration(configurationResource)); } - doNavigationByConfiguration(configurationResource: ConfigurationResource): void { + navigateByConfiguration(configurationResource: ConfigurationResource): void { if (hasLink(configurationResource, ConfigurationLinkRel.SETTING)) { - this.doInitialNavigation(ROUTES.POSTFACH); + this.navigate(ROUTES.POSTFACH); } else if (hasLink(configurationResource, ConfigurationLinkRel.AGGREGATION_MAPPINGS)) { - this.doInitialNavigation(ROUTES.STATISTIK); + this.navigate(ROUTES.STATISTIK); } else { - this.doInitialNavigation(ROUTES.UNAVAILABLE); + this.navigate(ROUTES.UNAVAILABLE); } this.unsubscribe(); } - doNavigationByApiRoot(apiRootResource: ApiRootResource): void { + navigateByApiRoot(apiRootResource: ApiRootResource): void { if (hasLink(apiRootResource, ApiRootLinkRel.USERS)) { - this.doInitialNavigation(ROUTES.BENUTZER_UND_ROLLEN); + this.navigate(ROUTES.BENUTZER_UND_ROLLEN); } else { - this.doInitialNavigation(ROUTES.UNAVAILABLE); + this.navigate(ROUTES.UNAVAILABLE); } this.unsubscribe(); } - private doInitialNavigation(routePath: string): void { + private navigate(routePath: string): void { this.router.navigate(['/' + routePath]); } diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts index 1ef750f989..14b3984a18 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts @@ -109,16 +109,16 @@ describe('AuthenticationService', () => { const event: OAuthEvent = createOAuthEvent(); beforeEach(() => { - service.shouldProceed = jest.fn().mockReturnValue(true); + service.shouldProceedByType = jest.fn().mockReturnValue(true); service.setCurrentUser = jest.fn(); service.unsubscribeEvents = jest.fn(); }); - it('should call shouldProceed on event trigger', () => { + it('should call shouldProceedByType on event trigger', () => { service.buildEventPromise(); eventsSubject.next(event); - expect(service.shouldProceed).toHaveBeenCalledWith(event); + expect(service.shouldProceedByType).toHaveBeenCalledWith(event); }); describe('on next', () => { @@ -165,13 +165,13 @@ describe('AuthenticationService', () => { }); }); - describe('should proceed', () => { + describe('should proceed by type', () => { const event: OAuthEvent = createOAuthEvent(); it('should call considered as login event', () => { service.consideredAsLoginEvent = jest.fn(); - service.shouldProceed(event); + service.shouldProceedByType(event); expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type); }); @@ -179,7 +179,7 @@ describe('AuthenticationService', () => { it('should return true on login event', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(true); - const proceed: boolean = service.shouldProceed(event); + const proceed: boolean = service.shouldProceedByType(event); expect(proceed).toBeTruthy(); }); @@ -188,7 +188,7 @@ describe('AuthenticationService', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); service.consideredAsPageReloadEvent = jest.fn(); - service.shouldProceed(event); + service.shouldProceedByType(event); expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type); }); @@ -197,7 +197,7 @@ describe('AuthenticationService', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true); - const proceed: boolean = service.shouldProceed(event); + const proceed: boolean = service.shouldProceedByType(event); expect(proceed).toBeTruthy(); }); @@ -206,7 +206,7 @@ describe('AuthenticationService', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false); - const proceed: boolean = service.shouldProceed(event); + const proceed: boolean = service.shouldProceedByType(event); expect(proceed).toBeFalsy(); }); diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts index 7dcfc4741a..b22baa5b45 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts @@ -51,8 +51,13 @@ export class AuthenticationService { } buildEventPromise(): Promise<void> { - return new Promise<void>((resolve, reject) => { - this.eventSubscription = this.oAuthService.events.pipe(filter((event: OAuthEvent) => this.shouldProceed(event))).subscribe({ + return new Promise<void>((resolve, reject) => this.handleOAuthEventsForPromise(resolve, reject)); + } + + private handleOAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void { + this.eventSubscription = this.oAuthService.events + .pipe(filter((event: OAuthEvent) => this.shouldProceedByType(event))) + .subscribe({ next: () => { this.setCurrentUser(); this.unsubscribeEvents(); @@ -63,10 +68,9 @@ export class AuthenticationService { reject(error); }, }); - }); } - shouldProceed(event: OAuthEvent): boolean { + shouldProceedByType(event: OAuthEvent): boolean { return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type); } -- GitLab From 96410d88d80d0e2ec83cec9aeee13d460c94186b Mon Sep 17 00:00:00 2001 From: Martin <git@mail.de> Date: Mon, 20 Jan 2025 12:25:02 +0100 Subject: [PATCH 5/5] OZG-6986 rename Functions --- .../src/lib/authentication.service.spec.ts | 42 +++++++++---------- .../src/lib/authentication.service.ts | 12 +++--- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts index 14b3984a18..486415f425 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.spec.ts @@ -55,7 +55,7 @@ describe('AuthenticationService', () => { describe('login', () => { beforeEach(() => { - service.buildEventPromise = jest.fn(); + service.buildAuthEventPromise = jest.fn(); }); it('should configure service with authConfig', async () => { @@ -81,12 +81,12 @@ describe('AuthenticationService', () => { expect(oAuthService.tokenValidationHandler).not.toBeNull(); }); - it('should build event promise', async () => { - service.buildEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve()); + it('should build auth event promise', async () => { + service.buildAuthEventPromise = jest.fn().mockResolvedValue(() => Promise.resolve()); await service.login(); - expect(service.buildEventPromise).toHaveBeenCalled(); + expect(service.buildAuthEventPromise).toHaveBeenCalled(); }); it('should load discovery document and login', () => { @@ -97,7 +97,7 @@ describe('AuthenticationService', () => { it('should return eventPromise', async () => { const promise: Promise<void> = Promise.resolve(); - service.buildEventPromise = jest.fn().mockResolvedValue(promise); + service.buildAuthEventPromise = jest.fn().mockResolvedValue(promise); const returnPromise: Promise<void> = service.login(); @@ -105,39 +105,39 @@ describe('AuthenticationService', () => { }); }); - describe('build event promise', () => { + describe('build auth event promise', () => { const event: OAuthEvent = createOAuthEvent(); beforeEach(() => { - service.shouldProceedByType = jest.fn().mockReturnValue(true); + service.shouldProceedByAuthEvent = jest.fn().mockReturnValue(true); service.setCurrentUser = jest.fn(); service.unsubscribeEvents = jest.fn(); }); - it('should call shouldProceedByType on event trigger', () => { - service.buildEventPromise(); + it('should call shouldProceedByAuthEvent on event trigger', () => { + service.buildAuthEventPromise(); eventsSubject.next(event); - expect(service.shouldProceedByType).toHaveBeenCalledWith(event); + expect(service.shouldProceedByAuthEvent).toHaveBeenCalledWith(event); }); describe('on next', () => { it('should set current user', () => { - service.buildEventPromise(); + service.buildAuthEventPromise(); eventsSubject.next(event); expect(service.setCurrentUser).toHaveBeenCalled(); }); it('should unsubscribe event', () => { - service.buildEventPromise(); + service.buildAuthEventPromise(); eventsSubject.next(event); expect(service.unsubscribeEvents).toHaveBeenCalled(); }); it('should resolved promise with a valid event', async () => { - const promise: Promise<void> = service.buildEventPromise(); + const promise: Promise<void> = service.buildAuthEventPromise(); eventsSubject.next(event); await expect(promise).resolves.toBeUndefined(); @@ -149,14 +149,14 @@ describe('AuthenticationService', () => { const error: Error = new Error(errorMessage); it('should unsubscribe event', () => { - service.buildEventPromise(); + service.buildAuthEventPromise(); eventsSubject.error(error); expect(service.unsubscribeEvents).toHaveBeenCalled(); }); it('should reject the promise with an error', async () => { - const promise: Promise<void> = service.buildEventPromise(); + const promise: Promise<void> = service.buildAuthEventPromise(); eventsSubject.error(error); @@ -165,13 +165,13 @@ describe('AuthenticationService', () => { }); }); - describe('should proceed by type', () => { + describe('should proceed by auth event', () => { const event: OAuthEvent = createOAuthEvent(); it('should call considered as login event', () => { service.consideredAsLoginEvent = jest.fn(); - service.shouldProceedByType(event); + service.shouldProceedByAuthEvent(event); expect(service.consideredAsLoginEvent).toHaveBeenCalledWith(event.type); }); @@ -179,7 +179,7 @@ describe('AuthenticationService', () => { it('should return true on login event', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(true); - const proceed: boolean = service.shouldProceedByType(event); + const proceed: boolean = service.shouldProceedByAuthEvent(event); expect(proceed).toBeTruthy(); }); @@ -188,7 +188,7 @@ describe('AuthenticationService', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); service.consideredAsPageReloadEvent = jest.fn(); - service.shouldProceedByType(event); + service.shouldProceedByAuthEvent(event); expect(service.consideredAsPageReloadEvent).toHaveBeenCalledWith(event.type); }); @@ -197,7 +197,7 @@ describe('AuthenticationService', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(true); - const proceed: boolean = service.shouldProceedByType(event); + const proceed: boolean = service.shouldProceedByAuthEvent(event); expect(proceed).toBeTruthy(); }); @@ -206,7 +206,7 @@ describe('AuthenticationService', () => { service.consideredAsLoginEvent = jest.fn().mockReturnValue(false); service.consideredAsPageReloadEvent = jest.fn().mockReturnValue(false); - const proceed: boolean = service.shouldProceedByType(event); + const proceed: boolean = service.shouldProceedByAuthEvent(event); expect(proceed).toBeFalsy(); }); diff --git a/alfa-client/libs/authentication/src/lib/authentication.service.ts b/alfa-client/libs/authentication/src/lib/authentication.service.ts index b22baa5b45..e350dcafe7 100644 --- a/alfa-client/libs/authentication/src/lib/authentication.service.ts +++ b/alfa-client/libs/authentication/src/lib/authentication.service.ts @@ -45,18 +45,18 @@ export class AuthenticationService { this.oAuthService.setupAutomaticSilentRefresh(); this.oAuthService.tokenValidationHandler = new JwksValidationHandler(); - const eventPromise: Promise<void> = this.buildEventPromise(); + const eventPromise: Promise<void> = this.buildAuthEventPromise(); await this.oAuthService.loadDiscoveryDocumentAndLogin(); return eventPromise; } - buildEventPromise(): Promise<void> { - return new Promise<void>((resolve, reject) => this.handleOAuthEventsForPromise(resolve, reject)); + buildAuthEventPromise(): Promise<void> { + return new Promise<void>((resolve, reject) => this.handleAuthEventsForPromise(resolve, reject)); } - private handleOAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void { + private handleAuthEventsForPromise(resolve: (value: void | PromiseLike<void>) => void, reject: (reason?: any) => void): void { this.eventSubscription = this.oAuthService.events - .pipe(filter((event: OAuthEvent) => this.shouldProceedByType(event))) + .pipe(filter((event: OAuthEvent) => this.shouldProceedByAuthEvent(event))) .subscribe({ next: () => { this.setCurrentUser(); @@ -70,7 +70,7 @@ export class AuthenticationService { }); } - shouldProceedByType(event: OAuthEvent): boolean { + shouldProceedByAuthEvent(event: OAuthEvent): boolean { return this.consideredAsLoginEvent(event.type) || this.consideredAsPageReloadEvent(event.type); } -- GitLab