diff --git a/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs b/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs index 019171ac7..fc7f41151 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/AppGrain.cs @@ -200,10 +200,12 @@ namespace Squidex.Domain.Apps.Entities.Apps { if (result is PlanResetResult) { - c.PlanId = null; + ResetPlan(c); + } + else + { + ChangePlan(c); } - - ChangePlan(c); } return result; @@ -306,6 +308,11 @@ namespace Squidex.Domain.Apps.Entities.Apps RaiseEvent(SimpleMapper.Map(command, new AppPlanChanged())); } + public void ResetPlan(ChangePlan command) + { + RaiseEvent(SimpleMapper.Map(command, new AppPlanReset())); + } + public void AddPattern(AddPattern command) { RaiseEvent(SimpleMapper.Map(command, new AppPatternAdded())); diff --git a/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs b/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs index d5c0a2539..0bd61beda 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/AppHistoryEventsCreator.cs @@ -17,13 +17,9 @@ namespace Squidex.Domain.Apps.Entities.Apps { public class AppHistoryEventsCreator : HistoryEventsCreatorBase { - private readonly IAppPlansProvider appPlansProvider; - - public AppHistoryEventsCreator(TypeNameRegistry typeNameRegistry, IAppPlansProvider appPlansProvider) + public AppHistoryEventsCreator(TypeNameRegistry typeNameRegistry) : base(typeNameRegistry) { - Guard.NotNull(appPlansProvider, nameof(appPlansProvider)); - AddEventMessage("AppContributorAssignedEvent", "assigned {user:[Contributor]} as {[Role]}"); @@ -51,6 +47,9 @@ namespace Squidex.Domain.Apps.Entities.Apps AddEventMessage( "changed plan to {[Plan]}"); + AddEventMessage( + "resetted plan"); + AddEventMessage( "added language {[Language]}"); @@ -80,7 +79,6 @@ namespace Squidex.Domain.Apps.Entities.Apps AddEventMessage( "updated role {[Name]}"); - this.appPlansProvider = appPlansProvider; } protected Task On(AppContributorRemoved @event) @@ -209,22 +207,30 @@ namespace Squidex.Domain.Apps.Entities.Apps .AddParameter("Name", @event.Name)); } + protected Task On(AppRoleDeleted @event) + { + const string channel = "settings.roles"; + + return Task.FromResult( + ForEvent(@event, channel) + .AddParameter("Name", @event.Name)); + } + protected Task On(AppPlanChanged @event) { const string channel = "settings.plan"; return Task.FromResult( ForEvent(@event, channel) - .AddParameter("Plan", @event.PlanId ?? appPlansProvider.GetFreePlan()?.Id ?? "free")); + .AddParameter("Plan", @event.PlanId)); } - protected Task On(AppRoleDeleted @event) + protected Task On(AppPlanReset @event) { - const string channel = "settings.roles"; + const string channel = "settings.plan"; return Task.FromResult( - ForEvent(@event, channel) - .AddParameter("Name", @event.Name)); + ForEvent(@event, channel)); } protected override Task CreateEventCoreAsync(Envelope @event) diff --git a/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs b/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs index a1176be44..4f31dbdc0 100644 --- a/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs +++ b/src/Squidex.Domain.Apps.Entities/Apps/State/AppState.cs @@ -57,6 +57,11 @@ namespace Squidex.Domain.Apps.Entities.Apps.State Plan = AppPlan.Build(@event.Actor, @event.PlanId); } + protected void On(AppPlanReset @event) + { + Plan = null; + } + protected void On(AppContributorAssigned @event) { Contributors = Contributors.Assign(@event.ContributorId, @event.Role); diff --git a/src/Squidex.Domain.Apps.Events/Apps/AppPlanChanged.cs b/src/Squidex.Domain.Apps.Events/Apps/AppPlanChanged.cs index 65e3975c2..f0ac9fdc8 100644 --- a/src/Squidex.Domain.Apps.Events/Apps/AppPlanChanged.cs +++ b/src/Squidex.Domain.Apps.Events/Apps/AppPlanChanged.cs @@ -5,11 +5,11 @@ // All rights reserved. Licensed under the MIT license. // ========================================================================== -using Squidex.Infrastructure; +using Squidex.Infrastructure.EventSourcing; namespace Squidex.Domain.Apps.Events.Apps { - [TypeName("AppPlanChanged")] + [EventType(nameof(AppPlanChanged))] public sealed class AppPlanChanged : AppEvent { public string PlanId { get; set; } diff --git a/src/Squidex.Domain.Apps.Events/Apps/AppPlanReset.cs b/src/Squidex.Domain.Apps.Events/Apps/AppPlanReset.cs new file mode 100644 index 000000000..e0995c314 --- /dev/null +++ b/src/Squidex.Domain.Apps.Events/Apps/AppPlanReset.cs @@ -0,0 +1,16 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschränkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure.EventSourcing; + +namespace Squidex.Domain.Apps.Events.Apps +{ + [EventType(nameof(AppPlanReset))] + public sealed class AppPlanReset : AppEvent + { + } +} diff --git a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs index 4113ef4cd..ecf131710 100644 --- a/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs +++ b/tests/Squidex.Domain.Apps.Entities.Tests/Apps/AppGrainTests.cs @@ -33,7 +33,8 @@ namespace Squidex.Domain.Apps.Entities.Apps private readonly string clientId = "client"; private readonly string clientNewName = "My Client"; private readonly string roleName = "My Role"; - private readonly string planId = "premium"; + private readonly string planIdPaid = "premium"; + private readonly string planIdFree = "free"; private readonly AppGrain sut; private readonly Guid patternId1 = Guid.NewGuid(); private readonly Guid patternId2 = Guid.NewGuid(); @@ -96,9 +97,9 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task ChangePlan_should_create_events_and_update_state() { - var command = new ChangePlan { PlanId = planId }; + var command = new ChangePlan { PlanId = planIdPaid }; - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planId)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planIdPaid)) .Returns(new PlanChangedResult()); await ExecuteCreateAsync(); @@ -107,23 +108,27 @@ namespace Squidex.Domain.Apps.Entities.Apps Assert.True(result.Value is PlanChangedResult); - Assert.Equal(planId, sut.Snapshot.Plan.PlanId); + Assert.Equal(planIdPaid, sut.Snapshot.Plan.PlanId); LastEvents .ShouldHaveSameEvents( - CreateEvent(new AppPlanChanged { PlanId = planId }) + CreateEvent(new AppPlanChanged { PlanId = planIdPaid }) ); } [Fact] public async Task ChangePlan_should_reset_plan_for_reset_plan() { - var command = new ChangePlan { PlanId = planId }; + var command = new ChangePlan { PlanId = planIdFree }; - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planId)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planIdPaid)) + .Returns(new PlanChangedResult()); + + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planIdFree)) .Returns(new PlanResetResult()); await ExecuteCreateAsync(); + await ExecuteChangePlanAsync(); var result = await sut.ExecuteAsync(CreateCommand(command)); @@ -133,16 +138,16 @@ namespace Squidex.Domain.Apps.Entities.Apps LastEvents .ShouldHaveSameEvents( - CreateEvent(new AppPlanChanged { PlanId = null }) + CreateEvent(new AppPlanReset()) ); } [Fact] public async Task ChangePlan_should_not_make_update_for_redirect_result() { - var command = new ChangePlan { PlanId = planId }; + var command = new ChangePlan { PlanId = planIdPaid }; - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planId)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planIdPaid)) .Returns(new RedirectToCheckoutResult(new Uri("http://squidex.io"))); await ExecuteCreateAsync(); @@ -157,7 +162,7 @@ namespace Squidex.Domain.Apps.Entities.Apps [Fact] public async Task ChangePlan_should_not_call_billing_manager_for_callback() { - var command = new ChangePlan { PlanId = planId, FromCallback = true }; + var command = new ChangePlan { PlanId = planIdPaid, FromCallback = true }; await ExecuteCreateAsync(); @@ -165,7 +170,7 @@ namespace Squidex.Domain.Apps.Entities.Apps result.ShouldBeEquivalent(new EntitySavedResult(5)); - A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planId)) + A.CallTo(() => appPlansBillingManager.ChangePlanAsync(User.Identifier, AppId, AppName, planIdPaid)) .MustNotHaveHappened(); } @@ -511,6 +516,11 @@ namespace Squidex.Domain.Apps.Entities.Apps return sut.ExecuteAsync(CreateCommand(new AddLanguage { Language = language })); } + private Task ExecuteChangePlanAsync() + { + return sut.ExecuteAsync(CreateCommand(new ChangePlan { PlanId = planIdPaid })); + } + private Task ExecuteArchiveAsync() { return sut.ExecuteAsync(CreateCommand(new ArchiveApp())); diff --git a/tools/Migrate_01/OldEvents/AppPlanChangedOld.cs b/tools/Migrate_01/OldEvents/AppPlanChangedOld.cs new file mode 100644 index 000000000..e5ae9dcec --- /dev/null +++ b/tools/Migrate_01/OldEvents/AppPlanChangedOld.cs @@ -0,0 +1,33 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Events; +using Squidex.Domain.Apps.Events.Apps; +using Squidex.Infrastructure; +using Squidex.Infrastructure.EventSourcing; +using Squidex.Infrastructure.Reflection; + +namespace Migrate_01.OldEvents +{ + [TypeName("AppPlanChanged")] + public sealed class AppPlanChangedOld : AppEvent, IMigrated + { + public string PlanId { get; set; } + + public IEvent Migrate() + { + if (!string.IsNullOrWhiteSpace(PlanId)) + { + return SimpleMapper.Map(this, new AppPlanChanged()); + } + else + { + return SimpleMapper.Map(this, new AppPlanReset()); + } + } + } +}