diff --git a/goofy-client/apps/goofy-e2e/docker-compose.yml b/goofy-client/apps/goofy-e2e/docker-compose.yml index 34b9df4fbe4a465b5e9b911541832ae7b02a0738..ea6bc11d6254959e66491b8b19dc4c232112417b 100644 --- a/goofy-client/apps/goofy-e2e/docker-compose.yml +++ b/goofy-client/apps/goofy-e2e/docker-compose.yml @@ -109,7 +109,7 @@ services: - KOP_KEYCLOAK_API_PASSWORD= - KOP_KEYCLOAK_API_REALM=by-e2e-local-dev - KOP_KEYCLOAK_API_CLIENT=alfa - - KOP_KEYCLOAK_SYNC_CRON=5 */5 * * * ? + - KOP_KEYCLOAK_SYNC_CRON=disabled - KEYCLOAK_URL=https://sso.dev.by.ozg-cloud.de - KOP_USER_MANAGER_URL=http://localhost:9092 - QUARKUS_MONGODB_CONNECTION_STRING=mongodb://ozg-mongodb:27017 diff --git a/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.spec.ts b/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.spec.ts index 0b54099e8046afd71836a2acebfb726f1d47503f..03366286a1e3e1ae92257ef11d94ce04e853991e 100644 --- a/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.spec.ts +++ b/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.spec.ts @@ -21,6 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ +import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; import { TestBed } from '@angular/core/testing'; import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot, UrlSegment } from '@angular/router'; import faker from '@faker-js/faker'; @@ -28,7 +29,7 @@ import { encodeUrlForEmbedding } from '@goofy-client/tech-shared'; import { mock } from '@goofy-client/test-utils'; import { SnackBarService } from '@goofy-client/ui'; import { WiedervorlageService } from '@goofy-client/wiedervorlage-shared'; -import { Observable, of } from 'rxjs'; +import { EMPTY, Observable, of } from 'rxjs'; import * as RouterHelper from '@angular/router'; import * as Guard from './wiedervorlage.guard'; @@ -39,6 +40,7 @@ const state: RouterStateSnapshot = { root: { url: [<UrlSegment>{}] } } as unknow describe('wiedervorlageGuard', () => { const wiedervorlageService = mock(WiedervorlageService); const snackbarService = mock(SnackBarService); + const createUrlTreeForVorgang = jest.spyOn(Guard, 'createUrlTreeForVorgang').mockReturnValue(<RouterHelper.UrlTree>{}); beforeEach(() => { TestBed.configureTestingModule({ @@ -54,7 +56,7 @@ describe('wiedervorlageGuard', () => { ] }); - jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(of(false)); + jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(EMPTY); }); @@ -65,6 +67,7 @@ describe('wiedervorlageGuard', () => { }); describe('wiedervorlageGuard', () => { + it('should call wiedervorlageService.hasEditLink', () => { const spy = jest.spyOn(wiedervorlageService, 'hasEditLink'); next.params['wiedervorlageUrl'] = encodeUrlForEmbedding(faker.internet.url()); @@ -74,37 +77,40 @@ describe('wiedervorlageGuard', () => { expect(spy).toHaveBeenCalled(); }) - it('should call createUrlTreeFromSnapshot', () => { - const createUrlTreeFromSnapshot = jest.spyOn(RouterHelper, 'createUrlTreeFromSnapshot'); + it('should return UrlTree object', (done) => { jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(of(false)); TestBed.runInInjectionContext(() => ( - Guard.wiedervorlageGuard(next, state) as Observable<RouterHelper.UrlTree>).subscribe() + Guard.wiedervorlageGuard(next, state) as Observable<RouterHelper.UrlTree>).subscribe( + result => { + expect(result).toBeInstanceOf(Object); + done(); + } + ) ) as unknown as CanActivateFn; - - expect(createUrlTreeFromSnapshot).toHaveBeenCalled(); }) - it.skip('should return UrlTree', (done) => { - jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(of(false)); + it('should return true', (done) => { + jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(of(true)); TestBed.runInInjectionContext(() => ( Guard.wiedervorlageGuard(next, state) as Observable<RouterHelper.UrlTree>).subscribe( result => { - expect(result).toBeInstanceOf(RouterHelper.UrlTree); + expect(result).toBeTruthy(); done(); } ) ) as unknown as CanActivateFn; }) - it('should return true', (done) => { - jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(of(true)); + it.skip('should call handleError if error occurs', (done) => { + jest.spyOn(wiedervorlageService, 'hasEditLink').mockReturnValue(of(new Error())); + const spy = jest.spyOn(Guard, 'handleError'); TestBed.runInInjectionContext(() => ( Guard.wiedervorlageGuard(next, state) as Observable<RouterHelper.UrlTree>).subscribe( - result => { - expect(result).toBeTruthy(); + () => { + expect(spy).toHaveBeenCalled(); done(); } ) @@ -121,7 +127,7 @@ describe('wiedervorlageGuard', () => { expect(result).toBeTruthy(); }) - it.skip('should call showSnackbar if hasLink is false', () => { + it('should call showSnackbar if hasLink is false', () => { const hasLink = false; const spy = jest.spyOn(Guard, 'showSnackbar'); @@ -130,14 +136,13 @@ describe('wiedervorlageGuard', () => { expect(spy).toHaveBeenCalled(); }) - it.skip('should return URLTree object if hasLink is false', () => { - const spy = jest.spyOn(RouterHelper, 'createUrlTreeFromSnapshot'); + it('should call createUrlTreeForVorgang if hasLink is false', () => { const hasLink = false; jest.spyOn(Guard, 'showSnackbar'); Guard.handleLinkCheck(hasLink, next, snackbarService as unknown as SnackBarService); - expect(spy).toHaveBeenCalled(); + expect(createUrlTreeForVorgang).toHaveBeenCalled(); }) }) @@ -151,4 +156,28 @@ describe('wiedervorlageGuard', () => { }) }) + describe('handleError', () => { + it('should return Observable<UrlTree> if HTTP Status 403', () => { + const error = createHttpError(HttpStatusCode.Forbidden); + + const res: RouterHelper.UrlTree = Guard.handleError(error, next); + + expect(res).toBeInstanceOf(Object); + + }) + + it('should return nothing if HTTP Status is not 403', () => { + const error = createHttpError(HttpStatusCode.Unauthorized); + + function monitorErrorThrowing() { + Guard.handleError(error, next); + } + + expect(monitorErrorThrowing).toThrow(); + }) + }) + + function createHttpError(status: HttpStatusCode): any { + return { error: new HttpErrorResponse({ status }) }; + } }); diff --git a/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.ts b/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.ts index 1238ee52f9c4ed9a8e298d00c1490a70b1909d74..261285469009982e60cbd3940bf5d942a7582c57 100644 --- a/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.ts +++ b/goofy-client/libs/wiedervorlage/src/lib/wiedervorlage.guard.ts @@ -23,11 +23,14 @@ */ import { inject } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivateFn, RouterStateSnapshot, UrlTree, createUrlTreeFromSnapshot } from '@angular/router'; +import { isForbidden } from '@goofy-client/tech-shared'; import { SnackBarService } from '@goofy-client/ui'; import { WiedervorlageService } from '@goofy-client/wiedervorlage-shared'; -import { map } from 'rxjs'; +import { Observable, catchError, map, of } from 'rxjs'; -export const wiedervorlageGuard: CanActivateFn = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => { +import * as Guard from './wiedervorlage.guard'; + +export const wiedervorlageGuard: CanActivateFn = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | Observable<boolean | UrlTree> | UrlTree => { const wiedervorlageService = inject(WiedervorlageService) const snackbarService = inject(SnackBarService); @@ -37,7 +40,8 @@ export const wiedervorlageGuard: CanActivateFn = (next: ActivatedRouteSnapshot, } return wiedervorlageService.hasEditLink(wiedervorlageUrl).pipe( - map(hasLink => handleLinkCheck(hasLink, next, snackbarService)) + map(hasLink => Guard.handleLinkCheck(hasLink, next, snackbarService)), + catchError((err) => of(Guard.handleError(err, next))) ); }; @@ -46,11 +50,23 @@ export function handleLinkCheck(hasLink: boolean, next: ActivatedRouteSnapshot, return true; } - showSnackbar(snackbarService); + Guard.showSnackbar(snackbarService); - return createUrlTreeFromSnapshot(next, ['/vorgang', next.params['vorgangWithEingangUrl']]); + return Guard.createUrlTreeForVorgang(next); } export function showSnackbar(snackbarService: SnackBarService): void { snackbarService.showError('Im Status "Zu löschen" ist die Bearbeitung von Wiedervorlagen nicht möglich.'); } + +export function handleError(err: any, next: ActivatedRouteSnapshot): UrlTree { + if (isForbidden(err.error.status)) { + return Guard.createUrlTreeForVorgang(next); + } + + throw err; +} + +export function createUrlTreeForVorgang(next: ActivatedRouteSnapshot): UrlTree { + return createUrlTreeFromSnapshot(next, ['/vorgang', next.params['vorgangWithEingangUrl']]); +} \ No newline at end of file