mirror of https://github.com/Squidex/squidex.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
499 lines
16 KiB
499 lines
16 KiB
// ==========================================================================
|
|
// Squidex Headless CMS
|
|
// ==========================================================================
|
|
// Copyright (c) Squidex UG (haftungsbeschränkt)
|
|
// All rights reserved. Licensed under the MIT license.
|
|
// ==========================================================================
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using Squidex.Domain.Apps.Core.Apps;
|
|
using Squidex.Domain.Apps.Entities.Apps.Commands;
|
|
using Squidex.Domain.Apps.Entities.Apps.Guards;
|
|
using Squidex.Domain.Apps.Entities.Apps.Plans;
|
|
using Squidex.Domain.Apps.Entities.Apps.State;
|
|
using Squidex.Domain.Apps.Events;
|
|
using Squidex.Domain.Apps.Events.Apps;
|
|
using Squidex.Infrastructure;
|
|
using Squidex.Infrastructure.Commands;
|
|
using Squidex.Infrastructure.EventSourcing;
|
|
using Squidex.Infrastructure.Log;
|
|
using Squidex.Infrastructure.Reflection;
|
|
using Squidex.Infrastructure.States;
|
|
using Squidex.Shared.Users;
|
|
|
|
namespace Squidex.Domain.Apps.Entities.Apps
|
|
{
|
|
public class AppDomainObject : DomainObject<AppState>
|
|
{
|
|
private readonly InitialPatterns initialPatterns;
|
|
private readonly IAppPlansProvider appPlansProvider;
|
|
private readonly IAppPlanBillingManager appPlansBillingManager;
|
|
private readonly IUserResolver userResolver;
|
|
|
|
public AppDomainObject(IStore<DomainId> store, ISemanticLog log,
|
|
InitialPatterns initialPatterns,
|
|
IAppPlansProvider appPlansProvider,
|
|
IAppPlanBillingManager appPlansBillingManager,
|
|
IUserResolver userResolver)
|
|
: base(store, log)
|
|
{
|
|
Guard.NotNull(initialPatterns, nameof(initialPatterns));
|
|
Guard.NotNull(userResolver, nameof(userResolver));
|
|
Guard.NotNull(appPlansProvider, nameof(appPlansProvider));
|
|
Guard.NotNull(appPlansBillingManager, nameof(appPlansBillingManager));
|
|
|
|
this.userResolver = userResolver;
|
|
this.appPlansProvider = appPlansProvider;
|
|
this.appPlansBillingManager = appPlansBillingManager;
|
|
this.initialPatterns = initialPatterns;
|
|
}
|
|
|
|
protected override bool IsDeleted()
|
|
{
|
|
return Snapshot.IsArchived;
|
|
}
|
|
|
|
protected override bool CanAcceptCreation(ICommand command)
|
|
{
|
|
return command is CreateApp;
|
|
}
|
|
|
|
protected override bool CanAccept(ICommand command)
|
|
{
|
|
return command is AppUpdateCommand update && Equals(update?.AppId?.Id, Snapshot.Id);
|
|
}
|
|
|
|
public override Task<object?> ExecuteAsync(IAggregateCommand command)
|
|
{
|
|
switch (command)
|
|
{
|
|
case CreateApp createApp:
|
|
return CreateReturn(createApp, c =>
|
|
{
|
|
GuardApp.CanCreate(c);
|
|
|
|
Create(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UpdateApp updateApp:
|
|
return UpdateReturn(updateApp, c =>
|
|
{
|
|
GuardApp.CanUpdate(c);
|
|
|
|
Update(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UploadAppImage uploadImage:
|
|
return UpdateReturn(uploadImage, c =>
|
|
{
|
|
GuardApp.CanUploadImage(c);
|
|
|
|
UploadImage(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case RemoveAppImage removeImage:
|
|
return UpdateReturn(removeImage, c =>
|
|
{
|
|
GuardApp.CanRemoveImage(c);
|
|
|
|
RemoveImage(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case AssignContributor assignContributor:
|
|
return UpdateReturnAsync(assignContributor, async c =>
|
|
{
|
|
await GuardAppContributors.CanAssign(Snapshot.Contributors, Snapshot.Roles, c, userResolver, GetPlan());
|
|
|
|
AssignContributor(c, !Snapshot.Contributors.ContainsKey(assignContributor.ContributorId));
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case RemoveContributor removeContributor:
|
|
return UpdateReturn(removeContributor, c =>
|
|
{
|
|
GuardAppContributors.CanRemove(Snapshot.Contributors, c);
|
|
|
|
RemoveContributor(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case AttachClient attachClient:
|
|
return UpdateReturn(attachClient, c =>
|
|
{
|
|
GuardAppClients.CanAttach(Snapshot.Clients, c);
|
|
|
|
AttachClient(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UpdateClient updateClient:
|
|
return UpdateReturn(updateClient, c =>
|
|
{
|
|
GuardAppClients.CanUpdate(Snapshot.Clients, c, Snapshot.Roles);
|
|
|
|
UpdateClient(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case RevokeClient revokeClient:
|
|
return UpdateReturn(revokeClient, c =>
|
|
{
|
|
GuardAppClients.CanRevoke(Snapshot.Clients, c);
|
|
|
|
RevokeClient(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case AddWorkflow addWorkflow:
|
|
return UpdateReturn(addWorkflow, c =>
|
|
{
|
|
GuardAppWorkflows.CanAdd(c);
|
|
|
|
AddWorkflow(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UpdateWorkflow updateWorkflow:
|
|
return UpdateReturn(updateWorkflow, c =>
|
|
{
|
|
GuardAppWorkflows.CanUpdate(Snapshot.Workflows, c);
|
|
|
|
UpdateWorkflow(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case DeleteWorkflow deleteWorkflow:
|
|
return UpdateReturn(deleteWorkflow, c =>
|
|
{
|
|
GuardAppWorkflows.CanDelete(Snapshot.Workflows, c);
|
|
|
|
DeleteWorkflow(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case AddLanguage addLanguage:
|
|
return UpdateReturn(addLanguage, c =>
|
|
{
|
|
GuardAppLanguages.CanAdd(Snapshot.Languages, c);
|
|
|
|
AddLanguage(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case RemoveLanguage removeLanguage:
|
|
return UpdateReturn(removeLanguage, c =>
|
|
{
|
|
GuardAppLanguages.CanRemove(Snapshot.Languages, c);
|
|
|
|
RemoveLanguage(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UpdateLanguage updateLanguage:
|
|
return UpdateReturn(updateLanguage, c =>
|
|
{
|
|
GuardAppLanguages.CanUpdate(Snapshot.Languages, c);
|
|
|
|
UpdateLanguage(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case AddRole addRole:
|
|
return UpdateReturn(addRole, c =>
|
|
{
|
|
GuardAppRoles.CanAdd(Snapshot.Roles, c);
|
|
|
|
AddRole(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case DeleteRole deleteRole:
|
|
return UpdateReturn(deleteRole, c =>
|
|
{
|
|
GuardAppRoles.CanDelete(Snapshot.Roles, c, Snapshot.Contributors, Snapshot.Clients);
|
|
|
|
DeleteRole(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UpdateRole updateRole:
|
|
return UpdateReturn(updateRole, c =>
|
|
{
|
|
GuardAppRoles.CanUpdate(Snapshot.Roles, c);
|
|
|
|
UpdateRole(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case AddPattern addPattern:
|
|
return UpdateReturn(addPattern, c =>
|
|
{
|
|
GuardAppPatterns.CanAdd(Snapshot.Patterns, c);
|
|
|
|
AddPattern(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case DeletePattern deletePattern:
|
|
return UpdateReturn(deletePattern, c =>
|
|
{
|
|
GuardAppPatterns.CanDelete(Snapshot.Patterns, c);
|
|
|
|
DeletePattern(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case UpdatePattern updatePattern:
|
|
return UpdateReturn(updatePattern, c =>
|
|
{
|
|
GuardAppPatterns.CanUpdate(Snapshot.Patterns, c);
|
|
|
|
UpdatePattern(c);
|
|
|
|
return Snapshot;
|
|
});
|
|
|
|
case ChangePlan changePlan:
|
|
return UpdateReturnAsync(changePlan, async c =>
|
|
{
|
|
GuardApp.CanChangePlan(c, Snapshot.Plan, appPlansProvider);
|
|
|
|
if (c.FromCallback)
|
|
{
|
|
ChangePlan(c);
|
|
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
var result = await appPlansBillingManager.ChangePlanAsync(c.Actor.Identifier, Snapshot.NamedId(), c.PlanId, c.Referer);
|
|
|
|
switch (result)
|
|
{
|
|
case PlanChangedResult _:
|
|
ChangePlan(c);
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
});
|
|
|
|
case ArchiveApp archiveApp:
|
|
return UpdateAsync(archiveApp, async c =>
|
|
{
|
|
await appPlansBillingManager.ChangePlanAsync(c.Actor.Identifier, Snapshot.NamedId(), null, null);
|
|
|
|
ArchiveApp(c);
|
|
});
|
|
|
|
default:
|
|
throw new NotSupportedException();
|
|
}
|
|
}
|
|
|
|
private IAppLimitsPlan GetPlan()
|
|
{
|
|
return appPlansProvider.GetPlanForApp(Snapshot).Plan;
|
|
}
|
|
|
|
public void Create(CreateApp command)
|
|
{
|
|
var appId = NamedId.Of(command.AppId, command.Name);
|
|
|
|
var events = new List<AppEvent>
|
|
{
|
|
CreateInitalEvent(command.Name),
|
|
CreateInitialLanguage()
|
|
};
|
|
|
|
if (command.Actor.IsSubject)
|
|
{
|
|
events.Add(CreateInitialOwner(command.Actor));
|
|
}
|
|
|
|
foreach (var (key, value) in initialPatterns)
|
|
{
|
|
events.Add(CreateInitialPattern(key, value));
|
|
}
|
|
|
|
foreach (var @event in events)
|
|
{
|
|
@event.Actor = command.Actor;
|
|
@event.AppId = appId;
|
|
|
|
RaiseEvent(@event);
|
|
}
|
|
}
|
|
|
|
public void ChangePlan(ChangePlan command)
|
|
{
|
|
if (string.Equals(appPlansProvider.GetFreePlan()?.Id, command.PlanId))
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppPlanReset()));
|
|
}
|
|
else
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppPlanChanged()));
|
|
}
|
|
}
|
|
|
|
public void Update(UpdateApp command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppUpdated()));
|
|
}
|
|
|
|
public void UpdateClient(UpdateClient command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppClientUpdated()));
|
|
}
|
|
|
|
public void UploadImage(UploadAppImage command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppImageUploaded { Image = new AppImage(command.File.MimeType) }));
|
|
}
|
|
|
|
public void RemoveImage(RemoveAppImage command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppImageRemoved()));
|
|
}
|
|
|
|
public void UpdateLanguage(UpdateLanguage command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppLanguageUpdated()));
|
|
}
|
|
|
|
public void AssignContributor(AssignContributor command, bool isAdded)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppContributorAssigned { IsAdded = isAdded }));
|
|
}
|
|
|
|
public void RemoveContributor(RemoveContributor command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppContributorRemoved()));
|
|
}
|
|
|
|
public void AttachClient(AttachClient command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppClientAttached()));
|
|
}
|
|
|
|
public void RevokeClient(RevokeClient command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppClientRevoked()));
|
|
}
|
|
|
|
public void AddWorkflow(AddWorkflow command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppWorkflowAdded()));
|
|
}
|
|
|
|
public void UpdateWorkflow(UpdateWorkflow command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppWorkflowUpdated()));
|
|
}
|
|
|
|
public void DeleteWorkflow(DeleteWorkflow command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppWorkflowDeleted()));
|
|
}
|
|
|
|
public void AddLanguage(AddLanguage command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppLanguageAdded()));
|
|
}
|
|
|
|
public void RemoveLanguage(RemoveLanguage command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppLanguageRemoved()));
|
|
}
|
|
|
|
public void AddPattern(AddPattern command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppPatternAdded()));
|
|
}
|
|
|
|
public void DeletePattern(DeletePattern command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppPatternDeleted()));
|
|
}
|
|
|
|
public void UpdatePattern(UpdatePattern command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppPatternUpdated()));
|
|
}
|
|
|
|
public void AddRole(AddRole command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppRoleAdded()));
|
|
}
|
|
|
|
public void DeleteRole(DeleteRole command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppRoleDeleted()));
|
|
}
|
|
|
|
public void UpdateRole(UpdateRole command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppRoleUpdated()));
|
|
}
|
|
|
|
public void ArchiveApp(ArchiveApp command)
|
|
{
|
|
RaiseEvent(SimpleMapper.Map(command, new AppArchived()));
|
|
}
|
|
|
|
private void RaiseEvent(AppEvent @event)
|
|
{
|
|
@event.AppId ??= Snapshot.NamedId();
|
|
|
|
RaiseEvent(Envelope.Create(@event));
|
|
}
|
|
|
|
private static AppCreated CreateInitalEvent(string name)
|
|
{
|
|
return new AppCreated { Name = name };
|
|
}
|
|
|
|
private static AppPatternAdded CreateInitialPattern(DomainId id, AppPattern pattern)
|
|
{
|
|
return new AppPatternAdded { PatternId = id, Name = pattern.Name, Pattern = pattern.Pattern, Message = pattern.Message };
|
|
}
|
|
|
|
private static AppLanguageAdded CreateInitialLanguage()
|
|
{
|
|
return new AppLanguageAdded { Language = Language.EN };
|
|
}
|
|
|
|
private static AppContributorAssigned CreateInitialOwner(RefToken actor)
|
|
{
|
|
return new AppContributorAssigned { ContributorId = actor.Identifier, Role = Role.Owner };
|
|
}
|
|
}
|
|
}
|
|
|