diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs index d4c0374c8..6257f4b47 100644 --- a/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/Status.cs @@ -5,7 +5,6 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; using System; namespace Squidex.Domain.Apps.Core.Contents @@ -16,6 +15,8 @@ namespace Squidex.Domain.Apps.Core.Contents public static readonly Status Draft = new Status("Draft"); public static readonly Status Published = new Status("Published"); + public const string FallbackColor = "#8091a5"; + private readonly string name; public string Name @@ -45,7 +46,7 @@ namespace Squidex.Domain.Apps.Core.Contents public override string ToString() { - return name; + return Name; } public static bool operator ==(Status lhs, Status rhs) diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/StatusColors.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/StatusColors.cs new file mode 100644 index 000000000..0e64ea00b --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/StatusColors.cs @@ -0,0 +1,16 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Contents +{ + public static class StatusColors + { + public const string Archived = "#eb3142"; + public const string Draft = "#8091a5"; + public const string Published = "#4bb958"; + } +} diff --git a/src/Squidex.Domain.Apps.Core.Model/Contents/StatusInfo.cs b/src/Squidex.Domain.Apps.Core.Model/Contents/StatusInfo.cs new file mode 100644 index 000000000..a444badaa --- /dev/null +++ b/src/Squidex.Domain.Apps.Core.Model/Contents/StatusInfo.cs @@ -0,0 +1,23 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Contents +{ + public sealed class StatusInfo + { + public Status Status { get; } + + public string Color { get; } + + public StatusInfo(Status status, string color) + { + Status = status; + + Color = color; + } + } +} diff --git a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs index fe2e0649c..7915d9812 100644 --- a/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs +++ b/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs @@ -53,6 +53,10 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents [BsonElement("ss")] public Status Status { get; set; } + [BsonIgnoreIfNull] + [BsonElement("sc")] + public string StatusColor { get; set; } + [BsonIgnoreIfNull] [BsonElement("do")] [BsonJson] diff --git a/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs b/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs index 9b79da894..901eb1e68 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs @@ -19,15 +19,6 @@ namespace Squidex.Domain.Apps.Entities.Apps public AppHistoryEventsCreator(TypeNameRegistry typeNameRegistry) : base(typeNameRegistry) { - AddEventMessage("AppContributorAssignedEvent", - "assigned {user:[Contributor]} as {[Role]}"); - - AddEventMessage("AppClientUpdatedEvent", - "updated client {[Id]}"); - - AddEventMessage("AppPlanChanged", - "changed plan to {[Plan]}"); - AddEventMessage( "assigned {user:[Contributor]} as {[Role]}"); diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs index 8b1b6aac1..4ce840659 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentEntity.cs @@ -38,6 +38,8 @@ namespace Squidex.Domain.Apps.Entities.Contents public Status Status { get; set; } + public string StatusColor { get; set; } + public bool IsPending { get; set; } } } \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs index 60af67527..a621fa3ce 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ContentGrain.cs @@ -83,9 +83,9 @@ namespace Squidex.Domain.Apps.Entities.Contents await ctx.ExecuteScriptAsync(s => s.Change, "Published", c, c.Data); } - var status = await contentWorkflow.GetInitialStatusAsync(ctx.Schema); + var statusInfo = await contentWorkflow.GetInitialStatusAsync(ctx.Schema); - Create(c, status); + Create(c, statusInfo.Status, statusInfo.Color); return Snapshot; }); @@ -127,6 +127,8 @@ namespace Squidex.Domain.Apps.Entities.Contents } else { + var statusInfo = await contentWorkflow.GetInfoAsync(c.Status); + StatusChange reason; if (c.Status == Status.Published) @@ -144,7 +146,7 @@ namespace Squidex.Domain.Apps.Entities.Contents await ctx.ExecuteScriptAsync(s => s.Change, reason, c, Snapshot.Data); - ChangeStatus(c, reason); + ChangeStatus(c, reason, statusInfo.Color); } } } @@ -229,13 +231,21 @@ namespace Squidex.Domain.Apps.Entities.Contents return Snapshot; } - public void Create(CreateContent command, Status status) + public void Create(CreateContent command, Status status, string color) { - RaiseEvent(SimpleMapper.Map(command, new ContentCreated { Status = status })); + RaiseEvent(SimpleMapper.Map(command, new ContentCreated + { + Status = status, + StatusColor = color + })); if (command.Publish) { - RaiseEvent(SimpleMapper.Map(command, new ContentStatusChanged { Status = Status.Published })); + RaiseEvent(SimpleMapper.Map(command, new ContentStatusChanged + { + Status = Status.Published, + StatusColor = StatusColors.Published + })); } } @@ -274,9 +284,9 @@ namespace Squidex.Domain.Apps.Entities.Contents RaiseEvent(SimpleMapper.Map(command, new ContentStatusScheduled { DueTime = command.DueTime.Value })); } - public void ChangeStatus(ChangeContentStatus command, StatusChange change) + public void ChangeStatus(ChangeContentStatus command, StatusChange change, string color) { - RaiseEvent(SimpleMapper.Map(command, new ContentStatusChanged { Change = change })); + RaiseEvent(SimpleMapper.Map(command, new ContentStatusChanged { Change = change, StatusColor = color })); } private void RaiseEvent(SchemaEvent @event) diff --git a/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs b/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs index a3da96afd..6d0156868 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/DefaultContentWorkflow.cs @@ -11,42 +11,77 @@ using System.Linq; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Entities.Schemas; -using Squidex.Infrastructure.Tasks; namespace Squidex.Domain.Apps.Entities.Contents { public sealed class DefaultContentWorkflow : IContentWorkflow { - private static readonly Status[] All = { Status.Archived, Status.Draft, Status.Published }; + private static readonly StatusInfo InfoArchived = new StatusInfo(Status.Archived, StatusColors.Archived); + private static readonly StatusInfo InfoDraft = new StatusInfo(Status.Draft, StatusColors.Draft); + private static readonly StatusInfo InfoPublished = new StatusInfo(Status.Published, StatusColors.Published); - private static readonly Dictionary Flow = new Dictionary + private static readonly StatusInfo[] All = { - [Status.Draft] = new[] { Status.Archived, Status.Published }, - [Status.Archived] = new[] { Status.Draft }, - [Status.Published] = new[] { Status.Draft, Status.Archived } + InfoArchived, + InfoDraft, + InfoPublished }; - public Task GetInitialStatusAsync(ISchemaEntity schema) + private static readonly Dictionary Flow = + new Dictionary + { + [Status.Archived] = (InfoArchived, new[] + { + InfoDraft + }), + [Status.Draft] = (InfoDraft, new[] + { + InfoArchived, + InfoPublished + }), + [Status.Published] = (InfoPublished, new[] + { + InfoDraft, + InfoArchived + }) + }; + + public Task GetInitialStatusAsync(ISchemaEntity schema) { - return Task.FromResult(Status.Draft); + var result = InfoDraft; + + return Task.FromResult(result); } public Task CanMoveToAsync(IContentEntity content, Status next) { - return Task.FromResult(Flow.TryGetValue(content.Status, out var state) && state.Contains(next)); + var result = Flow.TryGetValue(content.Status, out var step) && step.Transitions.Any(x => x.Status == next); + + return Task.FromResult(result); } public Task CanUpdateAsync(IContentEntity content) { - return Task.FromResult(content.Status != Status.Archived); + var result = content.Status != Status.Archived; + + return Task.FromResult(result); } - public Task GetNextsAsync(IContentEntity content) + public Task GetInfoAsync(Status status) { - return Task.FromResult(Flow.TryGetValue(content.Status, out var result) ? result : Array.Empty()); + var result = Flow[status].Info; + + return Task.FromResult(result); + } + + public Task GetNextsAsync(IContentEntity content) + { + var result = Flow.TryGetValue(content.Status, out var step) ? step.Transitions : Array.Empty(); + + return Task.FromResult(result); } - public Task GetAllAsync(ISchemaEntity schema) + public Task GetAllAsync(ISchemaEntity schema) { return Task.FromResult(All); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs index a6d876742..429847aed 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/ContentGraphType.cs @@ -78,6 +78,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL.Types Description = $"The the status of the {schemaName} content." }); + AddField(new FieldType + { + Name = "statusColor", + ResolvedType = AllTypes.NonNullString, + Resolver = Resolve(x => x.StatusColor), + Description = $"The color status of the {schemaName} content." + }); + AddField(new FieldType { Name = "url", diff --git a/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs b/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs index 1a7e53424..bc3263469 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/IContentEntity.cs @@ -24,6 +24,8 @@ namespace Squidex.Domain.Apps.Entities.Contents Status Status { get; } + string StatusColor { get; } + ScheduleJob ScheduleJob { get; } NamedContentData Data { get; } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs b/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs index c812f8a4f..8a2f0f571 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/IContentWorkflow.cs @@ -13,14 +13,16 @@ namespace Squidex.Domain.Apps.Entities.Contents { public interface IContentWorkflow { - Task GetInitialStatusAsync(ISchemaEntity schema); + Task GetInitialStatusAsync(ISchemaEntity schema); Task CanMoveToAsync(IContentEntity content, Status next); Task CanUpdateAsync(IContentEntity content); - Task GetNextsAsync(IContentEntity content); + Task GetInfoAsync(Status status); - Task GetAllAsync(ISchemaEntity schema); + Task GetNextsAsync(IContentEntity content); + + Task GetAllAsync(ISchemaEntity schema); } } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs b/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs index fe48b89e4..a9fd7f0ff 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/ScheduleJob.cs @@ -16,21 +16,24 @@ namespace Squidex.Domain.Apps.Entities.Contents { public Guid Id { get; } + public Instant DueTime { get; } + public Status Status { get; } - public RefToken ScheduledBy { get; } + public string StatusColor { get; set; } - public Instant DueTime { get; } + public RefToken ScheduledBy { get; } - public ScheduleJob(Guid id, Status status, RefToken scheduledBy, Instant dueTime) + public ScheduleJob(Guid id, Status status, string statusColor, RefToken scheduledBy, Instant dueTime) { Id = id; ScheduledBy = scheduledBy; Status = status; + StatusColor = statusColor; DueTime = dueTime; } - public static ScheduleJob Build(Status status, RefToken scheduledBy, Instant dueTime) + public static ScheduleJob Build(Status status, string statusColor, RefToken scheduledBy, Instant dueTime) { return new ScheduleJob(Guid.NewGuid(), status, scheduledBy, dueTime); } diff --git a/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs b/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs index 0f0234dc9..6c956951e 100644 --- a/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs +++ b/src/Squidex.Domain.Apps.Entities/Contents/State/ContentState.cs @@ -45,16 +45,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.State [DataMember] public Status Status { get; set; } + [DataMember] + public string StatusColor { get; set; } + protected void On(ContentCreated @event) { SimpleMapper.Map(@event, this); UpdateData(null, @event.Data, false); - - if (Status == default) - { - Status = Status.Draft; - } } protected void On(ContentChangesPublished @event) @@ -68,7 +66,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.State { ScheduleJob = null; - Status = @event.Status; + SimpleMapper.Map(@event, this); if (@event.Status == Status.Published) { diff --git a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs index f640cf173..21721c416 100644 --- a/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs +++ b/src/Squidex.Domain.Apps.Entities/Schemas/SchemaHistoryEventsCreator.cs @@ -19,12 +19,6 @@ namespace Squidex.Domain.Apps.Entities.Schemas public SchemaHistoryEventsCreator(TypeNameRegistry typeNameRegistry) : base(typeNameRegistry) { - AddEventMessage("SchemaCreatedEvent", - "created schema {[Name]}."); - - AddEventMessage("ScriptsConfiguredEvent", - "configured script of schema {[Name]}."); - AddEventMessage( "reordered fields of schema {[Name]}."); diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs index 317b3b176..0529f0bf6 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs @@ -10,11 +10,13 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Contents { - [EventType(nameof(ContentCreated))] + [EventType(nameof(ContentCreated), 2)] public sealed class ContentCreated : ContentEvent { public Status Status { get; set; } + public string StatusColor { get; set; } + public NamedContentData Data { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentStatusChanged.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentStatusChanged.cs index e7b201ffe..2ceb8c981 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentStatusChanged.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentStatusChanged.cs @@ -10,11 +10,13 @@ using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Contents { - [EventType(nameof(ContentStatusChanged))] + [EventType(nameof(ContentStatusChanged), 2)] public sealed class ContentStatusChanged : ContentEvent { public StatusChange Change { get; set; } public Status Status { get; set; } + + public string StatusColor { get; set; } } } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentStatusScheduled.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentStatusScheduled.cs index e0d0a5bac..81ad1ed5b 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentStatusScheduled.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentStatusScheduled.cs @@ -16,6 +16,8 @@ namespace Squidex.Domain.Apps.Events.Contents { public Status Status { get; set; } + public string StatusColor { get; set; } + public Instant DueTime { get; set; } } } diff --git a/src/Squidex.Web/Resource.cs b/src/Squidex.Web/Resource.cs index d3eba847d..31602a124 100644 --- a/src/Squidex.Web/Resource.cs +++ b/src/Squidex.Web/Resource.cs @@ -24,38 +24,38 @@ namespace Squidex.Web AddGetLink("self", href); } - public void AddGetLink(string rel, string href) + public void AddGetLink(string rel, string href, string metadata = null) { - AddLink(rel, "GET", href); + AddLink(rel, "GET", href, metadata); } - public void AddPatchLink(string rel, string href) + public void AddPatchLink(string rel, string href, string metadata = null) { - AddLink(rel, "PATCH", href); + AddLink(rel, "PATCH", href, metadata); } - public void AddPostLink(string rel, string href) + public void AddPostLink(string rel, string href, string metadata = null) { - AddLink(rel, "POST", href); + AddLink(rel, "POST", href, metadata); } - public void AddPutLink(string rel, string href) + public void AddPutLink(string rel, string href, string metadata = null) { - AddLink(rel, "PUT", href); + AddLink(rel, "PUT", href, metadata); } - public void AddDeleteLink(string rel, string href) + public void AddDeleteLink(string rel, string href, string metadata = null) { - AddLink(rel, "DELETE", href); + AddLink(rel, "DELETE", href, metadata); } - public void AddLink(string rel, string method, string href) + public void AddLink(string rel, string method, string href, string metadata = null) { Guard.NotNullOrEmpty(rel, nameof(rel)); Guard.NotNullOrEmpty(href, nameof(href)); Guard.NotNullOrEmpty(method, nameof(method)); - Links[rel] = new ResourceLink { Href = href, Method = method }; + Links[rel] = new ResourceLink { Href = href, Method = method, Metadata = metadata }; } } } diff --git a/src/Squidex.Web/ResourceLink.cs b/src/Squidex.Web/ResourceLink.cs index 964610e7d..2d2b4c0c5 100644 --- a/src/Squidex.Web/ResourceLink.cs +++ b/src/Squidex.Web/ResourceLink.cs @@ -18,5 +18,9 @@ namespace Squidex.Web [Required] [Display(Description = "The link method.")] public string Method { get; set; } + + [Required] + [Display(Description = "Additional data about the link.")] + public string Metadata { get; set; } } } diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs index 2a6afaacf..c53a154f8 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs @@ -71,10 +71,15 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models public Instant LastModified { get; set; } /// - /// The the status of the content. + /// The status of the content. /// public Status Status { get; set; } + /// + /// The color of the status. + /// + public string StatusColor { get; set; } + /// /// The version of the content. /// @@ -161,9 +166,9 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models foreach (var next in nextStatuses) { - if (controller.HasPermission(Helper.StatusPermission(app, schema, next))) + if (controller.HasPermission(Helper.StatusPermission(app, schema, next.Status))) { - AddPutLink($"status/{next}", controller.Url(x => nameof(x.PutContentStatus), values)); + AddPutLink($"status/{next.Status}", controller.Url(x => nameof(x.PutContentStatus), values), next.Color); } } diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs index afcecb7fe..23707b311 100644 --- a/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs +++ b/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs @@ -35,7 +35,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models /// The possible statuses. /// [Required] - public Status[] Statuses { get; set; } + public StatusInfoDto[] Statuses { get; set; } public string ToEtag() { @@ -69,7 +69,7 @@ namespace Squidex.Areas.Api.Controllers.Contents.Models { var allStatuses = await contentWorkflow.GetAllAsync(schema); - Statuses = allStatuses.ToArray(); + Statuses = allStatuses.Select(StatusInfoDto.FromStatusInfo).ToArray(); } private async Task AssignContentsAsync(IContentWorkflow contentWorkflow, IResultList contents, QueryContext context, ApiController controller) diff --git a/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs b/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs new file mode 100644 index 000000000..510ba8a7a --- /dev/null +++ b/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs @@ -0,0 +1,32 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.ComponentModel.DataAnnotations; +using Squidex.Domain.Apps.Core.Contents; + +namespace Squidex.Areas.Api.Controllers.Contents.Models +{ + public sealed class StatusInfoDto + { + /// + /// The name of the status. + /// + [Required] + public Status Status { get; set; } + + /// + /// The color of the status. + /// + [Required] + public string Color { get; set; } + + public static StatusInfoDto FromStatusInfo(StatusInfo statusInfo) + { + return new StatusInfoDto { Status = statusInfo.Status, Color = statusInfo.Color }; + } + } +} diff --git a/src/Squidex/Config/Domain/StoreServices.cs b/src/Squidex/Config/Domain/StoreServices.cs index 96b775fa0..7ce03c2f3 100644 --- a/src/Squidex/Config/Domain/StoreServices.cs +++ b/src/Squidex/Config/Domain/StoreServices.cs @@ -67,6 +67,9 @@ namespace Squidex.Config.Domain services.AddTransientAs(c => new RestructureContentCollection(c.GetRequiredService().GetDatabase(mongoContentDatabaseName))) .As(); + services.AddTransientAs(c => new CreateStatusColors(c.GetRequiredService().GetDatabase(mongoContentDatabaseName))) + .As(); + services.AddSingletonAs() .As(); diff --git a/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.html b/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.html index ea615ec67..600764d90 100644 --- a/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.html +++ b/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.html @@ -17,7 +17,7 @@ - {{query.name}} + {{query.name}} diff --git a/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.scss b/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.scss index 00bb31427..684ee4478 100644 --- a/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.scss +++ b/src/Squidex/app/features/content/pages/contents/contents-filters-page.component.scss @@ -3,4 +3,4 @@ .text-muted { pointer-events: none; -} \ No newline at end of file +} diff --git a/src/Squidex/app/framework/utils/hateos.ts b/src/Squidex/app/framework/utils/hateos.ts index cf2bc3faa..a499d85ae 100644 --- a/src/Squidex/app/framework/utils/hateos.ts +++ b/src/Squidex/app/framework/utils/hateos.ts @@ -13,7 +13,7 @@ export interface Resource { } export type ResourceLinks = { [rel: string]: ResourceLink }; -export type ResourceLink = { href: string; method: ResourceMethod; }; +export type ResourceLink = { href: string; method: ResourceMethod; metadata?: string; }; export type Metadata = { [rel: string]: string }; diff --git a/src/Squidex/app/shared/services/contents.service.spec.ts b/src/Squidex/app/shared/services/contents.service.spec.ts index 7c5e8880b..13c89f0fc 100644 --- a/src/Squidex/app/shared/services/contents.service.spec.ts +++ b/src/Squidex/app/shared/services/contents.service.spec.ts @@ -62,11 +62,13 @@ describe('ContentsService', () => { contentResponse(12), contentResponse(13) ], - statuses: ['Draft', 'Published'] + statuses: [{ + status: 'Draft', color: 'Gray' + }] }); expect(contents!).toEqual( - new ContentsDto(['Draft', 'Published'], 10, [ + new ContentsDto([{ status: 'Draft', color: 'Gray' }], 10, [ createContent(12), createContent(13) ])); diff --git a/src/Squidex/app/shared/services/contents.service.ts b/src/Squidex/app/shared/services/contents.service.ts index fae6b1927..5607a8156 100644 --- a/src/Squidex/app/shared/services/contents.service.ts +++ b/src/Squidex/app/shared/services/contents.service.ts @@ -34,9 +34,11 @@ export class ScheduleDto { } } +export type StatusInfo = { status: string; color: string; }; + export class ContentsDto extends ResultSet { constructor( - public readonly statuses: string[], + public readonly statuses: StatusInfo[], total: number, items: ContentDto[], links?: ResourceLinks @@ -133,7 +135,7 @@ export class ContentsService { const url = this.apiUrl.buildUrl(`/api/content/${appName}/${schemaName}?${fullQuery}`); - return this.http.get<{ total: number, items: [], statuses: string[] } & Resource>(url).pipe( + return this.http.get<{ total: number, items: [], statuses: StatusInfo[] } & Resource>(url).pipe( map(({ total, items, statuses, _links }) => { const contents = items.map(x => parseContent(x)); diff --git a/src/Squidex/app/shared/state/contents.state.ts b/src/Squidex/app/shared/state/contents.state.ts index 96ad17f18..c75eb0125 100644 --- a/src/Squidex/app/shared/state/contents.state.ts +++ b/src/Squidex/app/shared/state/contents.state.ts @@ -24,7 +24,7 @@ import { SchemaDto } from './../services/schemas.service'; import { AppsState } from './apps.state'; import { SchemasState } from './schemas.state'; -import { ContentDto, ContentsService } from './../services/contents.service'; +import { ContentDto, ContentsService, StatusInfo } from './../services/contents.service'; interface Snapshot { // The current comments. @@ -40,7 +40,7 @@ interface Snapshot { isLoaded?: boolean; // The statuses. - statuses?: string[]; + statuses?: StatusInfo[]; // The selected content. selectedContent?: ContentDto | null; @@ -348,10 +348,12 @@ export class ManualContentsState extends ContentsStateBase { } } -function buildQueries(x: string[] | undefined): { name: string; filter: string; }[] { - return x ? x.map(s => buildQuery(s)) : []; +export type ContentQuery = { color: string; name: string; filter: string; }; + +function buildQueries(statuses: StatusInfo[] | undefined): ContentQuery[] { + return statuses ? statuses.map(s => buildQuery(s)) : []; } -function buildQuery(s: string) { - return ({ name: s, filter: `$filter=status eq '${s}'` }); +function buildQuery(s: StatusInfo) { + return ({ name: s.status, color: s.color, filter: `$filter=status eq '${s}'` }); } diff --git a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs index 138e399c1..8cdac0bc8 100644 --- a/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs +++ b/tests/Squidex.Domain.Apps.Core.Tests/Model/Contents/StatusTests.cs @@ -12,40 +12,49 @@ namespace Squidex.Domain.Apps.Core.Model.Contents { public class StatusTests { + [Fact] + public void Should_initialize_default() + { + Status status = default; + + Assert.Equal("Unknown", status.Name); + Assert.Equal("Unknown", status.ToString()); + } + [Fact] public void Should_initialize_status_from_string() { - var result = new Status("Custom"); + var status = new Status("Custom"); - Assert.Equal("Custom", result.Name); - Assert.Equal("Custom", result.ToString()); + Assert.Equal("Custom", status.Name); + Assert.Equal("Custom", status.ToString()); } [Fact] public void Should_provide_draft_status() { - var result = Status.Draft; + var status = Status.Draft; - Assert.Equal("Draft", result.Name); - Assert.Equal("Draft", result.ToString()); + Assert.Equal("Draft", status.Name); + Assert.Equal("Draft", status.ToString()); } [Fact] public void Should_provide_archived_status() { - var result = Status.Archived; + var status = Status.Archived; - Assert.Equal("Archived", result.Name); - Assert.Equal("Archived", result.ToString()); + Assert.Equal("Archived", status.Name); + Assert.Equal("Archived", status.ToString()); } [Fact] public void Should_provide_published_status() { - var result = Status.Published; + var status = Status.Published; - Assert.Equal("Published", result.Name); - Assert.Equal("Published", result.ToString()); + Assert.Equal("Published", status.Name); + Assert.Equal("Published", status.ToString()); } [Fact] diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs index be800180e..fe4484b49 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentGrainTests.cs @@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents private readonly ISchemaEntity schema = A.Fake(); private readonly IScriptEngine scriptEngine = A.Fake(); private readonly IContentRepository contentRepository = A.Dummy(); - private readonly IContentWorkflow contentWorkflow = A.Fake(); + private readonly IContentWorkflow contentWorkflow = A.Fake(x => x.Wrapping(new DefaultContentWorkflow())); private readonly IAppProvider appProvider = A.Fake(); private readonly IAppEntity app = A.Fake(); private readonly LanguagesConfig languagesConfig = LanguagesConfig.Build(Language.DE); @@ -102,12 +102,6 @@ namespace Squidex.Domain.Apps.Entities.Contents A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, A.Ignored)) .ReturnsLazily(x => x.GetArgument(0).Data); - A.CallTo(() => contentWorkflow.CanUpdateAsync(A.Ignored)) - .Returns(true); - - A.CallTo(() => contentWorkflow.CanMoveToAsync(A.Ignored, A.Ignored)) - .Returns(true); - patched = patch.MergeInto(data); sut = new ContentGrain(Store, A.Dummy(), appProvider, A.Dummy(), scriptEngine, contentWorkflow, contentRepository); @@ -132,9 +126,12 @@ namespace Squidex.Domain.Apps.Entities.Contents result.ShouldBeEquivalent(sut.Snapshot); + Assert.Equal(Status.Draft, sut.Snapshot.Status); + Assert.Equal(StatusColors.Draft, sut.Snapshot.StatusColor); + LastEvents .ShouldHaveSameEvents( - CreateContentEvent(new ContentCreated { Data = data }) + CreateContentEvent(new ContentCreated { Data = data, Status = Status.Draft, StatusColor = StatusColors.Draft }) ); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "")) @@ -143,26 +140,6 @@ namespace Squidex.Domain.Apps.Entities.Contents .MustNotHaveHappened(); } - [Fact] - public async Task Create_should_create_events_and_update_state_with_custom_initial_status() - { - var command = new CreateContent { Data = data }; - - A.CallTo(() => contentWorkflow.GetInitialStatusAsync(schema)) - .Returns(Status.Archived); - - var result = await sut.ExecuteAsync(CreateContentCommand(command)); - - result.ShouldBeEquivalent(sut.Snapshot); - - Assert.Equal(Status.Archived, sut.Snapshot.Status); - - LastEvents - .ShouldHaveSameEvents( - CreateContentEvent(new ContentCreated { Data = data, Status = Status.Archived }) - ); - } - [Fact] public async Task Create_should_also_publish() { @@ -172,10 +149,22 @@ namespace Squidex.Domain.Apps.Entities.Contents result.ShouldBeEquivalent(sut.Snapshot); + Assert.Equal(Status.Published, sut.Snapshot.Status); + Assert.Equal(StatusColors.Published, sut.Snapshot.StatusColor); + LastEvents .ShouldHaveSameEvents( - CreateContentEvent(new ContentCreated { Data = data }), - CreateContentEvent(new ContentStatusChanged { Status = Status.Published }) + CreateContentEvent(new ContentCreated + { + Data = data, + Status = Status.Draft, + StatusColor = StatusColors.Draft + }), + CreateContentEvent(new ContentStatusChanged + { + Status = Status.Published, + StatusColor = StatusColors.Published + }) ); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "")) @@ -246,10 +235,7 @@ namespace Squidex.Domain.Apps.Entities.Contents result.ShouldBeEquivalent(sut.Snapshot); - LastEvents - .ShouldHaveSameEvents( - CreateContentEvent(new ContentCreated { Data = data }) - ); + Assert.Single(LastEvents); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "")) .MustNotHaveHappened(); @@ -319,10 +305,7 @@ namespace Squidex.Domain.Apps.Entities.Contents result.ShouldBeEquivalent(sut.Snapshot); - LastEvents - .ShouldHaveSameEvents( - CreateContentEvent(new ContentCreated { Data = data }) - ); + Assert.Single(LastEvents); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "")) .MustNotHaveHappened(); @@ -343,7 +326,12 @@ namespace Squidex.Domain.Apps.Entities.Contents LastEvents .ShouldHaveSameEvents( - CreateContentEvent(new ContentStatusChanged { Status = Status.Published, Change = StatusChange.Published }) + CreateContentEvent(new ContentStatusChanged + { + Change = StatusChange.Published, + Status = Status.Published, + StatusColor = StatusColors.Published + }) ); A.CallTo(() => scriptEngine.Execute(A.Ignored, "")) @@ -365,7 +353,11 @@ namespace Squidex.Domain.Apps.Entities.Contents LastEvents .ShouldHaveSameEvents( - CreateContentEvent(new ContentStatusChanged { Status = Status.Archived }) + CreateContentEvent(new ContentStatusChanged + { + Status = Status.Archived, + StatusColor = StatusColors.Archived + }) ); A.CallTo(() => scriptEngine.Execute(A.Ignored, "")) @@ -388,7 +380,12 @@ namespace Squidex.Domain.Apps.Entities.Contents LastEvents .ShouldHaveSameEvents( - CreateContentEvent(new ContentStatusChanged { Status = Status.Draft, Change = StatusChange.Unpublished }) + CreateContentEvent(new ContentStatusChanged + { + Change = StatusChange.Unpublished, + Status = Status.Draft, + StatusColor = StatusColors.Draft + }) ); A.CallTo(() => scriptEngine.Execute(A.Ignored, "")) @@ -411,7 +408,11 @@ namespace Squidex.Domain.Apps.Entities.Contents LastEvents .ShouldHaveSameEvents( - CreateContentEvent(new ContentStatusChanged { Status = Status.Draft }) + CreateContentEvent(new ContentStatusChanged + { + Status = Status.Draft, + StatusColor = StatusColors.Draft + }) ); A.CallTo(() => scriptEngine.Execute(A.Ignored, "")) @@ -472,11 +473,11 @@ namespace Squidex.Domain.Apps.Entities.Contents public async Task ChangeStatus_should_refresh_properties_and_revert_scheduling_when_invoked_by_scheduler() { await ExecuteCreateAsync(); - await ExecuteScheduledAsync(); + await ExecuteChangeStatusAsync(Status.Published, Instant.MaxValue); - var command = new ChangeContentStatus { Status = Status.Draft, JobId = sut.Snapshot.ScheduleJob.Id }; + var command = new ChangeContentStatus { Status = Status.Published, JobId = sut.Snapshot.ScheduleJob.Id }; - A.CallTo(() => contentWorkflow.CanMoveToAsync(sut.Snapshot, command.Status)) + A.CallTo(() => contentWorkflow.CanMoveToAsync(A.Ignored, Status.Published)) .Returns(false); var result = await sut.ExecuteAsync(CreateContentCommand(command)); @@ -549,9 +550,9 @@ namespace Squidex.Domain.Apps.Entities.Contents return sut.ExecuteAsync(CreateContentCommand(new UpdateContent { Data = otherData, AsDraft = true })); } - private Task ExecuteScheduledAsync() + private Task ExecuteChangeStatusAsync(Status status, Instant? dueTime = null) { - return sut.ExecuteAsync(CreateContentCommand(new ChangeContentStatus { Status = Status.Published, DueTime = Instant.MaxValue })); + return sut.ExecuteAsync(CreateContentCommand(new ChangeContentStatus { Status = status, DueTime = dueTime })); } private Task ExecuteDeleteAsync() diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs index 710eaff1f..0832ec984 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/DefaultContentWorkflowTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using FakeItEasy; +using FluentAssertions; using Squidex.Domain.Apps.Core.Contents; using Xunit; @@ -19,9 +20,11 @@ namespace Squidex.Domain.Apps.Entities.Contents [Fact] public async Task Should_draft_as_initial_status() { + var expected = new StatusInfo(Status.Draft, StatusColors.Draft); + var result = await sut.GetInitialStatusAsync(null); - Assert.Equal(Status.Draft, result); + result.Should().BeEquivalentTo(expected); } [Fact] @@ -69,11 +72,15 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = CreateContent(Status.Draft); - var expected = new[] { Status.Archived, Status.Published }; + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived), + new StatusInfo(Status.Published, StatusColors.Published) + }; var result = await sut.GetNextsAsync(content); - Assert.Equal(expected, result); + result.Should().BeEquivalentTo(expected); } [Fact] @@ -81,11 +88,14 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = CreateContent(Status.Archived); - var expected = new[] { Status.Draft }; + var expected = new[] + { + new StatusInfo(Status.Draft, StatusColors.Draft) + }; var result = await sut.GetNextsAsync(content); - Assert.Equal(expected, result); + result.Should().BeEquivalentTo(expected); } [Fact] @@ -93,21 +103,30 @@ namespace Squidex.Domain.Apps.Entities.Contents { var content = CreateContent(Status.Published); - var expected = new[] { Status.Draft, Status.Archived }; + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived), + new StatusInfo(Status.Draft, StatusColors.Draft) + }; var result = await sut.GetNextsAsync(content); - Assert.Equal(expected, result); + result.Should().BeEquivalentTo(expected); } [Fact] public async Task Should_return_all_statuses() { - var expected = new[] { Status.Archived, Status.Draft, Status.Published }; + var expected = new[] + { + new StatusInfo(Status.Archived, StatusColors.Archived), + new StatusInfo(Status.Draft, StatusColors.Draft), + new StatusInfo(Status.Published, StatusColors.Published) + }; var result = await sut.GetAllAsync(null); - Assert.Equal(expected, result); + result.Should().BeEquivalentTo(expected); } private IContentEntity CreateContent(Status status) diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs index 2e503ffdf..6b93b51b0 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLQueriesTests.cs @@ -262,6 +262,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL lastModified lastModifiedBy status + statusColor url data { myString { @@ -320,6 +321,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL lastModified = content.LastModified, lastModifiedBy = "subject:user2", status = "DRAFT", + statusColor = "red", url = $"contents/my-schema/{content.Id}", data = new { @@ -406,6 +408,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL lastModified lastModifiedBy status + statusColor url data { myString { @@ -462,6 +465,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL lastModified = content.LastModified, lastModifiedBy = "subject:user2", status = "DRAFT", + statusColor = "red", url = $"contents/my-schema/{content.Id}", data = new { @@ -605,6 +609,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL lastModified lastModifiedBy status + statusColor url data { myString { @@ -653,6 +658,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL lastModified = content.LastModified, lastModifiedBy = "subject:user2", status = "DRAFT", + statusColor = "red", url = $"contents/my-schema/{content.Id}", data = new { diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs index 93dc8b070..819482af8 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/GraphQLTestBase.cs @@ -157,7 +157,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.GraphQL LastModifiedBy = new RefToken(RefTokenType.Subject, "user2"), Data = data, DataDraft = dataDraft, - Status = Status.Draft + Status = Status.Draft, + StatusColor = "red" }; return content; diff --git a/tools/Migrate_01/MigrationPath.cs b/tools/Migrate_01/MigrationPath.cs index 90ecb63d9..3988129da 100644 --- a/tools/Migrate_01/MigrationPath.cs +++ b/tools/Migrate_01/MigrationPath.cs @@ -17,7 +17,7 @@ namespace Migrate_01 { public sealed class MigrationPath : IMigrationPath { - private const int CurrentVersion = 17; + private const int CurrentVersion = 18; private readonly IServiceProvider serviceProvider; public MigrationPath(IServiceProvider serviceProvider) @@ -115,6 +115,12 @@ namespace Migrate_01 yield return serviceProvider.GetService(); } + // Version 18: Status colors introduced + if (version < 17) + { + yield return serviceProvider.GetService(); + } + yield return serviceProvider.GetRequiredService(); } } diff --git a/tools/Migrate_01/Migrations/MongoDb/CreateStatusColors.cs b/tools/Migrate_01/Migrations/MongoDb/CreateStatusColors.cs new file mode 100644 index 000000000..377ffe9ac --- /dev/null +++ b/tools/Migrate_01/Migrations/MongoDb/CreateStatusColors.cs @@ -0,0 +1,42 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Threading.Tasks; +using MongoDB.Bson; +using MongoDB.Driver; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Infrastructure.Migrations; + +namespace Migrate_01.Migrations.MongoDb +{ + public sealed class CreateStatusColors : IMigration + { + private readonly IMongoDatabase contentDatabase; + + public CreateStatusColors(IMongoDatabase contentDatabase) + { + this.contentDatabase = contentDatabase; + } + + public async Task UpdateAsync() + { + var collection = contentDatabase.GetCollection("State_Contents"); + + await collection.UpdateManyAsync( + Builders.Filter.Eq("ss", "Archived"), + Builders.Update.Set("sc", StatusColors.Archived)); + + await collection.UpdateManyAsync( + Builders.Filter.Eq("ss", "Draft"), + Builders.Update.Set("sc", StatusColors.Draft)); + + await collection.UpdateManyAsync( + Builders.Filter.Eq("ss", "Published"), + Builders.Update.Set("sc", StatusColors.Published)); + } + } +} diff --git a/tools/Migrate_01/OldEvents/AppPlanChangedOld.cs b/tools/Migrate_01/OldEvents/AppPlanChanged.cs similarity index 84% rename from tools/Migrate_01/OldEvents/AppPlanChangedOld.cs rename to tools/Migrate_01/OldEvents/AppPlanChanged.cs index e5ae9dcec..e37c201d2 100644 --- a/tools/Migrate_01/OldEvents/AppPlanChangedOld.cs +++ b/tools/Migrate_01/OldEvents/AppPlanChanged.cs @@ -5,16 +5,19 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== +using System; using Squidex.Domain.Apps.Events; using Squidex.Domain.Apps.Events.Apps; using Squidex.Infrastructure; using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.Reflection; +using AppPlanChangedV2 = Squidex.Domain.Apps.Events.Apps.AppPlanChanged; namespace Migrate_01.OldEvents { [TypeName("AppPlanChanged")] - public sealed class AppPlanChangedOld : AppEvent, IMigrated + [Obsolete] + public sealed class AppPlanChanged : AppEvent, IMigrated { public string PlanId { get; set; } @@ -22,7 +25,7 @@ namespace Migrate_01.OldEvents { if (!string.IsNullOrWhiteSpace(PlanId)) { - return SimpleMapper.Map(this, new AppPlanChanged()); + return SimpleMapper.Map(this, new AppPlanChangedV2()); } else { diff --git a/tools/Migrate_01/OldEvents/ContentCreated.cs b/tools/Migrate_01/OldEvents/ContentCreated.cs new file mode 100644 index 000000000..68f592407 --- /dev/null +++ b/tools/Migrate_01/OldEvents/ContentCreated.cs @@ -0,0 +1,51 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Events.Contents; +using Squidex.Infrastructure; +using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Reflection; +using ContentCreatedV2 = Squidex.Domain.Apps.Events.Contents.ContentCreated; + +namespace Migrate_01.OldEvents +{ + [EventType(nameof(ContentCreated))] + [Obsolete] + public sealed class ContentCreated : ContentEvent, IMigrated + { + public Status Status { get; set; } + + public NamedContentData Data { get; set; } + + public IEvent Migrate() + { + var migrated = SimpleMapper.Map(this, new ContentCreatedV2()); + + if (migrated.Status == default) + { + migrated.Status = Status.Draft; + } + + if (Status == Status.Archived) + { + migrated.StatusColor = StatusColors.Archived; + } + else if (Status == Status.Published) + { + migrated.StatusColor = StatusColors.Published; + } + else + { + migrated.StatusColor = StatusColors.Draft; + } + + return this; + } + } +} diff --git a/tools/Migrate_01/OldEvents/ContentStatusChanged.cs b/tools/Migrate_01/OldEvents/ContentStatusChanged.cs new file mode 100644 index 000000000..d6efc8bde --- /dev/null +++ b/tools/Migrate_01/OldEvents/ContentStatusChanged.cs @@ -0,0 +1,60 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Events.Contents; +using Squidex.Infrastructure; +using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Reflection; +using ContentStatusChangedV2 = Squidex.Domain.Apps.Events.Contents.ContentStatusChanged; + +namespace Migrate_01.OldEvents +{ + [EventType(nameof(ContentStatusChanged))] + [Obsolete] + public sealed class ContentStatusChanged : ContentEvent, IMigrated + { + public string Change { get; set; } + + public Status Status { get; set; } + + public IEvent Migrate() + { + var migrated = SimpleMapper.Map(this, new ContentStatusChangedV2()); + + if (migrated.Status == default) + { + migrated.Status = Status.Draft; + } + + if (Enum.TryParse(Change, out var result)) + { + migrated.Change = result; + } + else + { + migrated.Change = StatusChange.Change; + } + + if (Status == Status.Archived) + { + migrated.StatusColor = StatusColors.Archived; + } + else if (Status == Status.Published) + { + migrated.StatusColor = StatusColors.Published; + } + else + { + migrated.StatusColor = StatusColors.Draft; + } + + return this; + } + } +} diff --git a/tools/Migrate_01/OldEvents/ContentStatusScheduled.cs b/tools/Migrate_01/OldEvents/ContentStatusScheduled.cs new file mode 100644 index 000000000..718679c52 --- /dev/null +++ b/tools/Migrate_01/OldEvents/ContentStatusScheduled.cs @@ -0,0 +1,52 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System; +using NodaTime; +using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Events.Contents; +using Squidex.Infrastructure; +using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Reflection; +using ContentStatusScheduledV2 = Squidex.Domain.Apps.Events.Contents.ContentStatusScheduled; + +namespace Migrate_01.OldEvents +{ + [EventType(nameof(ContentStatusScheduled))] + [Obsolete] + public sealed class ContentStatusScheduled : ContentEvent, IMigrated + { + public Status Status { get; set; } + + public Instant DueTime { get; set; } + + public IEvent Migrate() + { + var migrated = SimpleMapper.Map(this, new ContentStatusScheduledV2()); + + if (migrated.Status == default) + { + migrated.Status = Status.Draft; + } + + if (Status == Status.Archived) + { + migrated.StatusColor = StatusColors.Archived; + } + else if (Status == Status.Published) + { + migrated.StatusColor = StatusColors.Published; + } + else + { + migrated.StatusColor = StatusColors.Draft; + } + + return this; + } + } +}