diff --git a/zero.Core/ApplicationBuilderExtensions.cs b/zero.Core/ApplicationBuilderExtensions.cs
deleted file mode 100644
index 748ecebd..00000000
--- a/zero.Core/ApplicationBuilderExtensions.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-
-namespace zero;
-
-public static class ApplicationBuilderExtensions
-{
- public static IZeroApplicationBuilder UseZero(this IApplicationBuilder app) => new ZeroApplicationBuilder(app);
-}
diff --git a/zero.Core/Applications/Application.cs b/zero.Core/Applications/Application.cs
deleted file mode 100644
index 6e723a23..00000000
--- a/zero.Core/Applications/Application.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-namespace zero.Applications;
-
-///
-/// An application is a website or app. zero can host multiple websites at once which share common assets
-///
-public class Application
-{
- ///
- /// Raven database name for application data
- ///
- public string Database { get; set; }
-
- ///
- /// Full company or product name
- ///
- public string FullName { get; set; }
-
- ///
- /// Generic contact email. Can be used in various locations
- ///
- public string Email { get; set; }
-
- ///
- /// Image of the application
- ///
- public string ImageId { get; set; }
-
- ///
- /// Simple image of the application (can be used as favicon)
- ///
- public string IconId { get; set; }
-
- ///
- /// All assigned domains for this application
- ///
- public Uri[] Domains { get; set; } = Array.Empty();
-
- ///
- /// Features which are enabled for this application.
- /// Can be user-defined and affect both backoffice and frontend
- ///
- public List Features { get; set; } = new();
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/ApplicationOptions.cs b/zero.Core/Applications/ApplicationOptions.cs
deleted file mode 100644
index 4243c48c..00000000
--- a/zero.Core/Applications/ApplicationOptions.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-//namespace zero.Applications;
-
-//public class ApplicationOptions
-//{
-// public ApplicationOptions()
-// {
-// EnableMultiple = false;
-// }
-
-
-// public bool EnableMultiple { get; set; }
-//}
diff --git a/zero.Core/Applications/ApplicationRegistration.cs b/zero.Core/Applications/ApplicationRegistration.cs
deleted file mode 100644
index 75ad3637..00000000
--- a/zero.Core/Applications/ApplicationRegistration.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-namespace zero.Applications;
-
-public class ApplicationRegistration
-{
- ///
- /// Alias for this tenant
- ///
- public string Key { get; set; }
-
- ///
- /// Name of the tenant
- ///
- public string Name { get; set; }
-
- ///
- /// Raven database name for application data
- ///
- public string Database { get; set; }
-
- ///
- /// Generic contact email. Can be used in various locations
- ///
- public string Email { get; set; }
-
- ///
- /// All assigned domains for this application
- ///
- public Uri[] Domains { get; set; } = Array.Empty();
-
- ///
- /// Features which are enabled for this application.
- /// Can be user-defined and affect both backoffice and frontend
- ///
- public List Features { get; set; } = new();
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/ApplicationRegistry.cs b/zero.Core/Applications/ApplicationRegistry.cs
deleted file mode 100644
index 2e275865..00000000
--- a/zero.Core/Applications/ApplicationRegistry.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-namespace zero.Applications;
-
-public class ApplicationRegistry : IApplicationRegistry
-{
- protected IZeroOptions Options { get; set; }
-
-
- public ApplicationRegistry(IZeroOptions options)
- {
- Options = options;
- }
-
-
- ///
- public Task> GetAll()
- {
- return Task.FromResult>(Options.Applications);
- }
-}
-
-
-public interface IApplicationRegistry
-{
- ///
- /// Get all registered applications
- ///
- Task> GetAll();
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/ApplicationResolver.cs b/zero.Core/Applications/ApplicationResolver.cs
deleted file mode 100644
index 0dbb9f17..00000000
--- a/zero.Core/Applications/ApplicationResolver.cs
+++ /dev/null
@@ -1,260 +0,0 @@
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Http.Extensions;
-using Microsoft.Extensions.Logging;
-using Raven.Client.Documents;
-using Raven.Client.Documents.Session;
-using System.Security.Claims;
-
-namespace zero.Applications;
-
-public class ApplicationResolver : IApplicationResolver
-{
- protected IZeroStore Store { get; private set; }
-
- protected IZeroOptions Options { get; private set; }
-
- protected ILogger Logger { get; private set; }
-
- protected IHandlerHolder Handler { get; private set; }
-
- IList _apps;
-
- ///
- /// The system application is bound to the context in case no application was resolved
- ///
- SystemApplication _systemApplication;
-
-
-
- public ApplicationResolver(IZeroStore store, IZeroOptions options, ILogger logger, IHandlerHolder handler = null)
- {
- Store = store;
- Options = options;
- Logger = logger;
- Handler = handler;
-
- _systemApplication = new()
- {
- Id = "system",
- Name = "zero system",
- Database = Options.For().Database,
- Alias = "system"
- };
- }
-
-
- ///
- public async Task Resolve(HttpContext context, ClaimsPrincipal user)
- {
- if (context?.Request == null)
- {
- Logger.LogWarning("Could not resolve application as HTTP request is null");
- return _systemApplication;
- }
-
- Application app;
-
- if (context.IsBackofficeRequest(Options.ZeroPath))
- {
- ZeroUser userEntity = await GetBackofficeUser(user);
- app = await ResolveFromBackofficeHandlers(context, userEntity) ?? _systemApplication;
- }
- else
- {
- app = await ResolveFromHandlers(context) ?? await ResolveFromRequest(context);
- }
-
- if (app == null)
- {
- Logger.LogWarning("Could not resolve application for host {host}", context.Request.Host);
- return _systemApplication;
- }
-
- return app;
- }
-
-
- ///
- public async Task ResolveFromHandlers(HttpContext context)
- {
- IList apps = await GetApplications();
- IEnumerable handlers = Handler.GetAll();
-
- foreach (IApplicationResolverHandler handler in handlers)
- {
- if (handler.TryResolve(context, apps, out Application resolved))
- {
- return resolved;
- }
- }
-
- return null;
- }
-
-
- ///
- public async Task ResolveFromBackofficeHandlers(HttpContext context, ZeroUser user)
- {
- IList apps = await GetApplications();
- IEnumerable handlers = Handler.GetAll();
-
- foreach (IBackofficeApplicationResolverHandler handler in handlers)
- {
- if (handler.TryResolve(context, apps, user, out Application resolved))
- {
- return resolved;
- }
- }
-
- return null;
- }
-
-
- ///
- public async Task ResolveFromUser(ClaimsPrincipal user)
- {
- ZeroUser userEntity = await GetBackofficeUser(user);
- return await ResolveFromUser(userEntity);
- }
-
-
- ///
- public async Task ResolveFromUser(ZeroUser user)
- {
- if (user == null)
- {
- return null;
- }
-
- string appId;
- string[] allowedAppIds = user.GetAllowedAppIds();
-
- if (!user.CurrentAppId.IsNullOrEmpty())
- {
- if (user.IsSuper || allowedAppIds.Contains(user.CurrentAppId, StringComparer.InvariantCultureIgnoreCase))
- {
- appId = user.CurrentAppId;
- }
- else
- {
- appId = user.AppId;
- }
- }
- else
- {
- appId = user.AppId;
- }
-
- if (appId.IsNullOrEmpty())
- {
- throw new Exception($"User entity ${user.Id} needs a valid AppId");
- }
-
- IAsyncDocumentSession session = Store.Session(global: true);
- return await session.LoadAsync(appId);
- }
-
-
- ///
- public Task ResolveFromRequest(HttpContext context) => ResolveFromUri(context.Request.GetEncodedUrl());
-
-
- ///
- public async Task ResolveFromUri(string uriString) => ResolveFromUriInternal(new Uri(uriString, UriKind.Absolute), await GetApplications());
-
-
- ///
- public async Task ResolveFromUri(Uri uri) => ResolveFromUriInternal(uri, await GetApplications());
-
-
- ///
- /// Get matching application from an URI
- ///
- Application ResolveFromUriInternal(Uri uri, IList apps)
- {
- foreach (Application app in apps)
- {
- if (app.Domains?.Length < 1)
- {
- Logger.LogWarning("No domains specified for app {app}", app.Id);
- continue;
- }
-
- foreach (Uri domain in app.Domains)
- {
- int compareResult = Uri.Compare(uri, domain, UriComponents.HostAndPort, UriFormat.SafeUnescaped, StringComparison.OrdinalIgnoreCase);
- if (compareResult == 0)
- {
- return app;
- }
- }
- }
-
- return null;
- }
-
-
- ///
- /// Get all applications to choose from
- ///
- async Task> GetApplications()
- {
- if (_apps != null)
- {
- return _apps;
- }
-
- IAsyncDocumentSession session = Store.Session(global: true);
- _apps = await session.Query().ToListAsync();
- return _apps;
- }
-
-
- ///
- /// Get backoffice user from claims principal
- ///
- async Task GetBackofficeUser(ClaimsPrincipal user)
- {
- string userId = user.FindFirstValue(Constants.Auth.Claims.UserId);
-
- IAsyncDocumentSession session = Store.Session(global: true);
- return await session.LoadAsync(userId);
- }
-}
-
-
-public interface IApplicationResolver
-{
- ///
- /// Resolves the current application from either the backoffice user (in case it is backoffice request)
- /// or the domain (in case it is frontend request).
- ///
- Task Resolve(HttpContext context, ClaimsPrincipal user);
-
- ///
- /// Resolves the current application from the request path
- ///
- Task ResolveFromRequest(HttpContext context);
-
- ///
- /// Get matching application from an URI string
- ///
- Task ResolveFromUri(string uriString);
-
- ///
- /// Get matching application from an URI
- ///
- Task ResolveFromUri(Uri uri);
-
- ///
- /// Resolves the current application from the logged-in backoffice user.
- /// This method won't return apps the user has no access to.
- ///
- Task ResolveFromUser(ClaimsPrincipal user);
-
- ///
- /// Resolves the current application from a user.
- /// This method won't return apps the user has no access to.
- ///
- Task ResolveFromUser(ZeroUser user);
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/IApplicationResolverHandler.cs b/zero.Core/Applications/IApplicationResolverHandler.cs
deleted file mode 100644
index 26800c07..00000000
--- a/zero.Core/Applications/IApplicationResolverHandler.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using Microsoft.AspNetCore.Http;
-
-namespace zero.Applications;
-
-public interface IApplicationResolverHandler : IHandler
-{
- bool TryResolve(HttpContext context, IEnumerable applications, out Application resolved);
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/IBackofficeApplicationResolverHandler.cs b/zero.Core/Applications/IBackofficeApplicationResolverHandler.cs
deleted file mode 100644
index 3946fc5c..00000000
--- a/zero.Core/Applications/IBackofficeApplicationResolverHandler.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using Microsoft.AspNetCore.Http;
-
-namespace zero.Applications;
-
-public interface IBackofficeApplicationResolverHandler : IHandler
-{
- bool TryResolve(HttpContext context, IEnumerable applications, ZeroUser user, out Application resolved);
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/SystemApplication.cs b/zero.Core/Applications/SystemApplication.cs
deleted file mode 100644
index 3c13d2d5..00000000
--- a/zero.Core/Applications/SystemApplication.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace zero.Applications;
-
-public sealed class SystemApplication : Application
-{
-}
\ No newline at end of file
diff --git a/zero.Core/Applications/ZeroApplicationModule.cs b/zero.Core/Applications/ZeroApplicationModule.cs
deleted file mode 100644
index 356719b5..00000000
--- a/zero.Core/Applications/ZeroApplicationModule.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace zero.Applications;
-
-internal class ZeroApplicationModule : ZeroModule
-{
- public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
- {
- services.AddScoped();
- services.AddScoped();
- //services.AddOptions().Bind(configuration.GetSection("Zero:Applications"));
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscovery.cs b/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscovery.cs
deleted file mode 100644
index c1ffceaf..00000000
--- a/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscovery.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-using Microsoft.AspNetCore.Mvc.ApplicationParts;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyModel;
-using System.Reflection;
-
-namespace zero.Architecture;
-
-public class AssemblyDiscovery : IAssemblyDiscovery
-{
- public static IAssemblyDiscovery Current;
-
- AssemblyDiscoveryContext Context;
-
- IMvcBuilder Mvc;
-
-
-
- public AssemblyDiscovery(IMvcBuilder mvc)
- {
- Mvc = mvc;
- Context = new AssemblyDiscoveryContext();
- Current = this;
- }
-
-
- ///
- public void Execute(IEnumerable rules)
- {
- List assemblies = new List();
- DependencyContext dependencyContext = DependencyContext.Load(Context.EntryAssembly);
-
- if (dependencyContext == null)
- {
- return;
- }
-
- string[] existingLibs = Mvc.PartManager.ApplicationParts.OfType().Select(p => p.Name).ToArray();
-
- IEnumerable libraries = dependencyContext.RuntimeLibraries.Where(lib => !existingLibs.Contains(lib.Name, StringComparer.OrdinalIgnoreCase));
-
- foreach (RuntimeLibrary library in libraries)
- {
- if (rules.Any(rule => rule.IsValid(library, Context)))
- {
- IEnumerable libraryAssemblies = library.GetDefaultAssemblyNames(dependencyContext).Select(name => Assembly.Load(name));
-
- foreach (Assembly assembly in libraryAssemblies)
- {
- Mvc.AddApplicationPart(assembly);
- }
- }
- }
- }
-
-
- ///
- public void AddAssembly(Assembly assembly)
- {
- string[] existingLibs = Mvc.PartManager.ApplicationParts.OfType().Select(p => p.Name).ToArray();
-
- if (!existingLibs.Contains(assembly.GetName().Name))
- {
- Mvc.AddApplicationPart(assembly);
- }
- }
-
-
- ///
- public IEnumerable GetTypes(bool allowGenerics = false) => GetTypes(typeof(TService), allowGenerics);
-
- ///
- public IEnumerable GetTypes(IEnumerable parts, bool allowGenerics = false) => GetTypes(typeof(TService), parts, allowGenerics);
-
- ///
- public IEnumerable GetTypes(Type serviceType, bool allowGenerics = false) => GetAllClassTypes(allowGenerics).Where(t => serviceType.GetTypeInfo().IsAssignableFrom(t) && t.AsType() != serviceType);
-
- ///
- public IEnumerable GetTypes(Type serviceType, IEnumerable parts, bool allowGenerics = false) => GetAllClassTypes(parts, allowGenerics).Where(t => serviceType.GetTypeInfo().IsAssignableFrom(t) && t.AsType() != serviceType);
-
- ///
- public IEnumerable GetAllClassTypes(bool allowGenerics = false) => GetAllTypes().Where(t => t.IsClass && !t.IsAbstract && (allowGenerics || !t.ContainsGenericParameters));
-
- ///
- public IEnumerable GetAllClassTypes(IEnumerable parts, bool allowGenerics = false) => GetAllTypes(parts).Where(t => t.IsClass && !t.IsAbstract && (allowGenerics || !t.ContainsGenericParameters));
-
- ///
- public IEnumerable GetAssemblies() => Mvc.PartManager.ApplicationParts.OfType().Select(p => p.Assembly);
-
- ///
- public IEnumerable GetAssemblies(IEnumerable parts) => parts.OfType().Select(p => p.Assembly);
-
- ///
- public IEnumerable GetAllTypes() => Mvc.PartManager.ApplicationParts.OfType().SelectMany(p => p.Types);
-
- ///
- public IEnumerable GetAllTypes(IEnumerable parts) => parts.OfType().SelectMany(p => p.Types);
-}
-
-
-public interface IAssemblyDiscovery
-{
- ///
- /// Discovers runtime assemblies based on the given rules
- ///
- void Execute(IEnumerable rules);
-
- ///
- /// Manually add an assembly
- ///
- void AddAssembly(Assembly assembly);
-
- ///
- /// Get all discovered types which implement a certain service
- ///
- IEnumerable GetTypes(bool allowGenerics = false);
-
- ///
- /// Get all discovered types which implement a certain service
- ///
- IEnumerable GetTypes(IEnumerable parts, bool allowGenerics = false);
-
- ///
- /// Get all discovered types which implement a certain service
- ///
- IEnumerable GetTypes(Type serviceType, bool allowGenerics = false);
-
- ///
- /// Get all discovered types which implement a certain service
- ///
- IEnumerable GetTypes(Type serviceType, IEnumerable parts, bool allowGenerics = false);
-
- ///
- /// Get all registered types
- ///
- IEnumerable GetAllTypes();
-
- ///
- /// Get all registered types
- ///
- IEnumerable GetAllTypes(IEnumerable parts);
-
- ///
- /// Get all registered types
- ///
- IEnumerable GetAllClassTypes(bool allowGenerics = false);
-
- ///
- /// Get all registered types
- ///
- IEnumerable GetAllClassTypes(IEnumerable parts, bool allowGenerics = false);
-
- ///
- /// Get all registered assemblies
- ///
- IEnumerable GetAssemblies();
-
- ///
- /// Get all registered assemblies
- ///
- IEnumerable GetAssemblies(IEnumerable parts);
-}
diff --git a/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscoveryContext.cs b/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscoveryContext.cs
deleted file mode 100644
index 33cd0836..00000000
--- a/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscoveryContext.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-using System.Reflection;
-
-namespace zero.Architecture;
-
-public class AssemblyDiscoveryContext
-{
- public Assembly EntryAssembly { get; private set; }
-
- public string EntryAssemblyName { get; private set; }
-
- public bool HasEntryAssembly => EntryAssembly != null;
-
-
- public AssemblyDiscoveryContext()
- {
- EntryAssembly = Assembly.GetEntryAssembly();
- EntryAssemblyName = EntryAssembly?.GetName().Name;
- }
-
-
- public AssemblyDiscoveryContext(Assembly entryAssembly)
- {
- EntryAssembly = entryAssembly;
- EntryAssemblyName = entryAssembly.GetName().Name;
- }
-}
diff --git a/zero.Core/Architecture/AssemblyDiscovery/IAssemblyDiscoveryRule.cs b/zero.Core/Architecture/AssemblyDiscovery/IAssemblyDiscoveryRule.cs
deleted file mode 100644
index d2f4a5ab..00000000
--- a/zero.Core/Architecture/AssemblyDiscovery/IAssemblyDiscoveryRule.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using Microsoft.Extensions.DependencyModel;
-
-namespace zero.Architecture;
-
-public interface IAssemblyDiscoveryRule
-{
- ///
- /// Returns true if the specified runtime library should be added to
- /// the ApplicationPartManager; otherwise false.
- ///
- bool IsValid(RuntimeLibrary library, AssemblyDiscoveryContext context);
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/AssemblyDiscovery/ZeroAssemblyDiscoveryRule.cs b/zero.Core/Architecture/AssemblyDiscovery/ZeroAssemblyDiscoveryRule.cs
deleted file mode 100644
index be1f7ff7..00000000
--- a/zero.Core/Architecture/AssemblyDiscovery/ZeroAssemblyDiscoveryRule.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using Microsoft.Extensions.DependencyModel;
-
-namespace zero.Architecture;
-
-public class ZeroAssemblyDiscoveryRule : IAssemblyDiscoveryRule
-{
- const string ZERO_PREFIX = "zero.";
-
- ///
- public bool IsValid(RuntimeLibrary library, AssemblyDiscoveryContext context)
- {
- StringComparison casing = StringComparison.OrdinalIgnoreCase;
- // TODO we need to auto-add assemblies and discover their types which have implementations of IZeroPlugin
- return library.Name.StartsWith(ZERO_PREFIX, casing) || (context.HasEntryAssembly && library.Name.Contains(context.EntryAssemblyName, casing));
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Blueprints/Blueprint.cs b/zero.Core/Architecture/Blueprints/Blueprint.cs
deleted file mode 100644
index 49ec7b8c..00000000
--- a/zero.Core/Architecture/Blueprints/Blueprint.cs
+++ /dev/null
@@ -1,216 +0,0 @@
-using System.Linq.Expressions;
-using System.Text.Json.Serialization;
-
-namespace zero.Architecture;
-
-public sealed class DefaultShallowBlueprint : Blueprint
-{
- public DefaultShallowBlueprint(Type type) : base()
- {
- Alias = "shallow.default";
- ContentType = type;
- LockAll();
- }
-
-
- protected override BlueprintField AddField(Expression> selector)
- {
- throw new InvalidOperationException("Shallow blueprints can not contain unlocked fields");
- }
-}
-
-///
-///
-///
-public class Blueprint : Blueprint where T : ZeroEntity, new()
-{
- public List> UnlockedFields { get; private set; } = new();
-
- ///
- /// These fields are not copied by the ObjectCloner
- /// as they are either locked or copied manually by ApplyDefaults()
- ///
- protected static string[] DefaultUncopyFields { get; set; } = new[] { "id", "url", "name", "alias", "key", "sort", "isActive", "hash", "languageId", "createdById", "createdDate", "lastModifiedById", "lastModifiedDate", "blueprint" };
-
-
- public Blueprint() : base(typeof(T)) { }
-
-
- ///
- /// Merges blueprint data into a model based on the configuration
- ///
- public virtual T Apply(T blueprint, T model)
- {
- // reset blueprint options for model in case no blueprint was found
- if (blueprint == null || model.Blueprint == null)
- {
- model.Blueprint = null;
- return model;
- }
-
- // copy all properties which are synced from the blueprint to the model
- ApplyDefaults(blueprint, model);
- ObjectCopycat.CopyProperties(blueprint, model, DefaultUncopyFields.Union(model.Blueprint.Desync).ToArray());
-
- return model;
- }
-
-
- ///
- public override ZeroEntity Apply(ZeroEntity blueprint, ZeroEntity model) => Apply(blueprint as T, model as T);
-
-
- ///
- /// Update default entity data
- ///
- protected virtual void ApplyDefaults(T blueprint, T model)
- {
- if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.Name), StringComparer))
- {
- model.Name = blueprint.Name;
- model.Alias = blueprint.Alias;
- }
- if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.Key), StringComparer))
- {
- model.Key = blueprint.Key;
- }
- if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.Sort), StringComparer))
- {
- model.Sort = blueprint.Sort;
- }
- if (!model.Blueprint.Desync.Contains(nameof(ZeroEntity.IsActive), StringComparer))
- {
- model.IsActive = blueprint.IsActive;
- }
-
- // these values can't be overridden
- model.Hash = blueprint.Hash;
- model.LanguageId = blueprint.LanguageId;
- model.CreatedById = blueprint.CreatedById;
- model.CreatedDate = blueprint.CreatedDate;
- model.LastModifiedById = blueprint.LastModifiedById;
- model.LastModifiedDate = blueprint.LastModifiedDate;
- }
-
-
- ///
- /// Lock a field so it always get synchronized no and cannot be changed
- ///
- public virtual void LockAll()
- {
- UnlockedFields = new();
- }
-
-
- ///
- /// Lock a field so it always get synchronized no and cannot be changed
- ///
- public virtual void Lock(Expression> selector)
- {
- RemoveField(selector);
- }
-
-
- public virtual void Unlock(Expression> selector)
- {
- AddField(selector);
- }
-
-
- public virtual void UnlockDefaults()
- {
- AddField(x => x.Name);
- AddField(x => x.Alias);
- AddField(x => x.Sort);
- AddField(x => x.Key);
- AddField(x => x.IsActive);
- }
-
-
- ///
- public override IEnumerable GetUnlockedFieldNames()
- {
- foreach (BlueprintField field in UnlockedFields)
- {
- yield return field.FieldName.ToCamelCaseId();
- }
- }
-
-
- ///
- /// Get existing field or create a new one
- ///
- protected virtual BlueprintField AddField(Expression> selector)
- {
- BlueprintField tempField = new(selector);
- BlueprintField storedField = UnlockedFields.FirstOrDefault(x => x.FieldName.Equals(tempField.FieldName, StringComparison.InvariantCultureIgnoreCase));
-
- if (storedField != null)
- {
- return storedField;
- }
-
- UnlockedFields.Add(tempField);
- return tempField;
- }
-
-
- ///
- /// Removes a field
- ///
- protected virtual void RemoveField(Expression> selector)
- {
- BlueprintField tempField = new(selector);
-
- if (tempField != null)
- {
- UnlockedFields.RemoveAll(x => x.FieldName.Equals(tempField.FieldName, StringComparison.InvariantCultureIgnoreCase));
- }
- }
-}
-
-
-///
-///
-///
-public abstract class Blueprint
-{
- ///
- /// Type of the associated entity
- ///
- [JsonIgnore]
- public Type ContentType { get; protected set; }
-
- public string Alias { get; protected set; }
-
- ///
- /// String comparer for property name comparison
- ///
- protected readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase;
-
-
- public Blueprint(Type type)
- {
- ContentType = type;
- Alias = type.Name.ToCamelCaseId();
- }
-
- ///
- /// Merges blueprint data into a model based on the configuration
- ///
- public abstract ZeroEntity Apply(ZeroEntity blueprint, ZeroEntity model);
-
- ///
- /// Get all fields which have been unlocked
- ///
- public abstract IEnumerable GetUnlockedFieldNames();
-}
-
-
-public class DefaultBlueprint : Blueprint where T : ZeroEntity, new()
-{
- public DefaultBlueprint(Action> expression = null) : base()
- {
- expression?.Invoke(this);
- }
-}
diff --git a/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs b/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs
deleted file mode 100644
index cb921118..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintChildInterceptor.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-namespace zero.Architecture;
-
-public class BlueprintChildInterceptor : Interceptor, IBlueprintInterceptor
-{
- string configuredZeroDatabase;
-
-
- public BlueprintChildInterceptor(IZeroContext context)
- {
- Gravity = -1;
- configuredZeroDatabase = context.Options.For().Database;
- }
-
- ///
- /// Only run this interceptor when the database is an app database
- ///
- public override bool CanHandle(InterceptorParameters args, Type modelType) => args.Context.Store.ResolvedDatabase != configuredZeroDatabase;
-
-
- ///
- public override Task> Deleting(InterceptorParameters args, ZeroEntity model)
- {
- if (model.Blueprint == null)
- {
- return Task.FromResult>(default);
- }
-
- InterceptorResult result = new();
- result.Result = Result.Fail("@blueprint.errors.cannotDeleteChild");
- return Task.FromResult(result);
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Blueprints/BlueprintConfiguration.cs b/zero.Core/Architecture/Blueprints/BlueprintConfiguration.cs
deleted file mode 100644
index 5e3472f6..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintConfiguration.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace zero.Architecture;
-
-///
-/// Defines a base entity which is synced and properties which are overridden
-///
-public class BlueprintConfiguration
-{
- ///
- /// Id of the entity the synchronisation is based upon
- ///
- public string TargetId { get; set; }
-
- ///
- /// A shallow copy of a blueprint can not be changed and is always fully synchronised with the parent entity
- ///
- public bool IsShallow { get; set; }
-
- ///
- /// Properties which are not synced and have their own values
- ///
- public string[] Desync { get; set; } = Array.Empty();
-
- ///
- /// Additional custom sync options
- ///
- public Dictionary Options = new();
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Blueprints/BlueprintField.cs b/zero.Core/Architecture/Blueprints/BlueprintField.cs
deleted file mode 100644
index dd47a5e4..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintField.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Linq.Expressions;
-using System.Reflection;
-
-namespace zero.Architecture;
-
-public class BlueprintField where T : ZeroEntity
-{
- public Expression> Expression { get; private set; }
-
- public PropertyInfo PropertyInfo { get; private set; }
-
- public string FieldName { get; private set; }
-
- Action _applyHook { get; set; }
-
- Func _selectorFunc = null;
-
-
- internal BlueprintField(Expression> selector)
- {
- Expression = selector;
- FieldName = selector.GetPropertyPath(out MemberExpression member);
- PropertyInfo = member?.Member as PropertyInfo;
-
- if (PropertyInfo == null)
- {
- throw new ArgumentException("selector parameter has to be a property selector");
- }
-
- if (FieldName.IsNullOrEmpty())
- {
- throw new Exception("Could not find a matching field name");
- }
- }
-
-
- public virtual void Apply(T blueprint, T model)
- {
- if (_applyHook != null)
- {
- _applyHook(blueprint, model);
- return;
- }
-
- _selectorFunc ??= Expression.Compile();
- PropertyInfo.SetValue(model, _selectorFunc(blueprint));
- }
-
-
- public virtual void OnUpdate(Action onUpdate)
- {
- _applyHook = onUpdate;
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Blueprints/BlueprintInterceptor.cs b/zero.Core/Architecture/Blueprints/BlueprintInterceptor.cs
deleted file mode 100644
index ed912175..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintInterceptor.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-using Microsoft.Extensions.Logging;
-using Raven.Client.Documents;
-using Raven.Client.Documents.Session;
-
-namespace zero.Architecture;
-
-public class BlueprintInterceptor : Interceptor, IBlueprintInterceptor
-{
- protected IZeroContext Context { get; set; }
-
- protected IZeroStore Store { get; set; }
-
- protected ILogger Logger { get; set; }
-
- protected IBlueprintService BlueprintService { get; set; }
-
- IList apps;
-
- string configuredZeroDatabase;
-
-
- public BlueprintInterceptor(IZeroContext context, IZeroStore store, ILogger logger, IBlueprintService blueprintService)
- {
- Gravity = -1;
- Context = context;
- Store = store;
- Logger = logger;
- BlueprintService = blueprintService;
- configuredZeroDatabase = context.Options.For().Database;
- }
-
- ///
- /// Only run when operations are on the zero database
- ///
- public override bool CanHandle(InterceptorParameters args, Type modelType) => args.Context.Store.ResolvedDatabase == configuredZeroDatabase;
-
-
- ///
- public override Task Created(InterceptorParameters args, ZeroEntity model) => Saved(args, model, false);
-
-
- ///
- public override Task Updated(InterceptorParameters args, ZeroEntity model) => Saved(args, model, true);
-
-
- ///
- public async Task Saved(InterceptorParameters args, ZeroEntity model, bool update = false)
- {
- if (!BlueprintService.TryGetBlueprint(model, out Blueprint blueprint))
- {
- blueprint = new DefaultShallowBlueprint(model.GetType());
- }
-
- int count = 0;
-
- foreach (Application app in await GetApplications())
- {
- using ZeroContextScope scope = Context.CreateScope(app);
- IZeroDocumentSession session = scope.Store.Session(scope.Database);
-
- ZeroEntity child = await session.LoadAsync(model.Id);
-
- if (child == null)
- {
- child = ObjectCopycat.Clone(model);
- child.Blueprint = new()
- {
- TargetId = model.Id
- };
- }
- else
- {
- blueprint.Apply(model, child);
- }
-
- count += 1;
-
- InterceptorInstruction interceptor = update ? args.Interceptors.ForUpdate(model) : args.Interceptors.ForCreate(model);
- interceptor.Filter(x => x is not IBlueprintInterceptor);
-
- await interceptor.Start(args.Operations);
- await session.StoreAsync(child);
- await session.SaveChangesAsync();
- await interceptor.Complete();
- await session.SaveChangesAsync();
- }
-
- Logger.LogDebug("Blueprint: Synced {count} children for {name} ({id})", count, model.Name, model.Id);
- }
-
-
- ///
- public override async Task Deleted(InterceptorParameters args, ZeroEntity model)
- {
- if (!BlueprintService.TryGetBlueprint(model, out Blueprint blueprint))
- {
- return;
- }
-
- int count = 0;
-
- foreach (Application app in await GetApplications())
- {
- using ZeroContextScope scope = Context.CreateScope(app);
- IZeroDocumentSession session = scope.Store.Session(scope.Database);
-
- count += 1;
-
- InterceptorInstruction interceptor = args.Interceptors.ForDelete(model);
- interceptor.Filter(x => x is not IBlueprintInterceptor);
-
- await interceptor.Start(args.Operations);
- session.Delete(model.Id);
- await session.SaveChangesAsync();
- await interceptor.Complete();
- await session.SaveChangesAsync();
- }
-
- Logger.LogDebug("Blueprint: Deleted {count} children for {name} ({id})", count, model.Name, model.Id);
- }
-
-
- ///
- /// Get all applications to choose from
- ///
- async Task> GetApplications()
- {
- if (apps != null)
- {
- return apps;
- }
-
- IAsyncDocumentSession session = Store.Session(global: true);
- apps = await session.Query().ToListAsync();
- return apps;
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Blueprints/BlueprintOptions.cs b/zero.Core/Architecture/Blueprints/BlueprintOptions.cs
deleted file mode 100644
index f518c872..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintOptions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-namespace zero.Architecture;
-
-public class BlueprintOptions : List
-{
- public bool Enabled { get; set; } = false;
-
- public void Add() where T : Blueprint, new()
- {
- base.Add(new T());
- }
-
- public void Add(Blueprint implementation) where T : ZeroEntity, new()
- {
- base.Add(implementation);
- }
-
- public void Add(Action> createExpression = null) where T : ZeroEntity, new()
- {
- base.Add(new DefaultBlueprint(createExpression));
- }
-}
diff --git a/zero.Core/Architecture/Blueprints/BlueprintService.cs b/zero.Core/Architecture/Blueprints/BlueprintService.cs
deleted file mode 100644
index fb37ab45..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintService.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-namespace zero.Architecture;
-
-public class BlueprintService : IBlueprintService
-{
- protected IZeroOptions Options { get; set; }
-
- protected IReadOnlyCollection Blueprints { get; set; }
-
-
- public BlueprintService(IZeroOptions options)
- {
- Options = options;
- Blueprints = Options.For();
- }
-
-
- ///
- public bool IsEnabled(T model) => IsEnabled(model.GetType());
-
-
- ///
- public bool IsEnabled()=> IsEnabled(typeof(T));
-
-
- ///
- public bool IsEnabled(Type type) => Blueprints.Any(x => x.ContentType.IsAssignableFrom(type));
-
-
- ///
- public bool TryGetBlueprint(T model, out Blueprint blueprint) => TryGetBlueprint(model.GetType(), out blueprint);
-
-
- ///
- public bool TryGetBlueprint(out Blueprint blueprint) => TryGetBlueprint(typeof(T), out blueprint);
-
-
- ///
- public bool TryGetBlueprint(Type type, out Blueprint blueprint)
- {
- blueprint = Blueprints.FirstOrDefault(x => x.ContentType.IsAssignableFrom(type));
- return blueprint != null;
- }
-
- ///
- public Dictionary GetAllBlueprints()
- {
- return Blueprints.ToDictionary(x => x.ContentType, x => x);
- }
-}
-
-
-public interface IBlueprintService
-{
- ///
- /// Check whether blueprinting functionality is enabled for a certain entity
- ///
- bool IsEnabled();
-
- ///
- /// Check whether blueprinting functionality is enabled for a certain entity
- ///
- bool IsEnabled(T model);
-
- bool IsEnabled(Type type);
-
- bool TryGetBlueprint(T model, out Blueprint blueprint);
-
- bool TryGetBlueprint(out Blueprint blueprint);
-
- bool TryGetBlueprint(Type type, out Blueprint blueprint);
-
- ///
- /// Get all registered blueprint configurations
- ///
- Dictionary GetAllBlueprints();
-}
diff --git a/zero.Core/Architecture/Blueprints/BlueprintStatus.cs b/zero.Core/Architecture/Blueprints/BlueprintStatus.cs
deleted file mode 100644
index 8ea26131..00000000
--- a/zero.Core/Architecture/Blueprints/BlueprintStatus.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace zero.Architecture;
-
-public enum BlueprintStatus
-{
- ///
- /// This entity is standalone
- ///
- Standalone = 0,
- ///
- /// This entity is a blueprint
- ///
- Parent = 1,
- ///
- /// This entity is a child of blueprint
- ///
- Child = 2
-}
diff --git a/zero.Core/Architecture/Blueprints/IBlueprintInterceptor.cs b/zero.Core/Architecture/Blueprints/IBlueprintInterceptor.cs
deleted file mode 100644
index 564f2ad4..00000000
--- a/zero.Core/Architecture/Blueprints/IBlueprintInterceptor.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace zero.Architecture;
-
-public interface IBlueprintInterceptor
-{
-
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Plugins/IZeroBuiltInPlugin.cs b/zero.Core/Architecture/Plugins/IZeroBuiltInPlugin.cs
deleted file mode 100644
index 9221235b..00000000
--- a/zero.Core/Architecture/Plugins/IZeroBuiltInPlugin.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace zero.Architecture;
-
-internal interface IZeroBuiltInPlugin
-{
-
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Plugins/IZeroPlugin.cs b/zero.Core/Architecture/Plugins/IZeroPlugin.cs
deleted file mode 100644
index d7a3e424..00000000
--- a/zero.Core/Architecture/Plugins/IZeroPlugin.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Routing;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace zero.Architecture;
-
-public abstract class ZeroPlugin : IZeroPlugin
-{
- public IZeroPluginOptions Options { get; } = new ZeroPluginOptions();
-
- public virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration) { }
-
- public virtual void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) { }
-}
-
-
-public interface IZeroPlugin
-{
- IZeroPluginOptions Options { get; }
-
- void ConfigureServices(IServiceCollection services, IConfiguration configuration);
-
- void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider);
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/Plugins/ZeroPluginOptions.cs b/zero.Core/Architecture/Plugins/ZeroPluginOptions.cs
deleted file mode 100644
index a273812f..00000000
--- a/zero.Core/Architecture/Plugins/ZeroPluginOptions.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-namespace zero.Architecture;
-
-public class ZeroPluginOptions : IZeroPluginOptions
-{
- public string Name { get; set; }
-
- public string Description { get; set; }
-
- public List LocalizationPaths { get; private set; } = new List();
-
- public string PluginPath { get; set; }
-}
-
-
-public interface IZeroPluginOptions
-{
- string Name { get; set; }
-
- string Description { get; set; }
-
- List LocalizationPaths { get; }
-
- string PluginPath { get; set; }
-}
-
-
-public interface IZeroPluginStartup
-{
- Task Startup();
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/ZeroArchitectureModule.cs b/zero.Core/Architecture/ZeroArchitectureModule.cs
deleted file mode 100644
index 73aae0f8..00000000
--- a/zero.Core/Architecture/ZeroArchitectureModule.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace zero.Architecture;
-
-internal class ZeroArchitectureModule : ZeroModule
-{
- public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
- {
- services.AddScoped();
- //services.AddScoped();
- //services.AddScoped();
- services.AddOptions().Bind(configuration.GetSection("Zero:Blueprints"));
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/ZeroModule.cs b/zero.Core/Architecture/ZeroModule.cs
deleted file mode 100644
index 959cdea8..00000000
--- a/zero.Core/Architecture/ZeroModule.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Routing;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-
-namespace zero.Architecture;
-
-public abstract class ZeroModule : IZeroModule
-{
- ///
- public virtual int Order { get; } = 0;
-
- ///
- public virtual int ConfigureOrder => Order;
-
- ///
- public virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration) { }
-
- ///
- public virtual void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) { }
-}
-
-
-public interface IZeroModule
-{
- ///
- /// Get the value to use to order startups to configure services. The default is 0.
- ///
- int Order { get; }
-
- ///
- /// Get the value to use to order startups to build the pipeline. The default is the 'Order' property.
- ///
- int ConfigureOrder { get; }
-
- ///
- /// This method gets called by the runtime. Use this method to add services to the container.
- /// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
- ///
- /// The collection of service descriptors.
- void ConfigureServices(IServiceCollection services, IConfiguration configuration);
-
- ///
- /// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- ///
- ///
- ///
- ///
- void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider);
-}
\ No newline at end of file
diff --git a/zero.Core/Architecture/ZeroModuleCollection.cs b/zero.Core/Architecture/ZeroModuleCollection.cs
deleted file mode 100644
index 8ae3278b..00000000
--- a/zero.Core/Architecture/ZeroModuleCollection.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Routing;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using System.Collections.Concurrent;
-
-namespace zero.Architecture;
-
-public class ZeroModuleCollection : ZeroModule
-{
- ConcurrentDictionary _modules = new();
-
-
- ///
- /// Get all registered modules
- ///
- public IEnumerable GetAll() => _modules.Values;
-
-
- ///
- /// Adds a zero module
- ///
- public void Add() where T : class, IZeroModule, new()
- {
- Add(new T());
- }
-
-
- ///
- /// Adds a zero module
- ///
- public void Add(T moduleInstance) where T : IZeroModule
- {
- Add(typeof(T), moduleInstance);
- }
-
-
- ///
- /// Adds a zero module
- ///
- public void Add(Type moduleType, IZeroModule moduleInstance)
- {
- if (_modules.ContainsKey(moduleType))
- {
- return;
- }
-
- _modules.TryAdd(moduleType, moduleInstance);
- }
-
-
- ///
- public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
- {
- foreach (var module in _modules.OrderBy(x => x.Value.Order))
- {
- module.Value.ConfigureServices(services, configuration);
- }
- }
-
-
- ///
- public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
- {
- foreach (var module in _modules.OrderBy(x => x.Value.ConfigureOrder))
- {
- module.Value.Configure(app, routes, serviceProvider);
- }
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Handlers/IHandler.cs b/zero.Core/Communication/Handlers/IHandler.cs
deleted file mode 100644
index c2ea5d02..00000000
--- a/zero.Core/Communication/Handlers/IHandler.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-namespace zero.Communication;
-
-public interface IHandler
-{
-}
diff --git a/zero.Core/Communication/Handlers/IHandlerHolder.cs b/zero.Core/Communication/Handlers/IHandlerHolder.cs
deleted file mode 100644
index 096c88ef..00000000
--- a/zero.Core/Communication/Handlers/IHandlerHolder.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-
-namespace zero.Communication;
-
-public class HandlerHolder : IHandlerHolder
-{
- IServiceProvider Services { get; }
-
- public HandlerHolder(IServiceProvider services)
- {
- Services = services;
- }
-
-
- public T Get() where T : IHandler
- {
- return Services.GetService();
- }
-
-
- public IEnumerable GetAll() where T : IHandler
- {
- return Services.GetService>();
- }
-}
-
-public interface IHandlerHolder
-{
- T Get() where T : IHandler;
-
- IEnumerable GetAll() where T : IHandler;
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Interceptors/Interceptor.cs b/zero.Core/Communication/Interceptors/Interceptor.cs
deleted file mode 100644
index f47498c3..00000000
--- a/zero.Core/Communication/Interceptors/Interceptor.cs
+++ /dev/null
@@ -1,207 +0,0 @@
-namespace zero.Communication;
-
-
-public abstract partial class Interceptor : Interceptor, IInterceptor where T : ZeroIdEntity
-{
- ///
- public Type ModelType { get; protected set; }
-
-
- public Interceptor()
- {
- Gravity = 0;
- ModelType = typeof(T);
- Name = ModelType.Name;
- }
-
-
- ///
- public override bool CanHandle(InterceptorParameters args, Type modelType) => ModelType.IsAssignableFrom(modelType);
-
- ///
- public virtual Task> Creating(InterceptorParameters args, T model) => Task.FromResult>(default);
-
- ///
- public sealed override async Task> Creating(InterceptorParameters args, ZeroIdEntity model) => Convert(await Creating(args, model as T));
-
- ///
- public virtual Task> Updating(InterceptorParameters args, T model) => Task.FromResult>(default);
-
- ///
- public sealed override async Task> Updating(InterceptorParameters args, ZeroIdEntity model) => Convert(await Updating(args, model as T));
-
- ///
- public virtual Task> Deleting(InterceptorParameters args, T model) => Task.FromResult>(default);
-
- ///
- public sealed override async Task> Deleting(InterceptorParameters args, ZeroIdEntity model) => Convert(await Deleting(args, model as T));
-
- ///
- public virtual Task Created(InterceptorParameters args, T model) => Task.CompletedTask;
-
- ///
- public sealed override Task Created(InterceptorParameters args, ZeroIdEntity model) => Created(args, model as T);
-
- ///
- public virtual Task Updated(InterceptorParameters args, T model) => Task.CompletedTask;
-
- ///
- public sealed override Task Updated(InterceptorParameters args, ZeroIdEntity model) => Updated(args, model as T);
-
- ///
- public virtual Task Deleted(InterceptorParameters args, T model) => Task.CompletedTask;
-
- ///
- public sealed override Task Deleted(InterceptorParameters args, ZeroIdEntity model) => Deleted(args, model as T);
-
-
- InterceptorResult Convert(InterceptorResult result)
- {
- if (result == default)
- {
- return default;
- }
-
- return new InterceptorResult()
- {
- Continue = result.Continue,
- InterceptorHash = result.InterceptorHash,
- Result = result.Result != null ? result.Result.ConvertTo(result.Result.Model) : null
- };
- }
-}
-
-
-public abstract partial class Interceptor : IInterceptor
-{
- ///
- public int Gravity { get; protected set; }
-
- ///
- public string Name { get; protected set; }
-
- ///
- public string Hash { get; protected set; }
-
-
- public Interceptor()
- {
- Gravity = 0;
- Hash = IdGenerator.Create();
- }
-
-
- ///
- public virtual bool CanHandle(InterceptorParameters args, Type modelType) => true;
-
- ///
- public virtual Task> Creating(InterceptorParameters args, ZeroIdEntity model) => Task.FromResult>(default);
-
- ///
- public virtual Task> Updating(InterceptorParameters args, ZeroIdEntity model) => Task.FromResult>(default);
-
- ///
- public virtual Task> Deleting(InterceptorParameters args, ZeroIdEntity model) => Task.FromResult>(default);
-
- ///
- public virtual Task Created(InterceptorParameters args, ZeroIdEntity model) => Task.CompletedTask;
-
- ///
- public virtual Task Updated(InterceptorParameters args, ZeroIdEntity model) => Task.CompletedTask;
-
- ///
- public virtual Task Deleted(InterceptorParameters args, ZeroIdEntity model) => Task.CompletedTask;
-}
-
-
-public interface IInterceptor : IInterceptor where T : ZeroIdEntity
-{
- ///
- /// Type of the associated model
- ///
- Type ModelType { get; }
-
- ///
- /// Called after an entity has been stored but before the session has saved its changes
- ///
- Task Created(InterceptorParameters args, T model);
-
- ///
- /// Called before an entity is stored and validated
- ///
- Task> Creating(InterceptorParameters args, T model);
-
- ///
- /// Called after an entity has been deleted but before the session has saved its changes
- ///
- Task Deleted(InterceptorParameters args, T model);
-
- ///
- /// Called before an entity is deleted
- ///
- Task> Deleting(InterceptorParameters args, T model);
-
- ///
- /// Called after an entity has been updated but before the session has saved its changes
- ///
- Task Updated(InterceptorParameters args, T model);
-
- ///
- /// Called before an entity is stored and validated
- ///
- Task> Updating(InterceptorParameters args, T model);
-}
-
-
-public interface IInterceptor
-{
- ///
- /// Interceptors with a higher gravity will run before any with lower gravity
- ///
- int Gravity { get; }
-
- ///
- /// Readable name for this interceptor
- ///
- string Name { get; }
-
- ///
- /// Hash which is used for this interceptor to be able to pass results from Start to Complete methods
- ///
- string Hash { get; }
-
- ///
- /// Whether any of the interceptor methods is allowed to run based on the parameters
- ///
- bool CanHandle(InterceptorParameters args, Type modelType);
-
- ///
- /// Called after an entity has been stored but before the session has saved its changes
- ///
- Task Created(InterceptorParameters args, ZeroIdEntity model);
-
- ///
- /// Called before an entity is stored and validated
- ///
- Task> Creating(InterceptorParameters args, ZeroIdEntity model);
-
- ///
- /// Called after an entity has been deleted but before the session has saved its changes
- ///
- Task Deleted(InterceptorParameters args, ZeroIdEntity model);
-
- ///
- /// Called before an entity is deleted
- ///
- Task> Deleting(InterceptorParameters args, ZeroIdEntity model);
-
- ///
- /// Called after an entity has been updated but before the session has saved its changes
- ///
- Task Updated(InterceptorParameters args, ZeroIdEntity model);
-
- ///
- /// Called before an entity is stored and validated
- ///
- Task> Updating(InterceptorParameters args, ZeroIdEntity model);
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Interceptors/InterceptorInstruction.cs b/zero.Core/Communication/Interceptors/InterceptorInstruction.cs
deleted file mode 100644
index 9b88512d..00000000
--- a/zero.Core/Communication/Interceptors/InterceptorInstruction.cs
+++ /dev/null
@@ -1,148 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace zero.Communication;
-
-public class InterceptorInstruction where T : ZeroIdEntity, new()
-{
- public Guid Guid { get; private set; }
-
- public InterceptorRunType Runtype { get; private set; }
-
- public T Model { get; private set; }
-
- public T PreviousModel { get; private set; }
-
- public Type ModelType { get; private set; }
-
- public Result Result { get; private set; }
-
- protected IZeroContext Context { get; private set; }
-
- protected Lazy> Interceptors { get; private set; }
-
- protected Dictionary InterceptorCache { get; private set; } = new();
-
- protected IInterceptors InterceptorHandler { get; private set; }
-
- protected ILogger Logger { get; private set; }
-
- protected Func InterceptorFilter { get; private set; } = x => true;
-
-
- internal InterceptorInstruction(IInterceptors interceptors, IZeroContext context, Lazy> registrations, ILogger logger, InterceptorRunType runtype, T model, T previousModel = null)
- {
- InterceptorHandler = interceptors;
- Context = context;
- Guid = Guid.NewGuid();
- Logger = logger;
- Runtype = runtype;
- Model = model;
- PreviousModel = previousModel;
- Interceptors = registrations;
-
- ModelType = model.GetType();
- }
-
-
- ///
- /// Custom interceptor filter for this instruction (the CanHandle() method for each interceptor is still activated)
- ///
- public void Filter(Func predicate)
- {
- InterceptorFilter = predicate;
- }
-
-
- ///
- /// Run all interceptors (in order) which can handle the given type.
- /// Depending on the action any of the following methods on the interceptor is called: Creating(), Updating(), Deleting().
- /// If any of the interceptors returns a result the operation is cancelled and this result is returned.
- ///
- public async Task Start(IStoreOperations operations)
- {
- foreach (IInterceptor interceptor in GetInterceptors())
- {
- InterceptorParameters parameters = new()
- {
- Context = Context,
- Store = Context.Store,
- Properties = new(),
- Interceptors = InterceptorHandler,
- Operations = operations,
- PreviousModel = PreviousModel
- };
-
- if (!interceptor.CanHandle(parameters, ModelType))
- {
- continue;
- }
-
-
- Logger.LogDebug("Run interceptor {interceptor} for {type}:{operation}", interceptor.Name, ModelType, Runtype);
-
- InterceptorResult result = (await HandleBefore(interceptor, parameters)) ?? new();
- result.InterceptorHash = IdGenerator.Create(32);
-
- InterceptorCache.Add(interceptor, parameters);
-
- // we cancel all further interceptors if a result is available and return this instead
- if (result.Result != null)
- {
- Result = result.Result.ConvertTo(result.Result.Model as T);
- return false;
- }
-
- // the Continue task will cancel all further interceptors
- if (!result.Continue)
- {
- break;
- }
- }
-
- return true;
- }
-
-
- ///
- /// Run all interceptors (in order) which can handle the given type.
- /// Depending on the action any of the following methods on the interceptor is called: Created(), Updated(), Deleted().
- /// The parameters which are returned from the Start() operation are passed to the methods.
- ///
- public async Task Complete()
- {
- foreach ((IInterceptor interceptor, InterceptorParameters parameters) in InterceptorCache)
- {
- await HandleAfter(interceptor, parameters);
- }
- }
-
-
- protected IEnumerable GetInterceptors()
- {
- return Interceptors.Value.Where(InterceptorFilter).OrderByDescending(x => x.Gravity);
- }
-
-
- ///
- /// Proxy for handling methods on an interceptor
- ///
- protected Task> HandleBefore(IInterceptor interceptor, InterceptorParameters parameters) => Runtype switch
- {
- InterceptorRunType.Create => interceptor.Creating(parameters, Model),
- InterceptorRunType.Update => interceptor.Updating(parameters, Model),
- InterceptorRunType.Delete => interceptor.Deleting(parameters, Model),
- _ => throw new NotImplementedException()
- };
-
-
- ///
- /// Proxy for handling methods on an interceptor
- ///
- protected Task HandleAfter(IInterceptor interceptor, InterceptorParameters parameters) => Runtype switch
- {
- InterceptorRunType.Create => interceptor.Created(parameters, Model),
- InterceptorRunType.Update => interceptor.Updated(parameters, Model),
- InterceptorRunType.Delete => interceptor.Deleted(parameters, Model),
- _ => throw new NotImplementedException()
- };
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Interceptors/InterceptorParameters.cs b/zero.Core/Communication/Interceptors/InterceptorParameters.cs
deleted file mode 100644
index 2e36a170..00000000
--- a/zero.Core/Communication/Interceptors/InterceptorParameters.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-namespace zero.Communication;
-
-public class InterceptorParameters
-{
- ///
- /// The current zero context
- ///
- public IZeroContext Context { get; set; }
-
- ///
- /// Raven document store
- ///
- public IZeroStore Store { get; set; }
-
- ///
- /// Access to other interceptor methods
- ///
- public IInterceptors Interceptors { get; internal set; }
-
- ///
- /// Access to operations
- ///
- public IStoreOperations Operations { get; internal set; }
-
- ///
- /// Parameters from the interceptor which ran on before the operation (only available for completed operations)
- ///
- public Dictionary Properties { get; set; } = new();
-
- ///
- /// Get a typed property
- ///
- public TProp Property(string key) => Properties.GetValueOrDefault(key);
-
- ///
- /// Get a typed property
- ///
- public bool TryGetProperty(string key, out TProp property) => Properties.TryGetValue(key, out property);
-
- ///
- /// Holds a reference to the previously existing model when an update happens (can be null)
- ///
- public object PreviousModel { get; set; }
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Interceptors/InterceptorResult.cs b/zero.Core/Communication/Interceptors/InterceptorResult.cs
deleted file mode 100644
index 735ae3ba..00000000
--- a/zero.Core/Communication/Interceptors/InterceptorResult.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-namespace zero.Communication;
-
-public class InterceptorResult
-{
- ///
- /// Autoset. Hash used to match interceptors in order to correctly pass parameters
- ///
- internal string InterceptorHash { get; set; }
-
- ///
- /// Prevent further interceptors from running for this operation (only valid for the current interception type, e.g. Update/Created/Purge/...)
- ///
- public bool Continue { get; set; } = true;
-
- ///
- /// Set a result. This will prevent further execution of the operation and cancels all subsequent interceptors
- ///
- public Result Result { get; set; }
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Interceptors/InterceptorRunType.cs b/zero.Core/Communication/Interceptors/InterceptorRunType.cs
deleted file mode 100644
index 82be301e..00000000
--- a/zero.Core/Communication/Interceptors/InterceptorRunType.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace zero.Communication;
-
-public enum InterceptorRunType
-{
- Create = 1,
- Update = 2,
- Delete = 3
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Interceptors/Interceptors.cs b/zero.Core/Communication/Interceptors/Interceptors.cs
deleted file mode 100644
index 297f1676..00000000
--- a/zero.Core/Communication/Interceptors/Interceptors.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using Microsoft.Extensions.Logging;
-
-namespace zero.Communication;
-
-public class Interceptors : IInterceptors
-{
- protected IZeroContext Context { get; set; }
-
- protected Lazy> Registrations { get; set; }
-
- protected ILogger Logger { get; set; }
-
-
- public Interceptors(IZeroContext context, Lazy> registrations, ILogger logger)
- {
- Context = context;
- Registrations = registrations;
- Logger = logger;
- }
-
-
- ///
- public InterceptorInstruction ForCreate(T model) where T : ZeroIdEntity, new() => new(this, Context, Registrations, Logger, InterceptorRunType.Create, model);
-
- ///
- public InterceptorInstruction ForUpdate(T model, T previousModel = null) where T : ZeroIdEntity, new() => new(this, Context, Registrations, Logger, InterceptorRunType.Update, model, previousModel);
-
- ///
- public InterceptorInstruction ForDelete(T model) where T : ZeroIdEntity, new() => new(this, Context, Registrations, Logger, InterceptorRunType.Delete, model);
-}
-
-
-public interface IInterceptors
-{
- ///
- /// Instruction which can run interceptors before and after a creating an entity
- ///
- InterceptorInstruction ForCreate(T model) where T : ZeroIdEntity, new();
-
- ///
- /// Instruction which can run interceptors before and after updating an entity
- ///
- InterceptorInstruction ForUpdate(T model, T previousModel = null) where T : ZeroIdEntity, new();
-
- ///
- /// Instruction which can run interceptors before and after deleting an entity
- ///
- InterceptorInstruction ForDelete(T model) where T : ZeroIdEntity, new();
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/LazilyResolved.cs b/zero.Core/Communication/LazilyResolved.cs
deleted file mode 100644
index 0666dae4..00000000
--- a/zero.Core/Communication/LazilyResolved.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-
-namespace zero.Communication;
-
-public class LazilyResolved : Lazy
-{
- public LazilyResolved(IServiceProvider serviceProvider): base(serviceProvider.GetRequiredService)
- {
-
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Communication/Messages/IMessage.cs b/zero.Core/Communication/Messages/IMessage.cs
deleted file mode 100644
index 4c03d107..00000000
--- a/zero.Core/Communication/Messages/IMessage.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-
-namespace zero.Communication;
-
-public interface IMessage
-{
-}
diff --git a/zero.Core/Communication/Messages/IMessageHandler.cs b/zero.Core/Communication/Messages/IMessageHandler.cs
deleted file mode 100644
index a818e1de..00000000
--- a/zero.Core/Communication/Messages/IMessageHandler.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-namespace zero.Communication;
-
-///
-/// Indicates a handler that can perform an action when a message of
-/// a certain type is received. (could be an interface rather than concrete type)
-///
-public interface IMessageHandler where TMessage : IMessage
-{
- ///
- /// Method to invoke when a message of type TMessage is published
- ///
- Task Handle(TMessage message);
-}
-
-
-///
-/// Indicates a handler that can perform an action when a message of
-/// a certain type is received. (could be an interface rather than concrete type)
-///
-public interface IBatchMessageHandler : IMessageHandler where TMessage : IMessage
-{
- ///
- /// Method to invoke when a batch of messages of type TMessage are published
- ///
- Task HandleBatchAsync(IReadOnlyCollection message);
-}
diff --git a/zero.Core/Communication/Messages/MessageAggregator.cs b/zero.Core/Communication/Messages/MessageAggregator.cs
deleted file mode 100644
index cd6a3f37..00000000
--- a/zero.Core/Communication/Messages/MessageAggregator.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System.Collections.Concurrent;
-
-namespace zero.Communication;
-
-public class MessageAggregator : IMessageAggregator
-{
- readonly ConcurrentBag Subscription = new ConcurrentBag();
- readonly IServiceProvider ServiceProvider;
-
-
- public MessageAggregator(IServiceProvider serviceProvider)
- {
- ServiceProvider = serviceProvider;
- }
-
-
- ///
- public async Task Publish(TMessage message) where TMessage : class, IMessage
- {
- IEnumerable subscriptions = Subscription.Where(s => s.CanDeliver());
-
- foreach (IMessageSubscription subscription in subscriptions)
- {
- await subscription.Deliver(ServiceProvider, message);
- }
- }
-
-
- ///
- public void Activate()
- where TMessage : class, IMessage
- where TMessageHandler : IMessageHandler
- {
- Subscription.Add(new MessageSubscription());
- }
-}
-
-
-public interface IMessageAggregator
-{
- ///
- /// Publishes the specified message, invoking any handlers subscribed to the message.
- ///
- Task Publish(TMessage message) where TMessage : class, IMessage;
-
- ///
- /// Subscribes the specified handler to the spified message type
- ///
- void Activate()
- where TMessage : class, IMessage
- where TMessageHandler : IMessageHandler;
-}
diff --git a/zero.Core/Communication/Messages/MessageSubscription.cs b/zero.Core/Communication/Messages/MessageSubscription.cs
deleted file mode 100644
index 3698f175..00000000
--- a/zero.Core/Communication/Messages/MessageSubscription.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Microsoft.Extensions.DependencyInjection;
-using System.Reflection;
-
-namespace zero.Communication;
-
-internal class MessageSubscription : IMessageSubscription
- where TMessage : class, IMessage
- where TMessageHandler : IMessageHandler
-{
- public bool CanDeliver()
- {
- return typeof(TMessage).GetTypeInfo().IsAssignableFrom(typeof(T));
- }
-
- public async Task Deliver(IServiceProvider serviceProvider, object message)
- {
- if (message == null)
- {
- throw new ArgumentNullException(nameof(message));
- }
- if (!(message is TMessage))
- {
- throw new ArgumentException($"{ nameof(message) } must be of type '{typeof(TMessage).FullName}'");
- }
-
- var handlers = serviceProvider.GetServices();
-
- foreach (var handler in handlers)
- {
- await handler.Handle((TMessage)message);
- }
- }
-}
-
-
-public interface IMessageSubscription
-{
- bool CanDeliver