From 2493ca400fa1a20fdb07d36f80dd33824d09af7f Mon Sep 17 00:00:00 2001 From: Sebastian Date: Sat, 4 May 2019 22:35:45 +0200 Subject: [PATCH] Move business logic from service to states. --- .../app/shared/services/apps.service.spec.ts | 14 ++++-- .../app/shared/services/apps.service.ts | 27 ++++------ .../app/shared/services/rules.service.spec.ts | 34 +++++-------- .../app/shared/services/rules.service.ts | 38 +++++--------- .../shared/services/schemas.service.spec.ts | 27 +++++----- .../app/shared/services/schemas.service.ts | 49 ++++++------------- src/Squidex/app/shared/state/_test-helpers.ts | 3 -- .../app/shared/state/apps.state.spec.ts | 12 ++--- src/Squidex/app/shared/state/apps.state.ts | 22 ++++++++- .../shared/state/asset-uploader.state.spec.ts | 26 +++++----- .../app/shared/state/comments.state.spec.ts | 30 ++++++------ .../shared/state/contributors.state.spec.ts | 6 +-- .../app/shared/state/rules.state.spec.ts | 10 ++-- src/Squidex/app/shared/state/rules.state.ts | 39 ++++++++++++--- .../app/shared/state/schemas.state.spec.ts | 17 +++---- src/Squidex/app/shared/state/schemas.state.ts | 29 +++++++++-- src/Squidex/package-lock.json | 24 ++++----- src/Squidex/package.json | 8 +-- src/Squidex/tslint.json | 4 +- 19 files changed, 217 insertions(+), 202 deletions(-) diff --git a/src/Squidex/app/shared/services/apps.service.spec.ts b/src/Squidex/app/shared/services/apps.service.spec.ts index 75f064593..65d86a946 100644 --- a/src/Squidex/app/shared/services/apps.service.spec.ts +++ b/src/Squidex/app/shared/services/apps.service.spec.ts @@ -11,6 +11,7 @@ import { inject, TestBed } from '@angular/core/testing'; import { AnalyticsService, ApiUrlConfig, + AppCreatedDto, AppDto, AppsService, DateTime, @@ -18,8 +19,6 @@ import { } from '@app/shared/internal'; describe('AppsService', () => { - const now = DateTime.now(); - beforeEach(() => { TestBed.configureTestingModule({ imports: [ @@ -84,9 +83,9 @@ describe('AppsService', () => { const dto = { name: 'new-app' }; - let app: AppDto; + let app: AppCreatedDto; - appsService.postApp(dto, now).subscribe(result => { + appsService.postApp(dto).subscribe(result => { app = result; }); @@ -102,7 +101,12 @@ describe('AppsService', () => { planUpgrade: 'Enterprise' }); - expect(app!).toEqual(new AppDto('123', dto.name, [new Permission('Reader')], now, now, 'Basic', 'Enterprise')); + expect(app!).toEqual({ + id: '123', + permissions: ['Reader'], + planName: 'Basic', + planUpgrade: 'Enterprise' + }); })); it('should make delete request to archive app', diff --git a/src/Squidex/app/shared/services/apps.service.ts b/src/Squidex/app/shared/services/apps.service.ts index 382a14eeb..c80d71dc4 100644 --- a/src/Squidex/app/shared/services/apps.service.ts +++ b/src/Squidex/app/shared/services/apps.service.ts @@ -38,6 +38,13 @@ export interface CreateAppDto { readonly template?: string; } +export interface AppCreatedDto { + readonly id: string; + readonly permissions: string[]; + readonly planName?: string; + readonly planUpgrade?: string; +} + @Injectable() export class AppsService { constructor( @@ -70,26 +77,10 @@ export class AppsService { pretifyError('Failed to load apps. Please reload.')); } - public postApp(dto: CreateAppDto, now?: DateTime): Observable { + public postApp(dto: CreateAppDto): Observable { const url = this.apiUrl.buildUrl('api/apps'); - return this.http.post(url, dto).pipe( - map(body => { - now = now || DateTime.now(); - - const permissions = (body.permissions).map(x => new Permission(x)); - - const app = new AppDto( - body.id, - dto.name, - permissions, - now, - now, - body.planName, - body.planUpgrade); - - return app; - }), + return this.http.post(url, dto).pipe( tap(() => { this.analytics.trackEvent('App', 'Created', dto.name); }), diff --git a/src/Squidex/app/shared/services/rules.service.spec.ts b/src/Squidex/app/shared/services/rules.service.spec.ts index 955954bb4..7cc53c635 100644 --- a/src/Squidex/app/shared/services/rules.service.spec.ts +++ b/src/Squidex/app/shared/services/rules.service.spec.ts @@ -19,12 +19,12 @@ import { RuleEventDto, RuleEventsDto, RulesService, - Version + Version, + Versioned } from '@app/shared/internal'; +import { RuleCreatedDto } from './rules.service'; describe('RulesService', () => { - const now = DateTime.now(); - const user = 'me'; const version = new Version('1'); beforeEach(() => { @@ -179,9 +179,9 @@ describe('RulesService', () => { } }; - let rule: RuleDto; + let rule: Versioned; - rulesService.postRule('my-app', dto, user, now).subscribe(result => { + rulesService.postRule('my-app', dto).subscribe(result => { rule = result; }); @@ -190,28 +190,18 @@ describe('RulesService', () => { expect(req.request.method).toEqual('POST'); expect(req.request.headers.get('If-Match')).toBeNull(); - req.flush({ id: 'id1', sharedSecret: 'token1', schemaId: 'schema1' }, { + req.flush({ id: 'id1' }, { headers: { etag: '1' } }); - expect(rule!).toEqual( - new RuleDto('id1', user, user, now, now, - version, - true, - { - param1: 1, - param2: 2, - triggerType: 'ContentChanged' - }, - 'ContentChanged', - { - param3: 3, - param4: 4, - actionType: 'Webhook' - }, - 'Webhook')); + expect(rule!).toEqual({ + payload: { + id: 'id1' + }, + version + }); })); it('should make put request to update rule', diff --git a/src/Squidex/app/shared/services/rules.service.ts b/src/Squidex/app/shared/services/rules.service.ts index 820f3152b..7af1acfb7 100644 --- a/src/Squidex/app/shared/services/rules.service.ts +++ b/src/Squidex/app/shared/services/rules.service.ts @@ -15,6 +15,7 @@ import { ApiUrlConfig, DateTime, HTTP, + mapVersioned, Model, pretifyError, ResultSet, @@ -109,16 +110,18 @@ export class RuleEventDto extends Model { } } -export interface CreateRuleDto { - readonly trigger: any; - readonly action: any; +export interface UpsertRuleDto { + readonly trigger: RuleAction; + readonly action: RuleAction; } -export interface UpdateRuleDto { - readonly trigger?: any; - readonly action?: any; +export interface RuleCreatedDto { + readonly id: string; } +export type RuleAction = { actionType: string } & any; +export type RuleTrigger = { triggerType: string } & any; + @Injectable() export class RulesService { constructor( @@ -190,33 +193,18 @@ export class RulesService { pretifyError('Failed to load Rules. Please reload.')); } - public postRule(appName: string, dto: CreateRuleDto, user: string, now: DateTime): Observable { + public postRule(appName: string, dto: UpsertRuleDto): Observable> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/rules`); - return HTTP.postVersioned(this.http, url, dto).pipe( - map(({ version, payload }) => { - const body = payload.body; - - return new RuleDto( - body.id, - user, - user, - now, - now, - version, - true, - dto.trigger, - dto.trigger.triggerType, - dto.action, - dto.action.actionType); - }), + return HTTP.postVersioned(this.http, url, dto).pipe( + mapVersioned(({ body }) => body!), tap(() => { this.analytics.trackEvent('Rule', 'Created', appName); }), pretifyError('Failed to create rule. Please reload.')); } - public putRule(appName: string, id: string, dto: UpdateRuleDto, version: Version): Observable> { + public putRule(appName: string, id: string, dto: Partial, version: Version): Observable> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/rules/${id}`); return HTTP.putVersioned(this.http, url, dto, version).pipe( diff --git a/src/Squidex/app/shared/services/schemas.service.spec.ts b/src/Squidex/app/shared/services/schemas.service.spec.ts index c0405c407..21e69270d 100644 --- a/src/Squidex/app/shared/services/schemas.service.spec.ts +++ b/src/Squidex/app/shared/services/schemas.service.spec.ts @@ -9,11 +9,9 @@ import { HttpClientTestingModule, HttpTestingController } from '@angular/common/ import { inject, TestBed } from '@angular/core/testing'; import { - AddFieldDto, AnalyticsService, ApiUrlConfig, createProperties, - CreateSchemaDto, DateTime, FieldDto, NestedFieldDto, @@ -22,12 +20,12 @@ import { SchemaDto, SchemaPropertiesDto, SchemasService, - Version + Version, + Versioned } from '@app/shared/internal'; +import { SchemaCreatedDto } from './schemas.service'; describe('SchemasService', () => { - const now = DateTime.now(); - const user = 'me'; const version = new Version('1'); beforeEach(() => { @@ -330,11 +328,11 @@ describe('SchemasService', () => { it('should make post request to create schema', inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => { - const dto = new CreateSchemaDto('name', undefined, undefined, true); + const dto = { name: 'name' }; - let schema: SchemaDetailsDto; + let schema: Versioned; - schemasService.postSchema('my-app', dto, user, now).subscribe(result => { + schemasService.postSchema('my-app', dto).subscribe(result => { schema = result; }); @@ -347,11 +345,16 @@ describe('SchemasService', () => { id: '1' }, { headers: { - etag: '2' + etag: '1' } }); - expect(schema!).toEqual(new SchemaDetailsDto('1', dto.name, '', new SchemaPropertiesDto(), true, false, now, user, now, user, new Version('2'), [], {}, {})); + expect(schema!).toEqual({ + payload: { + id: '1' + }, + version + }); })); it('should make put request to update schema', @@ -417,7 +420,7 @@ describe('SchemasService', () => { it('should make post request to add field', inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => { - const dto = new AddFieldDto('name', 'invariant', createProperties('Number')); + const dto = { name: 'name', partitioning: 'invariant', properties: createProperties('Number') }; let field: FieldDto; @@ -464,7 +467,7 @@ describe('SchemasService', () => { it('should make post request to add nested field', inject([SchemasService, HttpTestingController], (schemasService: SchemasService, httpMock: HttpTestingController) => { - const dto = new AddFieldDto('name', 'invariant', createProperties('Number')); + const dto = { name: 'name', partitioning: 'invariant', properties: createProperties('Number') }; let field: FieldDto; diff --git a/src/Squidex/app/shared/services/schemas.service.ts b/src/Squidex/app/shared/services/schemas.service.ts index b3da2159d..f8b08abda 100644 --- a/src/Squidex/app/shared/services/schemas.service.ts +++ b/src/Squidex/app/shared/services/schemas.service.ts @@ -171,23 +171,21 @@ export class SchemaPropertiesDto { } } -export class AddFieldDto { - constructor( - public readonly name: string, - public readonly partitioning: string, - public readonly properties: FieldPropertiesDto - ) { - } +export interface AddFieldDto { + readonly name: string; + readonly partitioning: string; + readonly properties: FieldPropertiesDto; } -export class CreateSchemaDto { - constructor( - public readonly name: string, - public readonly fields?: RootFieldDto[], - public readonly properties?: SchemaPropertiesDto, - public readonly isSingleton?: boolean - ) { - } +export interface CreateSchemaDto { + readonly name: string; + readonly fields?: RootFieldDto[]; + readonly properties?: SchemaPropertiesDto; + readonly isSingleton?: boolean; +} + +export interface SchemaCreatedDto { + readonly id: string; } export interface UpdateSchemaCategoryDto { @@ -303,28 +301,11 @@ export class SchemasService { pretifyError('Failed to load schema. Please reload.')); } - public postSchema(appName: string, dto: CreateSchemaDto, user: string, now: DateTime): Observable { + public postSchema(appName: string, dto: CreateSchemaDto): Observable> { const url = this.apiUrl.buildUrl(`api/apps/${appName}/schemas`); return HTTP.postVersioned(this.http, url, dto).pipe( - map(({ version, payload }) => { - const body = payload.body; - - now = now || DateTime.now(); - - const schema = new SchemaDetailsDto( - body.id, - dto.name, '', - dto.properties || new SchemaPropertiesDto(), - dto.isSingleton === true, - false, - now, user, - now, user, - version, - dto.fields || []); - - return schema; - }), + mapVersioned(({ body }) => body!), tap(() => { this.analytics.trackEvent('Schema', 'Created', appName); }), diff --git a/src/Squidex/app/shared/state/_test-helpers.ts b/src/Squidex/app/shared/state/_test-helpers.ts index 69d6e55ce..d6a1c8f62 100644 --- a/src/Squidex/app/shared/state/_test-helpers.ts +++ b/src/Squidex/app/shared/state/_test-helpers.ts @@ -20,7 +20,6 @@ const creation = DateTime.today().addDays(-2); const creator = 'me'; const modified = DateTime.now().addDays(-1); const modifier = 'now-me'; -const now = DateTime.now(); const version = new Version('1'); const newVersion = new Version('2'); @@ -45,8 +44,6 @@ export const TestValues = { creator, modified, modifier, - now, newVersion, - userId: modifier, version }; \ No newline at end of file diff --git a/src/Squidex/app/shared/state/apps.state.spec.ts b/src/Squidex/app/shared/state/apps.state.spec.ts index c963063cc..aedec3170 100644 --- a/src/Squidex/app/shared/state/apps.state.spec.ts +++ b/src/Squidex/app/shared/state/apps.state.spec.ts @@ -88,9 +88,9 @@ describe('AppsState', () => { const request = { ...newApp }; appsService.setup(x => x.postApp(request)) - .returns(() => of(newApp)).verifiable(); + .returns(() => of({ ...newApp, permissions: ['Owner'] })).verifiable(); - appsState.create(request).subscribe(); + appsState.create(request, now).subscribe(); expect(appsState.snapshot.apps.values).toEqual([newApp, ...oldApps]); }); @@ -99,12 +99,12 @@ describe('AppsState', () => { const request = { ...newApp }; appsService.setup(x => x.postApp(request)) - .returns(() => of(newApp)).verifiable(); + .returns(() => of({ ...newApp, permissions: ['Owner'] })).verifiable(); appsService.setup(x => x.deleteApp(newApp.name)) .returns(() => of({})).verifiable(); - appsState.create(request).subscribe(); + appsState.create(request, now).subscribe(); const appsAfterCreate = appsState.snapshot.apps.values; @@ -120,12 +120,12 @@ describe('AppsState', () => { const request = { ...newApp }; appsService.setup(x => x.postApp(request)) - .returns(() => of(newApp)).verifiable(); + .returns(() => of({ ...newApp, permissions: ['Owner'] })).verifiable(); appsService.setup(x => x.deleteApp(newApp.name)) .returns(() => of({})).verifiable(); - appsState.create(request).subscribe(); + appsState.create(request, now).subscribe(); appsState.select(newApp.name).subscribe(); appsState.delete(newApp.name).subscribe(); diff --git a/src/Squidex/app/shared/state/apps.state.ts b/src/Squidex/app/shared/state/apps.state.ts index 2a97377cd..c3bf22d0a 100644 --- a/src/Squidex/app/shared/state/apps.state.ts +++ b/src/Squidex/app/shared/state/apps.state.ts @@ -10,13 +10,16 @@ import { Observable, of } from 'rxjs'; import { distinctUntilChanged, map, tap } from 'rxjs/operators'; import { + DateTime, DialogService, ImmutableArray, + Permission, shareSubscribed, State } from '@app/framework'; import { + AppCreatedDto, AppDto, AppsService, CreateAppDto @@ -79,11 +82,11 @@ export class AppsState extends State { shareSubscribed(this.dialogs)); } - public create(request: CreateAppDto): Observable { + public create(request: CreateAppDto, now?: DateTime): Observable { return this.appsService.postApp(request).pipe( tap(payload => { this.next(s => { - const apps = s.apps.push(payload).sortByStringAsc(x => x.name); + const apps = s.apps.push(createApp(request, payload, now)).sortByStringAsc(x => x.name); return { ...s, apps }; }); @@ -104,4 +107,19 @@ export class AppsState extends State { }), shareSubscribed(this.dialogs)); } +} + +function createApp(request: CreateAppDto, response: AppCreatedDto, now?: DateTime) { + now = now || DateTime.now(); + + const app = new AppDto( + response.id, + request.name, + response.permissions.map(x => new Permission(x)), + now, + now, + response.planName, + response.planUpgrade); + + return app; } \ No newline at end of file diff --git a/src/Squidex/app/shared/state/asset-uploader.state.spec.ts b/src/Squidex/app/shared/state/asset-uploader.state.spec.ts index 28215cf43..0a184eb31 100644 --- a/src/Squidex/app/shared/state/asset-uploader.state.spec.ts +++ b/src/Squidex/app/shared/state/asset-uploader.state.spec.ts @@ -31,9 +31,7 @@ describe('AssetsState', () => { creator, creation, modified, - modifier, - now, - userId + modifier } = TestValues; let assetsService: IMock; @@ -74,10 +72,10 @@ describe('AssetsState', () => { it('should create initial state when uploading file', () => { const file: File = { name: 'my-file' }; - assetsService.setup(x => x.uploadFile(app, file, userId, now)) + assetsService.setup(x => x.uploadFile(app, file, modifier, modified)) .returns(() => never()).verifiable(); - assetUploader.uploadFile(file, undefined, now).subscribe(); + assetUploader.uploadFile(file, undefined, modified).subscribe(); const upload = assetUploader.snapshot.uploads.at(0); @@ -88,10 +86,10 @@ describe('AssetsState', () => { it('should update progress when uploading file makes progress', () => { const file: File = { name: 'my-file' }; - assetsService.setup(x => x.uploadFile(app, file, userId, now)) + assetsService.setup(x => x.uploadFile(app, file, modifier, modified)) .returns(() => ofForever(10, 20)).verifiable(); - assetUploader.uploadFile(file, undefined, now).subscribe(); + assetUploader.uploadFile(file, undefined, modified).subscribe(); const upload = assetUploader.snapshot.uploads.at(0); @@ -102,10 +100,10 @@ describe('AssetsState', () => { it('should update status when uploading file failed', () => { const file: File = { name: 'my-file' }; - assetsService.setup(x => x.uploadFile(app, file, userId, now)) + assetsService.setup(x => x.uploadFile(app, file, modifier, modified)) .returns(() => throwError('Error')).verifiable(); - assetUploader.uploadFile(file, undefined, now).pipe(onErrorResumeNext()).subscribe(); + assetUploader.uploadFile(file, undefined, modified).pipe(onErrorResumeNext()).subscribe(); const upload = assetUploader.snapshot.uploads.at(0); @@ -116,12 +114,12 @@ describe('AssetsState', () => { it('should update status when uploading file completes', (cb) => { const file: File = { name: 'my-file' }; - assetsService.setup(x => x.uploadFile(app, file, userId, now)) + assetsService.setup(x => x.uploadFile(app, file, modifier, modified)) .returns(() => of(10, 20, asset)).verifiable(); let uploadedAsset: AssetDto; - assetUploader.uploadFile(file, undefined, now).subscribe(dto => { + assetUploader.uploadFile(file, undefined, modified).subscribe(dto => { if (Types.is(dto, AssetDto)) { uploadedAsset = dto; } @@ -142,7 +140,7 @@ describe('AssetsState', () => { assetsService.setup(x => x.replaceFile(app, asset.id, file, asset.version)) .returns(() => never()).verifiable(); - assetUploader.uploadAsset(asset, file, now).subscribe(); + assetUploader.uploadAsset(asset, file, modified).subscribe(); const upload = assetUploader.snapshot.uploads.at(0); @@ -156,7 +154,7 @@ describe('AssetsState', () => { assetsService.setup(x => x.replaceFile(app, asset.id, file, asset.version)) .returns(() => ofForever(10, 20)).verifiable(); - assetUploader.uploadAsset(asset, file, now).subscribe(); + assetUploader.uploadAsset(asset, file, modified).subscribe(); const upload = assetUploader.snapshot.uploads.at(0); @@ -170,7 +168,7 @@ describe('AssetsState', () => { assetsService.setup(x => x.replaceFile(app, asset.id, file, asset.version)) .returns(() => throwError('Error')).verifiable(); - assetUploader.uploadAsset(asset, file, now).pipe(onErrorResumeNext()).subscribe(); + assetUploader.uploadAsset(asset, file, modified).pipe(onErrorResumeNext()).subscribe(); const upload = assetUploader.snapshot.uploads.at(0); diff --git a/src/Squidex/app/shared/state/comments.state.spec.ts b/src/Squidex/app/shared/state/comments.state.spec.ts index 54fdf9e3e..05169f4e3 100644 --- a/src/Squidex/app/shared/state/comments.state.spec.ts +++ b/src/Squidex/app/shared/state/comments.state.spec.ts @@ -25,14 +25,14 @@ describe('CommentsState', () => { app, appsState, creator, - now + modified } = TestValues; const commentsId = 'my-comments'; const oldComments = new CommentsDto([ - new CommentDto('1', now, 'text1', creator), - new CommentDto('2', now, 'text2', creator) + new CommentDto('1', modified, 'text1', creator), + new CommentDto('2', modified, 'text2', creator) ], [], [], new Version('1')); let dialogs: IMock; @@ -53,9 +53,9 @@ describe('CommentsState', () => { describe('Loading', () => { it('should load and merge comments', () => { const newComments = new CommentsDto([ - new CommentDto('3', now, 'text3', creator) + new CommentDto('3', modified, 'text3', creator) ], [ - new CommentDto('2', now, 'text2_2', creator) + new CommentDto('2', modified, 'text2_2', creator) ], ['1'], new Version('2')); commentsService.setup(x => x.getComments(app, commentsId, new Version('-1'))) @@ -69,8 +69,8 @@ describe('CommentsState', () => { expect(commentsState.snapshot.isLoaded).toBeTruthy(); expect(commentsState.snapshot.comments).toEqual(ImmutableArray.of([ - new CommentDto('2', now, 'text2_2', creator), - new CommentDto('3', now, 'text3', creator) + new CommentDto('2', modified, 'text2_2', creator), + new CommentDto('3', modified, 'text3', creator) ])); }); }); @@ -84,7 +84,7 @@ describe('CommentsState', () => { }); it('should add comment to snapshot when created', () => { - const newComment = new CommentDto('3', now, 'text3', creator); + const newComment = new CommentDto('3', modified, 'text3', creator); const request = { text: 'text3' }; @@ -94,9 +94,9 @@ describe('CommentsState', () => { commentsState.create('text3').subscribe(); expect(commentsState.snapshot.comments).toEqual(ImmutableArray.of([ - new CommentDto('1', now, 'text1', creator), - new CommentDto('2', now, 'text2', creator), - new CommentDto('3', now, 'text3', creator) + new CommentDto('1', modified, 'text1', creator), + new CommentDto('2', modified, 'text2', creator), + new CommentDto('3', modified, 'text3', creator) ])); }); @@ -106,11 +106,11 @@ describe('CommentsState', () => { commentsService.setup(x => x.putComment(app, commentsId, '2', request)) .returns(() => of({})).verifiable(); - commentsState.update(oldComments.createdComments[1], 'text2_2', now).subscribe(); + commentsState.update(oldComments.createdComments[1], 'text2_2', modified).subscribe(); expect(commentsState.snapshot.comments).toEqual(ImmutableArray.of([ - new CommentDto('1', now, 'text1', creator), - new CommentDto('2', now, 'text2_2', creator) + new CommentDto('1', modified, 'text1', creator), + new CommentDto('2', modified, 'text2_2', creator) ])); }); @@ -121,7 +121,7 @@ describe('CommentsState', () => { commentsState.delete(oldComments.createdComments[1]).subscribe(); expect(commentsState.snapshot.comments).toEqual(ImmutableArray.of([ - new CommentDto('1', now, 'text1', creator) + new CommentDto('1', modified, 'text1', creator) ])); }); }); diff --git a/src/Squidex/app/shared/state/contributors.state.spec.ts b/src/Squidex/app/shared/state/contributors.state.spec.ts index d7e85a301..f103f4bad 100644 --- a/src/Squidex/app/shared/state/contributors.state.spec.ts +++ b/src/Squidex/app/shared/state/contributors.state.spec.ts @@ -23,14 +23,14 @@ describe('ContributorsState', () => { app, appsState, authService, + modifier, newVersion, - userId, version } = TestValues; const oldContributors = [ new ContributorDto('id1', 'Developer'), - new ContributorDto(userId, 'Developer') + new ContributorDto(modifier, 'Developer') ]; let dialogs: IMock; @@ -109,7 +109,7 @@ describe('ContributorsState', () => { }); it('should update contributor in snapshot when assigned and already added', () => { - const newContributor = new ContributorDto(userId, 'Owner'); + const newContributor = new ContributorDto(modifier, 'Owner'); const request = { ...newContributor }; const response = { contributorId: newContributor.contributorId, isCreated: true }; diff --git a/src/Squidex/app/shared/state/rules.state.spec.ts b/src/Squidex/app/shared/state/rules.state.spec.ts index c296c968b..6b8a8cdd5 100644 --- a/src/Squidex/app/shared/state/rules.state.spec.ts +++ b/src/Squidex/app/shared/state/rules.state.spec.ts @@ -87,14 +87,14 @@ describe('RulesState', () => { }); it('should add rule to snapshot when created', () => { - const newRule = new RuleDto('id3', creator, creator, creation, creation, version, false, {}, 'trigger3', {}, 'action3'); + const newRule = new RuleDto('id3', modifier, modifier, modified, modified, version, true, { value: 3 }, 'trigger3', { value: 1 }, 'action3'); - const request = { action: {}, trigger: {} }; + const request = { trigger: { triggerType: 'trigger3', value: 3 }, action: { actionType: 'action3', value: 1 } }; - rulesService.setup(x => x.postRule(app, request, modifier, creation)) - .returns(() => of(newRule)); + rulesService.setup(x => x.postRule(app, request)) + .returns(() => of(versioned(version, { id: 'id3' }))); - rulesState.create(request, creation).subscribe(); + rulesState.create(request, modified).subscribe(); expect(rulesState.snapshot.rules.values).toEqual([...oldRules, newRule]); }); diff --git a/src/Squidex/app/shared/state/rules.state.ts b/src/Squidex/app/shared/state/rules.state.ts index e75b71f6c..d01cb1233 100644 --- a/src/Squidex/app/shared/state/rules.state.ts +++ b/src/Squidex/app/shared/state/rules.state.ts @@ -15,16 +15,18 @@ import { ImmutableArray, shareSubscribed, State, - Version + Version, + Versioned } from '@app/framework'; import { AuthService} from './../services/auth.service'; import { AppsState } from './apps.state'; import { - CreateRuleDto, + RuleCreatedDto, RuleDto, - RulesService + RulesService, + UpsertRuleDto } from './../services/rules.service'; interface Snapshot { @@ -76,11 +78,11 @@ export class RulesState extends State { shareSubscribed(this.dialogs)); } - public create(request: CreateRuleDto, now?: DateTime): Observable { - return this.rulesService.postRule(this.appName, request, this.user, now || DateTime.now()).pipe( - tap(rule => { + public create(request: UpsertRuleDto, now?: DateTime): Observable { + return this.rulesService.postRule(this.appName, request).pipe( + tap(response => { this.next(s => { - const rules = s.rules.push(rule); + const rules = s.rules.push(createRule(request, response, this.user, now)); return { ...s, rules }; }); @@ -178,3 +180,26 @@ const setEnabled = (rule: RuleDto, isEnabled: boolean, user: string, version: Ve lastModifiedBy: user, version }); + +function createRule(request: UpsertRuleDto, { payload, version }: Versioned, user: string, now?: DateTime) { + now = now || DateTime.now(); + + const { triggerType, ...trigger } = request.trigger; + + const { actionType, ...action } = request.action; + + const rule = new RuleDto( + payload.id, + user, + user, + now, + now, + version, + true, + trigger, + triggerType, + action, + actionType); + + return rule; +} \ No newline at end of file diff --git a/src/Squidex/app/shared/state/schemas.state.spec.ts b/src/Squidex/app/shared/state/schemas.state.spec.ts index 7d5229824..5b084eab0 100644 --- a/src/Squidex/app/shared/state/schemas.state.spec.ts +++ b/src/Squidex/app/shared/state/schemas.state.spec.ts @@ -11,14 +11,13 @@ import { IMock, It, Mock, Times } from 'typemoq'; import { SchemasState } from './schemas.state'; import { - AddFieldDto, createProperties, - CreateSchemaDto, DialogService, NestedFieldDto, RootFieldDto, SchemaDetailsDto, SchemaDto, + SchemaPropertiesDto, SchemasService, UpdateSchemaCategoryDto, versioned @@ -298,17 +297,17 @@ describe('SchemasState', () => { }); it('should add schema to snapshot when created', () => { - const request = new CreateSchemaDto('newName'); + const request = { name: 'newName' }; - const result = new SchemaDetailsDto('id4', 'newName', '', {}, false, false, modified, modifier, modified, modifier, version); + const result = new SchemaDetailsDto('id4', 'newName', '', new SchemaPropertiesDto(), false, false, modified, modifier, modified, modifier, version); - schemasService.setup(x => x.postSchema(app, request, modifier, modified)) - .returns(() => of(result)).verifiable(); + schemasService.setup(x => x.postSchema(app, request)) + .returns(() => of(versioned(version, { id: 'id4' }))).verifiable(); schemasState.create(request, modified).subscribe(); expect(schemasState.snapshot.schemas.values.length).toBe(3); - expect(schemasState.snapshot.schemas.at(2)).toBe(result); + expect(schemasState.snapshot.schemas.at(2)).toEqual(result); }); it('should remove schema from snapshot when deleted', () => { @@ -322,7 +321,7 @@ describe('SchemasState', () => { }); it('should add field and update user info when field added', () => { - const request = new AddFieldDto(field1.name, field1.partitioning, field1.properties); + const request = { ...field1 }; const newField = new RootFieldDto(3, '3', createProperties('String'), 'invariant'); @@ -338,7 +337,7 @@ describe('SchemasState', () => { }); it('should add field and update user info when nested field added', () => { - const request = new AddFieldDto(field1.name, field1.partitioning, field1.properties); + const request = { ...field1 }; const newField = new NestedFieldDto(3, '3', createProperties('String'), 2); diff --git a/src/Squidex/app/shared/state/schemas.state.ts b/src/Squidex/app/shared/state/schemas.state.ts index 6e2928ed5..b5285958b 100644 --- a/src/Squidex/app/shared/state/schemas.state.ts +++ b/src/Squidex/app/shared/state/schemas.state.ts @@ -17,7 +17,8 @@ import { shareSubscribed, State, Types, - Version + Version, + Versioned } from '@app/framework'; import { AuthService } from './../services/auth.service'; @@ -29,6 +30,7 @@ import { FieldDto, NestedFieldDto, RootFieldDto, + SchemaCreatedDto, SchemaDetailsDto, SchemaDto, SchemaPropertiesDto, @@ -136,10 +138,10 @@ export class SchemasState extends State { } public create(request: CreateSchemaDto, now?: DateTime): Observable { - return this.schemasService.postSchema(this.appName, request, this.user, now || DateTime.now()).pipe( - tap(payload => { + return this.schemasService.postSchema(this.appName, request).pipe( + tap(response => { this.next(s => { - const schemas = s.schemas.push(payload).sortByStringAsc(x => x.displayName); + const schemas = s.schemas.push(createSchema(request, response, this.user, now)).sortByStringAsc(x => x.displayName); return { ...s, schemas }; }); @@ -513,4 +515,21 @@ const pidof = (field: T) => Types.is(field, NestedFieldDto) ? field.parentId : undefined; const pid = (field?: RootFieldDto) => - field ? field.fieldId : undefined; \ No newline at end of file + field ? field.fieldId : undefined; + +function createSchema(request: CreateSchemaDto, { payload, version }: Versioned, user: string, now?: DateTime) { + now = now || DateTime.now(); + + const schema = new SchemaDetailsDto( + payload.id, + request.name, '', + request.properties || new SchemaPropertiesDto(), + request.isSingleton === true, + false, + now, user, + now, user, + version, + request.fields || []); + + return schema; +} \ No newline at end of file diff --git a/src/Squidex/package-lock.json b/src/Squidex/package-lock.json index d1e634ee7..3051cf82b 100644 --- a/src/Squidex/package-lock.json +++ b/src/Squidex/package-lock.json @@ -1670,9 +1670,9 @@ "dev": true }, "@types/node": { - "version": "11.13.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.13.8.tgz", - "integrity": "sha512-szA3x/3miL90ZJxUCzx9haNbK5/zmPieGraZEe4WI+3srN0eGLiT22NXeMHmyhNEopn+IrxqMc7wdVwvPl8meg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.0.tgz", + "integrity": "sha512-Jrb/x3HT4PTJp6a4avhmJCDEVrPdqLfl3e8GGMbpkGGdwAV5UGlIs4vVEfsHHfylZVOKZWpOqmqFH8CbfOZ6kg==", "dev": true }, "@types/prop-types": { @@ -1688,9 +1688,9 @@ "dev": true }, "@types/react": { - "version": "16.8.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.14.tgz", - "integrity": "sha512-26tFVJ1omGmzIdFTFmnC5zhz1GTaqCjxgUxV4KzWvsybF42P7/j4RBn6UeO3KbHPXqKWZszMXMoI65xIWm954A==", + "version": "16.8.16", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.8.16.tgz", + "integrity": "sha512-A0+6kS6zwPtvubOLiCJmZ8li5bm3wKIkoKV0h3RdMDOnCj9cYkUnj3bWbE03/lcICdQmwBmUfoFiHeNhbFiyHQ==", "dev": true, "requires": { "@types/prop-types": "*", @@ -15023,9 +15023,9 @@ } }, "ts-loader": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.4.tgz", - "integrity": "sha512-haLwWMts/tCruBFbLUWOR9hZezZ89TMW3EntrAEtYARDnPZSQt6dPA5tN3fvlsmUIYXVWDHO5SUhw8ndAomVlw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-5.4.5.tgz", + "integrity": "sha512-XYsjfnRQCBum9AMRZpk2rTYSVpdZBpZK+kDh0TeT3kxmQNBDVIeUjdPjY5RZry4eIAb8XHc4gYSUiUWPYvzSRw==", "dev": true, "requires": { "chalk": "^2.3.0", @@ -18772,9 +18772,9 @@ "dev": true }, "zone.js": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.9.0.tgz", - "integrity": "sha512-EfygvVnLxPSCMSgJ4h7SoY+XNr7ybdwvvwEQ70lvMFl9coNnciXSyWi8Kg6znK1ubyUSffkCKvleSQpLuUKw0Q==" + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.9.1.tgz", + "integrity": "sha512-GkPiJL8jifSrKReKaTZ5jkhrMEgXbXYC+IPo1iquBjayRa0q86w3Dipjn8b415jpitMExe9lV8iTsv8tk3DGag==" } } } diff --git a/src/Squidex/package.json b/src/Squidex/package.json index 539bdd9da..f9ed9c7e6 100644 --- a/src/Squidex/package.json +++ b/src/Squidex/package.json @@ -44,7 +44,7 @@ "slugify": "1.3.4", "sortablejs": "1.9.0", "tslib": "1.9.3", - "zone.js": "0.9.0" + "zone.js": "0.9.1" }, "devDependencies": { "@angular/compiler": "7.2.14", @@ -54,8 +54,8 @@ "@types/jasmine": "3.3.12", "@types/marked": "0.6.5", "@types/mousetrap": "1.6", - "@types/node": "11.13.8", - "@types/react": "16.8.14", + "@types/node": "12.0.0", + "@types/react": "16.8.16", "@types/react-dom": "16.8.4", "@types/sortablejs": "1.7.2", "angular-router-loader": "0.8.5", @@ -91,7 +91,7 @@ "sass-lint": "1.13.1", "sass-loader": "7.1.0", "style-loader": "0.23.1", - "ts-loader": "^5.4.4", + "ts-loader": "5.4.5", "tsconfig-paths-webpack-plugin": "3.2.0", "tslint": "5.16.0", "tslint-webpack-plugin": "2.0.4", diff --git a/src/Squidex/tslint.json b/src/Squidex/tslint.json index 88d7ea0ad..9654b463a 100644 --- a/src/Squidex/tslint.json +++ b/src/Squidex/tslint.json @@ -65,6 +65,7 @@ ], "no-input-rename": false, "no-output-rename": false, + "no-pipe-impure": true, "no-shadowed-variable": true, "no-string-literal": false, "no-switch-case-fall-through": true, @@ -103,7 +104,8 @@ true, "always" ], - "templates-no-negated-async": true, + "template-no-negated-async": true, + "template-use-track-by-function": true, "trailing-comma": [ true, {