diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts index 1f32f6c10ef12e86fad7b474f8516d8d952eac4d..9fcd500a1b5e338a41dbce953502042b46a61b2a 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.ts @@ -123,14 +123,13 @@ export class BescheidService { return { resource: this.vorgangService.getVorgangWithEingang(), getLinkRel: VorgangWithEingangLinkRel.BESCHEID_DRAFT, - editLinkRel: null, + delete: { linkRel: BescheidLinkRel.DELETE, order: CommandOrder.DELETE_BESCHEID }, }; } buildBescheidListServiceConfig(): ListResourceServiceConfig<VorgangWithEingangResource> { return { baseResource: this.vorgangService.getVorgangWithEingang(), - createLinkRel: null, listLinkRel: VorgangWithEingangLinkRel.BESCHEIDE, }; } diff --git a/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts b/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts index be256c5e2d6dd61e2bceebbd1012bb4f0f1b0dff..0f1608566b39496da4c29248ac4d94975df6d5c8 100644 --- a/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/+state/command.reducer.spec.ts @@ -1,4 +1,3 @@ -import { CommandResource, CreateCommand } from '@alfa-client/command-shared'; import { ApiError, createEmptyStateResource, @@ -8,14 +7,15 @@ import { import { HttpErrorResponse } from '@angular/common/http'; import { Action } from '@ngrx/store'; import { Resource, ResourceUri } from '@ngxp/rest'; -import { createCommandResource, createCreateCommand } from 'libs/command-shared/test/command'; -import { createApiError, createHttpErrorResponse } from 'libs/tech-shared/test/error'; -import { createDummyResource } from 'libs/tech-shared/test/resource'; +import { createApiError, createHttpErrorResponse } from '../../../../tech-shared/test/error'; +import { createDummyResource } from '../../../../tech-shared/test/resource'; +import { createCommandResource, createCreateCommand } from '../../../test/command'; +import { CommandResource, CreateCommand } from '../command.model'; import { CommandState, initialState, reducer } from './command.reducer'; import faker from '@faker-js/faker'; -import * as CommandActions from '@alfa-client/command-shared'; +import * as CommandActions from '../+state/command.actions'; describe('Command Reducer', () => { describe('unknown action', () => { diff --git a/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts b/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts index 65ab3989b73be46cc1631f535d6655981426aacd..fcfe5311cce57fa663f06048bd636ce649803df8 100644 --- a/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts +++ b/alfa-client/libs/command-shared/src/lib/+state/command.selectors.ts @@ -1,7 +1,7 @@ -import { CommandOrder } from '@alfa-client/command-shared'; import { createEmptyStateResource } from '@alfa-client/tech-shared'; import { MemoizedSelector, createFeatureSelector, createSelector } from '@ngrx/store'; import { isUndefined } from 'lodash-es'; +import { CommandOrder } from '../command.model'; import { COMMAND_FEATURE_KEY, CommandState } from './command.reducer'; const getCommandState: MemoizedSelector<object, CommandState> = diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts index 89623c8f67c8878de91a700f5a2544281304b33d..73c60da70421cec72dc85f7be6a696a3e7884aae 100644 --- a/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.spec.ts @@ -36,7 +36,7 @@ describe('CommandResourceService', () => { config = { resource: configStateResource$, getLinkRel, - editLinkRel, + edit: { linkRel: editLinkRel }, delete: { order: deleteOrder, linkRel: deleteLinkRel }, }; repository = mock(ResourceRepository); diff --git a/alfa-client/libs/command-shared/src/lib/command-resource.service.ts b/alfa-client/libs/command-shared/src/lib/command-resource.service.ts index 1c9adb7ba705e1ac994bbf8c53d96142ff0b86ac..0eb9f03aa4979479a1bcb27c9d79d7d959d6ff2d 100644 --- a/alfa-client/libs/command-shared/src/lib/command-resource.service.ts +++ b/alfa-client/libs/command-shared/src/lib/command-resource.service.ts @@ -27,6 +27,10 @@ export class CommandResourceService<B extends Resource, T extends Resource> exte super(config, repository); } + doSave(resource: T, toSave: unknown): Observable<T> { + throw new Error('Method not implemented.'); + } + public delete(): Observable<StateResource<CommandResource>> { this.verifyDeleteLinkRel(); return this.commandService.createCommandByProps(this.buildDeleteCommandProps()); diff --git a/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts index 85677d89699f6287043b22853246d7e6a047a361..8d4f98c231fd11e38aed3562bf23171b1b25387d 100644 --- a/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/assistive-technologies.util.spec.ts @@ -1,5 +1,5 @@ +import { EMPTY_STRING } from '../lib/tech.util'; import { createAriaLabelForIconButton } from './assistive-technologies.util'; -import { EMPTY_STRING } from '@alfa-client/tech-shared'; describe('createAriaLabelForIconButton', () => { const tooltip = 'Tooltip text'; diff --git a/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts b/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts index 10b94e399d82a1ef6c97eb156995e20584aebd4e..b28c779d60e0cc7f1a1e9e4517ae9b480c86e7e7 100644 --- a/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/decorator/catch-http-error.decorator.spec.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { CatchHttpError } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { CatchHttpError } from '../decorator/catch-http-error.decorator'; import { HttpErrorHandler } from '../error/error.handler'; import { catchHttpErrorHandleErrorResponse, diff --git a/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts b/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts index 3b4e3082a758ae9b5739f2ca415d1c95a828a9cc..b458fd3d70280cb5e9eeecf5976286683173074c 100644 --- a/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts +++ b/alfa-client/libs/tech-shared/src/lib/decorator/skip-error-interceptor.decorator.ts @@ -21,8 +21,8 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { HttpErrorHandler } from '@alfa-client/tech-shared'; import { finalize } from 'rxjs/operators'; +import { HttpErrorHandler } from '../error/error.handler'; import { disableInterceptorDefaultHandling, enableInterceptorDefaultHandling, diff --git a/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts b/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts index a7dcd4c44cf9af5283a5af62eda4c707cababcf7..b7bc5aa087526edd757c5dc66365f93040bcc8ec 100644 --- a/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts +++ b/alfa-client/libs/tech-shared/src/lib/interceptor/http-xsrf.interceptor.ts @@ -29,9 +29,9 @@ import { HttpXsrfTokenExtractor, } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { addRequestHeader, isNotNull } from '@alfa-client/tech-shared'; import { Observable } from 'rxjs'; -import { existRequestHeader, isChangingDataRequest } from '../http.util'; +import { addRequestHeader, existRequestHeader, isChangingDataRequest } from '../http.util'; +import { isNotNull } from '../tech.util'; @Injectable() export class HttpXsrfInterceptor implements HttpInterceptor { diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts index 81dbaf12263936f5f336bbd4afe1564b99fc825d..4776a773776cfc49b979333162834fd651a34cfd 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.spec.ts @@ -1,9 +1,13 @@ import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; -import { Observable, of } from 'rxjs'; +import { fakeAsync, tick } from '@angular/core/testing'; import { Resource } from '@ngxp/rest'; -import { createDummyResource } from 'libs/tech-shared/test/resource'; +import { createProblemDetail } from 'libs/tech-shared/test/error'; +import { Observable, of, throwError } from 'rxjs'; +import { singleCold, singleHot } from '../../../test//marbles'; +import { createDummyResource } from '../../../test/resource'; +import { HttpError, ProblemDetail } from '../tech.model'; import { ApiResourceService } from './api-resource.service'; -import { LinkRelationName, ResourceServiceConfig } from './resource.model'; +import { LinkRelationName, ResourceServiceConfig, SaveResourceData } from './resource.model'; import { ResourceRepository } from './resource.repository'; import { StateResource, createStateResource } from './resource.util'; @@ -18,12 +22,14 @@ describe('ApiResourceService', () => { const editLinkRel: string = 'dummyEditLinkRel'; const getLinkRel: LinkRelationName = 'dummyGetLinkRel'; + const deleteLinkRel: LinkRelationName = 'dummyDeleteLinkRel'; beforeEach(() => { config = { resource: configStateResource$, getLinkRel, - editLinkRel, + edit: { linkRel: editLinkRel }, + delete: { linkRel: deleteLinkRel }, }; repository = mock(ResourceRepository); @@ -33,4 +39,97 @@ describe('ApiResourceService', () => { it('should be created', () => { expect(service).toBeTruthy(); }); + + describe('save', () => { + const dummyToSave: unknown = {}; + const loadedResource: Resource = createDummyResource(); + + const resourceWithEditLinkRel: Resource = createDummyResource([editLinkRel]); + + it('should throw error if edit link not exists', () => { + service.stateResource.next(createStateResource(createDummyResource())); + + expect(() => service.save(dummyToSave)).toThrowError( + 'No edit link exists on current stateresource.', + ); + }); + + it('should call repository', fakeAsync(() => { + service.stateResource.next(createStateResource(resourceWithEditLinkRel)); + repository.save.mockReturnValue(of(loadedResource)); + + service.save(dummyToSave).subscribe(); + tick(); + + const expectedSaveResourceData: SaveResourceData<Resource> = { + resource: resourceWithEditLinkRel, + linkRel: editLinkRel, + toSave: dummyToSave, + }; + expect(repository.save).toHaveBeenCalledWith(expectedSaveResourceData); + })); + + it('should return saved object', () => { + service.stateResource.next(createStateResource(resourceWithEditLinkRel)); + repository.save.mockReturnValue(singleHot(loadedResource)); + + const saved: Observable<StateResource<Resource | HttpError>> = service.save(dummyToSave); + + expect(saved).toBeObservable(singleCold(createStateResource(loadedResource))); + }); + + it('should call handleError', () => { + service.stateResource.next(createStateResource(createDummyResource([config.edit.linkRel]))); + const errorResponse: ProblemDetail = createProblemDetail(); + repository.save.mockReturnValue(throwError(() => errorResponse)); + service.handleError = jest.fn(); + + service.save(<any>{}).subscribe(); + + expect(service.handleError).toHaveBeenCalledWith(errorResponse); + }); + + it('should update state resource subject', fakeAsync(() => { + service.stateResource.next(createStateResource(resourceWithEditLinkRel)); + repository.save.mockReturnValue(of(loadedResource)); + + service.save(dummyToSave).subscribe(); + tick(); + + expect(service.stateResource.value).toEqual(createStateResource(loadedResource)); + })); + }); + + describe('delete', () => { + const resourceWithDeleteLinkRel: Resource = createDummyResource([deleteLinkRel]); + const stateResourceWithDeleteLink: StateResource<Resource> = + createStateResource(resourceWithDeleteLinkRel); + + beforeEach(() => { + service.stateResource.next(stateResourceWithDeleteLink); + }); + + it('should throw error if delete linkRel not exists on current stateresource', () => { + service.stateResource.next(createStateResource(createDummyResource())); + + expect(() => service.delete()).toThrowError( + 'No delete link exists on current stateresource.', + ); + }); + + it('should call repository', () => { + service.delete(); + + expect(repository.delete).toHaveBeenCalledWith(resourceWithDeleteLinkRel, deleteLinkRel); + }); + + it('should return value', () => { + const deleteResource: Resource = createDummyResource(); + repository.delete.mockReturnValue(singleHot(deleteResource)); + + const deletedResource: Observable<Resource> = service.delete(); + + expect(deletedResource).toBeObservable(singleCold(deleteResource)); + }); + }); }); diff --git a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts index e744c170f150788f4231ca98bdf527c4d186cf4f..2f328bcfd4ada2264cfc13c8df28b33a2ac81691 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/api-resource.service.ts @@ -1,4 +1,5 @@ import { Resource } from '@ngxp/rest'; +import { Observable } from 'rxjs'; import { ResourceServiceConfig } from './resource.model'; import { ResourceRepository } from './resource.repository'; import { ResourceService } from './resource.service'; @@ -13,4 +14,17 @@ export class ApiResourceService<B extends Resource, T extends Resource> extends ) { super(config, repository); } + + doSave(resource: T, toSave: unknown): Observable<T> { + return <Observable<T>>this.repository.save({ + resource, + linkRel: this.config.edit.linkRel, + toSave, + }); + } + + public delete(): Observable<Resource> { + this.verifyDeleteLinkRel(); + return this.repository.delete(this.getResource(), this.config.delete.linkRel); + } } diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts index 3617275710c2def1ed2c9a5a7f9c795283e03ac1..e7e4b3264d1648063ce6d8e85ebe27ffcd779f3e 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.model.ts @@ -5,7 +5,7 @@ import { StateResource } from './resource.util'; export interface ListResourceServiceConfig<B> { baseResource: Observable<StateResource<B>>; listLinkRel: LinkRelationName; - createLinkRel: LinkRelationName; + createLinkRel?: LinkRelationName; } export interface CreateResourceData<T> { @@ -26,6 +26,6 @@ export declare type LinkRelationName = string; export interface ResourceServiceConfig<B> { resource: Observable<StateResource<B>>; getLinkRel: LinkRelationName; - editLinkRel: LinkRelationName; - delete?: { order: string; linkRel: string }; + delete?: { linkRel: LinkRelationName; order?: string }; + edit?: { linkRel: LinkRelationName; order?: string }; } diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts index 2e6894ecb1529b743a0ce877c406421b95bd5c2f..e5a9f28f281136f4ac735e04259cc76ce15a051e 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource.util.spec.ts @@ -22,25 +22,19 @@ * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { - containsLoading, - createErrorStateResource, - EMPTY_ARRAY, - getSuccessfullyLoaded, - StateResource, -} from '@alfa-client/tech-shared'; import { Resource } from '@ngxp/rest'; -import { - createDummyListResource, - createDummyResource, - toResource, -} from 'libs/tech-shared/test/resource'; import { DummyListLinkRel } from '../../../test/dummy'; import { createApiError } from '../../../test/error'; +import { createDummyListResource, createDummyResource, toResource } from '../../../test/resource'; +import { EMPTY_ARRAY } from '../tech.util'; import { + StateResource, + containsLoading, createEmptyStateResource, + createErrorStateResource, createStateResource, getEmbeddedResources, + getSuccessfullyLoaded, isInvalidResourceCombination, isLoaded, isLoadingRequired,