mirror of https://github.com/Squidex/squidex.git
Browse Source
# Conflicts: # src/Squidex/Areas/Api/Controllers/Apps/AppWorkflowsController.cspull/382/head
42 changed files with 615 additions and 173 deletions
@ -0,0 +1,14 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents.Commands |
||||
|
{ |
||||
|
public abstract class ContentUpdateCommand : ContentDataCommand |
||||
|
{ |
||||
|
public bool AsDraft { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,57 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Infrastructure; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents |
||||
|
{ |
||||
|
public sealed class DefaultWorkflowsValidator : IWorkflowsValidator |
||||
|
{ |
||||
|
private readonly IAppProvider appProvider; |
||||
|
|
||||
|
public DefaultWorkflowsValidator(IAppProvider appProvider) |
||||
|
{ |
||||
|
Guard.NotNull(appProvider, nameof(appProvider)); |
||||
|
|
||||
|
this.appProvider = appProvider; |
||||
|
} |
||||
|
|
||||
|
public async Task<IReadOnlyList<string>> ValidateAsync(Guid appId, Workflows workflows) |
||||
|
{ |
||||
|
Guard.NotNull(workflows, nameof(workflows)); |
||||
|
|
||||
|
var errors = new List<string>(); |
||||
|
|
||||
|
if (workflows.Values.Count(x => x.SchemaIds.Count == 0) > 1) |
||||
|
{ |
||||
|
errors.Add("Multiple workflows cover all schemas."); |
||||
|
} |
||||
|
|
||||
|
var uniqueSchemaIds = workflows.Values.SelectMany(x => x.SchemaIds).Distinct().ToList(); |
||||
|
|
||||
|
foreach (var schemaId in uniqueSchemaIds) |
||||
|
{ |
||||
|
if (workflows.Values.Count(x => x.SchemaIds.Contains(schemaId)) > 1) |
||||
|
{ |
||||
|
var schema = await appProvider.GetSchemaAsync(appId, schemaId); |
||||
|
|
||||
|
if (schema != null) |
||||
|
{ |
||||
|
errors.Add($"The schema `{schema.SchemaDef.Name}` is covered by multiple workflows."); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return errors; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,2 +1,8 @@ |
|||||
@import '_vars'; |
@import '_vars'; |
||||
@import '_mixins'; |
@import '_mixins'; |
||||
|
|
||||
|
.panel-alert { |
||||
|
ul { |
||||
|
margin: 0; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,115 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Threading.Tasks; |
||||
|
using FakeItEasy; |
||||
|
using Squidex.Domain.Apps.Core.Contents; |
||||
|
using Squidex.Domain.Apps.Core.Schemas; |
||||
|
using Squidex.Domain.Apps.Entities.Schemas; |
||||
|
using Squidex.Infrastructure; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Squidex.Domain.Apps.Entities.Contents |
||||
|
{ |
||||
|
public class DefaultWorkflowsValidatorTests |
||||
|
{ |
||||
|
private readonly IAppProvider appProvider = A.Fake<IAppProvider>(); |
||||
|
private readonly NamedId<Guid> appId = NamedId.Of(Guid.NewGuid(), "my-app"); |
||||
|
private readonly NamedId<Guid> schemaId = NamedId.Of(Guid.NewGuid(), "my-schema"); |
||||
|
private readonly DefaultWorkflowsValidator sut; |
||||
|
|
||||
|
public DefaultWorkflowsValidatorTests() |
||||
|
{ |
||||
|
var schema = A.Fake<ISchemaEntity>(); |
||||
|
|
||||
|
A.CallTo(() => schema.Id).Returns(schemaId.Id); |
||||
|
A.CallTo(() => schema.SchemaDef).Returns(new Schema(schemaId.Name)); |
||||
|
|
||||
|
A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, A<Guid>.Ignored, false)) |
||||
|
.Returns(Task.FromResult<ISchemaEntity>(null)); |
||||
|
|
||||
|
A.CallTo(() => appProvider.GetSchemaAsync(appId.Id, schemaId.Id, false)) |
||||
|
.Returns(schema); |
||||
|
|
||||
|
sut = new DefaultWorkflowsValidator(appProvider); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_generate_error_if_multiple_workflows_cover_all_schemas() |
||||
|
{ |
||||
|
var workflows = Workflows.Empty |
||||
|
.Add(Guid.NewGuid(), "workflow1") |
||||
|
.Add(Guid.NewGuid(), "workflow2"); |
||||
|
|
||||
|
var errors = await sut.ValidateAsync(appId.Id, workflows); |
||||
|
|
||||
|
Assert.Equal(errors, new string[] { "Multiple workflows cover all schemas." }); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_generate_error_if_multiple_workflows_cover_specific_schema() |
||||
|
{ |
||||
|
var id1 = Guid.NewGuid(); |
||||
|
var id2 = Guid.NewGuid(); |
||||
|
|
||||
|
var workflows = Workflows.Empty |
||||
|
.Add(id1, "workflow1") |
||||
|
.Add(id2, "workflow2") |
||||
|
.Update(id1, new Workflow(default, Workflow.EmptySteps, new List<Guid> { schemaId.Id })) |
||||
|
.Update(id2, new Workflow(default, Workflow.EmptySteps, new List<Guid> { schemaId.Id })); |
||||
|
|
||||
|
var errors = await sut.ValidateAsync(appId.Id, workflows); |
||||
|
|
||||
|
Assert.Equal(errors, new string[] { "The schema `my-schema` is covered by multiple workflows." }); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_not_generate_error_if_schema_deleted() |
||||
|
{ |
||||
|
var id1 = Guid.NewGuid(); |
||||
|
var id2 = Guid.NewGuid(); |
||||
|
|
||||
|
var oldSchemaId = Guid.NewGuid(); |
||||
|
|
||||
|
var workflows = Workflows.Empty |
||||
|
.Add(id1, "workflow1") |
||||
|
.Add(id2, "workflow2") |
||||
|
.Update(id1, new Workflow(default, Workflow.EmptySteps, new List<Guid> { oldSchemaId })) |
||||
|
.Update(id2, new Workflow(default, Workflow.EmptySteps, new List<Guid> { oldSchemaId })); |
||||
|
|
||||
|
var errors = await sut.ValidateAsync(appId.Id, workflows); |
||||
|
|
||||
|
Assert.Empty(errors); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_not_generate_errors_for_no_overlaps() |
||||
|
{ |
||||
|
var id1 = Guid.NewGuid(); |
||||
|
var id2 = Guid.NewGuid(); |
||||
|
|
||||
|
var workflows = Workflows.Empty |
||||
|
.Add(id1, "workflow1") |
||||
|
.Add(id2, "workflow2") |
||||
|
.Update(id1, new Workflow(default, Workflow.EmptySteps, new List<Guid> { schemaId.Id })); |
||||
|
|
||||
|
var errors = await sut.ValidateAsync(appId.Id, workflows); |
||||
|
|
||||
|
Assert.Empty(errors); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Should_not_generate_errors_for_empty_workflows() |
||||
|
{ |
||||
|
var errors = await sut.ValidateAsync(appId.Id, Workflows.Empty); |
||||
|
|
||||
|
Assert.Empty(errors); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue