From b6c5e9d85d4274e2039fed9967857980cedd1778 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Wed, 31 Mar 2021 15:51:30 +0200 Subject: [PATCH 1/2] Fix for validate on publish. --- .../Contents/ContentExtensions.cs | 5 +++++ .../DomainObject/ContentDomainObject.State.cs | 2 +- .../DomainObject/ContentDomainObject.cs | 18 ++++++++--------- .../Guards/ValidationExtensions.cs | 20 +++++++++---------- frontend/app/shared/state/assets.state.ts | 6 +++++- frontend/app/shared/state/contents.state.ts | 8 ++++++-- 6 files changed, 36 insertions(+), 23 deletions(-) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentExtensions.cs index b5a47f0f5..469ff9d7d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentExtensions.cs @@ -45,6 +45,11 @@ namespace Squidex.Domain.Apps.Entities.Contents return content.NewStatus ?? content.Status; } + public static bool IsPublished(this IContentEntity content) + { + return content.EditingStatus() == Status.Published; + } + public static SearchScope Scope(this Context context) { return context.ShouldProvideUnpublished() || context.IsFrontendClient ? SearchScope.All : SearchScope.Published; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs index 0e90b9082..3f343f063 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject [IgnoreDataMember] public Status Status { - get => CurrentVersion.Status; + get => CurrentVersion?.Status ?? Status.Draft; } public override bool ApplyEvent(IEvent @event, EnvelopeHeaders headers) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs index 8e590ad31..23b4940fe 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs @@ -114,7 +114,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject operation.MustHavePermission(Permissions.AppContentsReadOwn); - await operation.ValidateContentAndInputAsync(Snapshot.Data, false); + await operation.ValidateContentAndInputAsync(Snapshot.Data, false, Snapshot.IsPublished()); return true; }); @@ -226,7 +226,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate) { - await operation.ValidateInputAsync(c.Data, c.OptimizeValidation); + await operation.ValidateInputAsync(c.Data, c.OptimizeValidation, Snapshot.IsPublished()); } var status = await operation.GetInitialStatusAsync(); @@ -240,7 +240,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate) { - await operation.ValidateContentAsync(c.Data, c.OptimizeValidation); + await operation.ValidateContentAsync(c.Data, c.OptimizeValidation, Snapshot.IsPublished()); } Create(c, status); @@ -293,7 +293,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate && c.Status == Status.Published && operation.SchemaDef.Properties.ValidateOnPublish) { - await operation.ValidateContentAndInputAsync(Snapshot.Data, c.OptimizeValidation); + await operation.ValidateContentAndInputAsync(Snapshot.Data, c.OptimizeValidation, true); } ChangeStatus(c); @@ -306,7 +306,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate) { - await operation.ValidateInputPartialAsync(c.Data, c.OptimizeValidation); + await operation.ValidateInputPartialAsync(c.Data, c.OptimizeValidation, Snapshot.IsPublished()); } if (!c.DoNotValidateWorkflow) @@ -328,7 +328,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate) { - await operation.ValidateContentAsync(newData, c.OptimizeValidation); + await operation.ValidateContentAsync(newData, c.OptimizeValidation, Snapshot.IsPublished()); } Update(c, newData); @@ -341,7 +341,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate) { - await operation.ValidateInputPartialAsync(c.Data, c.OptimizeValidation); + await operation.ValidateInputPartialAsync(c.Data, c.OptimizeValidation, Snapshot.IsPublished()); } if (!c.DoNotValidateWorkflow) @@ -363,7 +363,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject if (!c.DoNotValidate) { - await operation.ValidateContentAsync(newData, c.OptimizeValidation); + await operation.ValidateContentAsync(newData, c.OptimizeValidation, Snapshot.IsPublished()); } Update(c, newData); @@ -438,7 +438,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject { return StatusChange.Published; } - else if (Snapshot.EditingStatus() == Status.Published) + else if (Snapshot.IsPublished()) { return StatusChange.Unpublished; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs index 7a74908c9..78e083eb9 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs @@ -48,36 +48,36 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards } } - public static async Task ValidateInputAsync(this OperationContext context, ContentData data, bool optimize) + public static async Task ValidateInputAsync(this OperationContext context, ContentData data, bool optimize, bool published) { - var validator = GetValidator(context, optimize); + var validator = GetValidator(context, optimize, published); await validator.ValidateInputAsync(data); context.AddErrors(validator.Errors).ThrowOnErrors(); } - public static async Task ValidateInputPartialAsync(this OperationContext context, ContentData data, bool optimize) + public static async Task ValidateInputPartialAsync(this OperationContext context, ContentData data, bool optimize, bool published) { - var validator = GetValidator(context, optimize); + var validator = GetValidator(context, optimize, published); await validator.ValidateInputPartialAsync(data); context.AddErrors(validator.Errors).ThrowOnErrors(); } - public static async Task ValidateContentAsync(this OperationContext context, ContentData data, bool optimize) + public static async Task ValidateContentAsync(this OperationContext context, ContentData data, bool optimize, bool published) { - var validator = GetValidator(context, optimize); + var validator = GetValidator(context, optimize, published); await validator.ValidateContentAsync(data); context.AddErrors(validator.Errors).ThrowOnErrors(); } - public static async Task ValidateContentAndInputAsync(this OperationContext operation, ContentData data, bool optimize) + public static async Task ValidateContentAndInputAsync(this OperationContext operation, ContentData data, bool optimize, bool published) { - var validator = GetValidator(operation, optimize); + var validator = GetValidator(operation, optimize, published); await validator.ValidateInputAsync(data); await validator.ValidateContentAsync(data); @@ -102,7 +102,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards } } - private static ContentValidator GetValidator(this OperationContext context, bool optimize) + private static ContentValidator GetValidator(this OperationContext context, bool optimize, bool published) { var validationContext = new ValidationContext(context.Resolve(), @@ -110,7 +110,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject.Guards context.Schema.NamedId(), context.SchemaDef, context.ContentId) - .Optimized(optimize); + .Optimized(optimize).AsPublishing(published); var validator = new ContentValidator(context.Partition(), diff --git a/frontend/app/shared/state/assets.state.ts b/frontend/app/shared/state/assets.state.ts index 7dec5de33..4bec937a8 100644 --- a/frontend/app/shared/state/assets.state.ts +++ b/frontend/app/shared/state/assets.state.ts @@ -286,7 +286,7 @@ export abstract class AssetsStateBase extends State { public deleteAsset(asset: AssetDto) { return this.assetsService.deleteAssetItem(this.appName, asset, true, asset.version).pipe( catchError((error: ErrorDto) => { - if (error.statusCode === 400) { + if (isReferrerError(error)) { return this.dialogs.confirm( 'i18n:assets.deleteReferrerConfirmTitle', 'i18n:assets.deleteReferrerConfirmText', @@ -401,6 +401,10 @@ export abstract class AssetsStateBase extends State { } } +function isReferrerError(error?: ErrorDto) { + return error?.statusCode === 400 && (!error?.details || error?.details.length === 0); +} + function updateTags(snapshot: Snapshot, newAsset?: AssetDto, oldAsset?: AssetDto) { if (!oldAsset && newAsset) { oldAsset = snapshot.assets.find(x => x.id === newAsset.id); diff --git a/frontend/app/shared/state/contents.state.ts b/frontend/app/shared/state/contents.state.ts index 5c11555e3..1e5474812 100644 --- a/frontend/app/shared/state/contents.state.ts +++ b/frontend/app/shared/state/contents.state.ts @@ -6,7 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { DialogService, getPagingInfo, ListState, shareSubscribed, State, Types, Version, Versioned } from '@app/framework'; +import { DialogService, ErrorDto, getPagingInfo, ListState, shareSubscribed, State, Types, Version, Versioned } from '@app/framework'; import { EMPTY, Observable, of } from 'rxjs'; import { catchError, finalize, map, switchMap, tap } from 'rxjs/operators'; import { BulkResultDto, BulkUpdateJobDto, ContentDto, ContentsDto, ContentsService, StatusInfo } from './../services/contents.service'; @@ -342,7 +342,7 @@ export abstract class ContentsStateBase extends State { private bulkWithRetry(contents: ReadonlyArray, job: Partial, confirmTitle: string, confirmText: string, confirmKey: string): Observable> { return this.bulkMany(contents, true, job).pipe( switchMap(results => { - const failed = contents.filter(x => results.find(r => r.contentId === x.id)?.error?.statusCode === 400); + const failed = contents.filter(x => isReferrerError(results.find(r => r.contentId === x.id)?.error)); if (failed.length > 0) { return this.dialogs.confirm(confirmTitle, confirmText, confirmKey).pipe( @@ -395,6 +395,10 @@ export abstract class ContentsStateBase extends State { public abstract get schemaName(): string; } +function isReferrerError(error?: ErrorDto) { + return error?.statusCode === 400 && (!error?.details || error?.details.length === 0); +} + @Injectable() export class ContentsState extends ContentsStateBase { constructor(appsState: AppsState, contentsService: ContentsService, dialogs: DialogService, From 0363aa98c749f8e79b023e4b780dc068623978fd Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Wed, 31 Mar 2021 16:35:19 +0200 Subject: [PATCH 2/2] Temp. --- .../Contents/DomainObject/ContentDomainObject.State.cs | 2 +- .../Contents/DomainObject/ContentDomainObject.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs index 3f343f063..ad3c923ce 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.State.cs @@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject [IgnoreDataMember] public Status Status { - get => CurrentVersion?.Status ?? Status.Draft; + get => CurrentVersion?.Status ?? default; } public override bool ApplyEvent(IEvent @event, EnvelopeHeaders headers) diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs index 23b4940fe..985711c69 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs @@ -265,7 +265,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.DomainObject await operation.CheckTransitionAsync(c.Status); } - if (c.CheckReferrers && Snapshot.Status == Status.Published) + if (c.CheckReferrers && Snapshot.IsPublished()) { await operation.CheckReferrersAsync(); }