Skip to content
Snippets Groups Projects
Commit 550cbc94 authored by OZGCloud's avatar OZGCloud
Browse files

OZG-4949 OZG-5112 refactor abstract formservice; cleanup

parent 30d694d2
No related branches found
No related tags found
No related merge requests found
Showing
with 183 additions and 121 deletions
export enum SettingListLinkRel {
CREATE = '',
LIST = 'settings',
}
...@@ -24,22 +24,17 @@ ...@@ -24,22 +24,17 @@
import { ListResource } from '@alfa-client/tech-shared'; import { ListResource } from '@alfa-client/tech-shared';
import { Resource } from '@ngxp/rest'; import { Resource } from '@ngxp/rest';
export interface SettingsListResource extends ListResource { export interface SettingListResource extends ListResource {
_embedded: { settings: SettingsItemResource[] }; _embedded: { settings: SettingItemResource[] };
} }
export enum SettingsName { export enum SettingName {
POSTFACH = 'Postfach', POSTFACH = 'Postfach',
} }
export interface SettingsItem { export interface SettingItem {
name: SettingsName; name: SettingName;
settingsBody: unknown; settingsBody: unknown;
} }
export declare type SettingsItemResource = Resource & SettingsItem; export declare type SettingItemResource = Resource & SettingItem;
export enum SettingsListLinkRel {
CREATE = '',
LIST = 'settings',
}
import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository'; import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository';
import { SettingsService } from './admin-settings.service'; import { SettingsService } from './admin-settings.service';
import { SettingsListLinkRel, SettingsListResource } from './admin-settings.model'; import { SettingListResource } from './admin-settings.model';
import { import {
createEmptyStateResource, createEmptyStateResource,
createStateResource, createStateResource,
...@@ -10,12 +10,13 @@ import { ...@@ -10,12 +10,13 @@ import {
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { ListResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model'; import { ListResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model';
import { PostfachResource } from './postfach/postfach.model'; import { PostfachResource } from './postfach/postfach.model';
import { createEmptyResource, createPostfachResource } from '../../test/postfach/postfach'; import { createSettingItemResource, createPostfachResource } from '../../test/postfach/postfach';
import { createSettingsListResource } from '../../test/admin-settings'; import { createSettingsListResource } from '../../test/admin-settings';
import { ConfigurationService } from './configuration/configuration.service'; import { ConfigurationService } from './configuration/configuration.service';
import { createConfigurationResource } from '../../test/configuration/configuration'; import { createConfigurationResource } from '../../test/configuration/configuration';
import { ConfigurationResource } from './configuration/configuration.model'; import { ConfigurationResource } from './configuration/configuration.model';
import { singleCold } from '../../../tech-shared/src/lib/resource/marbles'; import { singleCold } from '../../../tech-shared/src/lib/resource/marbles';
import { SettingListLinkRel } from './admin-settings.linkrel';
describe('SettingsService', () => { describe('SettingsService', () => {
let service: SettingsService; let service: SettingsService;
...@@ -53,13 +54,13 @@ describe('SettingsService', () => { ...@@ -53,13 +54,13 @@ describe('SettingsService', () => {
it('should have createLinkRel', () => { it('should have createLinkRel', () => {
const config: ListResourceServiceConfig<ConfigurationResource> = service.buildConfig(); const config: ListResourceServiceConfig<ConfigurationResource> = service.buildConfig();
expect(config.createLinkRel).toBe(SettingsListLinkRel.CREATE); expect(config.createLinkRel).toBe(SettingListLinkRel.CREATE);
}); });
it('should have istLinKRel', () => { it('should have istLinKRel', () => {
const config: ListResourceServiceConfig<ConfigurationResource> = service.buildConfig(); const config: ListResourceServiceConfig<ConfigurationResource> = service.buildConfig();
expect(config.listLinkRel).toBe(SettingsListLinkRel.LIST); expect(config.listLinkRel).toBe(SettingListLinkRel.LIST);
}); });
}); });
...@@ -67,7 +68,7 @@ describe('SettingsService', () => { ...@@ -67,7 +68,7 @@ describe('SettingsService', () => {
const postfachResource = createPostfachResource(); const postfachResource = createPostfachResource();
const postfachStateResource: StateResource<PostfachResource> = const postfachStateResource: StateResource<PostfachResource> =
createStateResource(postfachResource); createStateResource(postfachResource);
const settingsListResource: StateResource<SettingsListResource> = createStateResource( const settingsListResource: StateResource<SettingListResource> = createStateResource(
createSettingsListResource([postfachResource]), createSettingsListResource([postfachResource]),
); );
...@@ -81,23 +82,23 @@ describe('SettingsService', () => { ...@@ -81,23 +82,23 @@ describe('SettingsService', () => {
expect(service.resourceService.getList).toHaveBeenCalled(); expect(service.resourceService.getList).toHaveBeenCalled();
}); });
it('should return null for missing postfach resource', () => { it('should return null for non postfach resource', () => {
const emptySettingsListResource = createStateResource( const emptySettingsListResource: StateResource<SettingListResource> = createStateResource(
createSettingsListResource([createEmptyResource()]), createSettingsListResource([createSettingItemResource()]),
); );
service.resourceService.getList = jest service.resourceService.getList = jest
.fn() .fn()
.mockReturnValue(singleCold(emptySettingsListResource)); .mockReturnValue(singleCold(emptySettingsListResource));
const postfach = service.getPostfach(); const postfach: Observable<StateResource<PostfachResource>> = service.getPostfach();
expect(postfach).toBeObservable(singleCold(createEmptyStateResource())); expect(postfach).toBeObservable(singleCold(createEmptyStateResource()));
}); });
it('should return item resource as postfach resource', () => { it('should return item resource as postfach resource', () => {
service.resourceService.getList = jest.fn().mockReturnValue(singleCold(settingsListResource)); service.resourceService.getList = jest.fn().mockReturnValue(singleCold(settingsListResource));
const postfach = service.getPostfach(); const postfach: Observable<StateResource<PostfachResource>> = service.getPostfach();
expect(postfach).toBeObservable(singleCold(postfachStateResource)); expect(postfach).toBeObservable(singleCold(postfachStateResource));
}); });
......
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ResourceListService } from 'libs/tech-shared/src/lib/resource/list-resource.service'; import { ResourceListService } from 'libs/tech-shared/src/lib/resource/list-resource.service';
import { import { SettingItemResource, SettingListResource } from './admin-settings.model';
SettingsItemResource,
SettingsListLinkRel,
SettingsListResource,
} from './admin-settings.model';
import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository'; import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository';
import { ListResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model'; import { ListResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model';
import { map, Observable } from 'rxjs'; import { map, Observable } from 'rxjs';
...@@ -13,13 +9,14 @@ import { PostfachResource } from './postfach/postfach.model'; ...@@ -13,13 +9,14 @@ import { PostfachResource } from './postfach/postfach.model';
import { ConfigurationService } from './configuration/configuration.service'; import { ConfigurationService } from './configuration/configuration.service';
import { ConfigurationResource } from './configuration/configuration.model'; import { ConfigurationResource } from './configuration/configuration.model';
import { getPostfachResource } from './admin-settings.util'; import { getPostfachResource } from './admin-settings.util';
import { SettingListLinkRel } from './admin-settings.linkrel';
@Injectable() @Injectable()
export class SettingsService { export class SettingsService {
resourceService: ResourceListService< resourceService: ResourceListService<
ConfigurationResource, ConfigurationResource,
SettingsListResource, SettingListResource,
SettingsItemResource SettingItemResource
>; >;
constructor( constructor(
...@@ -32,8 +29,8 @@ export class SettingsService { ...@@ -32,8 +29,8 @@ export class SettingsService {
buildConfig(): ListResourceServiceConfig<ConfigurationResource> { buildConfig(): ListResourceServiceConfig<ConfigurationResource> {
return { return {
baseResource: this.configurationService.getConfigurationResource(), baseResource: this.configurationService.getConfigurationResource(),
createLinkRel: SettingsListLinkRel.CREATE, createLinkRel: SettingListLinkRel.CREATE,
listLinkRel: SettingsListLinkRel.LIST, listLinkRel: SettingListLinkRel.LIST,
}; };
} }
......
...@@ -5,14 +5,14 @@ import { ...@@ -5,14 +5,14 @@ import {
createStateResource, createStateResource,
StateResource, StateResource,
} from '@alfa-client/tech-shared'; } from '@alfa-client/tech-shared';
import { SettingsListResource } from './admin-settings.model'; import { SettingListResource } from './admin-settings.model';
import { createFilledSettingsListResource } from '../../test/admin-settings'; import { createFilledSettingsListResource } from '../../test/admin-settings';
import { getPostfachResource } from './admin-settings.util'; import { getPostfachResource } from './admin-settings.util';
describe('get postfach resource', () => { describe('get postfach resource', () => {
it('should return state resource with postfach resource if exists', () => { it('should return state resource with postfach resource if exists', () => {
const postfachResource: PostfachResource = createPostfachResource(); const postfachResource: PostfachResource = createPostfachResource();
const settingsListResource: StateResource<SettingsListResource> = createStateResource( const settingsListResource: StateResource<SettingListResource> = createStateResource(
createFilledSettingsListResource([postfachResource]), createFilledSettingsListResource([postfachResource]),
); );
...@@ -23,7 +23,7 @@ describe('get postfach resource', () => { ...@@ -23,7 +23,7 @@ describe('get postfach resource', () => {
}); });
it('should return empty state resource if postfach resource NOT exists', () => { it('should return empty state resource if postfach resource NOT exists', () => {
const settingsListResource: StateResource<SettingsListResource> = createStateResource( const settingsListResource: StateResource<SettingListResource> = createStateResource(
createFilledSettingsListResource([]), createFilledSettingsListResource([]),
); );
......
...@@ -6,21 +6,22 @@ import { ...@@ -6,21 +6,22 @@ import {
StateResource, StateResource,
} from '@alfa-client/tech-shared'; } from '@alfa-client/tech-shared';
import { PostfachResource } from './postfach/postfach.model'; import { PostfachResource } from './postfach/postfach.model';
import { import { SettingItemResource, SettingListResource, SettingName } from './admin-settings.model';
SettingsItemResource, import { SettingListLinkRel } from './admin-settings.linkrel';
SettingsListLinkRel,
SettingsListResource, SettingsName,
} from './admin-settings.model';
export function getPostfachResource( export function getPostfachResource(
settingsListResource: StateResource<SettingsListResource>, settingsListResource: StateResource<SettingListResource>,
): StateResource<PostfachResource> { ): StateResource<PostfachResource> {
const entries: SettingsItemResource[] = getEmbeddedResources( const entries: SettingItemResource[] = getEmbeddedResources(
settingsListResource, settingsListResource,
SettingsListLinkRel.LIST, SettingListLinkRel.LIST,
); );
const postfachEntry = entries.find((item) => item.name === SettingsName.POSTFACH); const postfachSettingItemResource: SettingItemResource = entries.find(isPostfachSettingItem);
return isNotNil(postfachEntry) ? return isNotNil(postfachSettingItemResource) ?
createStateResource(postfachEntry as PostfachResource) createStateResource(postfachSettingItemResource as PostfachResource)
: createEmptyStateResource(); : createEmptyStateResource();
} }
function isPostfachSettingItem(item: SettingItemResource): boolean {
return item.name === SettingName.POSTFACH;
}
export enum ConfigurationLinkRel {
SETTING = 'settings',
}
import { HttpStatusCode } from '@angular/common/http';
import { ValidationMessageCode } from '../../../../tech-shared/src/lib/validation/tech.validation.messages';
export interface ProblemDetail {
type?: string;
title: string;
status: HttpStatusCode;
detail: string;
instance: string;
}
export interface InvalidParamsItem {
name: string;
reason: ValidationMessageCode;
}
export interface ValidationProblemDetails extends ProblemDetail {
['invalid-params']: InvalidParamsItem[];
}
...@@ -15,18 +15,20 @@ import { PostfachFormService } from './postfach.formservice'; ...@@ -15,18 +15,20 @@ import { PostfachFormService } from './postfach.formservice';
import { MockComponent, ngMocks } from 'ng-mocks'; import { MockComponent, ngMocks } from 'ng-mocks';
import { TextFieldComponent } from '../../../shared/text-field/text-field.component'; import { TextFieldComponent } from '../../../shared/text-field/text-field.component';
import { createPostfachResource } from '../../../../../test/postfach/postfach'; import { createPostfachResource } from '../../../../../test/postfach/postfach';
import { createStateResource } from '@alfa-client/tech-shared'; import { ProblemDetail, createStateResource } from '@alfa-client/tech-shared';
import { PostfachService } from '../../postfach.service'; import { PostfachService } from '../../postfach.service';
import { createValidationProblemDetails } from '../../../../../../tech-shared/test/error';
import { PostfachResource } from '../../postfach.model'; import { PostfachResource } from '../../postfach.model';
import { EMPTY } from 'rxjs'; import { EMPTY } from 'rxjs';
import { singleCold } from '../../../../../../tech-shared/src/lib/resource/marbles'; import { singleCold } from '../../../../../../tech-shared/src/lib/resource/marbles';
import { createInvalidParam, createProblemDetail } from '../../../../../../tech-shared/test/error';
describe('PostfachFormComponent', () => { describe('PostfachFormComponent', () => {
let component: PostfachFormComponent; let component: PostfachFormComponent;
let fixture: ComponentFixture<PostfachFormComponent>; let fixture: ComponentFixture<PostfachFormComponent>;
const postfachService = mock(PostfachService);
let formService: PostfachFormService; let formService: PostfachFormService;
const postfachService = mock(PostfachService);
const saveButton: string = getDataTestIdOf('save-button'); const saveButton: string = getDataTestIdOf('save-button');
const invalidMessageSpan: string = getDataTestIdOf('invalid-empty-message-span'); const invalidMessageSpan: string = getDataTestIdOf('invalid-empty-message-span');
...@@ -68,9 +70,10 @@ describe('PostfachFormComponent', () => { ...@@ -68,9 +70,10 @@ describe('PostfachFormComponent', () => {
describe('updatePostfachResource', () => { describe('updatePostfachResource', () => {
it('should patch form with input postfach resource', () => { it('should patch form with input postfach resource', () => {
const patchFn = jest.spyOn(formService, 'patch'); const patchFn = jest.spyOn(formService, 'patch');
const postfachResource: PostfachResource = createPostfachResource();
const postfachResource = createPostfachResource();
component.updatePostfachResource(postfachResource); component.updatePostfachResource(postfachResource);
expect(patchFn).toHaveBeenCalledWith(postfachResource.settingsBody); expect(patchFn).toHaveBeenCalledWith(postfachResource.settingsBody);
}); });
}); });
...@@ -151,13 +154,20 @@ describe('PostfachFormComponent', () => { ...@@ -151,13 +154,20 @@ describe('PostfachFormComponent', () => {
describe('invalid message', () => { describe('invalid message', () => {
it('should show if form invalidEmpty', () => { it('should show if form invalidEmpty', () => {
formService.setValidationDetails(createValidationProblemDetails()); formService.setErrorByProblemDetail(createProblemDetailForAbsenderName());
fixture.detectChanges(); fixture.detectChanges();
existsAsHtmlElement(fixture, invalidMessageSpan); existsAsHtmlElement(fixture, invalidMessageSpan);
}); });
function createProblemDetailForAbsenderName(): ProblemDetail {
return {
...createProblemDetail(),
'invalid-params': [{ ...createInvalidParam(), name: 'settingsBody.absender.name' }],
};
}
it('should not show if form valid', () => { it('should not show if form valid', () => {
expect(formService.form.invalid).toBeFalsy(); expect(formService.form.invalid).toBeFalsy();
......
import { AbstractFormService, StateResource } from '@alfa-client/tech-shared'; import { AbstractFormService, HttpError, StateResource } from '@alfa-client/tech-shared';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
...@@ -8,12 +8,13 @@ import { isNil } from 'lodash-es'; ...@@ -8,12 +8,13 @@ import { isNil } from 'lodash-es';
@Injectable() @Injectable()
export class PostfachFormService extends AbstractFormService { export class PostfachFormService extends AbstractFormService {
public static readonly NAME_FIELD: string = 'name';
public static readonly ASBSENDER_GROUP: string = 'absender'; public static readonly ASBSENDER_GROUP: string = 'absender';
public static readonly NAME_FIELD: string = 'name';
public static readonly ANSCHRIFT_FIELD: string = 'anschrift'; public static readonly ANSCHRIFT_FIELD: string = 'anschrift';
public static readonly DIENST_FIELD: string = 'dienst'; public static readonly DIENST_FIELD: string = 'dienst';
public static readonly MANDANT_FIELD: string = 'mandant'; public static readonly MANDANT_FIELD: string = 'mandant';
public static readonly GEMEINDESCHLUESSEL_FIELD: string = 'gemeindeschluessel'; public static readonly GEMEINDESCHLUESSEL_FIELD: string = 'gemeindeschluessel';
public static readonly SIGNATUR_FIELD: string = 'signatur'; public static readonly SIGNATUR_FIELD: string = 'signatur';
constructor( constructor(
...@@ -36,7 +37,7 @@ export class PostfachFormService extends AbstractFormService { ...@@ -36,7 +37,7 @@ export class PostfachFormService extends AbstractFormService {
}); });
} }
protected doSubmit(): Observable<StateResource<PostfachResource>> { protected doSubmit(): Observable<StateResource<PostfachResource | HttpError>> {
const value: Postfach = this.getFormValue(); const value: Postfach = this.getFormValue();
if (this.shouldSkipAbsender(value)) { if (this.shouldSkipAbsender(value)) {
delete value.absender; delete value.absender;
...@@ -54,4 +55,8 @@ export class PostfachFormService extends AbstractFormService { ...@@ -54,4 +55,8 @@ export class PostfachFormService extends AbstractFormService {
protected getPathPrefix(): string { protected getPathPrefix(): string {
return 'settingsBody'; return 'settingsBody';
} }
public get invalidEmpty(): boolean {
return this.form.invalid;
}
} }
...@@ -3,7 +3,7 @@ import { PostfachNavigationItemComponent } from './postfach-navigation-item.comp ...@@ -3,7 +3,7 @@ import { PostfachNavigationItemComponent } from './postfach-navigation-item.comp
import { MockComponent } from 'ng-mocks'; import { MockComponent } from 'ng-mocks';
import { NavigationItemComponent } from '@admin-client/admin-settings'; import { NavigationItemComponent } from '@admin-client/admin-settings';
import { getMockComponent } from '@alfa-client/test-utils'; import { getMockComponent } from '@alfa-client/test-utils';
import { SettingsName } from '../../admin-settings.model'; import { SettingName } from '../../admin-settings.model';
describe('PostfachNavigationItemComponent', () => { describe('PostfachNavigationItemComponent', () => {
let component: PostfachNavigationItemComponent; let component: PostfachNavigationItemComponent;
...@@ -31,7 +31,7 @@ describe('PostfachNavigationItemComponent', () => { ...@@ -31,7 +31,7 @@ describe('PostfachNavigationItemComponent', () => {
}); });
it('should be called with name', () => { it('should be called with name', () => {
expect(navigationItemComponent.name).toBe(SettingsName.POSTFACH); expect(navigationItemComponent.name).toBe(SettingName.POSTFACH);
}); });
it('should be called with imageSrc', () => { it('should be called with imageSrc', () => {
......
export enum PostfachLinkRel {
SELF = 'self',
}
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
import { Resource } from '@ngxp/rest'; import { Resource } from '@ngxp/rest';
import { SettingsName } from '../admin-settings.model'; import { SettingName } from '../admin-settings.model';
export interface Absender { export interface Absender {
name: string; name: string;
...@@ -39,11 +39,8 @@ export interface Postfach { ...@@ -39,11 +39,8 @@ export interface Postfach {
} }
export declare type PostfachSettingsItem = { export declare type PostfachSettingsItem = {
name: SettingsName.POSTFACH; name: SettingName.POSTFACH;
settingsBody: Postfach; settingsBody: Postfach;
}; };
export declare type PostfachResource = Resource & PostfachSettingsItem;
export enum PostfachLinkRel { export declare type PostfachResource = Resource & PostfachSettingsItem;
SELF = 'self',
}
import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
import { PostfachLinkRel, PostfachResource } from './postfach.model'; import { PostfachResource } from './postfach.model';
import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository'; import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository';
import { PostfachService } from './postfach.service'; import { PostfachService } from './postfach.service';
import { SettingsService } from '../admin-settings.service'; import { SettingsService } from '../admin-settings.service';
import { import { createPostfachResource, createPostfachSettingItem } from '../../../test/postfach/postfach';
createPostfachResource, import { createStateResource, HttpError, StateResource } from '@alfa-client/tech-shared';
createPostfachSettingsItem,
} from '../../../test/postfach/postfach';
import { createStateResource, StateResource } from '@alfa-client/tech-shared';
import { Observable, of } from 'rxjs'; import { Observable, of } from 'rxjs';
import { ResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model'; import { ResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model';
import { singleCold, singleHot } from 'libs/tech-shared/src/lib/resource/marbles'; import { singleCold, singleHot } from 'libs/tech-shared/src/lib/resource/marbles';
import { PostfachLinkRel } from './postfach.linkrel';
describe('PostfachService', () => { describe('PostfachService', () => {
let service: PostfachService; let service: PostfachService;
...@@ -64,7 +62,7 @@ describe('PostfachService', () => { ...@@ -64,7 +62,7 @@ describe('PostfachService', () => {
}); });
describe('save', () => { describe('save', () => {
const postfachSettingsItem = createPostfachSettingsItem(); const postfachSettingsItem = createPostfachSettingItem();
it('should call resourceService', () => { it('should call resourceService', () => {
service.resourceService.save = jest.fn(); service.resourceService.save = jest.fn();
...@@ -80,7 +78,7 @@ describe('PostfachService', () => { ...@@ -80,7 +78,7 @@ describe('PostfachService', () => {
createStateResource(postfachResource); createStateResource(postfachResource);
service.resourceService.save = jest.fn().mockReturnValue(singleCold(postfachStateResource)); service.resourceService.save = jest.fn().mockReturnValue(singleCold(postfachStateResource));
const savedPostfach: Observable<StateResource<PostfachResource>> = service.save( const savedPostfach: Observable<StateResource<PostfachResource | HttpError>> = service.save(
postfachResource.settingsBody, postfachResource.settingsBody,
); );
......
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository'; import { ResourceRepository } from 'libs/tech-shared/src/lib/resource/resource.repository';
import { import { Postfach, PostfachResource, PostfachSettingsItem } from './postfach.model';
Postfach,
PostfachLinkRel,
PostfachResource,
PostfachSettingsItem,
} from './postfach.model';
import { ResourceService } from 'libs/tech-shared/src/lib/resource/resource.service'; import { ResourceService } from 'libs/tech-shared/src/lib/resource/resource.service';
import { SettingsService } from '../admin-settings.service'; import { SettingsService } from '../admin-settings.service';
import { ResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model'; import { ResourceServiceConfig } from 'libs/tech-shared/src/lib/resource/resource.model';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { StateResource } from '@alfa-client/tech-shared'; import { HttpError, StateResource } from '@alfa-client/tech-shared';
import { SettingsName } from '../admin-settings.model'; import { SettingName } from '../admin-settings.model';
import { PostfachLinkRel } from './postfach.linkrel';
@Injectable() @Injectable()
export class PostfachService { export class PostfachService {
...@@ -33,10 +29,14 @@ export class PostfachService { ...@@ -33,10 +29,14 @@ export class PostfachService {
}; };
} }
public save(postfach: Postfach): Observable<StateResource<PostfachResource>> { public save(postfach: Postfach): Observable<StateResource<PostfachResource | HttpError>> {
return this.resourceService.save({ return this.resourceService.save(this.buildPostfachSettingItem(postfach));
name: SettingsName.POSTFACH, }
private buildPostfachSettingItem(postfach: Postfach): PostfachSettingsItem {
return {
name: SettingName.POSTFACH,
settingsBody: postfach, settingsBody: postfach,
} as PostfachSettingsItem); };
} }
} }
import { Resource } from '@ngxp/rest'; import { Resource } from '@ngxp/rest';
import { import { SettingItemResource, SettingListResource } from '../src/lib/admin-settings.model';
SettingsItemResource,
SettingsListLinkRel,
SettingsListResource,
} from '../src/lib/admin-settings.model';
import { toResource } from '../../tech-shared/test/resource'; import { toResource } from '../../tech-shared/test/resource';
import { SettingListLinkRel } from '../src/lib/admin-settings.linkrel';
export function createSettingsListResource( export function createSettingsListResource(
settingsItems: SettingsItemResource[], settingsItems: SettingItemResource[],
): SettingsListResource { ): SettingListResource {
return toResource({}, [], { return toResource({}, [], {
settings: settingsItems, settings: settingsItems,
}); });
...@@ -17,8 +14,8 @@ export function createSettingsListResource( ...@@ -17,8 +14,8 @@ export function createSettingsListResource(
export function createFilledSettingsListResource( export function createFilledSettingsListResource(
resources: Resource[], resources: Resource[],
linkRelations: string[] = [], linkRelations: string[] = [],
): SettingsListResource { ): SettingListResource {
return toResource({}, [...linkRelations], { return toResource({}, [...linkRelations], {
[SettingsListLinkRel.LIST]: resources, [SettingListLinkRel.LIST]: resources,
}); });
} }
import { ConfigurationResource } from '../../src/lib/configuration/configuration.model'; import { ConfigurationResource } from '../../src/lib/configuration/configuration.model';
import { toResource } from '../../../tech-shared/test/resource'; import { toResource } from '../../../tech-shared/test/resource';
import { ConfigurationLinkRel } from '../../src/lib/configuration/configuration.linkrel';
export function createConfigurationResource(): ConfigurationResource { export function createConfigurationResource(): ConfigurationResource {
return toResource({}, ['settings']); return toResource({}, [ConfigurationLinkRel.SETTING]);
} }
...@@ -4,7 +4,7 @@ import { ...@@ -4,7 +4,7 @@ import {
PostfachSettingsItem, PostfachSettingsItem,
} from '../../src/lib/postfach/postfach.model'; } from '../../src/lib/postfach/postfach.model';
import { toResource } from '../../../tech-shared/test/resource'; import { toResource } from '../../../tech-shared/test/resource';
import { SettingsItemResource, SettingsName } from '../../src/lib/admin-settings.model'; import { SettingItemResource, SettingName } from '../../src/lib/admin-settings.model';
import faker from '@faker-js/faker'; import faker from '@faker-js/faker';
export function createPostfach(): Postfach { export function createPostfach(): Postfach {
...@@ -20,20 +20,20 @@ export function createPostfach(): Postfach { ...@@ -20,20 +20,20 @@ export function createPostfach(): Postfach {
}; };
} }
export function createPostfachSettingsItem(): PostfachSettingsItem { export function createPostfachSettingItem(): PostfachSettingsItem {
return { return {
name: SettingsName.POSTFACH, name: SettingName.POSTFACH,
settingsBody: createPostfach(), settingsBody: createPostfach(),
}; };
} }
export function createPostfachResource(): PostfachResource { export function createPostfachResource(): PostfachResource {
return toResource(createPostfachSettingsItem()); return toResource(createPostfachSettingItem());
} }
export function createEmptyResource(): SettingsItemResource { export function createSettingItemResource(): SettingItemResource {
return toResource({ return toResource({
name: 'Empty', name: faker.random.word(),
settingsBody: {}, settingsBody: {},
}); });
} }
import { Mock, mock, useFromMock } from '@alfa-client/test-utils'; import { Mock, mock, useFromMock } from '@alfa-client/test-utils';
import { Observable, of } from 'rxjs'; import { Observable, lastValueFrom, of, throwError } from 'rxjs';
import { ResourceService } from './resource.service'; import { ResourceService } from './resource.service';
import { ResourceRepository } from './resource.repository'; import { ResourceRepository } from './resource.repository';
import { LinkRelationName, ResourceServiceConfig, SaveResourceData } from './resource.model'; import { LinkRelationName, ResourceServiceConfig, SaveResourceData } from './resource.model';
import { Resource, ResourceUri, getUrl } from '@ngxp/rest'; import { Resource, ResourceUri, getUrl } from '@ngxp/rest';
import { createDummyResource } from 'libs/tech-shared/test/resource'; import { createDummyResource } from 'libs/tech-shared/test/resource';
import { StateResource, createEmptyStateResource, createStateResource } from './resource.util'; import {
StateResource,
createEmptyStateResource,
createErrorStateResource,
createStateResource,
} from './resource.util';
import { fakeAsync, tick } from '@angular/core/testing'; import { fakeAsync, tick } from '@angular/core/testing';
import { singleCold, singleHot } from './marbles'; import { singleCold, singleHot } from './marbles';
import faker from '@faker-js/faker'; import faker from '@faker-js/faker';
import { HttpErrorResponse } from '@angular/common/http';
import { createProblemDetail } from 'libs/tech-shared/test/error';
import { HttpError, ProblemDetail } from '../tech.model';
describe('ResourceService', () => { describe('ResourceService', () => {
let service: ResourceService<Resource, Resource>; let service: ResourceService<Resource, Resource>;
...@@ -126,10 +134,46 @@ describe('ResourceService', () => { ...@@ -126,10 +134,46 @@ describe('ResourceService', () => {
service.resource.next(createStateResource(createDummyResource([config.editLinkRel]))); service.resource.next(createStateResource(createDummyResource([config.editLinkRel])));
repository.save.mockReturnValue(singleHot(loadedResource)); repository.save.mockReturnValue(singleHot(loadedResource));
const saved: Observable<StateResource<Resource>> = service.save(dummyToSave); const saved: Observable<StateResource<Resource | HttpError>> = service.save(dummyToSave);
expect(saved).toBeObservable(singleCold(createStateResource(loadedResource))); expect(saved).toBeObservable(singleCold(createStateResource(loadedResource)));
}); });
it('should call handleError', () => {
service.resource.next(createStateResource(createDummyResource([config.editLinkRel])));
const errorResponse: ProblemDetail = createProblemDetail();
repository.save.mockReturnValue(throwError(() => errorResponse));
service.handleError = jest.fn();
service.save(<any>{}).subscribe();
expect(service.handleError).toHaveBeenCalledWith(errorResponse);
});
});
describe('handleError', () => {
it('should return error stateresource on problem unprocessable entity', (done) => {
const error: ProblemDetail = createProblemDetail();
service
.handleError(<HttpErrorResponse>(<any>error))
.subscribe((responseError: StateResource<HttpError>) => {
expect(responseError).toEqual(createErrorStateResource(error));
done();
});
});
it('should rethrow error', () => {
const error: HttpErrorResponse = <HttpErrorResponse>{
status: 500,
statusText: 'Internal Server Error',
};
const thrownError$: Observable<StateResource<HttpError>> = service.handleError(error);
expect.assertions(1);
expect(lastValueFrom(thrownError$)).rejects.toThrowError('Internal Server Error');
});
}); });
describe('refresh', () => { describe('refresh', () => {
......
import { BehaviorSubject, Observable, first, map, mergeMap, of } from 'rxjs'; import {
BehaviorSubject,
Observable,
catchError,
first,
map,
mergeMap,
of,
throwError,
} from 'rxjs';
import { ResourceServiceConfig } from './resource.model'; import { ResourceServiceConfig } from './resource.model';
import { StateResource, createEmptyStateResource, createStateResource } from './resource.util'; import {
StateResource,
createEmptyStateResource,
createErrorStateResource,
createStateResource,
} from './resource.util';
import { Resource, ResourceUri, getUrl, hasLink } from '@ngxp/rest'; import { Resource, ResourceUri, getUrl, hasLink } from '@ngxp/rest';
import { ResourceRepository } from './resource.repository'; import { ResourceRepository } from './resource.repository';
import { isNull } from 'lodash-es'; import { isNull } from 'lodash-es';
import { isNotNull } from '../tech.util'; import { isNotNull } from '../tech.util';
import { HttpErrorResponse } from '@angular/common/http';
import { isUnprocessableEntity } from '../http.util';
import { HttpError, ProblemDetail } from '../tech.model';
/** /**
* B = Type of baseresource * B = Type of baseresource
...@@ -42,13 +59,14 @@ export class ResourceService<B extends Resource, T extends Resource> { ...@@ -42,13 +59,14 @@ export class ResourceService<B extends Resource, T extends Resource> {
this.throwErrorOn(!hasLink(baseResource, this.config.getLinkRel), 'No get link exists.'); this.throwErrorOn(!hasLink(baseResource, this.config.getLinkRel), 'No get link exists.');
} }
public save(toSave: unknown): Observable<StateResource<T>> { public save(toSave: unknown): Observable<StateResource<T | HttpError>> {
this.verifyEditLinkRel(); this.verifyEditLinkRel();
return this.resource.asObservable().pipe( return this.resource.asObservable().pipe(
mergeMap((selectedResource: StateResource<T>) => mergeMap((selectedResource: StateResource<T>) =>
this.doSave(selectedResource.resource, toSave), this.doSave(selectedResource.resource, toSave),
), ),
map((loadedResource: T) => createStateResource(loadedResource)), map((loadedResource: T) => createStateResource(loadedResource)),
catchError((errorResponse: HttpErrorResponse) => this.handleError(errorResponse)),
); );
} }
...@@ -68,6 +86,13 @@ export class ResourceService<B extends Resource, T extends Resource> { ...@@ -68,6 +86,13 @@ export class ResourceService<B extends Resource, T extends Resource> {
}); });
} }
handleError(errorResponse: HttpErrorResponse): Observable<StateResource<HttpError>> {
if (isUnprocessableEntity(errorResponse.status)) {
return of(createErrorStateResource((<any>errorResponse) as ProblemDetail));
}
return throwError(() => errorResponse);
}
public canEdit(): boolean { public canEdit(): boolean {
return this.hasLinkRel(this.config.editLinkRel); return this.hasLinkRel(this.config.editLinkRel);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment