diff --git a/.vscode/settings.json b/.vscode/settings.json index 02ffa78fc20462c7539afdc7ef4cc8b7b63bdd1b..9b1e5446992d170181e31942d75d020e12bbe5d3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "angular.enable-strict-mode-prompt": false, - "java.debug.settings.onBuildFailureProceed": true + "java.debug.settings.onBuildFailureProceed": true, + "java.compile.nullAnalysis.mode": "automatic" } \ No newline at end of file diff --git a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts index dbd5760dbef9a22d5739ee2e05a7b1c7df37c73b..9433275b79fafd874af6f7fbef835e5ad2deb76f 100644 --- a/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts +++ b/alfa-client/apps/alfa-e2e/src/components/vorgang/vorgang-zusammenarbeit.e2e.component.ts @@ -5,7 +5,7 @@ export class VorgangZusammenarbeitE2EComponent { private readonly zustaendigeStelleButton: string = 'organisations-einheit-search-button'; private readonly titelText: string = 'Titel-text-input'; private readonly messageText: string = 'Nachricht-textarea'; - private readonly sendButton: string = 'collaboration-request-send-button'; + private readonly sendButton: string = 'collaboration-request-submit-button'; private readonly cancelButton: string = 'collaboration-request-cancel-button'; public getAnfrageButton(): Cypress.Chainable<JQuery<HTMLElement>> { diff --git a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts index f0f740181ae37e11538d269dd8d64a10b36c2b3b..6fba31ec8361dbb715becde41d640de4cc06b93e 100644 --- a/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts +++ b/alfa-client/libs/bescheid-shared/src/lib/bescheid.service.spec.ts @@ -11,13 +11,13 @@ import { } from '@alfa-client/command-shared'; import { ApiError, - createEmptyStateResource, - createErrorStateResource, - createStateResource, EMPTY_ARRAY, EMPTY_STRING, HttpError, StateResource, + createEmptyStateResource, + createErrorStateResource, + createStateResource, } from '@alfa-client/tech-shared'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { @@ -28,12 +28,12 @@ import { } from '@alfa-client/vorgang-shared'; import { fakeAsync, tick } from '@angular/core/testing'; import faker from '@faker-js/faker'; -import { getUrl, ResourceUri } from '@ngxp/rest'; +import { ResourceUri, getUrl } from '@ngxp/rest'; import { cold } from 'jest-marbles'; import { CommandLinkRel } from 'libs/command-shared/src/lib/command.linkrel'; import { createApiError } from 'libs/tech-shared/test/error'; import { createVorgangWithEingangResource } from 'libs/vorgang-shared/test/vorgang'; -import { first, Observable, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { createBinaryFileListResource, createBinaryFileResource, @@ -153,7 +153,7 @@ describe('BescheidService', () => { }); it('should call facade', () => { - service.createBescheid(vorgangWithEingang).pipe(first()).subscribe(); + service.createBescheid(vorgangWithEingang).subscribe(); expect(facade.createBescheidDraft).toHaveBeenCalledWith(vorgangWithEingang, { order: CommandOrder.CREATE_BESCHEID, @@ -162,7 +162,7 @@ describe('BescheidService', () => { }); it('should set resource by uri', () => { - service.createBescheid(vorgangWithEingang).pipe(first()).subscribe(); + service.createBescheid(vorgangWithEingang).subscribe(); expect(service.bescheidResourceService.loadByResourceUri).toHaveBeenCalledWith( getUrl(command, CommandLinkRel.EFFECTED_RESOURCE), @@ -450,7 +450,6 @@ describe('BescheidService', () => { it('should set resource by uri', (done) => { service .updateBescheid(bescheid) - .pipe(first()) .subscribe((commandStateResource: StateResource<CommandResource>) => { expect(service.bescheidResourceService.loadByResourceUri).toHaveBeenCalledWith( getUrl(commandStateResource.resource, CommandLinkRel.EFFECTED_RESOURCE), @@ -1134,7 +1133,7 @@ describe('BescheidService', () => { }); it('should get resource', () => { - service.bescheidVerwerfen().pipe(first()).subscribe(); + service.bescheidVerwerfen().subscribe(); expect(service.getResource).toHaveBeenCalled(); }); @@ -1316,19 +1315,19 @@ describe('BescheidService', () => { }); it('should get items', () => { - service.getLastBescheid().pipe(first()).subscribe(); + service.getLastBescheid().subscribe(); expect(getItemsSpy).toHaveBeenCalled(); }); it('should filter by sent status', () => { - service.getLastBescheid().pipe(first()).subscribe(); + service.getLastBescheid().subscribe(); expect(service.filterBySentStatus).toHaveBeenCalledWith(bescheide); }); it('should sort by beschieden am', () => { - service.getLastBescheid().pipe(first()).subscribe(); + service.getLastBescheid().subscribe(); expect(sortByGermanDateStrSpy).toHaveBeenCalledWith(bescheide, expect.any(Function)); }); @@ -1357,13 +1356,13 @@ describe('BescheidService', () => { }); it('should get items', () => { - service.existBescheid().pipe(first()).subscribe(); + service.existBescheid().subscribe(); expect(getItemsSpy).toHaveBeenCalled(); }); it('should filter by sent status', () => { - service.existBescheid().pipe(first()).subscribe(); + service.existBescheid().subscribe(); expect(service.filterBySentStatus).toHaveBeenCalledWith(bescheide); }); diff --git a/alfa-client/libs/collaboration-shared/src/index.ts b/alfa-client/libs/collaboration-shared/src/index.ts index 06849e9b26984071d6ee28a69bc0e9315a4ef10e..cd761bf34a9d3d1e63337bb36e92e56977ef0b1e 100644 --- a/alfa-client/libs/collaboration-shared/src/index.ts +++ b/alfa-client/libs/collaboration-shared/src/index.ts @@ -1,4 +1,6 @@ export * from './lib/collaboration-shared.module'; +export * from './lib/collaboration.linkrel'; +export * from './lib/collaboration.model'; export * from './lib/organisations-einheit.linkrel'; export * from './lib/organisations-einheit.model'; export * from './lib/organisations-einheit.service'; diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration-list-resource.service.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration-list-resource.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..fa6f47d5d6292485b6d84de0040fc1913c692569 --- /dev/null +++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration-list-resource.service.ts @@ -0,0 +1,34 @@ +import { + ListResourceServiceConfig, + ResourceListService, + ResourceRepository, +} from '@alfa-client/tech-shared'; +import { + VorgangResource, + VorgangService, + VorgangWithEingangLinkRel, +} from '@alfa-client/vorgang-shared'; +import { CollaborationListLinkRel } from './collaboration.linkrel'; +import { CollaborationListResource, CollaborationResource } from './collaboration.model'; + +export class CollaborationListResourceService extends ResourceListService< + VorgangResource, + CollaborationListResource, + CollaborationResource +> {} + +export function createCollaborationListResourceService( + repository: ResourceRepository, + vorgangService: VorgangService, +) { + return new ResourceListService(buildConfig(vorgangService), repository); +} + +function buildConfig(vorgangService: VorgangService): ListResourceServiceConfig<VorgangResource> { + return { + baseResource: vorgangService.getVorgangWithEingang(), + listLinkRel: VorgangWithEingangLinkRel.COLLABORATIONS, + listResourceListLinkRel: CollaborationListLinkRel.COLLABORATION_LIST, + createLinkRel: CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST, + }; +} diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts index 1dc63e9f65aede42e64a9f3b2bfea0f295e7a80f..b4a95fe57bb26a6a1fe9cd8de98e6c2422b0033b 100644 --- a/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts +++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration-shared.module.ts @@ -2,6 +2,10 @@ import { ResourceRepository } from '@alfa-client/tech-shared'; import { VorgangService } from '@alfa-client/vorgang-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { + CollaborationListResourceService, + createCollaborationListResourceService, +} from './collaboration-list-resource.service'; import { CollaborationService } from './collaboration.service'; import { OrganisationsEinheitResourceSearchService, @@ -14,6 +18,11 @@ import { OrganisationsEinheitService } from './organisations-einheit.service'; providers: [ CollaborationService, OrganisationsEinheitService, + { + provide: CollaborationListResourceService, + useFactory: createCollaborationListResourceService, + deps: [ResourceRepository, VorgangService], + }, { provide: OrganisationsEinheitResourceSearchService, useFactory: createOrganisationsEinheitResourceSearchService, diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.linkrel.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.linkrel.ts new file mode 100644 index 0000000000000000000000000000000000000000..967a0a0a1990749d02d9153c1e2d1a4d88869936 --- /dev/null +++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.linkrel.ts @@ -0,0 +1,4 @@ +export enum CollaborationListLinkRel { + COLLABORATION_LIST = 'collaborationList', + CREATE_COLLABORATION_REQUEST = 'createCollaborationRequest', +} diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.model.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e5a678748f2ac3076ff3a7cd94f60d5bf69eae0 --- /dev/null +++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.model.ts @@ -0,0 +1,11 @@ +import { ListItemResource, ListResource } from '@alfa-client/tech-shared'; +import { Resource, ResourceUri } from '@ngxp/rest'; + +export interface Collaboration { + titel: string; + anfrage: string; + zustaendigeStelle: ResourceUri; +} + +export interface CollaborationResource extends Collaboration, Resource, ListItemResource {} +export interface CollaborationListResource extends ListResource {} diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts index e0e2979bbb5773ae0ac729f4f48272bd9071f261..d5cdf3d7a38229b500188f238c7ed137ac9a475b 100644 --- a/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts +++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.spec.ts @@ -1,10 +1,53 @@ +import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared'; +import { StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; +import { createCommandResource } from 'libs/command-shared/test/command'; +import { singleColdCompleted } from 'libs/tech-shared/test/marbles'; +import { Observable, of } from 'rxjs'; +import { + createCollaboration, + createCollaborationListResource, +} from '../../../collaboration-shared/test/collaboration'; +import { CollaborationListResourceService } from './collaboration-list-resource.service'; +import { CollaborationListLinkRel } from './collaboration.linkrel'; +import { Collaboration, CollaborationListResource } from './collaboration.model'; import { CollaborationService } from './collaboration.service'; +jest.mock('./collaboration-list-resource.service'); + describe('CollaborationService', () => { let service: CollaborationService; + let listService: Mock<CollaborationListResourceService>; + let commandService: Mock<CommandService>; + + const collaborationListResource: CollaborationListResource = createCollaborationListResource(); + const collaborationStateListResource: StateResource<CollaborationListResource> = + createStateResource(collaborationListResource); + beforeEach(() => { - service = new CollaborationService(); + listService = mock(CollaborationListResourceService); + commandService = mock(CommandService); + + service = new CollaborationService(useFromMock(listService), useFromMock(commandService)); + }); + + describe('get list', () => { + beforeEach(() => { + listService.getList.mockReturnValue(of(collaborationStateListResource)); + }); + + it('should call service', () => { + service.getList(); + + expect(listService.getList).toHaveBeenCalled(); + }); + + it('should return value', () => { + const list$: Observable<StateResource<CollaborationListResource>> = service.getList(); + + expect(list$).toBeObservable(singleColdCompleted(collaborationStateListResource)); + }); }); describe('is request form visible', () => { @@ -39,4 +82,38 @@ describe('CollaborationService', () => { expect(service.showRequestForm$.value).toBeFalsy(); }); }); + + describe('create', () => { + const collaborationListResource: CollaborationListResource = createCollaborationListResource(); + const commandStateResource: StateResource<CommandResource> = + createStateResource(createCommandResource()); + const collaboration: Collaboration = createCollaboration(); + + beforeEach(() => { + commandService.createCommandByProps.mockReturnValue(of(commandStateResource)); + }); + + it('should call command service', () => { + service.create(collaborationListResource, collaboration); + + expect(commandService.createCommandByProps).toHaveBeenCalledWith({ + linkRel: CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST, + resource: collaborationListResource, + command: { + order: CommandOrder.CREATE_COLLABORATION_REQUEST, + body: collaboration, + }, + snackBarMessage: 'Die Zuarbeit wurde angefragt.', + }); + }); + + it('should return value', () => { + const created$: Observable<StateResource<CommandResource>> = service.create( + collaborationListResource, + collaboration, + ); + + expect(created$).toBeObservable(singleColdCompleted(commandStateResource)); + }); + }); }); diff --git a/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts index 825e329acd0761272b43e287cf94cfa94b3bb93b..f210a1133df3293f5bfa9da2bdd97fe033af1f6c 100644 --- a/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts +++ b/alfa-client/libs/collaboration-shared/src/lib/collaboration.service.ts @@ -1,10 +1,24 @@ +import { CommandOrder, CommandResource, CommandService } from '@alfa-client/command-shared'; +import { StateResource } from '@alfa-client/tech-shared'; import { Injectable } from '@angular/core'; import { BehaviorSubject, Observable } from 'rxjs'; +import { CollaborationListResourceService } from './collaboration-list-resource.service'; +import { CollaborationListLinkRel } from './collaboration.linkrel'; +import { Collaboration, CollaborationListResource } from './collaboration.model'; @Injectable() export class CollaborationService { showRequestForm$: BehaviorSubject<boolean> = new BehaviorSubject(false); + constructor( + private listService: CollaborationListResourceService, + private commandService: CommandService, + ) {} + + public getList(): Observable<StateResource<CollaborationListResource>> { + return this.listService.getList(); + } + public isRequestFormVisible(): Observable<boolean> { return this.showRequestForm$.asObservable(); } @@ -16,4 +30,19 @@ export class CollaborationService { public hideRequestForm(): void { this.showRequestForm$.next(false); } + + public create( + listResource: CollaborationListResource, + collaborationRequest: Collaboration, + ): Observable<StateResource<CommandResource>> { + return this.commandService.createCommandByProps({ + linkRel: CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST, + resource: listResource, + command: { + order: CommandOrder.CREATE_COLLABORATION_REQUEST, + body: collaborationRequest, + }, + snackBarMessage: 'Die Zuarbeit wurde angefragt.', + }); + } } diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts index b1d9a7a6511203304b7367a91df208012eaf3070..f264006658fe044ac57ad9a2926427046ba6f029 100644 --- a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts +++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.spec.ts @@ -69,11 +69,11 @@ describe('OrganisationsEinheitService', () => { }); describe('get selected result', () => { - const organisationsEinheitStateResource: StateResource<OrganisationsEinheitResource> = - createStateResource(createOrganisationsEinheitResource()); + const organisationsEinheitResource: OrganisationsEinheitResource = + createOrganisationsEinheitResource(); beforeEach(() => { - searchService.getSelectedResult.mockReturnValue(of(organisationsEinheitStateResource)); + searchService.getSelectedResult.mockReturnValue(of(organisationsEinheitResource)); }); it('should call service', () => { @@ -83,12 +83,9 @@ describe('OrganisationsEinheitService', () => { }); it('should return result', () => { - const selectedResult$: Observable<StateResource<OrganisationsEinheitResource>> = - service.getSelectedResult(); + const selectedResult$: Observable<OrganisationsEinheitResource> = service.getSelectedResult(); - expect(selectedResult$).toBeObservable( - singleColdCompleted(organisationsEinheitStateResource), - ); + expect(selectedResult$).toBeObservable(singleColdCompleted(organisationsEinheitResource)); }); }); @@ -102,4 +99,12 @@ describe('OrganisationsEinheitService', () => { expect(searchService.selectResult).toHaveBeenCalledWith(organisationsEinheitResource); }); }); + + describe('clear selected result', () => { + it('should call service', () => { + service.clearSelectedResult(); + + expect(searchService.clearSelectedResult).toHaveBeenCalled(); + }); + }); }); diff --git a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts index 64e7ad7d286c23556b3a5fbfa305dfc4bea06d86..495c115446391b8d126feef91bc6b02ad9c24134 100644 --- a/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts +++ b/alfa-client/libs/collaboration-shared/src/lib/organisations-einheit.service.ts @@ -23,11 +23,15 @@ export class OrganisationsEinheitService { this.searchService.clearResultList(); } - public getSelectedResult(): Observable<StateResource<OrganisationsEinheitResource>> { + public getSelectedResult(): Observable<OrganisationsEinheitResource> { return this.searchService.getSelectedResult(); } public selectSearchResult(organisationsEinheitResource: OrganisationsEinheitResource): void { this.searchService.selectResult(organisationsEinheitResource); } + + public clearSelectedResult(): void { + this.searchService.clearSelectedResult(); + } } diff --git a/alfa-client/libs/collaboration-shared/test/collaboration.ts b/alfa-client/libs/collaboration-shared/test/collaboration.ts new file mode 100644 index 0000000000000000000000000000000000000000..fef47c56b2280e8cc85ae90773b90ba9d910d868 --- /dev/null +++ b/alfa-client/libs/collaboration-shared/test/collaboration.ts @@ -0,0 +1,38 @@ +import faker from '@faker-js/faker'; +import { times } from 'lodash-es'; +import { LinkRelationName } from '../../tech-shared/src'; +import { toResource } from '../../tech-shared/test/resource'; +import { CollaborationListLinkRel, OrganisationsEinheitResource } from '../src'; +import { + Collaboration, + CollaborationListResource, + CollaborationResource, +} from '../src/lib/collaboration.model'; + +export function createCollaboration(): Collaboration { + return { + titel: faker.random.words(2), + anfrage: faker.random.words(10), + zustaendigeStelle: faker.internet.url(), + }; +} + +export function createCollaborationResource( + linkRelations: LinkRelationName[] = [], +): CollaborationResource { + return toResource(createCollaboration(), linkRelations); +} + +export function createCollaborationResources( + linkRelations: LinkRelationName[] = [], +): OrganisationsEinheitResource[] { + return times(10, () => toResource(createCollaborationResource(), [...linkRelations])); +} + +export function createCollaborationListResource( + linkRelations: LinkRelationName[] = [], +): CollaborationListResource { + return toResource({}, [...linkRelations], { + [CollaborationListLinkRel.COLLABORATION_LIST]: createCollaborationResources(), + }); +} diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html index f27618ee6c09178f91b15400a43babd3d4088d6a..d0d5db82cd5b543c578693ef03c4907a134077f8 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.html @@ -1,17 +1,8 @@ -<ng-template #anfrageErstellenButton> - <ods-button - variant="outline" - text="Anfrage erstellen" - dataTestId="anfrage-erstellen-button" - (clickEmitter)="showRequestForm()" - > - <ods-collaboration-icon icon /> - </ods-button> -</ng-template> - -<ng-container *ngIf="isRequestFormVisible$ | async; else anfrageErstellenButton"> - <alfa-collaboration-request-form - data-test-id="collaboration-request-form" - (hide)="hideRequestForm()" - ></alfa-collaboration-request-form> -</ng-container> +<alfa-collaboration-in-vorgang + data-test-id="collaboration-in-vorgang" + [collaborationStateListResource]="collaborationStateListResource$ | async" + [isRequestFormVisible]="isRequestFormVisible$ | async" + [organisationsEinheit]="selectedOrganisationsEinheit$ | async" + (hideRequestForm)="hideRequestForm()" + (showRequestForm)="showRequestForm()" +></alfa-collaboration-in-vorgang> diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts index cf09233c2433ac766cbc1b600069666d836013b5..a5e6e9e22dc4c22f174f59115b1bb954d1addaf3 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.spec.ts @@ -1,44 +1,52 @@ import { - Mock, - dispatchEventFromFixture, - existsAsHtmlElement, - mock, - notExistsAsHtmlElement, -} from '@alfa-client/test-utils'; + CollaborationListResource, + OrganisationsEinheitResource, +} from '@alfa-client/collaboration-shared'; +import { StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { Mock, dispatchEventFromFixture, getMockComponent, mock } from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { ButtonComponent, CollaborationIconComponent } from '@ods/system'; import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; -import { getDataTestIdAttributeOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { OrganisationsEinheitResourceSearchService } from 'libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service'; +import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration'; +import { createOrganisationsEinheitResource } from 'libs/collaboration-shared/test/organisations-einheit'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; import { CollaborationInVorgangContainerComponent } from './collaboration-in-vorgang-container.component'; -import { CollaborationRequestFormComponent } from './collaboration-request-form/collaboration-request-form.component'; +import { CollaborationInVorgangComponent } from './collaboration-in-vorgang/collaboration-in-vorgang.component'; + +jest.mock('libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service'); describe('CollaborationInVorgangContainerComponent', () => { let component: CollaborationInVorgangContainerComponent; let fixture: ComponentFixture<CollaborationInVorgangContainerComponent>; - const anfrageErstellenButton: string = getDataTestIdAttributeOf('anfrage-erstellen-button'); - const collaborationRequestForm: string = getDataTestIdOf('collaboration-request-form'); + const collaborationInVorgangComp: string = getDataTestIdOf('collaboration-in-vorgang'); const service: Mock<CollaborationService> = { ...mock(CollaborationService), isRequestFormVisible: jest.fn().mockReturnValue(of(false)), }; + const organisationsEinheitSearchService: Mock<OrganisationsEinheitResourceSearchService> = mock( + OrganisationsEinheitResourceSearchService, + ); + beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ CollaborationInVorgangContainerComponent, - MockComponent(ButtonComponent), - MockComponent(CollaborationRequestFormComponent), - MockComponent(CollaborationIconComponent), + MockComponent(CollaborationInVorgangComponent), ], providers: [ { provide: CollaborationService, useValue: service, }, + { + provide: OrganisationsEinheitResourceSearchService, + useValue: organisationsEinheitSearchService, + }, ], }).compileComponents(); @@ -52,69 +60,107 @@ describe('CollaborationInVorgangContainerComponent', () => { }); describe('ngOnInit', () => { - it('should call service', () => { + it('should call service to get collaboration state list resource', () => { + component.ngOnInit(); + + expect(service.getList).toHaveBeenCalled(); + }); + + it('should call service to get request form visbility', () => { component.ngOnInit(); expect(service.isRequestFormVisible).toHaveBeenCalled(); }); + + it('should get selected result', () => { + component.ngOnInit(); + + expect(organisationsEinheitSearchService.getSelectedResult).toHaveBeenCalled(); + }); }); - describe('anfrage erstellen button', () => { - describe('on request form visibility false', () => { - beforeEach(() => { - component.isRequestFormVisible$ = of(false); - }); + describe('collaboration in vorgang component', () => { + const collaborationListResource: CollaborationListResource = createCollaborationListResource(); + const collaborationStateListResource: StateResource<CollaborationListResource> = + createStateResource(collaborationListResource); + + describe('should be called with', () => { + it('collaboration state list resource', () => { + component.collaborationStateListResource$ = of(collaborationStateListResource); - it('should be shown', () => { fixture.detectChanges(); - existsAsHtmlElement(fixture, anfrageErstellenButton); + expect(getCollaborationInVorgangComponent().collaborationStateListResource).toBe( + collaborationStateListResource, + ); }); - it('should call service on click', () => { + it('is request form visible', () => { + component.isRequestFormVisible$ = of(true); + fixture.detectChanges(); - dispatchEventFromFixture(fixture, anfrageErstellenButton, 'clickEmitter'); + expect(getCollaborationInVorgangComponent().isRequestFormVisible).toBeTruthy(); + }); + + it('organisations einheit', () => { + const organisationsEinheitResource: OrganisationsEinheitResource = + createOrganisationsEinheitResource(); + component.selectedOrganisationsEinheit$ = of(organisationsEinheitResource); - expect(service.showRequestForm).toHaveBeenCalled(); + fixture.detectChanges(); + + expect(getCollaborationInVorgangComponent().organisationsEinheit).toBe( + organisationsEinheitResource, + ); }); + + function getCollaborationInVorgangComponent(): CollaborationInVorgangComponent { + return getMockComponent<CollaborationInVorgangComponent>( + fixture, + CollaborationInVorgangComponent, + ); + } }); - it('should be hidden if request form visibility is true', () => { - component.isRequestFormVisible$ = of(true); + it('should call hideRequestForm on output', () => { + component.hideRequestForm = jest.fn(); - fixture.detectChanges(); + dispatchEventFromFixture(fixture, collaborationInVorgangComp, 'hideRequestForm'); - notExistsAsHtmlElement(fixture, anfrageErstellenButton); + expect(component.hideRequestForm).toHaveBeenCalled(); }); - }); - describe('zustaendige stelle', () => { - describe('on request form visibility true', () => { - beforeEach(() => { - component.isRequestFormVisible$ = of(true); - }); - it('should be shown', () => { - fixture.detectChanges(); + it('should call showRequestForm on output', () => { + component.showRequestForm = jest.fn(); - existsAsHtmlElement(fixture, collaborationRequestForm); - }); + dispatchEventFromFixture(fixture, collaborationInVorgangComp, 'showRequestForm'); - it('should call service on hideFormular output', () => { - fixture.detectChanges(); + expect(component.showRequestForm).toHaveBeenCalled(); + }); + }); - dispatchEventFromFixture(fixture, collaborationRequestForm, 'hide'); + describe('show request form', () => { + it('should call service', () => { + component.showRequestForm(); - expect(service.hideRequestForm).toHaveBeenCalled(); - }); + expect(service.showRequestForm).toHaveBeenCalled(); }); + }); - it('should be hidden if request form visibility is false', () => { - component.isRequestFormVisible$ = of(false); + describe('hide request form', () => { + it('should call service', () => { + component.hideRequestForm(); + + expect(service.hideRequestForm).toHaveBeenCalled(); + }); + }); - fixture.detectChanges(); + describe('ngOnDestroy', () => { + it('should call service to clear selected result', () => { + component.ngOnDestroy(); - notExistsAsHtmlElement(fixture, collaborationRequestForm); + expect(organisationsEinheitSearchService.clearSelectedResult).toHaveBeenCalled(); }); }); }); diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts index a3f82c8ae46118a9e50407cb6ec43c3eb22560f5..50c5d04bcffdbd5cd7171a14c5f696839b7447ea 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang-container.component.ts @@ -1,18 +1,29 @@ -import { Component, OnInit } from '@angular/core'; +import { OrganisationsEinheitResource } from '@alfa-client/collaboration-shared'; +import { StateResource } from '@alfa-client/tech-shared'; +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { CollaborationListResource } from 'libs/collaboration-shared/src/lib/collaboration.model'; import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; +import { OrganisationsEinheitResourceSearchService } from 'libs/collaboration-shared/src/lib/organisations-einheit-resource-search.service'; import { Observable } from 'rxjs'; @Component({ selector: 'alfa-collaboration-in-vorgang-container', templateUrl: './collaboration-in-vorgang-container.component.html', }) -export class CollaborationInVorgangContainerComponent implements OnInit { +export class CollaborationInVorgangContainerComponent implements OnInit, OnDestroy { + public collaborationStateListResource$: Observable<StateResource<CollaborationListResource>>; public isRequestFormVisible$: Observable<boolean>; + public selectedOrganisationsEinheit$: Observable<OrganisationsEinheitResource>; - constructor(private service: CollaborationService) {} + constructor( + private readonly service: CollaborationService, + private readonly searchService: OrganisationsEinheitResourceSearchService, + ) {} ngOnInit(): void { + this.collaborationStateListResource$ = this.service.getList(); this.isRequestFormVisible$ = this.service.isRequestFormVisible(); + this.selectedOrganisationsEinheit$ = this.searchService.getSelectedResult(); } public showRequestForm(): void { @@ -22,4 +33,8 @@ export class CollaborationInVorgangContainerComponent implements OnInit { public hideRequestForm(): void { this.service.hideRequestForm(); } + + ngOnDestroy(): void { + this.searchService.clearSelectedResult(); + } } diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html new file mode 100644 index 0000000000000000000000000000000000000000..733601490e198e7d93d37626f597974081b8367a --- /dev/null +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.html @@ -0,0 +1,38 @@ +<ng-container + *ngIf=" + collaborationStateListResource.resource + | hasLink: collaborationListLinkRel.CREATE_COLLABORATION_REQUEST + " +> + <ng-template #anfrageErstellenButton> + <ods-button + variant="outline" + text="Anfrage erstellen" + dataTestId="anfrage-erstellen-button" + (clickEmitter)="showRequestForm.emit()" + > + <ods-collaboration-icon icon /> + </ods-button> + </ng-template> + + <ng-container *ngIf="isRequestFormVisible; else anfrageErstellenButton"> + <alfa-collaboration-request-form + data-test-id="collaboration-request-form" + [collaborationListResource]="collaborationStateListResource.resource" + (hide)="hideRequestForm.emit()" + (showResult)="setCollaboration($event)" + ></alfa-collaboration-request-form> + </ng-container> +</ng-container> +<ng-container *ngIf="collaboration"> + <div data-test-id="collaboration-request-result"> + <div class="flex items-center gap-3"> + <ods-office-icon size="large" class="fill-text" /> + <alfa-organisations-einheit + [organisationsEinheitResource]="organisationsEinheit" + ></alfa-organisations-einheit> + </div> + <h4 class="my-6 text-xl font-medium">{{ collaboration.titel }}</h4> + <p class="text-base">{{ collaboration.anfrage }}</p> + </div> +</ng-container> diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b17cd273cc3b503a6accb79219bb149c351041a --- /dev/null +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.spec.ts @@ -0,0 +1,189 @@ +import { + Collaboration, + CollaborationListLinkRel, + CollaborationListResource, +} from '@alfa-client/collaboration-shared'; +import { HasLinkPipe, createStateResource } from '@alfa-client/tech-shared'; +import { + EventData, + dispatchEventFromFixture, + existsAsHtmlElement, + getMockComponent, + notExistsAsHtmlElement, + triggerEvent, +} from '@alfa-client/test-utils'; +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ButtonComponent, CollaborationIconComponent, OfficeIconComponent } from '@ods/system'; +import { + createCollaboration, + createCollaborationListResource, +} from 'libs/collaboration-shared/test/collaboration'; +import { getDataTestIdAttributeOf, getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { MockComponent } from 'ng-mocks'; +import { CollaborationRequestFormComponent } from '../collaboration-request-form/collaboration-request-form.component'; +import { OrganisationsEinheitComponent } from '../collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component'; +import { CollaborationInVorgangComponent } from './collaboration-in-vorgang.component'; + +describe('CollaborationInVorgangComponent', () => { + let component: CollaborationInVorgangComponent; + let fixture: ComponentFixture<CollaborationInVorgangComponent>; + + const anfrageErstellenButton: string = getDataTestIdAttributeOf('anfrage-erstellen-button'); + const collaborationRequestForm: string = getDataTestIdOf('collaboration-request-form'); + const collaborationRequestResult: string = getDataTestIdOf('collaboration-request-result'); + + const collaborationListResource: CollaborationListResource = createCollaborationListResource(); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + CollaborationInVorgangComponent, + HasLinkPipe, + MockComponent(ButtonComponent), + MockComponent(CollaborationRequestFormComponent), + MockComponent(CollaborationIconComponent), + MockComponent(OfficeIconComponent), + MockComponent(OrganisationsEinheitComponent), + ], + }).compileComponents(); + + fixture = TestBed.createComponent(CollaborationInVorgangComponent); + component = fixture.componentInstance; + component.collaborationStateListResource = createStateResource(collaborationListResource); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('if create collaboration request link exists', () => { + const collaborationListResourceWithLink: CollaborationListResource = + createCollaborationListResource([CollaborationListLinkRel.CREATE_COLLABORATION_REQUEST]); + beforeEach(() => { + component.collaborationStateListResource = createStateResource( + collaborationListResourceWithLink, + ); + fixture.detectChanges(); + }); + + describe('anfrage erstellen button', () => { + describe('on request form visibility false', () => { + beforeEach(() => { + component.isRequestFormVisible = false; + }); + + it('should be shown', () => { + fixture.detectChanges(); + + existsAsHtmlElement(fixture, anfrageErstellenButton); + }); + + it('should call service on click', () => { + fixture.detectChanges(); + const showRequestFormSpy: jest.SpyInstance = (component.showRequestForm.emit = jest.fn()); + + dispatchEventFromFixture(fixture, anfrageErstellenButton, 'clickEmitter'); + + expect(showRequestFormSpy).toHaveBeenCalled(); + }); + }); + + it('should be hidden if request form visibility is true', () => { + component.isRequestFormVisible = true; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, anfrageErstellenButton); + }); + }); + + describe('zustaendige stelle', () => { + describe('on request form visibility true', () => { + beforeEach(() => { + component.isRequestFormVisible = true; + }); + it('should be shown', () => { + fixture.detectChanges(); + + existsAsHtmlElement(fixture, collaborationRequestForm); + }); + + describe('component', () => { + it('should call service on hideFormular output', () => { + fixture.detectChanges(); + const hideRequestFormSpy: jest.SpyInstance = (component.hideRequestForm.emit = + jest.fn()); + + dispatchEventFromFixture(fixture, collaborationRequestForm, 'hide'); + + expect(hideRequestFormSpy).toHaveBeenCalled(); + }); + + it('should call set collaboration on showResult output', () => { + fixture.detectChanges(); + component.setCollaboration = jest.fn(); + const collaboration: Collaboration = createCollaboration(); + + const eventData: EventData<CollaborationInVorgangComponent> = { + fixture, + elementSelector: collaborationRequestForm, + name: 'showResult', + data: collaboration, + }; + triggerEvent(eventData); + + expect(component.setCollaboration).toHaveBeenCalledWith(collaboration); + }); + + it('should be called with', () => { + fixture.detectChanges(); + + const comp: CollaborationRequestFormComponent = + getMockComponent<CollaborationRequestFormComponent>( + fixture, + CollaborationRequestFormComponent, + ); + expect(comp.collaborationListResource).toBe(collaborationListResourceWithLink); + }); + }); + }); + + it('should be hidden if request form visibility is false', () => { + component.isRequestFormVisible = false; + + fixture.detectChanges(); + + notExistsAsHtmlElement(fixture, collaborationRequestForm); + }); + }); + }); + + describe('on existing collaboration', () => { + it('should show result', () => { + component.collaboration = createCollaboration(); + + fixture.detectChanges(); + + existsAsHtmlElement(fixture, collaborationRequestResult); + }); + }); + + describe('set collaboration', () => { + const collaboration: Collaboration = createCollaboration(); + + it('should set attribute', () => { + component.setCollaboration(collaboration); + + expect(component.collaboration).toBe(collaboration); + }); + + it('should call emitter', () => { + const hideRequestFormEmitSpy: jest.SpyInstance = (component.hideRequestForm.emit = jest.fn()); + + component.setCollaboration(collaboration); + + expect(hideRequestFormEmitSpy).toBeCalled(); + }); + }); +}); diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..3216f10156d4e4506b3a028a833700a04b4eb96b --- /dev/null +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component.ts @@ -0,0 +1,30 @@ +import { + Collaboration, + CollaborationListLinkRel, + CollaborationListResource, + OrganisationsEinheitResource, +} from '@alfa-client/collaboration-shared'; +import { StateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'alfa-collaboration-in-vorgang', + templateUrl: './collaboration-in-vorgang.component.html', +}) +export class CollaborationInVorgangComponent { + @Input() public collaborationStateListResource: StateResource<CollaborationListResource>; + @Input() public isRequestFormVisible: boolean; + @Input() public organisationsEinheit: OrganisationsEinheitResource; + + @Output() public readonly showRequestForm: EventEmitter<void> = new EventEmitter<void>(); + @Output() public readonly hideRequestForm: EventEmitter<void> = new EventEmitter<void>(); + + public readonly collaborationListLinkRel = CollaborationListLinkRel; + + public collaboration: Collaboration; + + public setCollaboration(collaboration: Collaboration) { + this.collaboration = collaboration; + this.hideRequestForm.emit(); + } +} diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html index d2cb5eb2d470b1275c22300d5440f78d5465c5ed..bbb5fd59fc99d36e5f449e35d879bdc5b50bde88 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.html @@ -1,5 +1,5 @@ <alfa-organisations-einheit-container - [fieldControl]="formService.form.controls.organisationseinheit" + [fieldControl]="formService.form.controls.zustaendigeStelle" ></alfa-organisations-einheit-container> <form [formGroup]="formService.form" class="mt-4 flex flex-col gap-2"> @@ -16,11 +16,13 @@ </form> <div class="mt-4 flex items-center gap-6"> - <ods-button + <ods-button-with-spinner text="Zuarbeit anfragen" - dataTestId="collaboration-request-send-button" - (clickEmitter)="formService.submit()" - ></ods-button> + dataTestId="collaboration-request-submit-button" + [stateResource]="submitInProgress$ | async" + (clickEmitter)="submit()" + > + </ods-button-with-spinner> <ods-button variant="outline" text="Abbrechen" diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts index e9d674ae5d0d85b070adaac2278b30d66927cb6a..0ec28ea4c355c960aeb9be676a5ef47cd6026814 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.spec.ts @@ -1,10 +1,27 @@ -import { dispatchEventFromFixture } from '@alfa-client/test-utils'; +import { CollaborationListResource } from '@alfa-client/collaboration-shared'; +import { CommandLinkRel, CommandResource } from '@alfa-client/command-shared'; +import { StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { + dispatchEventFromFixture, + getMockComponent, + mock, + useFromMock, +} from '@alfa-client/test-utils'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormBuilder, ReactiveFormsModule } from '@angular/forms'; -import { TextEditorComponent, TextareaEditorComponent } from '@ods/component'; +import { + ButtonWithSpinnerComponent, + TextEditorComponent, + TextareaEditorComponent, +} from '@ods/component'; import { ButtonComponent, CloseIconComponent } from '@ods/system'; +import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; +import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration'; +import { createCommandResource } from 'libs/command-shared/test/command'; import { getDataTestIdAttributeOf } from 'libs/tech-shared/test/data-test'; +import { singleColdCompleted } from 'libs/tech-shared/test/marbles'; import { MockComponent } from 'ng-mocks'; +import { of } from 'rxjs'; import { CollaborationRequestFormComponent } from './collaboration-request-form.component'; import { CollaborationRequestFormService } from './collaboration.request.formservice'; import { OrganisationsEinheitContainerComponent } from './organisations-einheit-container/organisations-einheit-container.component'; @@ -14,17 +31,34 @@ describe('CollaborationRequestFormComponent', () => { let fixture: ComponentFixture<CollaborationRequestFormComponent>; const cancelButton: string = getDataTestIdAttributeOf('collaboration-request-cancel-button'); + const submitButton: string = getDataTestIdAttributeOf('collaboration-request-submit-button'); - const formService: CollaborationRequestFormService = new CollaborationRequestFormService( - new FormBuilder(), - ); + let formService: CollaborationRequestFormService; + + const stateCommandResource: StateResource<CommandResource> = + createStateResource(createCommandResource()); beforeEach(async () => { + formService = new CollaborationRequestFormService( + new FormBuilder(), + useFromMock(mock(CollaborationService)), + ); + TestBed.overrideComponent(CollaborationRequestFormComponent, { + set: { + providers: [ + { + provide: CollaborationRequestFormService, + useValue: formService, + }, + ], + }, + }); await TestBed.configureTestingModule({ imports: [ReactiveFormsModule], declarations: [ CollaborationRequestFormComponent, MockComponent(ButtonComponent), + MockComponent(ButtonWithSpinnerComponent), MockComponent(CloseIconComponent), MockComponent(TextEditorComponent), MockComponent(TextareaEditorComponent), @@ -37,7 +71,6 @@ describe('CollaborationRequestFormComponent', () => { }, ], }).compileComponents(); - fixture = TestBed.createComponent(CollaborationRequestFormComponent); component = fixture.componentInstance; fixture.detectChanges(); @@ -56,4 +89,88 @@ describe('CollaborationRequestFormComponent', () => { expect(emitSpy).toHaveBeenCalled(); }); }); + + describe('submit button', () => { + describe('component', () => { + it('should be called with state resource', () => { + component.submitInProgress$ = of(stateCommandResource); + + fixture.detectChanges(); + + const submitButtonComp: ButtonWithSpinnerComponent = + getMockComponent<ButtonWithSpinnerComponent>(fixture, ButtonWithSpinnerComponent); + expect(submitButtonComp.stateResource).toBe(stateCommandResource); + }); + }); + + it('should call submit on output', () => { + component.submit = jest.fn(); + + dispatchEventFromFixture(fixture, submitButton, 'clickEmitter'); + + expect(component.submit).toHaveBeenCalled(); + }); + }); + + describe('submit', () => { + it('should call doSubmit', () => { + component.doSubmit = jest.fn(); + + component.submit(); + + expect(component.doSubmit).toHaveBeenCalled(); + }); + + it('should set submitInProgress', () => { + component.doSubmit = jest.fn().mockReturnValue(of(stateCommandResource)); + + component.submit(); + + expect(component.submitInProgress$).toBeObservable(singleColdCompleted(stateCommandResource)); + }); + }); + + describe('do submit', () => { + beforeEach(() => { + formService.submit = jest + .fn() + .mockReturnValue( + of(createStateResource(createCommandResource([CommandLinkRel.EFFECTED_RESOURCE]))), + ); + }); + + it('should call formService', () => { + formService.submit = jest.fn().mockReturnValue(of(stateCommandResource)); + + component.doSubmit().subscribe(); + + expect(formService.submit).toHaveBeenCalled(); + }); + + it('should emit show result', () => { + const showResultSpy: jest.SpyInstance = (component.showResult.emit = jest.fn()); + + component.doSubmit().subscribe(); + + expect(showResultSpy).toHaveBeenCalledWith(formService.form.value); + }); + + it('should return value', () => { + formService.submit = jest.fn().mockReturnValue(of(stateCommandResource)); + + expect(component.doSubmit()).toBeObservable(singleColdCompleted(stateCommandResource)); + }); + }); + + describe('set collaboration list resource', () => { + it('should call set list resource on formService', () => { + formService.setListResource = jest.fn(); + const collaborationListResource: CollaborationListResource = + createCollaborationListResource(); + + component.collaborationListResource = collaborationListResource; + + expect(formService.setListResource).toHaveBeenCalledWith(collaborationListResource); + }); + }); }); diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts index 4dcfcb9ce9658a59b3f87777522b3a99d5cce2d2..ccaf4fd89ec7f6af5d2afe69d3ff397669cd841c 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component.ts @@ -1,4 +1,8 @@ -import { Component, EventEmitter, Output } from '@angular/core'; +import { Collaboration, CollaborationListResource } from '@alfa-client/collaboration-shared'; +import { CommandResource, tapOnCommandSuccessfullyDone } from '@alfa-client/command-shared'; +import { HttpError, StateResource, createEmptyStateResource } from '@alfa-client/tech-shared'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Observable, of } from 'rxjs'; import { CollaborationRequestFormService } from './collaboration.request.formservice'; @Component({ @@ -8,8 +12,31 @@ import { CollaborationRequestFormService } from './collaboration.request.formser }) export class CollaborationRequestFormComponent { @Output() public hide: EventEmitter<void> = new EventEmitter<void>(); + @Output() public showResult: EventEmitter<Collaboration> = new EventEmitter<Collaboration>(); + + @Input() public set collaborationListResource( + collaborationListResource: CollaborationListResource, + ) { + this.formService.setListResource(collaborationListResource); + } + + public submitInProgress$: Observable<StateResource<CommandResource | HttpError>> = of( + createEmptyStateResource<CommandResource>(), + ); constructor(readonly formService: CollaborationRequestFormService) {} public readonly formServiceClass = CollaborationRequestFormService; + + public submit(): void { + this.submitInProgress$ = this.doSubmit(); + } + + doSubmit(): Observable<StateResource<CommandResource>> { + return this.formService + .submit() + .pipe( + tapOnCommandSuccessfullyDone(() => this.showResult.emit(this.formService.getFormValue())), + ); + } } diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts index 7f76f28a47ec441ac67defcb897a2abc557390bb..a9f135fc6a49e51d32f30ee11708d49189343178 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.spec.ts @@ -1,16 +1,67 @@ +import { CollaborationListResource } from '@alfa-client/collaboration-shared'; +import { CommandResource } from '@alfa-client/command-shared'; +import { HttpError, StateResource, createStateResource } from '@alfa-client/tech-shared'; +import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { UntypedFormBuilder } from '@angular/forms'; +import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; +import { createCollaborationListResource } from 'libs/collaboration-shared/test/collaboration'; +import { createCommandResource } from 'libs/command-shared/test/command'; +import { singleColdCompleted } from 'libs/tech-shared/test/marbles'; +import { Observable, of } from 'rxjs'; import { CollaborationRequestFormService } from './collaboration.request.formservice'; describe('CollaborationRequestFormService', () => { let formService: CollaborationRequestFormService; + let service: Mock<CollaborationService>; + const formBuilder: UntypedFormBuilder = new UntypedFormBuilder(); + const collaborationListResource: CollaborationListResource = createCollaborationListResource(); + beforeEach(() => { - formService = new CollaborationRequestFormService(formBuilder); + service = mock(CollaborationService); + + formService = new CollaborationRequestFormService(formBuilder, useFromMock(service)); }); it('should create', () => { expect(formService).toBeTruthy(); }); + + describe('do submit', () => { + const stateCommandResource: StateResource<CommandResource> = + createStateResource(createCommandResource()); + + beforeEach(() => { + formService.listResource = collaborationListResource; + service.create.mockReturnValue(of(stateCommandResource)); + }); + + it('should call service', () => { + formService.submit(); + + expect(service.create).toHaveBeenCalledWith( + collaborationListResource, + formService.form.value, + ); + }); + + it('should return stateCommandResource', () => { + const response$: Observable<StateResource<CommandResource | HttpError>> = + formService.submit(); + + expect(response$).toBeObservable(singleColdCompleted(stateCommandResource)); + }); + }); + + describe('set list resource', () => { + it('should set given list resource', () => { + formService.listResource = undefined; + + formService.setListResource(collaborationListResource); + + expect(formService.listResource).toBe(collaborationListResource); + }); + }); }); diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts index eb6812cfda23cd62542bde49af42a42148c2ebba..eedf11fea57b5413757b863d50fee87000986a58 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/collaboration.request.formservice.ts @@ -1,25 +1,32 @@ +import { CollaborationListResource } from '@alfa-client/collaboration-shared'; import { CommandResource } from '@alfa-client/command-shared'; import { AbstractFormService, StateResource } from '@alfa-client/tech-shared'; import { Injectable } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { ResourceUri } from '@ngxp/rest'; -import { Observable, of } from 'rxjs'; +import { CollaborationService } from 'libs/collaboration-shared/src/lib/collaboration.service'; +import { Observable } from 'rxjs'; @Injectable() -export class CollaborationRequestFormService extends AbstractFormService { - public static readonly FIELD_ORGANISATIONS_EINHEIT: string = 'organisationseinheit'; +export class CollaborationRequestFormService extends AbstractFormService<CommandResource> { + public static readonly FIELD_ZUSTAENDIGE_STELLE: string = 'zustaendigeStelle'; public static readonly FIELD_TITLE: string = 'titel'; - public static readonly FIELD_NACHRICHT: string = 'nachricht'; + public static readonly FIELD_NACHRICHT: string = 'anfrage'; private static readonly PATH_PREFIX: string = 'command.body'; - constructor(formBuilder: FormBuilder) { + listResource: CollaborationListResource; + + constructor( + formBuilder: FormBuilder, + private service: CollaborationService, + ) { super(formBuilder); } protected initForm(): FormGroup { return this.formBuilder.group({ - [CollaborationRequestFormService.FIELD_ORGANISATIONS_EINHEIT]: new FormControl<ResourceUri>( + [CollaborationRequestFormService.FIELD_ZUSTAENDIGE_STELLE]: new FormControl<ResourceUri>( null, ), [CollaborationRequestFormService.FIELD_TITLE]: new FormControl<string>(null), @@ -28,11 +35,14 @@ export class CollaborationRequestFormService extends AbstractFormService { } protected doSubmit(): Observable<StateResource<CommandResource>> { - console.info('FormValue: ', this.getFormValue()); - return of(); + return this.service.create(this.listResource, this.getFormValue()); } protected getPathPrefix(): string { return CollaborationRequestFormService.PATH_PREFIX; } + + public setListResource(listResource: CollaborationListResource): void { + this.listResource = listResource; + } } diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html index 36cee6fb596565233bad6c63435fe246bd75fe06..26bf7894a39f4bc7fb5d5d1e07d51dc2cd2976cd 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.html @@ -1,6 +1,8 @@ -<ng-container *ngIf="organisationsEinheitResource; else searchButton"> +<ng-container + *ngIf="organisationsEinheitResource$ | async as organisationsEinheitResource; else searchButton" +> <div class="flex items-center gap-3"> - <ods-office-icon size="large" class="flex-none" /> + <ods-office-icon size="large" class="fill-text" /> <alfa-organisations-einheit data-test-id="organisations-einheit-in-collaboration" [organisationsEinheitResource]="organisationsEinheitResource" diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts index 49f71ddf4203ac77dd0d4f0aa2baa697d896706e..9fe951c4b33dbd191a352467286baaa168922529 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.spec.ts @@ -1,4 +1,7 @@ -import { OrganisationsEinheitResource } from '@alfa-client/collaboration-shared'; +import { + OrganisationsEinheitResource, + OrganisationsEinheitService, +} from '@alfa-client/collaboration-shared'; import { Mock, dispatchEventFromFixture, @@ -7,7 +10,7 @@ import { mock, } from '@alfa-client/test-utils'; import { OzgcloudDialogService } from '@alfa-client/ui'; -import { DialogConfig, DialogRef } from '@angular/cdk/dialog'; +import { DialogConfig } from '@angular/cdk/dialog'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FormControl } from '@angular/forms'; import { getUrl } from '@ngxp/rest'; @@ -16,7 +19,7 @@ import { createOrganisationsEinheitResource } from 'libs/collaboration-shared/te import { SearchIconComponent } from 'libs/design-system/src/lib/icons/search-icon/search-icon.component'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; -import { Subject } from 'rxjs'; +import { of } from 'rxjs'; import { SearchOrganisationsEinheitContainerComponent } from '../../../search-organisations-einheit-container/search-organisations-einheit-container.component'; import { OrganisationsEinheitContainerComponent } from './organisations-einheit-container.component'; import { OrganisationsEinheitComponent } from './organisations-einheit/organisations-einheit.component'; @@ -25,7 +28,9 @@ describe('OrganisationsEinheitContainerComponent', () => { let component: OrganisationsEinheitContainerComponent; let fixture: ComponentFixture<OrganisationsEinheitContainerComponent>; - const searchOrganisationsEinheit: string = getDataTestIdOf('organisations-einheit-search-button'); + const searchOrganisationsEinheitButton: string = getDataTestIdOf( + 'organisations-einheit-search-button', + ); const organisationsEinheitComp: string = getDataTestIdOf( 'organisations-einheit-in-collaboration', ); @@ -33,9 +38,25 @@ describe('OrganisationsEinheitContainerComponent', () => { const organisationsEinheitResource: OrganisationsEinheitResource = createOrganisationsEinheitResource(); - const dialogService: Mock<OzgcloudDialogService> = mock(OzgcloudDialogService); + let dialogService: Mock<OzgcloudDialogService>; + let service: Mock<OrganisationsEinheitService>; beforeEach(async () => { + dialogService = mock(OzgcloudDialogService); + service = { + ...mock(OrganisationsEinheitService), + getSelectedResult: jest.fn().mockReturnValue(of(createOrganisationsEinheitResource())), + }; + TestBed.overrideComponent(OrganisationsEinheitContainerComponent, { + set: { + providers: [ + { + provide: OrganisationsEinheitService, + useValue: service, + }, + ], + }, + }); await TestBed.configureTestingModule({ declarations: [ OrganisationsEinheitContainerComponent, @@ -49,6 +70,10 @@ describe('OrganisationsEinheitContainerComponent', () => { provide: OzgcloudDialogService, useValue: dialogService, }, + { + provide: OrganisationsEinheitService, + useValue: service, + }, ], }).compileComponents(); @@ -61,21 +86,102 @@ describe('OrganisationsEinheitContainerComponent', () => { expect(component).toBeTruthy(); }); + describe('ngOnInt', () => { + beforeEach(() => { + component.getSelectedResult = jest.fn().mockReturnValue(of(organisationsEinheitResource)); + }); + + it('should call getSelectedResult', () => { + component.getSelectedResult = jest.fn(); + + component.ngOnInit(); + + expect(component.getSelectedResult).toHaveBeenCalled(); + }); + + it('should set organisationsEinheitResource', (done) => { + component.ngOnInit(); + + component.organisationsEinheitResource$.subscribe( + (organisationsEinheitResource: OrganisationsEinheitResource) => { + expect(organisationsEinheitResource).toBe(organisationsEinheitResource); + done(); + }, + ); + }); + }); + + describe('get selected result', () => { + const organisationsEinheitResource: OrganisationsEinheitResource = + createOrganisationsEinheitResource(); + + beforeEach(() => { + service.getSelectedResult.mockReturnValue(of(organisationsEinheitResource)); + }); + + it('should call service', () => { + component.getSelectedResult().subscribe(); + + expect(service.getSelectedResult).toHaveBeenCalled(); + }); + + it('should call handleResult', () => { + component.handleResult = jest.fn(); + + component.getSelectedResult().subscribe(); + + expect(component.handleResult).toHaveBeenCalledWith(organisationsEinheitResource); + }); + + it('should return value', (done) => { + component.handleResult = jest.fn(); + + component.getSelectedResult().subscribe((result) => { + expect(result).toBe(organisationsEinheitResource); + done(); + }); + }); + }); + + describe('handle result', () => { + beforeEach(() => { + component.fieldControl = new FormControl(); + }); + + it('should patch fieldControl with resource uri', () => { + const fieldControlPatchSpy: jest.SpyInstance = (component.fieldControl.patchValue = + jest.fn()); + + component.handleResult(organisationsEinheitResource); + + expect(fieldControlPatchSpy).toHaveBeenCalledWith(getUrl(organisationsEinheitResource)); + }); + + it('should not patch fieldControl if organisationsEinheit resource is null', () => { + const fieldControlPatchSpy: jest.SpyInstance = (component.fieldControl.patchValue = + jest.fn()); + + component.handleResult(null); + + expect(fieldControlPatchSpy).not.toHaveBeenCalled(); + }); + }); + describe('search zustaendige stelle button', () => { beforeEach(() => { - component.organisationsEinheitResource = undefined; + component.organisationsEinheitResource$ = of(undefined); }); it('should be visible on missing organisationsEinheit', () => { fixture.detectChanges(); - existsAsHtmlElement(fixture, searchOrganisationsEinheit); + existsAsHtmlElement(fixture, searchOrganisationsEinheitButton); }); it('should call openSearchDialog', () => { component.openSearchDialog = jest.fn(); fixture.detectChanges(); - dispatchEventFromFixture(fixture, searchOrganisationsEinheit, 'clickEmitter'); + dispatchEventFromFixture(fixture, searchOrganisationsEinheitButton, 'clickEmitter'); expect(component.openSearchDialog).toHaveBeenCalled(); }); @@ -83,7 +189,7 @@ describe('OrganisationsEinheitContainerComponent', () => { describe('organisationsEinheit component', () => { beforeEach(() => { - component.organisationsEinheitResource = organisationsEinheitResource; + component.organisationsEinheitResource$ = of(organisationsEinheitResource); }); it('should be visible on existing organisationsEinheit', () => { @@ -104,10 +210,6 @@ describe('OrganisationsEinheitContainerComponent', () => { }); describe('open search dialog', () => { - beforeEach(() => { - component.listenToDialogClose = jest.fn(); - }); - it('should call dialog service', () => { const DIALOG_CONFIG: DialogConfig = { backdropClass: ['backdrop-blur-1', 'bg-greybackdrop'], @@ -122,47 +224,5 @@ describe('OrganisationsEinheitContainerComponent', () => { DIALOG_CONFIG, ); }); - - it('should call listenToDialogClose', () => { - component.openSearchDialog(); - - expect(component.listenToDialogClose).toHaveBeenCalled(); - }); - }); - - describe('listen to dialog close, after closed', () => { - it('should call handleDialogClosed', () => { - const closedSubj: Subject<OrganisationsEinheitResource> = new Subject(); - component.dialogRef = <DialogRef>{ closed: closedSubj.asObservable() }; - component.handleDialogClosed = jest.fn(); - - component.listenToDialogClose(); - closedSubj.next(organisationsEinheitResource); - - expect(component.handleDialogClosed).toHaveBeenCalledWith(organisationsEinheitResource); - }); - }); - - describe('handle dialog closed', () => { - beforeEach(() => { - component.fieldControl = new FormControl(); - }); - - it('should set organisationsEinheit', () => { - component.organisationsEinheitResource = undefined; - - component.handleDialogClosed(organisationsEinheitResource); - - expect(component.organisationsEinheitResource).toBe(organisationsEinheitResource); - }); - - it('should patch fieldControl with resource uri', () => { - const fieldControlPatchSpy: jest.SpyInstance = (component.fieldControl.patchValue = - jest.fn()); - - component.handleDialogClosed(organisationsEinheitResource); - - expect(fieldControlPatchSpy).toHaveBeenCalledWith(getUrl(organisationsEinheitResource)); - }); }); }); diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts index 872efeefb5fb60b6f26fae4c2800bea525b4149c..2bddc100f8d72ccd8560386dd144574e532a58e6 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component.ts @@ -2,12 +2,13 @@ import { OrganisationsEinheitResource, OrganisationsEinheitService, } from '@alfa-client/collaboration-shared'; +import { isNotNull } from '@alfa-client/tech-shared'; import { OzgcloudDialogService } from '@alfa-client/ui'; -import { DialogConfig, DialogRef } from '@angular/cdk/dialog'; -import { Component, Input, ViewContainerRef } from '@angular/core'; -import { FormControl } from '@angular/forms'; +import { DialogConfig } from '@angular/cdk/dialog'; +import { Component, Input, OnInit, ViewContainerRef } from '@angular/core'; +import { AbstractControl } from '@angular/forms'; import { ResourceUri, getUrl } from '@ngxp/rest'; -import { first } from 'rxjs'; +import { Observable, tap } from 'rxjs'; import { SearchOrganisationsEinheitContainerComponent } from '../../../search-organisations-einheit-container/search-organisations-einheit-container.component'; const DIALOG_CONFIG: DialogConfig = { @@ -19,37 +20,43 @@ const DIALOG_CONFIG: DialogConfig = { templateUrl: './organisations-einheit-container.component.html', providers: [OrganisationsEinheitService], }) -export class OrganisationsEinheitContainerComponent { - @Input() public fieldControl: FormControl<ResourceUri>; +export class OrganisationsEinheitContainerComponent implements OnInit { + @Input() public fieldControl: AbstractControl<ResourceUri>; - public organisationsEinheitResource: OrganisationsEinheitResource; - - dialogRef: DialogRef; + public organisationsEinheitResource$: Observable<OrganisationsEinheitResource>; constructor( private readonly dialogService: OzgcloudDialogService, readonly viewContainerRef: ViewContainerRef, + private readonly service: OrganisationsEinheitService, ) {} - public openSearchDialog(): void { - this.dialogRef = - this.dialogService.openInCallingComponentContext<SearchOrganisationsEinheitContainerComponent>( - SearchOrganisationsEinheitContainerComponent, - this.viewContainerRef, - null, - DIALOG_CONFIG, + ngOnInit(): void { + this.organisationsEinheitResource$ = this.getSelectedResult(); + } + + getSelectedResult(): Observable<OrganisationsEinheitResource> { + return this.service + .getSelectedResult() + .pipe( + tap((organisationsEinheitResource: OrganisationsEinheitResource) => + this.handleResult(organisationsEinheitResource), + ), ); - this.listenToDialogClose(); } - listenToDialogClose(): void { - this.dialogRef.closed - .pipe(first()) - .subscribe((result: OrganisationsEinheitResource) => this.handleDialogClosed(result)); + handleResult(organisationsEinheitResource: OrganisationsEinheitResource): void { + if (isNotNull(organisationsEinheitResource)) { + this.fieldControl.patchValue(getUrl(organisationsEinheitResource)); + } } - handleDialogClosed(organisationsEinheitResource: OrganisationsEinheitResource): void { - this.organisationsEinheitResource = organisationsEinheitResource; - this.fieldControl.patchValue(getUrl(organisationsEinheitResource)); + public openSearchDialog(): void { + this.dialogService.openInCallingComponentContext<SearchOrganisationsEinheitContainerComponent>( + SearchOrganisationsEinheitContainerComponent, + this.viewContainerRef, + null, //FIXME bitte null nicht als Parameter nehmen + DIALOG_CONFIG, + ); } } diff --git a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts index 490dab5d431c35493aa38e8c323ea990706c0ec3..8e6eaa1ea513256ec82992961078976755078248 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component.spec.ts @@ -25,7 +25,7 @@ describe('OrganisationsEinheitComponent', () => { }); describe('set organisationsEinheit', () => { - it('should call update by organisationsEinehit', () => { + it('should call update by organisationsEinheit', () => { component.updateByOrganisationsEinheit = jest.fn(); component.organisationsEinheitResource = organisationsEinheitResource; diff --git a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts index bbe069e5b79e331041e43cbb62ed661f085e2d72..82a66754b9da100acdf4bf900a6669832f24a4ab 100644 --- a/alfa-client/libs/collaboration/src/lib/collaboration.module.ts +++ b/alfa-client/libs/collaboration/src/lib/collaboration.module.ts @@ -3,7 +3,11 @@ import { TechSharedModule } from '@alfa-client/tech-shared'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { TextEditorComponent, TextareaEditorComponent } from '@ods/component'; +import { + ButtonWithSpinnerComponent, + TextEditorComponent, + TextareaEditorComponent, +} from '@ods/component'; import { ButtonComponent, CloseIconComponent, @@ -14,6 +18,7 @@ import { SearchIconComponent, } from '@ods/system'; import { CollaborationInVorgangContainerComponent } from './collaboration-in-vorgang-container/collaboration-in-vorgang-container.component'; +import { CollaborationInVorgangComponent } from './collaboration-in-vorgang-container/collaboration-in-vorgang/collaboration-in-vorgang.component'; import { CollaborationRequestFormComponent } from './collaboration-in-vorgang-container/collaboration-request-form/collaboration-request-form.component'; import { OrganisationsEinheitContainerComponent } from './collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit-container.component'; import { OrganisationsEinheitComponent } from './collaboration-in-vorgang-container/collaboration-request-form/organisations-einheit-container/organisations-einheit/organisations-einheit.component'; @@ -36,9 +41,11 @@ import { SearchOrganisationsEinheitFormComponent } from './search-organisations- ReactiveFormsModule, InstantSearchComponent, TechSharedModule, + ButtonWithSpinnerComponent, ], declarations: [ CollaborationInVorgangContainerComponent, + CollaborationInVorgangComponent, CollaborationRequestFormComponent, SearchOrganisationsEinheitContainerComponent, SearchOrganisationsEinheitFormComponent, diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts index 21d770d9c3bd231de7d5d039c5a29f079c04476b..2f94294e437896891c8c55521ca86c71a7b255d8 100644 --- a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts +++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.spec.ts @@ -160,6 +160,12 @@ describe('SearchOrganisationsEinheitContainerComponent', () => { }); describe('select search result', () => { + it('should set select result', () => { + component.selectSearchResult(organisationsEinheitResource); + + expect(service.selectSearchResult).toHaveBeenCalledWith(organisationsEinheitResource); + }); + it('should call service', () => { component.selectSearchResult(organisationsEinheitResource); @@ -169,7 +175,7 @@ describe('SearchOrganisationsEinheitContainerComponent', () => { it('should close dialog', () => { component.selectSearchResult(organisationsEinheitResource); - expect(dialogRefMock.close).toHaveBeenCalledWith(organisationsEinheitResource); + expect(dialogRefMock.close).toHaveBeenCalledWith(); }); }); diff --git a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts index b27e9b6358068fe7e7871cdc27dc8d434abd8ad3..963ef863886ec30268528d90e3d9c5ea09d877d6 100644 --- a/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts +++ b/alfa-client/libs/collaboration/src/lib/search-organisations-einheit-container/search-organisations-einheit-container.component.ts @@ -36,8 +36,9 @@ export class SearchOrganisationsEinheitContainerComponent implements OnInit { } public selectSearchResult(organisationsEinheit: OrganisationsEinheitResource): void { + this.service.selectSearchResult(organisationsEinheit); this.service.clearSearchResult(); - this.dialogRef.close(organisationsEinheit); + this.dialogRef.close(); } public clearSearchResult(): void { diff --git a/alfa-client/libs/command-shared/src/lib/+state/command.effects.spec.ts b/alfa-client/libs/command-shared/src/lib/+state/command.effects.spec.ts index c461fcffe58c1bff6b679c9175b70af066484b98..2ee1199a7ec572ca5c33e21ed788c098f2b95015 100644 --- a/alfa-client/libs/command-shared/src/lib/+state/command.effects.spec.ts +++ b/alfa-client/libs/command-shared/src/lib/+state/command.effects.spec.ts @@ -1,4 +1,3 @@ -import { TestBed } from '@angular/core/testing'; import { ApiError, ApiErrorAction, @@ -7,6 +6,7 @@ import { } from '@alfa-client/tech-shared'; import { Mock, mock } from '@alfa-client/test-utils'; import { SnackBarService } from '@alfa-client/ui'; +import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action, Store, createAction, props } from '@ngrx/store'; import { TypedAction } from '@ngrx/store/src/models'; @@ -26,7 +26,12 @@ import { CommandLinkRel } from '../command.linkrel'; import { CREATE_COMMAND_MESSAGE_BY_ORDER, CommandErrorMessage } from '../command.message'; import { CommandListResource, CommandResource, CreateCommandProps } from '../command.model'; import { CommandRepository } from '../command.repository'; -import { CommandProps, LoadCommandListSuccessProps, createCommandFailure } from './command.actions'; +import { + CommandProps, + LoadCommandListSuccessProps, + SnackBarProps, + createCommandFailure, +} from './command.actions'; import { CommandEffects } from './command.effects'; import * as CommandActions from './command.actions'; @@ -35,13 +40,17 @@ describe('CommandEffects', () => { let actions: Observable<Action>; let effects: CommandEffects; - const repository: Mock<CommandRepository> = mock(CommandRepository); - const snackBarService: Mock<SnackBarService> = mock(SnackBarService); - const store: Mock<SnackBarService> = mock(SnackBarService); + let repository: Mock<CommandRepository>; + let snackBarService: Mock<SnackBarService>; + let store: Mock<Store>; let testScheduler: TestScheduler; beforeEach(() => { + repository = mock(CommandRepository); + snackBarService = mock(SnackBarService); + store = mock(Store); + testScheduler = new TestScheduler((actual, expected) => expect(actual).toEqual(expected)); TestBed.configureTestingModule({ @@ -374,7 +383,8 @@ describe('CommandEffects', () => { const createCommandProps: CreateCommandProps = createCreateCommandProps(); const command: CommandResource = createCommandResource(); - it('should show snackBar on existing snackBarMessage', () => { + it('should call handle snackbar by command', () => { + effects.handleSnackbarByCommand = jest.fn(); const showSnackbarAction: TypedAction<string> = CommandActions.showSnackbar({ createCommandProps, command, @@ -383,6 +393,19 @@ describe('CommandEffects', () => { actions = of(showSnackbarAction); effects.showSnackbar$.subscribe(); + expect(effects.handleSnackbarByCommand).toHaveBeenCalled(); + }); + }); + + describe('handle snackbar by command', () => { + const createCommandProps: CreateCommandProps = createCreateCommandProps(); + const command: CommandResource = createCommandResource(); + + it('should show snackBar on existing snackBarMessage', () => { + const snackBarProps: SnackBarProps = { createCommandProps, command }; + + effects.handleSnackbarByCommand(snackBarProps); + expect(snackBarService.show).toHaveBeenCalledWith( command, createCommandProps.snackBarMessage, @@ -390,13 +413,12 @@ describe('CommandEffects', () => { }); it('should show snackBar on undefined snackBarMessage', () => { - const showSnackbarAction: TypedAction<string> = CommandActions.showSnackbar({ + const snackBarProps: SnackBarProps = { createCommandProps: { ...createCommandProps, snackBarMessage: undefined }, command, - }); + }; - actions = of(showSnackbarAction); - effects.showSnackbar$.subscribe(); + effects.handleSnackbarByCommand(snackBarProps); expect(snackBarService.show).toHaveBeenCalledWith( command, @@ -404,16 +426,24 @@ describe('CommandEffects', () => { ); }); - //Faellt um, wenn man ihn mit den anderen Tests zusammen laufen laesst - it.skip('FIXME should NOT show snackBar on empty snackBarMessage', () => { - const showSnackbarAction: TypedAction<string> = CommandActions.showSnackbar({ + it('should NOT show snackBar on empty snackBarMessage', () => { + const snackBarProps: SnackBarProps = { createCommandProps: { ...createCommandProps, snackBarMessage: EMPTY_STRING }, command, - }); - snackBarService.show.mockClear(); + }; - effects.showSnackbar$.subscribe(); - actions = of(showSnackbarAction); + effects.handleSnackbarByCommand(snackBarProps); + + expect(snackBarService.show).not.toHaveBeenCalled(); + }); + + it('should NOT show snackBar on existing error message', () => { + const snackBarProps: SnackBarProps = { + createCommandProps, + command: { ...command, errorMessage: 'dummyErrorMessage' }, + }; + + effects.handleSnackbarByCommand(snackBarProps); expect(snackBarService.show).not.toHaveBeenCalled(); }); diff --git a/alfa-client/libs/command-shared/src/lib/+state/command.effects.ts b/alfa-client/libs/command-shared/src/lib/+state/command.effects.ts index 3d7151381f57a1c9843bf17179f320bd3c28022c..76c42d3899bc776736f109e5af66d73cccd23aa1 100644 --- a/alfa-client/libs/command-shared/src/lib/+state/command.effects.ts +++ b/alfa-client/libs/command-shared/src/lib/+state/command.effects.ts @@ -1,14 +1,21 @@ -import { Injectable } from '@angular/core'; +import { EMPTY_STRING } from '@alfa-client/tech-shared'; import { SnackBarService } from '@alfa-client/ui'; +import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { TypedAction } from '@ngrx/store/src/models'; +import { isEmpty, isEqual, isUndefined } from 'lodash-es'; import { of } from 'rxjs'; import { catchError, delay, map, mergeMap, switchMap, tap } from 'rxjs/operators'; import { COMMAND_ERROR_MESSAGES, CREATE_COMMAND_MESSAGE_BY_ORDER } from '../command.message'; import { CommandListResource, CommandResource, CreateCommandProps } from '../command.model'; import { CommandRepository } from '../command.repository'; -import { hasCommandError, isConcurrentModification, isPending, isRevokeable } from '../command.util'; +import { + hasCommandError, + isConcurrentModification, + isPending, + isRevokeable, +} from '../command.util'; import { CommandProps, LoadCommandListProps, @@ -27,8 +34,6 @@ import { showRevokeSnackbar, showSnackbar, } from './command.actions'; -import { isEqual, isUndefined } from 'lodash-es'; -import { EMPTY_STRING } from '@alfa-client/tech-shared'; @Injectable() export class CommandEffects { @@ -99,6 +104,8 @@ export class CommandEffects { } if (hasCommandError(command) && isConcurrentModification(command.errorMessage)) { this.showError(command); + //FIXME Anstelle der createCommandSucess Action sollte eine createCommandFailure Action geworfen werden. + //Hierzu muss ein HttpErrorResponse für die errorMessage definieren werden return [createCommandSuccess({ command }), publishConcurrentModificationAction()]; } return [createCommandSuccess({ command }), showSnackbar({ createCommandProps, command })]; @@ -131,15 +138,20 @@ export class CommandEffects { () => this.actions$.pipe( ofType(showSnackbar), - tap((props: SnackBarProps) => { - if (!isEqual(props.createCommandProps.snackBarMessage, EMPTY_STRING)) { - this.snackbarService.show(props.command, this.getSnackBarMessage(props)); - } - }), + tap((props: SnackBarProps) => this.handleSnackbarByCommand(props)), ), { dispatch: false }, ); + handleSnackbarByCommand(props: SnackBarProps): void { + if ( + !isEqual(props.createCommandProps.snackBarMessage, EMPTY_STRING) && + isEmpty(props.command.errorMessage) + ) { + this.snackbarService.show(props.command, this.getSnackBarMessage(props)); + } + } + private getSnackBarMessage(props: SnackBarProps): string { return isUndefined(props.createCommandProps.snackBarMessage) ? CREATE_COMMAND_MESSAGE_BY_ORDER[props.command.order] diff --git a/alfa-client/libs/command-shared/src/lib/command.model.ts b/alfa-client/libs/command-shared/src/lib/command.model.ts index 947b7251c473ceec77e0438c299eca6c799a0752..2803459c58ea9b583b8ffa79355811c592c2747d 100644 --- a/alfa-client/libs/command-shared/src/lib/command.model.ts +++ b/alfa-client/libs/command-shared/src/lib/command.model.ts @@ -86,6 +86,7 @@ export enum CommandOrder { CREATE_BESCHEID_DOCUMENT_FROM_FILE = 'CREATE_BESCHEID_DOCUMENT_FROM_FILE', CREATE_BESCHEID_DOCUMENT = 'CREATE_BESCHEID_DOCUMENT', SEND_BESCHEID = 'SEND_BESCHEID', + CREATE_COLLABORATION_REQUEST = 'CREATE_COLLABORATION_REQUEST', } export interface CreateCommandProps { diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts index a4873730938d80aa0efe333f7177aca4e2e4ff28..eef4a6cad0cd8c46e932d45a93b11eab29005b62 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.spec.ts @@ -23,7 +23,7 @@ */ import { getEmbeddedResource } from '@ngxp/rest'; import { DummyListLinkRel } from 'libs/tech-shared/test/dummy'; -import { createDummyListResource } from 'libs/tech-shared/test/resource'; +import { createDummyListResource, toResource } from 'libs/tech-shared/test/resource'; import { ListResource } from '../resource/resource.util'; import { EMPTY_ARRAY } from '../tech.util'; import { ToEmbeddedResourcesPipe } from './to-embedded-resource.pipe'; @@ -55,5 +55,11 @@ describe('ToEmbeddedResourcesPipe', () => { expect(result).toBe(EMPTY_ARRAY); }); + + it('should return empty array non existing resources', () => { + const result: unknown[] = pipe.transform(toResource({}), DummyListLinkRel.LIST); + + expect(result).toBe(EMPTY_ARRAY); + }); }); }); diff --git a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts index 77e51945183b3b392c2b3d49647af0bf4a0e02ea..f310e40a994c86031869c1137adf3a3387864b38 100644 --- a/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts +++ b/alfa-client/libs/tech-shared/src/lib/pipe/to-embedded-resource.pipe.ts @@ -23,7 +23,7 @@ */ import { Pipe, PipeTransform } from '@angular/core'; import { Resource, getEmbeddedResource } from '@ngxp/rest'; -import { isNil } from 'lodash-es'; +import { isNil, isNull } from 'lodash-es'; import { LinkRelationName } from '../resource/resource.model'; import { ListResource } from '../resource/resource.util'; import { EMPTY_ARRAY } from '../tech.util'; @@ -32,6 +32,7 @@ import { EMPTY_ARRAY } from '../tech.util'; export class ToEmbeddedResourcesPipe implements PipeTransform { transform(listResource: ListResource, linkRel: LinkRelationName): Resource[] { if (isNil(listResource) || isNil(linkRel)) return EMPTY_ARRAY; - return getEmbeddedResource(listResource, linkRel); + const embeddedReources: Resource[] = getEmbeddedResource(listResource, linkRel); + return isNull(embeddedReources) ? EMPTY_ARRAY : embeddedReources; } } diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts index cec2eb392cca4a78a1ae77660048157d00169deb..1c1d30cbcd83ef02da378247d4e2792ff750d3a0 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.spec.ts @@ -1,7 +1,7 @@ import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { fakeAsync, tick } from '@angular/core/testing'; import faker from '@faker-js/faker'; -import { Resource, getUrl } from '@ngxp/rest'; +import { Resource } from '@ngxp/rest'; import { DummyLinkRel } from 'libs/tech-shared/test/dummy'; import { createDummyListResource, createDummyResource } from 'libs/tech-shared/test/resource'; import { BehaviorSubject, Observable, of } from 'rxjs'; @@ -170,59 +170,37 @@ describe('ResourceSearchService', () => { }); describe('get selected', () => { - const dummyStateResource: StateResource<Resource> = createStateResource(createDummyResource()); + const dummyResource: Resource = createDummyResource(); it('should return selected resource', () => { - service.getSelectedResult = jest.fn().mockReturnValue(of(dummyStateResource)); - const selectedResult$: Observable<StateResource<Resource>> = service.getSelectedResult(); + service.getSelectedResult = jest.fn().mockReturnValue(of(dummyResource)); + const selectedResult$: Observable<Resource> = service.getSelectedResult(); - expect(selectedResult$).toBeObservable(singleColdCompleted(dummyStateResource)); + expect(selectedResult$).toBeObservable(singleColdCompleted(dummyResource)); }); }); describe('select result', () => { const dummyResource: Resource = createDummyResource(); - beforeEach(() => { - service.setSelectedResourceLoading = jest.fn(); - repository.getResource.mockReturnValue(of(dummyResource)); - }); - - it('should call setSelectedResourceLoading', () => { - service.selectResult(dummyResource); - - expect(service.setSelectedResourceLoading).toHaveBeenCalled(); - }); - - it('should call repository', () => { - service.selectResult(dummyResource); - - expect(repository.getResource).toHaveBeenCalledWith(getUrl(dummyResource)); - }); - it('should update selected resource', () => { - service.selectedResource.next(createEmptyStateResource()); + service.selectedResource.next(null); service.selectResult(dummyResource); - expect(service.selectedResource.value).toEqual(createStateResource(dummyResource)); + expect(service.selectedResource.value).toEqual(dummyResource); }); }); - describe('set selected resource loading', () => { - const selectedDummyResource: Resource = createDummyResource(); - const selectedDummyStateResource: StateResource<Resource> = - createStateResource(selectedDummyResource); + describe('clear select result', () => { + const dummyResource: Resource = createDummyResource(); - it('should set loading flag to true', () => { - service.selectedResource.next(selectedDummyStateResource); + it('should update selected resource to null', () => { + service.selectedResource.next(dummyResource); - service.setSelectedResourceLoading(); + service.clearSelectedResult(); - expect(service.selectedResource.value).toEqual({ - ...selectedDummyStateResource, - loading: true, - }); + expect(service.selectedResource.value).toBeNull(); }); }); }); diff --git a/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts index c21f6e99a23e4392ef858d4ef5bd4e655a894fae..f8e52663e186ba7c2ebe4b8d6bec0dd593163e3a 100644 --- a/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts +++ b/alfa-client/libs/tech-shared/src/lib/resource/resource-search.service.ts @@ -1,4 +1,4 @@ -import { Resource, getUrl } from '@ngxp/rest'; +import { Resource } from '@ngxp/rest'; import { isEmpty } from 'lodash-es'; import { BehaviorSubject, Observable, first, map, tap, withLatestFrom } from 'rxjs'; import { EMPTY_STRING, isNotEmpty } from '../tech.util'; @@ -25,9 +25,7 @@ export class ResourceSearchService< createEmptyStateResource(), ); readonly searchBy: BehaviorSubject<string> = new BehaviorSubject<string>(EMPTY_STRING); - readonly selectedResource: BehaviorSubject<StateResource<I>> = new BehaviorSubject< - StateResource<I> - >(createEmptyStateResource()); + readonly selectedResource: BehaviorSubject<I> = new BehaviorSubject<I>(null); constructor( private config: SearchResourceServiceConfig<B>, @@ -93,28 +91,15 @@ export class ResourceSearchService< this.listResource.next({ ...this.listResource.value, loading: true }); } - public getSelectedResult(): Observable<StateResource<I>> { + public getSelectedResult(): Observable<I> { return this.selectedResource.asObservable(); } public selectResult(selected: I): void { - this.dispatchInitSelectResult(selected); + this.selectedResource.next(selected); } - private dispatchInitSelectResult(selected: I) { - this.setSelectedResourceLoading(); - this.repository - .getResource(getUrl(selected)) - .pipe(first()) - .subscribe((result: I) => { - this.selectedResource.next(createStateResource(result)); - }); - } - - setSelectedResourceLoading(): void { - this.selectedResource.next({ - ...this.selectedResource.value, - loading: true, - }); + public clearSelectedResult(): void { + this.selectedResource.next(null); } } diff --git a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts index 1af38f9f8065ae4685acb7326d1a65b3d88fcd69..956266f7c268dc575e7e29307b0530a31555f43f 100644 --- a/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts +++ b/alfa-client/libs/tech-shared/src/lib/service/formservice.abstract.ts @@ -32,7 +32,7 @@ import { HttpError, InvalidParam, ProblemDetail } from '../tech.model'; import { isNotUndefined } from '../tech.util'; import { setInvalidParamValidationError } from '../validation/tech.validation.util'; -export abstract class AbstractFormService { +export abstract class AbstractFormService<T extends Resource = Resource> { form: UntypedFormGroup; pathPrefix: string; source: any; @@ -46,17 +46,17 @@ export abstract class AbstractFormService { protected abstract initForm(): UntypedFormGroup; public submit( - afterSubmit: OperatorFunction<StateResource<Resource>, StateResource<Resource>> = identity, - ): Observable<StateResource<Resource | HttpError>> { + afterSubmit: OperatorFunction<StateResource<T>, StateResource<T>> = identity, + ): Observable<StateResource<T | HttpError>> { return this.doSubmit().pipe( afterSubmit, map((result) => this.handleResponse(result)), ); } - protected abstract doSubmit(): Observable<StateResource<Resource | HttpError>>; + protected abstract doSubmit(): Observable<StateResource<T | HttpError>>; - handleResponse(result: StateResource<Resource | HttpError>): StateResource<Resource | HttpError> { + handleResponse(result: StateResource<T | HttpError>): StateResource<T | HttpError> { if (result.loading) return result; if (hasStateResourceError(result)) { this.handleError(result.error); diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html index fc5ca5be41c842695b25ff62b2e6b1251ab27a75..2d16e8047196cf952d24fea9f905b058d7a3e9d9 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.html @@ -54,7 +54,7 @@ <div class="section one-column" - *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.CREATE_COLLABORATION_REQUEST" + *ngIf="vorgangResource | hasLink: vorgangWithEingangLinkRel.COLLABORATIONS" > <ozgcloud-expansion-panel headline="Zusammenarbeit" diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts index 239dd66734f6d2a249fcad3d17b6f41c388c412a..7786b45a3e33dc073681a9cb53887a78d3a9587e 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-area/vorgang-detail-area.component.spec.ts @@ -108,7 +108,7 @@ describe('VorgangDetailAreaComponent', () => { describe('Collaboration', () => { it('should be visibile if link is present', () => { component.vorgangStateResource = createStateResource( - createVorgangWithEingangResource([VorgangWithEingangLinkRel.CREATE_COLLABORATION_REQUEST]), + createVorgangWithEingangResource([VorgangWithEingangLinkRel.COLLABORATIONS]), ); fixture.detectChanges(); diff --git a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts index 22332fc5187c9ce1bc318ceb77b4b7ad0e30e833..b97073aba59db97bc5c523bfb34b83155061bf7a 100644 --- a/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts +++ b/alfa-client/libs/vorgang-detail/src/lib/vorgang-detail-page/vorgang-detail-bescheiden/vorgang-detail-bescheiden-result/vorgang-detail-bescheiden-result.component.spec.ts @@ -413,7 +413,7 @@ describe('VorgangDetailBescheidenResultComponent', () => { }); it('should call formservice submit', () => { - component.doUpdateAndSend(bescheidDraft, jest.fn()).pipe(first()).subscribe(); + component.doUpdateAndSend(bescheidDraft, jest.fn()).subscribe(); expect(formService.submit).toHaveBeenCalled(); }); @@ -607,7 +607,7 @@ describe('VorgangDetailBescheidenResultComponent', () => { describe('get active step', () => { it('should call formService', () => { - component.getActiveStep().pipe(first()).subscribe(); + component.getActiveStep().subscribe(); expect(formService.getActiveStep).toHaveBeenCalled(); }); @@ -617,7 +617,7 @@ describe('VorgangDetailBescheidenResultComponent', () => { (step: number) => { formService.getActiveStep.mockReturnValue(of(step)); - component.getActiveStep().pipe(first()).subscribe(); + component.getActiveStep().subscribe(); expect(bescheidService.clearAttachmentUpload).toHaveBeenCalled(); }, @@ -633,7 +633,7 @@ describe('VorgangDetailBescheidenResultComponent', () => { (step: number) => { formService.getActiveStep.mockReturnValue(of(step)); - component.getActiveStep().pipe(first()).subscribe(); + component.getActiveStep().subscribe(); expect(component.resetSend).toHaveBeenCalled(); }, @@ -642,7 +642,7 @@ describe('VorgangDetailBescheidenResultComponent', () => { it('should not be called on last step', () => { formService.getActiveStep.mockReturnValue(of(3)); - component.getActiveStep().pipe(first()).subscribe(); + component.getActiveStep().subscribe(); expect(component.resetSend).not.toHaveBeenCalled(); }); @@ -656,7 +656,6 @@ describe('VorgangDetailBescheidenResultComponent', () => { component.resetSend(); component.saveAndSendInProgress$ - .pipe(first()) .subscribe((saveAndSendInProgress: StateResource<CommandResource>) => { expect(saveAndSendInProgress).toEqual(createEmptyStateResource()); done(); diff --git a/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts b/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts index a10af56d72cac1ad7b7d9ce522d924cce6ee4d09..a06768b2ed6d34e4c9a6e3fd4f7352a6de6edc89 100644 --- a/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts +++ b/alfa-client/libs/vorgang-shared/src/lib/vorgang.linkrel.ts @@ -65,8 +65,9 @@ export enum VorgangWithEingangLinkRel { UEBERSPRINGEN_UND_ABSCHLIESSEN = 'ueberspringen_und_abschliessen', DOWNLOAD_ATTACHMENTS = 'downloadAttachments', - CREATE_COLLABORATION_REQUEST = 'createCollaborationRequest', SEARCH_ORGANISATIONS_EINHEIT = 'searchOrganisationsEinheit', + + COLLABORATIONS = 'collaborations', } export enum LoeschAnforderungLinkRel { diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Collaboration.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Collaboration.java new file mode 100644 index 0000000000000000000000000000000000000000..a6e8f794e96951c0eb215b97dc73b49205ce0234 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/Collaboration.java @@ -0,0 +1,24 @@ +package de.ozgcloud.alfa.collaboration; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import de.ozgcloud.alfa.common.LinkedResource; +import de.ozgcloud.alfa.common.command.CommandBody; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class Collaboration implements CommandBody { + + @JsonIgnore + private String vorgangId; + @JsonIgnore + private String collaborationVorgangId; + + private String titel; + private String anfrage; + + @LinkedResource(controllerClass = OrganisationsEinheitController.class) + private String zustaendigeStelle; +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationController.java new file mode 100644 index 0000000000000000000000000000000000000000..63a1fa8edc08547408395b4b70739cd766ef27fe --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationController.java @@ -0,0 +1,26 @@ +package de.ozgcloud.alfa.collaboration; + +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping(CollaborationController.PATH) +@RequiredArgsConstructor +public class CollaborationController { + + private final CollaborationModelAssembler assembler; + private final CollaborationService service; + + static final String PATH = "/api/vorgangs"; // NOSONAR + + @GetMapping("/{vorgangId}/collaborations") + public CollectionModel<EntityModel<Collaboration>> getAllByVorgangId(@PathVariable String vorgangId) { + return assembler.toCollectionModel(service.getCollaborations(vorgangId), vorgangId); + } +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java new file mode 100644 index 0000000000000000000000000000000000000000..0323c66fe4fa72971c00afc34815b8d92a064670 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssembler.java @@ -0,0 +1,48 @@ +package de.ozgcloud.alfa.collaboration; + +import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*; + +import java.util.stream.Stream; + +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.LinkRelation; +import org.springframework.hateoas.server.RepresentationModelAssembler; +import org.springframework.stereotype.Component; + +import de.ozgcloud.alfa.common.ModelBuilder; +import de.ozgcloud.alfa.common.command.CommandController; +import de.ozgcloud.alfa.vorgang.VorgangController; +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +class CollaborationModelAssembler implements RepresentationModelAssembler<Collaboration, EntityModel<Collaboration>> { + + static final LinkRelation REL_CREATE_COLLABORATION_REQUEST = LinkRelation.of("createCollaborationRequest"); + + private final VorgangController vorgangController; + + @Override + public EntityModel<Collaboration> toModel(Collaboration collaboration) { + return ModelBuilder.fromEntity(collaboration) + // TODO: Wenn Schnittstelle zum laden der Collaboration existiert, muss self + // link ergänzt werden + .buildModel(); + } + + public CollectionModel<EntityModel<Collaboration>> toCollectionModel(Stream<? extends Collaboration> entities, String vorgangId) { + var collectionModel = CollectionModel.of(entities.map(this::toModel).toList()) + .add(linkTo(methodOn(CollaborationController.class).getAllByVorgangId(vorgangId)).withSelfRel()); + return collectionModel + .addIf(collectionModel.getContent().isEmpty(), () -> buildCreateCollaborationRequestLink(vorgangId)); + } + + Link buildCreateCollaborationRequestLink(String vorgangId) { + var vorgang = vorgangController.getVorgang(vorgangId); + return linkTo(methodOn(CommandController.CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), + vorgang.getVersion(), null)).withRel(REL_CREATE_COLLABORATION_REQUEST); + } + +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationRemoteService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationRemoteService.java new file mode 100644 index 0000000000000000000000000000000000000000..a81de9638ea305b333fbebb229520bb0d42ad33c --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationRemoteService.java @@ -0,0 +1,14 @@ +package de.ozgcloud.alfa.collaboration; + +import java.util.stream.Stream; + +import org.springframework.stereotype.Service; + +@Service +public class CollaborationRemoteService { + + public Stream<Collaboration> getCollaborations(String vorgangId) { + // TODO: Replace Dummy Data with real grpc call + return Stream.empty(); + } +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationService.java new file mode 100644 index 0000000000000000000000000000000000000000..8b4406b926453d570d635b13a556ef6e9050b65b --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationService.java @@ -0,0 +1,23 @@ +package de.ozgcloud.alfa.collaboration; + +import java.util.stream.Stream; + +import org.springframework.stereotype.Service; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +class CollaborationService { + + private final CollaborationRemoteService remoteService; + + public Stream<Collaboration> getCollaborations(String vorgangId) { + return remoteService.getCollaborations(vorgangId); + } + + public boolean hasCollaboration(String vorgangId) { + return remoteService.getCollaborations(vorgangId).findAny().isPresent(); + } + +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java index a8b01feec3ac1c8e1ece0e0e089fc7acd22f07df..c8c7378a3ea53c202a34f4cf8582a30e71b8da09 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessor.java @@ -11,7 +11,6 @@ import org.springframework.hateoas.server.RepresentationModelProcessor; import org.springframework.stereotype.Component; import de.ozgcloud.alfa.common.ModelBuilder; -import de.ozgcloud.alfa.common.command.CommandController; import de.ozgcloud.alfa.common.user.CurrentUserService; import de.ozgcloud.alfa.common.user.UserRole; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; @@ -22,10 +21,11 @@ import lombok.RequiredArgsConstructor; @ConditionalOnProperty("ozgcloud.feature.collaboration-enabled") class CollaborationVorgangProcessor implements RepresentationModelProcessor<EntityModel<VorgangWithEingang>> { - static final LinkRelation REL_CREATE_COLLABORATION_REQUEST = LinkRelation.of("createCollaborationRequest"); + static final LinkRelation REL_COLLABORATIONS = LinkRelation.of("collaborations"); static final LinkRelation REL_SEARCH_ORGANISATIONS_EINHEIT = LinkRelation.of("searchOrganisationsEinheit"); private final CurrentUserService currentUserService; + private final CollaborationService collaborationService; @Override public EntityModel<VorgangWithEingang> process(EntityModel<VorgangWithEingang> model) { @@ -36,10 +36,9 @@ class CollaborationVorgangProcessor implements RepresentationModelProcessor<Enti } return ModelBuilder.fromModel(model) - .addLinks( - linkTo(methodOn(CommandController.CommandByRelationController.class).createCommand(vorgang.getId(), vorgang.getId(), - vorgang.getVersion(), null)).withRel(REL_CREATE_COLLABORATION_REQUEST), - linkTo(methodOn(OrganisationsEinheitController.class).getAllBySearchBy(null)).withRel(REL_SEARCH_ORGANISATIONS_EINHEIT)) + .ifMatch(() -> !collaborationService.hasCollaboration(vorgang.getId())) + .addLink(linkTo(methodOn(OrganisationsEinheitController.class).search(null)).withRel(REL_SEARCH_ORGANISATIONS_EINHEIT)) + .addLink(linkTo(methodOn(CollaborationController.class).getAllByVorgangId(vorgang.getId())).withRel(REL_COLLABORATIONS)) .buildModel(); } } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java index 8b1deacb31d69aa7de439d3ef5112e68dfd6ada2..33bbb03f0d3e3ccfb854740dd9d97e9316d0a691 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheit.java @@ -10,4 +10,5 @@ import lombok.extern.jackson.Jacksonized; class OrganisationsEinheit { private String id; + private XzufiId xzufiId; } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java index 301528e79ac9d1058a54bd31fd611d83104d0eac..e60539a72396755760875f86af415b3cc547dd9d 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitController.java @@ -31,7 +31,7 @@ class OrganisationsEinheitController { } @GetMapping(params = { SEARCH_BY_PARAM }) - public CollectionModel<EntityModel<OrganisationsEinheitHeader>> getAllBySearchBy(@RequestParam String searchBy) { + public CollectionModel<EntityModel<OrganisationsEinheitHeader>> search(@RequestParam String searchBy) { return headerModelAssembler.toCollectionModel(service.searchOrganisationsEinheiten(searchBy).toList()); } } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/XzufiId.java b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/XzufiId.java new file mode 100644 index 0000000000000000000000000000000000000000..49e1f5f3ecafe67ad7ca22daf104406e5a8f39a2 --- /dev/null +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/collaboration/XzufiId.java @@ -0,0 +1,11 @@ +package de.ozgcloud.alfa.collaboration; + +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class XzufiId { + private String id; + private String schemeAgencyId; +} diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java index 8bdf5bbab7eee1d9c6040bdc844cc568546e88bd..42f3ec714dd2a8c466b34cf2670977e2eba6d45a 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandBody.java @@ -29,6 +29,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes.Type; import de.ozgcloud.alfa.aktenzeichen.AktenzeichenCommandBody; import de.ozgcloud.alfa.bescheid.Bescheid; import de.ozgcloud.alfa.bescheid.BescheidDocumentFromFileBody; +import de.ozgcloud.alfa.collaboration.Collaboration; import de.ozgcloud.alfa.kommentar.Kommentar; import de.ozgcloud.alfa.loeschanforderung.DeleteLoeschAnforderung; import de.ozgcloud.alfa.loeschanforderung.LoeschAnforderung; @@ -54,7 +55,8 @@ import de.ozgcloud.alfa.wiedervorlage.Wiedervorlage; @Type(value = Bescheid.class, name = "UPDATE_BESCHEID"), @Type(value = ProcessVorgangBody.class, name = "PROCESS_VORGANG"), @Type(value = AktenzeichenCommandBody.class, name = "SET_AKTENZEICHEN"), - @Type(value = BescheidDocumentFromFileBody.class, name = "CREATE_BESCHEID_DOCUMENT_FROM_FILE") + @Type(value = BescheidDocumentFromFileBody.class, name = "CREATE_BESCHEID_DOCUMENT_FROM_FILE"), + @Type(value = Collaboration.class, name = "CREATE_COLLABORATION_REQUEST") }) public interface CommandBody { } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java index 843c170180851a807ec32a4cdc2cc2c019095d3e..d8825572907482b5b7acaae723eea79c2cde445b 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandModelAssembler.java @@ -38,6 +38,7 @@ import org.springframework.stereotype.Component; import de.ozgcloud.alfa.bescheid.BescheidController; import de.ozgcloud.alfa.bescheid.DocumentController; +import de.ozgcloud.alfa.collaboration.CollaborationController; import de.ozgcloud.alfa.common.ModelBuilder; import de.ozgcloud.alfa.kommentar.KommentarController; import de.ozgcloud.alfa.postfach.PostfachMailController; @@ -82,6 +83,7 @@ class CommandModelAssembler implements RepresentationModelAssembler<Command, Ent case WIEDERVORLAGE -> linkTo(WiedervorlageController.class).slash(entity.getRelationId()); case BESCHEID -> linkTo(methodOn(BescheidController.class).getDraft(entity.getVorgangId())); case DOCUMENT -> linkTo(DocumentController.class).slash(entity.getCreatedResource()); + case COLLABORATION -> linkTo(methodOn(CollaborationController.class).getAllByVorgangId(entity.getVorgangId())); case NONE -> throw new IllegalArgumentException("Unknown CommandOrder: " + entity.getOrder()); }; diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java index 2ecc444afffdd33e851266564ec0356fd19ff164..f2a74744787b4e860b4b0ce2234a62719625dffc 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/command/CommandOrder.java @@ -73,10 +73,12 @@ public enum CommandOrder { PROCESS_VORGANG(false, Type.VORGANG), + CREATE_COLLABORATION_REQUEST(false, Type.COLLABORATION), + UNBEKANNT(false, Type.NONE); enum Type { - VORGANG, VORGANG_LIST, WIEDERVORLAGE, KOMMENTAR, FORWARDING, POSTFACH, BESCHEID, DOCUMENT, NONE + VORGANG, VORGANG_LIST, WIEDERVORLAGE, KOMMENTAR, FORWARDING, POSTFACH, BESCHEID, DOCUMENT, COLLABORATION, NONE } private final boolean revokeable; diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java index 159f038b04b56863c3532950ec5ebef062bf48f4..540170e893ab437f58b3609e4b1ab16c3971e4cd 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/bescheid/BescheidModelAssemblerTest.java @@ -249,7 +249,7 @@ class BescheidModelAssemblerTest { callMethod(); - verify(assembler).toCollectionModel(List.of(bescheid)); + verify(assembler).toModel(bescheid); } @Test diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationControllerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..87122cbb75c58ec12784d345654fd573f534ed70 --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationControllerTest.java @@ -0,0 +1,148 @@ +package de.ozgcloud.alfa.collaboration; + +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +import java.util.Collections; +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.util.UriComponentsBuilder; + +import lombok.SneakyThrows; + +class CollaborationControllerTest { + + @InjectMocks + private CollaborationController controller; + + @Mock + private CollaborationService service; + + @Mock + private CollaborationModelAssembler assembler; + + private MockMvc mockMvc; + + @BeforeEach + void initTest() { + mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); + } + + @Nested + class TestGetAllByVorgangId { + + private final Collaboration collaboration = CollaborationTestFactory.create(); + + @SneakyThrows + @Test + void shouldCallCollaborationService() { + performRequest(); + + verify(service).getCollaborations(CollaborationTestFactory.VORGANG_ID); + } + + @Nested + class TestOnExistingCollaboration { + + private final Stream<Collaboration> collaborations = Stream.of(collaboration); + + @BeforeEach + void mock() { + when(service.getCollaborations(CollaborationTestFactory.VORGANG_ID)).thenReturn(collaborations); + } + + @Test + void shouldCallAssembler() { + performRequest(); + + verify(assembler).toCollectionModel(collaborations, CollaborationTestFactory.VORGANG_ID); + } + + @SneakyThrows + @Test + void shouldReturnStatusOk() { + when(assembler.toCollectionModel(collaborations, CollaborationTestFactory.VORGANG_ID)) + .thenReturn(CollectionModel.of(Collections.singletonList(EntityModel.of(collaboration)))); + + var response = performRequest(); + + response.andExpect(status().isOk()); + } + + @Nested + class TestResponseBody { + + @BeforeEach + void mockAssembler() { + when(assembler.toCollectionModel(collaborations, CollaborationTestFactory.VORGANG_ID)) + .thenReturn(CollectionModel.of(Collections.singletonList(EntityModel.of(collaboration)))); + } + + @SneakyThrows + @Test + void shouldNotHaveVorgangId() { + var response = performRequest(); + + response.andExpect(jsonPath("$.vorgangId").doesNotExist()); + } + + @SneakyThrows + @Test + void shouldNotHaveCollaborationVorgangId() { + var response = performRequest(); + + response.andExpect(jsonPath("$.collaborationVorgangId").doesNotExist()); + } + + @SneakyThrows + @Test + void shouldHaveTitel() { + var response = performRequest(); + + response.andExpect(jsonPath("$.content[0].titel").value(CollaborationTestFactory.TITEL)); + } + + @SneakyThrows + @Test + void shouldHaveAnfrage() { + var response = performRequest(); + + System.out.println(response.andReturn().getResponse().getContentAsString()); + + response.andExpect(jsonPath("$.content[0].anfrage").value(CollaborationTestFactory.ANFRAGE)); + } + + @SneakyThrows + @Test + void shouldHaveZustaendigeStelle() { + var expectedLink = UriComponentsBuilder + .fromUriString("http://localhost") + .path(OrganisationsEinheitController.PATH) + .pathSegment(CollaborationTestFactory.ZUSTAENDIGE_STELLE) + .build(); + + var response = performRequest(); + + response.andExpect(jsonPath("$.content[0].zustaendigeStelle") + .value(expectedLink.toString())); + } + } + } + + @SneakyThrows + private ResultActions performRequest() { + return mockMvc.perform(get(CollaborationController.PATH + "/" + CollaborationTestFactory.VORGANG_ID + "/collaborations")); + } + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java new file mode 100644 index 0000000000000000000000000000000000000000..42ccdb43a2d39ed2bf5f6f71874eec71e57d36ed --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationModelAssemblerTest.java @@ -0,0 +1,183 @@ +package de.ozgcloud.alfa.collaboration; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.stream.Stream; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.springframework.hateoas.CollectionModel; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.IanaLinkRelations; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.UriTemplate; + +import de.ozgcloud.alfa.common.ModelBuilder; +import de.ozgcloud.alfa.common.command.CommandController.CommandByRelationController; +import de.ozgcloud.alfa.vorgang.VorgangController; +import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; +import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import de.ozgcloud.alfa.vorgang.VorgangWithEingangTestFactory; + +class CollaborationModelAssemblerTest { + + @Spy + @InjectMocks + private CollaborationModelAssembler assembler; + + @Mock + private VorgangController vorgangController; + + @Nested + class TestToModel { + + private static final String REL_ZUSTAENDIGE_STELLE = "zustaendigeStelle"; + private final Collaboration collaboration = CollaborationTestFactory.create(); + + @Test + void shouldHaveContent() { + var entityModel = callAssembler(); + + assertThat(entityModel.getContent()).isEqualTo(collaboration); + } + + @Test + void shouldHaveLinkToOrganisationsEinheit() { + var entityModel = callAssembler(); + + assertThat(entityModel.getLink(REL_ZUSTAENDIGE_STELLE)).get().extracting(Link::getHref) + .isEqualTo(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID); + } + + private EntityModel<Collaboration> callAssembler() { + return assembler.toModel(collaboration); + } + } + + @Nested + class TestToCollectionModel { + private final Collaboration collaboration = CollaborationTestFactory.create(); + + @Nested + class OnNonEmptyCollaborationList { + + @Test + void shouldCallToModel() { + callAssembler(); + + verify(assembler).toModel(collaboration); + } + + @Test + void shouldHaveEntityModel() { + var entityModel = ModelBuilder.fromEntity(collaboration).buildModel(); + doReturn(entityModel).when(assembler).toModel(collaboration); + + var collectionModel = callAssembler(); + + assertThat(collectionModel.getContent()).containsExactly(entityModel); + } + + @Test + void shouldHaveSelfLink() { + var collectionModel = callAssembler(); + + assertThat(collectionModel.getLink(IanaLinkRelations.SELF_VALUE)).get().extracting(Link::getHref) + .isEqualTo(CollaborationController.PATH + "/" + VorgangHeaderTestFactory.ID + "/collaborations"); + } + + @Test + void shouldNotHaveCreateCollaborationRequestLink() { + var collectionModel = callAssembler(); + + assertThat(collectionModel.getLink(CollaborationModelAssembler.REL_CREATE_COLLABORATION_REQUEST)).isEmpty(); + } + + private CollectionModel<EntityModel<Collaboration>> callAssembler() { + return assembler.toCollectionModel(Stream.of(collaboration), VorgangHeaderTestFactory.ID); + } + } + + @Nested + class OnEmptyCollaborationList { + + @Mock + private Link createCollaborationRequestLink; + + @BeforeEach + void mock() { + doReturn(createCollaborationRequestLink).when(assembler).buildCreateCollaborationRequestLink(VorgangHeaderTestFactory.ID); + } + + @Test + void shouldHaveEmptyContent() { + var collectionModel = callAssembler(); + + assertThat(collectionModel.getContent()).isEmpty(); + } + + @Test + void shouldHaveSelfLink() { + var collectionModel = callAssembler(); + + assertThat(collectionModel.getLink(IanaLinkRelations.SELF_VALUE)).get().extracting(Link::getHref) + .isEqualTo(CollaborationController.PATH + "/" + VorgangHeaderTestFactory.ID + "/collaborations"); + } + + @Test + void shouldHaveCreateCollaborationRequestLink() { + var collectionModel = callAssembler(); + + assertThat(collectionModel.getLinks()).contains(createCollaborationRequestLink); + } + + private CollectionModel<EntityModel<Collaboration>> callAssembler() { + return assembler.toCollectionModel(Stream.empty(), VorgangHeaderTestFactory.ID); + } + } + } + + @Nested + class TestBuildCreateCollaborationRequestLink { + + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @BeforeEach + void mockVorgangController() { + when(vorgangController.getVorgang(VorgangHeaderTestFactory.ID)).thenReturn(vorgang); + } + + @Test + void shouldCallVorgangController() { + callAssembler(); + + verify(vorgangController).getVorgang(VorgangHeaderTestFactory.ID); + } + + @Test + void shouldHaveHrefToCreateCommand() { + var expectedHref = UriTemplate.of(CommandByRelationController.COMMAND_BY_RELATION_PATH) + .expand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString(); + + var link = callAssembler(); + + assertThat(link).extracting(Link::getHref).isEqualTo(expectedHref); + } + + @Test + void shouldHaveCreateCollaborationRequestRelation() { + var link = callAssembler(); + + assertThat(link).extracting(Link::getRel).isEqualTo(CollaborationModelAssembler.REL_CREATE_COLLABORATION_REQUEST); + } + + private Link callAssembler() { + return assembler.buildCreateCollaborationRequestLink(VorgangHeaderTestFactory.ID); + } + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2659c7fce3f402080694a5b38cdd0fe11f3507f1 --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationServiceTest.java @@ -0,0 +1,84 @@ +package de.ozgcloud.alfa.collaboration; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import java.util.UUID; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +class CollaborationServiceTest { + + @InjectMocks + private CollaborationService service; + + @Mock + private CollaborationRemoteService remoteService; + + @Nested + class TestGetCollaborations { + + private final String id = UUID.randomUUID().toString(); + + @Test + void shouldCallRemoteService() { + callService(); + + verify(remoteService).getCollaborations(id); + } + + @Test + void shouldReturnCollaboration() { + var collaboration = CollaborationTestFactory.create(); + when(remoteService.getCollaborations(id)).thenReturn(Stream.of(collaboration)); + + var returnedCollaboration = callService(); + + assertThat(returnedCollaboration).contains(collaboration); + } + + private Stream<Collaboration> callService() { + return service.getCollaborations(id); + } + } + + @Nested + class TestHasCollaboration { + + private final String id = UUID.randomUUID().toString(); + + @Test + void shouldCallRemoteService() { + callService(); + + verify(remoteService).getCollaborations(id); + } + + @Test + void shouldReturnTrue() { + var collaboration = CollaborationTestFactory.create(); + when(remoteService.getCollaborations(id)).thenReturn(Stream.of(collaboration)); + + var hasCollaboration = callService(); + + assertThat(hasCollaboration).isTrue(); + } + + @Test + void shouldReturnFalse() { + when(remoteService.getCollaborations(id)).thenReturn(Stream.empty()); + + var hasCollaboration = callService(); + + assertThat(hasCollaboration).isFalse(); + } + + private boolean callService() { + return service.hasCollaboration(id); + } + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..133acf57bb11cd6d048f2c578405f4ceadd4ae4b --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationTestFactory.java @@ -0,0 +1,30 @@ +package de.ozgcloud.alfa.collaboration; + +import java.util.UUID; + +import com.thedeanda.lorem.LoremIpsum; + +import de.ozgcloud.alfa.collaboration.Collaboration.CollaborationBuilder; + +public class CollaborationTestFactory { + + public static final String VORGANG_ID = UUID.randomUUID().toString(); + public static final String COLLABORATION_VORGANG_ID = UUID.randomUUID().toString(); + public static final String TITEL = LoremIpsum.getInstance().getWords(7); + public static final String ANFRAGE = LoremIpsum.getInstance().getParagraphs(2, 5); + public static final String ZUSTAENDIGE_STELLE = OrganisationsEinheitTestFactory.ID; + + public static Collaboration create() { + return createBuilder() + .build(); + } + + private static CollaborationBuilder createBuilder() { + return Collaboration.builder() + .vorgangId(VORGANG_ID) + .collaborationVorgangId(COLLABORATION_VORGANG_ID) + .titel(TITEL) + .anfrage(ANFRAGE) + .zustaendigeStelle(ZUSTAENDIGE_STELLE); + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java index f298e909253839bb53643caced64f281f6c554c1..8e28fca8d28c0752644af390b656228fef93ea26 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/CollaborationVorgangProcessorTest.java @@ -4,6 +4,7 @@ import static de.ozgcloud.alfa.common.UserProfileUrlProviderTestFactory.*; import static org.assertj.core.api.Assertions.*; import static org.mockito.Mockito.*; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; @@ -11,11 +12,10 @@ import org.mockito.Mock; import org.mockito.Spy; import org.springframework.hateoas.EntityModel; import org.springframework.hateoas.Link; -import org.springframework.hateoas.UriTemplate; +import org.springframework.web.util.UriComponentsBuilder; import de.ozgcloud.alfa.common.EntityModelTestFactory; import de.ozgcloud.alfa.common.UserProfileUrlProvider; -import de.ozgcloud.alfa.common.command.CommandController; import de.ozgcloud.alfa.common.user.CurrentUserService; import de.ozgcloud.alfa.common.user.UserRole; import de.ozgcloud.alfa.vorgang.VorgangHeaderTestFactory; @@ -28,6 +28,9 @@ class CollaborationVorgangProcessorTest { @InjectMocks private CollaborationVorgangProcessor processor; + @Mock + private CollaborationService collaborationService; + @Mock private CurrentUserService currentUserService; @@ -36,96 +39,125 @@ class CollaborationVorgangProcessorTest { @Nested class TestProcess { - @Test - void shouldNotAddLinksIfVorgangIsNull() { - var model = processor.process(EntityModelTestFactory.NULLABLE); - - assertThat(model.hasLinks()).isFalse(); - } - @Nested - class LinkToCreateCollaborationRequest { + class OnNullVorgang { @Test - void shouldAddLink() { - initUserProfileUrlProvider(urlProvider); - givenUserHasRoleVerwaltungUser(); - - var model = callProcessor(); + void shouldNotAddLinksIfVorgangIsNull() { + var model = processor.process(EntityModelTestFactory.NULLABLE); - assertThat(model.getLink(CollaborationVorgangProcessor.REL_CREATE_COLLABORATION_REQUEST)).isPresent(); + assertThat(model.hasLinks()).isFalse(); } + } - @Test - void shouldHaveHref() { - initUserProfileUrlProvider(urlProvider); - givenUserHasRoleVerwaltungUser(); - - var model = callProcessor(); + @Nested + class OnNotVerwaltungUserRole { - assertThat(model.getLink(CollaborationVorgangProcessor.REL_CREATE_COLLABORATION_REQUEST)).get() - .extracting(Link::getHref) - .isEqualTo(UriTemplate.of(CommandController.CommandByRelationController.COMMAND_BY_RELATION_PATH) - .expand(VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.ID, VorgangHeaderTestFactory.VERSION).toString()); + @BeforeEach + void mockUserService() { + when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(false); } @Test - void shouldNotAddLinkIfUserHasNoRole() { - givenUserDoesNotHaveRoleVerwaltungUser(); - - var model = callProcessor(); + void shouldNotAddLinks() { + var model = processor.process(EntityModel.of(VorgangWithEingangTestFactory.create())); - assertThat(model.getLink(CollaborationVorgangProcessor.REL_CREATE_COLLABORATION_REQUEST)).isEmpty(); + assertThat(model.hasLinks()).isFalse(); } + } @Nested - class LinkToSearchOrganisationsEinheit { + class OnNonNullVorgangAndOnVerwaltungUserRole { - @Test - void shouldAddLink() { + @BeforeEach + void prepareBuilder() { initUserProfileUrlProvider(urlProvider); - givenUserHasRoleVerwaltungUser(); - - var model = callProcessor(); + } - assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).isPresent(); + @BeforeEach + void mockUserService() { + when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(true); } - @Test - void shouldHaveHref() { - initUserProfileUrlProvider(urlProvider); - givenUserHasRoleVerwaltungUser(); + @Nested + class OnCollaborationPresent { - var model = callProcessor(); + @BeforeEach + void setUpMock() { + when(collaborationService.hasCollaboration(VorgangHeaderTestFactory.ID)).thenReturn(true); + } - assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).get() - .extracting(Link::getHref) - .isEqualTo( - String.format("%s?%s={%s}", OrganisationsEinheitController.PATH, OrganisationsEinheitController.SEARCH_BY_PARAM, - OrganisationsEinheitController.SEARCH_BY_PARAM)); - } + @Test + void shouldHaveTwoLinks() { + var model = callProcessor(); - @Test - void shouldNotAddLinkIfUserHasNoRole() { - givenUserDoesNotHaveRoleVerwaltungUser(); + assertThat(model.getLinks()).hasSize(2); + } + + @Test + void shouldNotAddSearchOrganisationsEinheitLink() { + var model = callProcessor(); - var model = callProcessor(); + assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).isEmpty(); + } - assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).isEmpty(); + @Test + void shouldAddCollaborationsLink() { + var model = callProcessor(); + + assertThat(model.getLink(CollaborationVorgangProcessor.REL_COLLABORATIONS)).get() + .extracting(Link::getHref) + .isEqualTo(CollaborationController.PATH + "/" + VorgangHeaderTestFactory.ID + "/collaborations"); + } } - } - private void givenUserHasRoleVerwaltungUser() { - when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(true); - } + @Nested + class OnCollaborationsNotPresent { - private void givenUserDoesNotHaveRoleVerwaltungUser() { - when(currentUserService.hasRole(UserRole.VERWALTUNG_USER)).thenReturn(false); - } + @BeforeEach + void setUpMock() { + when(collaborationService.hasCollaboration(VorgangHeaderTestFactory.ID)).thenReturn(false); + } + + @Test + void shouldHaveThreeLinks() { + var model = callProcessor(); + + assertThat(model.getLinks()).hasSize(3); - private EntityModel<VorgangWithEingang> callProcessor() { - return processor.process(EntityModel.of(VorgangWithEingangTestFactory.create())); + } + + @Test + void shouldAddSearchOrganisationsEinheitLink() { + var expectedHref = UriComponentsBuilder.fromUriString(OrganisationsEinheitController.PATH) + .queryParam(OrganisationsEinheitController.SEARCH_BY_PARAM, "{" + OrganisationsEinheitController.SEARCH_BY_PARAM + "}") + .build().toString(); + + var model = callProcessor(); + + assertThat(model.getLink(CollaborationVorgangProcessor.REL_SEARCH_ORGANISATIONS_EINHEIT)).get() + .extracting(Link::getHref) + .isEqualTo(expectedHref); + } + + @Test + void shouldAddCollaborationsLink() { + var expectedHref = UriComponentsBuilder.fromUriString(CollaborationController.PATH) + .pathSegment(VorgangHeaderTestFactory.ID, "collaborations") + .build().toString(); + + var model = callProcessor(); + + assertThat(model.getLink(CollaborationVorgangProcessor.REL_COLLABORATIONS)).get() + .extracting(Link::getHref) + .isEqualTo(expectedHref); + } + } + + private EntityModel<VorgangWithEingang> callProcessor() { + return processor.process(EntityModel.of(VorgangWithEingangTestFactory.create())); + } } } } diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java index aad546fdba57c6e25e5638b54fa8b6b33a72769b..1edb729801079868c6a347d885ff88d9e659bec3 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitControllerTest.java @@ -88,6 +88,26 @@ class OrganisationsEinheitControllerTest { response.andExpect(jsonPath("$.id").value(OrganisationsEinheitTestFactory.ID)); } + @SneakyThrows + @Test + void shouldHaveOrganisationsEinheitXzufiId() { + when(assembler.toModel(organisationsEinheit)).thenReturn(EntityModel.of(organisationsEinheit)); + + var response = performRequest(); + + response.andExpect(jsonPath("$.xzufiId.id").value(XzufiIdTestFactory.ID)); + } + + @SneakyThrows + @Test + void shouldHaveOrganisationsEinheitXzufiSchemeAgencyId() { + when(assembler.toModel(organisationsEinheit)).thenReturn(EntityModel.of(organisationsEinheit)); + + var response = performRequest(); + + response.andExpect(jsonPath("$.xzufiId.schemeAgencyId").value(XzufiIdTestFactory.SCHEME_AGENCY_ID)); + } + @SneakyThrows private ResultActions performRequest() { return mockMvc.perform(get(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID)); @@ -95,7 +115,7 @@ class OrganisationsEinheitControllerTest { } @Nested - class TestGetAllBySearchBy { + class TestSearch { private final OrganisationsEinheitHeader organisationsEinheitHeader1 = OrganisationsEinheitHeaderTestFactory.create(); private final OrganisationsEinheitHeader organisationsEinheitHeader2 = OrganisationsEinheitHeaderTestFactory.createBuilder() diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java index 8f51eeb7262a0f8f8e62bb91a264d8561efaa7e8..fba797d96ceb4bfb9d9ea85b39e0600c9b10b6dd 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitModelAssemblerTest.java @@ -7,6 +7,7 @@ import org.junit.jupiter.api.Test; import org.mockito.Spy; import org.springframework.hateoas.IanaLinkRelations; import org.springframework.hateoas.Link; +import org.springframework.web.util.UriComponentsBuilder; class OrganisationsEinheitModelAssemblerTest { @@ -18,10 +19,14 @@ class OrganisationsEinheitModelAssemblerTest { @Test void shouldHaveSelfLink() { + var expectedHref = UriComponentsBuilder.fromUriString(OrganisationsEinheitController.PATH) + .pathSegment(OrganisationsEinheitTestFactory.ID) + .build().toString(); + var model = assembler.toModel(OrganisationsEinheitTestFactory.create()); assertThat(model.getLink(IanaLinkRelations.SELF_VALUE)).isPresent().get().extracting(Link::getHref) - .isEqualTo(OrganisationsEinheitController.PATH + "/" + OrganisationsEinheitTestFactory.ID); + .isEqualTo(expectedHref); } } } diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java index dea40a930f381d7a0ae3c45ba7af4cef19588a5a..59c6f03c06961983f4eefbe169474118e11b1087 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/OrganisationsEinheitTestFactory.java @@ -28,6 +28,7 @@ import de.ozgcloud.alfa.collaboration.OrganisationsEinheit.OrganisationsEinheitB public class OrganisationsEinheitTestFactory { public static final String ID = OrganisationsEinheitHeaderTestFactory.ID; + public static final XzufiId XZUFI_ID = XzufiIdTestFactory.create(); public static OrganisationsEinheit create() { return createBuilder().build(); @@ -35,6 +36,7 @@ public class OrganisationsEinheitTestFactory { public static OrganisationsEinheitBuilder createBuilder() { return OrganisationsEinheit.builder() - .id(ID); + .id(ID) + .xzufiId(XZUFI_ID); } } diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/XzufiIdTestFactory.java b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/XzufiIdTestFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..49ddf54180fa8074dbc4867fb3b16110797f277a --- /dev/null +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/collaboration/XzufiIdTestFactory.java @@ -0,0 +1,17 @@ +package de.ozgcloud.alfa.collaboration; + +public class XzufiIdTestFactory { + + public static final String ID = GrpcXzufiIdTestFactory.ORGANISATIONS_EINHEIT_ID; + public static final String SCHEME_AGENCY_ID = GrpcXzufiIdTestFactory.SCHEME_AGENCY_ID; + + public static XzufiId create() { + return createBuilder().build(); + } + + public static XzufiId.XzufiIdBuilder createBuilder() { + return XzufiId.builder() + .id(ID) + .schemeAgencyId(SCHEME_AGENCY_ID); + } +} diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java index 01c57942b5967158fdf4d50b0e9b7219ae527867..fdf074c51c83c4ad34eb6e1c188f0af89c273dfa 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/common/command/CommandModelAssemblerTest.java @@ -76,7 +76,7 @@ class CommandModelAssemblerTest { @Nested class TestOnVorgang { - private final String VORGANG_URL = "/api/vorgangs/" + RELATION_ID; + private static final String VORGANG_URL = "/api/vorgangs/" + RELATION_ID; @ParameterizedTest @EnumSource(mode = Mode.INCLUDE, names = { "FINISHED", "REVOKED" }) @@ -103,7 +103,7 @@ class CommandModelAssemblerTest { @Nested class TestOnForwarding { - private final String FORWARDING_URL = "/api/forwardings?vorgangId=" + VorgangHeaderTestFactory.ID; + private static final String FORWARDING_URL = "/api/forwardings?vorgangId=" + VorgangHeaderTestFactory.ID; @ParameterizedTest @ValueSource(strings = { "FORWARD_SUCCESSFULL", "FORWARD_FAILED", "REDIRECT_VORGANG" }) @@ -119,7 +119,7 @@ class CommandModelAssemblerTest { @Nested class TestOnPostfach { - private final String POSTFACH_URL = "/api/postfachMails?vorgangId=" + VorgangHeaderTestFactory.ID; + private static final String POSTFACH_URL = "/api/postfachMails?vorgangId=" + VorgangHeaderTestFactory.ID; @ParameterizedTest @ValueSource(strings = { "SEND_POSTFACH_MAIL" }) @@ -135,7 +135,7 @@ class CommandModelAssemblerTest { @Nested class TestOnBescheid { - private final String BESCHEID_URL = "/api/bescheids?vorgangId=" + VorgangHeaderTestFactory.ID; + private static final String BESCHEID_URL = "/api/bescheids?vorgangId=" + VorgangHeaderTestFactory.ID; @ParameterizedTest @ValueSource(strings = { "CREATE_BESCHEID", "UPDATE_BESCHEID" }) @@ -152,7 +152,7 @@ class CommandModelAssemblerTest { @Nested class TestOnDocument { - private final String DOCUMENT_URL = "/api/bescheids/documents/" + RELATION_ID; + private static final String DOCUMENT_URL = "/api/bescheids/documents/" + RELATION_ID; @Test void shouldHaveLinkToBescheidDokument() { @@ -166,6 +166,21 @@ class CommandModelAssemblerTest { } } + @DisplayName("on collaboration") + @Nested + class TestOnCollaboration { + + private static final String COLLABORATIONS_URL = "/api/vorgangs/" + VORGANG_ID + "/collaborations"; + + @Test + void shouldHaveLinkToCollaborations() { + var model = toModelWithOrder("CREATE_COLLABORATION_REQUEST"); + + assertThat(model.getLink(CommandModelAssembler.REL_EFFECTED_RESOURCE)).isPresent().get() + .extracting(Link::getHref).isEqualTo(COLLABORATIONS_URL); + } + } + @DisplayName("on unknown Order") @Nested class TestOnUnknownOrder { @@ -223,7 +238,7 @@ class CommandModelAssemblerTest { "UPDATE_ATTACHED_ITEM", "PATCH_ATTACHED_ITEM", "RECEIVE_POSTFACH_NACHRICHT", "VORGANG_LOESCHEN", "DELETE_ATTACHED_ITEM", "VORGANG_ZUM_LOESCHEN_MARKIEREN", "LOESCH_ANFORDERUNG_ZURUECKNEHMEN", "CREATE_BESCHEID", "PROCESS_VORGANG", "SET_AKTENZEICHEN", "DELETE_BESCHEID", "UPDATE_BESCHEID", "CREATE_BESCHEID_DOCUMENT_FROM_FILE", "CREATE_BESCHEID_DOCUMENT", "SEND_BESCHEID", - "UNBEKANNT" }) + "UNBEKANNT", "CREATE_COLLABORATION_REQUEST" }) void shouldBePresentOnOrder(CommandOrder order) { var model = toModelWithOrder(order.name()); diff --git a/pom.xml b/pom.xml index ea5ae9ff598c2dabd88fd1b3c1421b523a0f31fa..a824ac03c6c5b1db540c09c85bb3cb6fb6b694b6 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ <parent> <groupId>de.ozgcloud.common</groupId> <artifactId>ozgcloud-common-parent</artifactId> - <version>4.3.1</version> + <version>4.3.2</version> </parent> <groupId>de.ozgcloud.alfa</groupId>