diff --git a/zero.Backoffice/Configuration/BackofficeOptions.cs b/zero.Backoffice/Configuration/BackofficeOptions.cs
index 688f6901..b10fbc24 100644
--- a/zero.Backoffice/Configuration/BackofficeOptions.cs
+++ b/zero.Backoffice/Configuration/BackofficeOptions.cs
@@ -26,4 +26,14 @@ public class BackofficeOptions
/// Options for configuring the vite development server
///
public ZeroDevOptions DevServer { get; set; } = new();
+
+ ///
+ /// Default language ISO code
+ ///
+ public string DefaultLanguage { get; set; }
+
+ ///
+ /// Language ISO codes which are supported by the zero backoffice
+ ///
+ public string[] SupportedLanguages { get; internal set; }
}
\ No newline at end of file
diff --git a/zero.Backoffice/Plugin.cs b/zero.Backoffice/Plugin.cs
index dee88f6c..a9836fee 100644
--- a/zero.Backoffice/Plugin.cs
+++ b/zero.Backoffice/Plugin.cs
@@ -56,6 +56,9 @@ public class ZeroBackofficePlugin : ZeroPlugin
Prefix = "fth"
});
+ options.SupportedLanguages = new string[2] { "en-US", "de-DE" };
+ options.DefaultLanguage = options.SupportedLanguages[0];
+
//Map().Display((x, res, opts) =>
//{
// PageType pageType = opts.Pages.GetByAlias(x.PageTypeAlias);
diff --git a/zero.Backoffice/UIComposition/ServiceCollectionExtensions.cs b/zero.Backoffice/UIComposition/ServiceCollectionExtensions.cs
index 1a0bf8da..f6a5ff32 100644
--- a/zero.Backoffice/UIComposition/ServiceCollectionExtensions.cs
+++ b/zero.Backoffice/UIComposition/ServiceCollectionExtensions.cs
@@ -17,6 +17,8 @@ public static class ServiceCollectionExtensions
services.AddScoped();
+ services.AddOptions();
+
return services;
}
}
\ No newline at end of file
diff --git a/zero.Backoffice/UIComposition/Settings/SettingsOptions.cs b/zero.Backoffice/UIComposition/Settings/SettingsOptions.cs
new file mode 100644
index 00000000..ea18b15d
--- /dev/null
+++ b/zero.Backoffice/UIComposition/Settings/SettingsOptions.cs
@@ -0,0 +1,49 @@
+namespace zero.Backoffice.UIComposition;
+
+public class BackofficeSettingsOptions : List
+{
+ public void AddGroup(int index = -1) where T : SettingsGroup, new()
+ {
+ if (index > -1 && index < Count)
+ {
+ Insert(index, new T());
+ }
+ else
+ {
+ Add(new T());
+ }
+ }
+
+
+ public void AddGroup(SettingsGroup group, int index = -1)
+ {
+ if (index > -1 && index < Count)
+ {
+ Insert(index, group);
+ }
+ else
+ {
+ Add(group);
+ }
+ }
+
+
+ public void AddToDefaultGroup(SettingsArea item, int index = -1)
+ {
+ SettingsGroup group = this.FirstOrDefault(x => x.Name == "@settings.groups.system");
+
+ if (group == null)
+ {
+ return;
+ }
+
+ if (index > -1 && index < group.Areas.Count)
+ {
+ group.Areas.Insert(index, item);
+ }
+ else
+ {
+ group.Areas.Add(item);
+ }
+ }
+}
diff --git a/zero.Core/Architecture/Blueprints/BlueprintOptions.cs b/zero.Core/Architecture/Blueprints/BlueprintOptions.cs
index daddb9ea..94a07ea9 100644
--- a/zero.Core/Architecture/Blueprints/BlueprintOptions.cs
+++ b/zero.Core/Architecture/Blueprints/BlueprintOptions.cs
@@ -1,30 +1,21 @@
namespace zero.Architecture;
-public class BlueprintOptions : OptionsEnumerable, IOptionsEnumerable
+public class BlueprintOptions : List
{
- public BlueprintOptions()
- {
- Enabled = false;
- }
-
-
- public bool Enabled { get; set; }
-
+ public bool Enabled { get; set; } = false;
public void Add() where T : Blueprint, new()
{
- Items.Add(new T());
+ Add(new T());
}
-
public void Add(Blueprint implementation) where T : ZeroEntity, new()
{
- Items.Add(implementation);
+ Add(implementation);
}
-
public void Add(Action> createExpression = null) where T : ZeroEntity, new()
{
- Items.Add(new DefaultBlueprint(createExpression));
+ Add(new DefaultBlueprint(createExpression));
}
}
diff --git a/zero.Core/Communication/Handlers/IModuleTypeHandler.cs b/zero.Core/Communication/Handlers/IModuleTypeHandler.cs
deleted file mode 100644
index e42ef0e3..00000000
--- a/zero.Core/Communication/Handlers/IModuleTypeHandler.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace zero.Communication;
-
-public interface IModuleTypeHandler : IHandler
-{
- IEnumerable GetAllowedModuleTypes(Application application, IEnumerable registeredTypes, Page page = default, string[] tags = default);
-}
diff --git a/zero.Core/Configuration/ConfigurationParts/SettingsOptions.cs b/zero.Core/Configuration/ConfigurationParts/SettingsOptions.cs
deleted file mode 100644
index 9b431d31..00000000
--- a/zero.Core/Configuration/ConfigurationParts/SettingsOptions.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using System.Linq;
-using zero.Core.Entities;
-
-namespace zero.Configuration;
-
-public class SettingsOptions : OptionsEnumerable, IOptionsEnumerable
-{
- public void AddGroup(int index = -1) where T : SettingsGroup, new()
- {
- if (index > -1 && index < Items.Count)
- {
- Items.Insert(index, new T());
- }
- else
- {
- Items.Add(new T());
- }
- }
-
-
- public void AddGroup(SettingsGroup group, int index = -1)
- {
- if (index > -1 && index < Items.Count)
- {
- Items.Insert(index, group);
- }
- else
- {
- Items.Add(group);
- }
- }
-
-
- public void AddToDefaultGroup(SettingsArea item, int index = -1)
- {
- SettingsGroup group = Items.FirstOrDefault(x => x.Name == "@settings.groups.system");
-
- if (group == null)
- {
- return;
- }
-
- if (index > -1 && index < group.Items.Count)
- {
- group.Items.Insert(index, item);
- }
- else
- {
- group.Items.Add(item);
- }
- }
-}
diff --git a/zero.Core/Configuration/Features/Feature.cs b/zero.Core/Configuration/Features/Feature.cs
new file mode 100644
index 00000000..35a8d20d
--- /dev/null
+++ b/zero.Core/Configuration/Features/Feature.cs
@@ -0,0 +1,22 @@
+namespace zero.Configuration;
+
+///
+/// A feature can affect both the backoffice and the frontend
+///
+public class Feature
+{
+ ///
+ /// The alias
+ ///
+ public string Alias { get; set; }
+
+ ///
+ /// The name of the feature
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Additional description
+ ///
+ public string Description { get; set; }
+}
\ No newline at end of file
diff --git a/zero.Core/Configuration/ConfigurationParts/FeatureOptions.cs b/zero.Core/Configuration/Features/FeatureOptions.cs
similarity index 65%
rename from zero.Core/Configuration/ConfigurationParts/FeatureOptions.cs
rename to zero.Core/Configuration/Features/FeatureOptions.cs
index bb01a67a..e222a407 100644
--- a/zero.Core/Configuration/ConfigurationParts/FeatureOptions.cs
+++ b/zero.Core/Configuration/Features/FeatureOptions.cs
@@ -1,19 +1,19 @@
namespace zero.Configuration;
-public class FeatureOptions : OptionsEnumerable, IOptionsEnumerable
+public class FeatureOptions : List
{
public void Add() where T : Feature, new()
{
- Items.Add(new T());
+ Add(new T());
}
public void Add(string alias, string name, string description)
{
- Items.Add(new Feature()
+ Add(new Feature()
{
Alias = alias,
Name = name,
Description = description
});
}
-}
+}
\ No newline at end of file
diff --git a/zero.Core/Configuration/ConfigurationParts/IntegrationOptions.cs b/zero.Core/Configuration/Integrations/IntegrationOptions.cs
similarity index 78%
rename from zero.Core/Configuration/ConfigurationParts/IntegrationOptions.cs
rename to zero.Core/Configuration/Integrations/IntegrationOptions.cs
index c244b621..2d8373fe 100644
--- a/zero.Core/Configuration/ConfigurationParts/IntegrationOptions.cs
+++ b/zero.Core/Configuration/Integrations/IntegrationOptions.cs
@@ -2,17 +2,17 @@
namespace zero.Configuration;
-public class IntegrationOptions : OptionsEnumerable, IOptionsEnumerable
+public class IntegrationOptions : List
{
public void Add(IntegrationType integration) where T : Integration, new()
{
- Items.Add(IntegrationType.Convert(integration));
+ Add(IntegrationType.Convert(integration));
}
public void Add(string alias, string name, string description, List tags = default, string imagePath = null, IValidator validator = null) where T : Integration, new()
{
- Items.Add(new IntegrationType(typeof(T))
+ Add(new IntegrationType(typeof(T))
{
Alias = alias,
Name = name,
@@ -26,7 +26,7 @@ public class IntegrationOptions : OptionsEnumerable, IOptionsEn
public void Add(Type type, string alias, string name, string description, List tags = default, string imagePath = null, IValidator validator = null)
{
- Items.Add(new IntegrationType(type)
+ Add(new IntegrationType(type)
{
Alias = alias,
Name = name,
diff --git a/zero.Core/Configuration/Integrations/IntegrationService.cs b/zero.Core/Configuration/Integrations/IntegrationService.cs
index b48f888b..ca3e3de9 100644
--- a/zero.Core/Configuration/Integrations/IntegrationService.cs
+++ b/zero.Core/Configuration/Integrations/IntegrationService.cs
@@ -1,14 +1,14 @@
-using Microsoft.Extensions.Logging;
+//using Microsoft.Extensions.Logging;
-namespace zero.Configuration;
+//namespace zero.Configuration;
-public class IntegrationService : IntegrationsCollection, IIntegrationService
-{
- public IntegrationService(IStoreContext context, ILogger logger) : base(context, logger)
- {
- Options = new(false);
- }
-}
+//public class IntegrationService : IntegrationsCollection, IIntegrationService
+//{
+// public IntegrationService(IStoreContext context, ILogger logger) : base(context, logger)
+// {
+// Options = new(false);
+// }
+//}
-public interface IIntegrationService : IIntegrationsCollection { }
\ No newline at end of file
+//public interface IIntegrationService : IIntegrationsCollection { }
\ No newline at end of file
diff --git a/zero.Core/Configuration/Integrations/IntegrationsCollection.cs b/zero.Core/Configuration/Integrations/IntegrationsCollection.cs
index bf105bb3..b0404d1b 100644
--- a/zero.Core/Configuration/Integrations/IntegrationsCollection.cs
+++ b/zero.Core/Configuration/Integrations/IntegrationsCollection.cs
@@ -1,287 +1,287 @@
-using Microsoft.Extensions.Logging;
-using Raven.Client.Documents;
-using Raven.Client.Documents.Linq;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using zero.Core.Integrations;
+//using Microsoft.Extensions.Logging;
+//using Raven.Client.Documents;
+//using Raven.Client.Documents.Linq;
+//using System;
+//using System.Collections.Generic;
+//using System.Linq;
+//using System.Threading.Tasks;
+//using zero.Core.Integrations;
-namespace zero.Core.Collections
-{
- public class IntegrationsCollection : EntityStore, IIntegrationsCollection
- {
- ///
- public IReadOnlyCollection RegisteredTypes { get; private set; }
+//namespace zero.Core.Collections
+//{
+// public class IntegrationsCollection : EntityStore, IIntegrationsCollection
+// {
+// ///
+// public IReadOnlyCollection RegisteredTypes { get; private set; }
- protected ILogger Logger { get; private set; }
+// protected ILogger Logger { get; private set; }
- public IntegrationsCollection(IStoreContext context, ILogger logger) : base(context)
- {
- Options = new(true);
- RegisteredTypes = Context.Options.Integrations.GetAllItems();
- Logger = logger;
- }
+// public IntegrationsCollection(IStoreContext context, ILogger logger) : base(context)
+// {
+// Options = new(true);
+// RegisteredTypes = Context.Options.Integrations.GetAllItems();
+// Logger = logger;
+// }
- ///
- public Integration GetEmpty(string alias)
- {
- IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase));
+// ///
+// public Integration GetEmpty(string alias)
+// {
+// IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase));
- if (type == null)
- {
- return null;
- }
+// if (type == null)
+// {
+// return null;
+// }
- try
- {
- Integration model = Activator.CreateInstance(type.ContentType) as Integration;
- model.TypeAlias = type.Alias;
- return model;
- }
- catch
- {
- Logger.LogWarning("Could not create integration with type {alias}", alias);
- }
+// try
+// {
+// Integration model = Activator.CreateInstance(type.ContentType) as Integration;
+// model.TypeAlias = type.Alias;
+// return model;
+// }
+// catch
+// {
+// Logger.LogWarning("Could not create integration with type {alias}", alias);
+// }
- return null;
- }
+// return null;
+// }
- ///
- public async Task GetByAlias(string alias)
- {
- IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase));
- return await Load(type);
- }
+// ///
+// public async Task GetByAlias(string alias)
+// {
+// IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase));
+// return await Load(type);
+// }
- ///
- public async Task Get(string alias = null) where T : Integration, new()
- {
- IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.ContentType == typeof(T) && (alias.IsNullOrEmpty() || x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)));
- return await Load(type);
- }
+// ///
+// public async Task Get(string alias = null) where T : Integration, new()
+// {
+// IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.ContentType == typeof(T) && (alias.IsNullOrEmpty() || x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)));
+// return await Load(type);
+// }
- ///
- public async Task> GetByTag(string tag)
- {
- IEnumerable types = RegisteredTypes.Where(x => x.Tags.Contains(tag, StringComparer.InvariantCultureIgnoreCase));
+// ///
+// public async Task> GetByTag(string tag)
+// {
+// IEnumerable types = RegisteredTypes.Where(x => x.Tags.Contains(tag, StringComparer.InvariantCultureIgnoreCase));
- if (!types.Any())
- {
- return new List();
- }
+// if (!types.Any())
+// {
+// return new List();
+// }
- string[] aliases = types.Select(x => x.Alias).ToArray();
- return await Session.Query().Where(x => x.TypeAlias.In(aliases)).ToListAsync();
- }
+// string[] aliases = types.Select(x => x.Alias).ToArray();
+// return await Session.Query().Where(x => x.TypeAlias.In(aliases)).ToListAsync();
+// }
- ///
- public async Task Any(string tag)
- {
- return (await GetByTag(tag)).Any(x => x.IsActive);
- }
+// ///
+// public async Task Any(string tag)
+// {
+// return (await GetByTag(tag)).Any(x => x.IsActive);
+// }
- ///
- public override async Task> Load(ListQuery query)
- {
- List result = new();
- List models = await Session.Query().ToListAsync();
+// ///
+// public override async Task> Load(ListQuery query)
+// {
+// List result = new();
+// List models = await Session.Query().ToListAsync();
- foreach (IntegrationType type in RegisteredTypes)
- {
- Integration model = models.FirstOrDefault(x => x.TypeAlias == type.Alias);
+// foreach (IntegrationType type in RegisteredTypes)
+// {
+// Integration model = models.FirstOrDefault(x => x.TypeAlias == type.Alias);
- if (model != null)
- {
- model.Name = type.Name;
- result.Add(model);
- }
- }
+// if (model != null)
+// {
+// model.Name = type.Name;
+// result.Add(model);
+// }
+// }
- return result.ToQueriedList(query);
- }
+// return result.ToQueriedList(query);
+// }
- ///
- public async Task> GetTypesWithStatus()
- {
- List result = new();
- List models = await Session.Query().ToListAsync();
+// ///
+// public async Task> GetTypesWithStatus()
+// {
+// List result = new();
+// List models = await Session.Query().ToListAsync();
- foreach (IntegrationType type in RegisteredTypes)
- {
- Integration model = models.FirstOrDefault(x => x.TypeAlias == type.Alias);
+// foreach (IntegrationType type in RegisteredTypes)
+// {
+// Integration model = models.FirstOrDefault(x => x.TypeAlias == type.Alias);
- result.Add(new()
- {
- Type = type,
- Id = model?.Id,
- IsActive = model?.IsActive ?? false,
- IsConfigured = model != null
- });
- }
+// result.Add(new()
+// {
+// Type = type,
+// Id = model?.Id,
+// IsActive = model?.IsActive ?? false,
+// IsConfigured = model != null
+// });
+// }
- return result.OrderByDescending(x => x.IsActive).ThenByDescending(x => x.IsConfigured).ThenByDescending(x => x.Type.Name).ToList();
- }
+// return result.OrderByDescending(x => x.IsActive).ThenByDescending(x => x.IsConfigured).ThenByDescending(x => x.Type.Name).ToList();
+// }
- ///
- public override async Task> Save(Integration model)
- {
- if (model == null)
- {
- return EntityResult.Fail("@integration.errors.notfound");
- }
+// ///
+// public override async Task> Save(Integration model)
+// {
+// if (model == null)
+// {
+// return EntityResult.Fail("@integration.errors.notfound");
+// }
- IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(model.TypeAlias, StringComparison.InvariantCultureIgnoreCase));
+// IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(model.TypeAlias, StringComparison.InvariantCultureIgnoreCase));
- if (type == null)
- {
- return EntityResult.Fail("@integration.errors.typenotfound");
- }
+// if (type == null)
+// {
+// return EntityResult.Fail("@integration.errors.typenotfound");
+// }
- string existingId = await Session.Query().Where(x => x.TypeAlias == type.Alias).Select(x => x.Id).FirstOrDefaultAsync();
+// string existingId = await Session.Query().Where(x => x.TypeAlias == type.Alias).Select(x => x.Id).FirstOrDefaultAsync();
- if (!existingId.IsNullOrEmpty() && existingId != model.Id)
- {
- return EntityResult.Fail("@integration.errors.multiplenotallowed");
- }
+// if (!existingId.IsNullOrEmpty() && existingId != model.Id)
+// {
+// return EntityResult.Fail("@integration.errors.multiplenotallowed");
+// }
- model.Alias = type.Alias;
- model.Name = null;
+// model.Alias = type.Alias;
+// model.Name = null;
- EntityResult result = await base.Save(model);
+// EntityResult result = await base.Save(model);
- if (result.IsSuccess)
- {
- result.Model.Name = type.Name;
- }
+// if (result.IsSuccess)
+// {
+// result.Model.Name = type.Name;
+// }
- return result;
- }
+// return result;
+// }
- ///
- public async Task> Activate(string alias)
- {
- Integration model = await GetByAlias(alias);
- if (model != null)
- {
- model.IsActive = true;
- }
- return await Save(model);
- }
+// ///
+// public async Task> Activate(string alias)
+// {
+// Integration model = await GetByAlias(alias);
+// if (model != null)
+// {
+// model.IsActive = true;
+// }
+// return await Save(model);
+// }
- ///
- public async Task> Deactivate(string alias)
- {
- Integration model = await GetByAlias(alias);
- if (model != null)
- {
- model.IsActive = false;
- }
- return await Save(model);
- }
+// ///
+// public async Task> Deactivate(string alias)
+// {
+// Integration model = await GetByAlias(alias);
+// if (model != null)
+// {
+// model.IsActive = false;
+// }
+// return await Save(model);
+// }
- ///
- public async Task> DeleteByAlias(string alias)
- {
- return await base.Delete(await GetByAlias(alias));
- }
+// ///
+// public async Task> DeleteByAlias(string alias)
+// {
+// return await base.Delete(await GetByAlias(alias));
+// }
- ///
- /// Get integration data from database
- ///
- protected async Task Load(IntegrationType type) where T : Integration, new()
- {
- if (type == null)
- {
- return default;
- }
+// ///
+// /// Get integration data from database
+// ///
+// protected async Task Load(IntegrationType type) where T : Integration, new()
+// {
+// if (type == null)
+// {
+// return default;
+// }
- T entity = await Session.Query().FirstOrDefaultAsync(x => x.TypeAlias == type.Alias);
+// T entity = await Session.Query().FirstOrDefaultAsync(x => x.TypeAlias == type.Alias);
- if (entity != null)
- {
- entity.Name = type.Name;
- entity.TypeAlias = type.Alias;
- }
+// if (entity != null)
+// {
+// entity.Name = type.Name;
+// entity.TypeAlias = type.Alias;
+// }
- return WhenActive(entity) as T;
- }
- }
+// return WhenActive(entity) as T;
+// }
+// }
- public interface IIntegrationsCollection
- {
- ///
- /// Get all registered integration types
- ///
- IReadOnlyCollection RegisteredTypes { get; }
+// public interface IIntegrationsCollection
+// {
+// ///
+// /// Get all registered integration types
+// ///
+// IReadOnlyCollection RegisteredTypes { get; }
- ///
- /// Get new integration model for the specified integration type alias
- ///
- Integration GetEmpty(string alias);
+// ///
+// /// Get new integration model for the specified integration type alias
+// ///
+// Integration GetEmpty(string alias);
- ///
- /// Get integration by an alias
- ///
- Task GetByAlias(string alias);
+// ///
+// /// Get integration by an alias
+// ///
+// Task GetByAlias(string alias);
- ///
- /// Get an integration by type and optional alias
- ///
- Task Get(string alias = null) where T : Integration, new();
+// ///
+// /// Get an integration by type and optional alias
+// ///
+// Task Get(string alias = null) where T : Integration, new();
- ///
- /// Get all integrations by a certain tag
- ///
- Task> GetByTag(string tag);
+// ///
+// /// Get all integrations by a certain tag
+// ///
+// Task> GetByTag(string tag);
- ///
- /// Check if any integrations of certain tag are activated
- ///
- Task Any(string tag);
+// ///
+// /// Check if any integrations of certain tag are activated
+// ///
+// Task Any(string tag);
- ///
- /// Get all integrations with the specified query
- ///
- Task> Load(ListQuery query);
+// ///
+// /// Get all integrations with the specified query
+// ///
+// Task> Load(ListQuery query);
- ///
- /// Get all integration types with their configuration status
- ///
- Task> GetTypesWithStatus();
+// ///
+// /// Get all integration types with their configuration status
+// ///
+// Task> GetTypesWithStatus();
- ///
- /// Saves an integration
- ///
- Task> Save(Integration model);
+// ///
+// /// Saves an integration
+// ///
+// Task> Save(Integration model);
- ///
- /// Activates a configured integration
- ///
- Task> Activate(string alias);
+// ///
+// /// Activates a configured integration
+// ///
+// Task> Activate(string alias);
- ///
- /// Disables a configured integration
- ///
- Task> Deactivate(string alias);
+// ///
+// /// Disables a configured integration
+// ///
+// Task> Deactivate(string alias);
- ///
- /// Deletes configuration of an integration and disables it
- ///
- Task> DeleteByAlias(string alias);
- }
-}
+// ///
+// /// Deletes configuration of an integration and disables it
+// ///
+// Task> DeleteByAlias(string alias);
+// }
+//}
diff --git a/zero.Core/Configuration/OptionsEnumerable.cs b/zero.Core/Configuration/OptionsEnumerable.cs
deleted file mode 100644
index ba517c52..00000000
--- a/zero.Core/Configuration/OptionsEnumerable.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-namespace zero.Configuration;
-
-public abstract class OptionsEnumerable
-{
- protected List Items { get; set; } = new List();
-
-
- public IReadOnlyCollection GetAllItems()
- {
- return Items.AsReadOnly();
- }
-
-
- public void RemoveAt(int index)
- {
- Items.RemoveAt(index);
- }
-
-
- public bool Remove(T item)
- {
- return Items.Remove(item);
- }
-}
-
-
-public interface IOptionsEnumerable { }
\ No newline at end of file
diff --git a/zero.Core/Configuration/ServiceCollectionExtensions.cs b/zero.Core/Configuration/ServiceCollectionExtensions.cs
index a89ad3a6..a48201ce 100644
--- a/zero.Core/Configuration/ServiceCollectionExtensions.cs
+++ b/zero.Core/Configuration/ServiceCollectionExtensions.cs
@@ -12,6 +12,7 @@ internal static class ServiceCollectionExtensions
{
opts.Version = "0.0.1-alpha.1";
opts.ZeroPath = "/zero";
+ opts.TokenExpiration = TimeSpan.FromHours(3);
});
services.AddTransient(factory => factory.GetService>().CurrentValue);
return services;
diff --git a/zero.Core/Configuration/ZeroOptions.cs b/zero.Core/Configuration/ZeroOptions.cs
index c97ed144..1960ecf8 100644
--- a/zero.Core/Configuration/ZeroOptions.cs
+++ b/zero.Core/Configuration/ZeroOptions.cs
@@ -6,6 +6,19 @@ namespace zero.Configuration;
public class ZeroOptions : IZeroOptions
{
+ ///
+ public bool Initialized => !String.IsNullOrEmpty(For()?.Database);
+
+ ///
+ public string Version { get; set; }
+
+ ///
+ public string ZeroPath { get; set; }
+
+ ///
+ public TimeSpan TokenExpiration { get; set; }
+
+
protected IServiceProvider ServiceProvider { get; set; }
protected ConcurrentDictionary OptionsCache { get; private set; } = new();
@@ -14,16 +27,6 @@ public class ZeroOptions : IZeroOptions
public ZeroOptions(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
-
- //SupportedLanguages = new string[2] { "en-US", "de-DE" };
- //DefaultLanguage = SupportedLanguages[0];
- //TokenExpiration = 60 * 3;
- //BackofficePath = "/zero";
- //ExcludedPaths = new() { };
- //Raven = new()
- //{
- // CollectionPrefix = String.Empty
- //};
}
@@ -41,54 +44,6 @@ public class ZeroOptions : IZeroOptions
return value as TOptions;
}
-
-
-
- ///
- public bool Initialized => !String.IsNullOrEmpty(For()?.Database);
-
- ///
- public string Version { get; set; }
-
- ///
- public string ZeroPath { get; set; }
-
- /////
- //public string DefaultLanguage { get; set; }
-
- /////
- //public string[] SupportedLanguages { get; private set; }
-
- /////
- //public int TokenExpiration { get; set; }
-
- /////
- //public RavenOptions Raven { get; set; }
-
- /////
- //public ApplicationOptions Applications { get; set; }
-
-
- /////
- //public FeatureOptions Features { get; private set; }
-
- /////
- //public PageOptions Pages { get; private set; }
-
- /////
- //public ModuleOptions Modules { get; private set; }
-
- /////
- //public SettingsOptions Settings { get; private set; }
-
- /////
- //public SpaceOptions Spaces { get; private set; }
-
- /////
- //public IntegrationOptions Integrations { get; private set; }
-
- /////
- //public BlueprintOptions Blueprints { get; private set; }
}
@@ -110,33 +65,13 @@ public interface IZeroOptions
///
bool Initialized { get; }
+ ///
+ /// Expiration of a generated change token for an entity
+ ///
+ TimeSpan TokenExpiration { get; set; }
+
///
/// Get typed options (proxy to IOptions)
///
TOptions For() where TOptions : class;
-
- /////
- ///// Default language ISO code
- /////
- //string DefaultLanguage { get; set; }
-
- /////
- ///// Language ISO codes which are supported by the zero backoffice
- /////
- //string[] SupportedLanguages { get; }
-
- /////
- ///// Expiration in minutes of a generated change token for an entity
- /////
- //int TokenExpiration { get; set; }
-
- /////
- ///// RavenDB configuration data
- /////
- //RavenOptions Raven { get; set; }
-
- /////
- ///// Application options
- /////
- //ApplicationOptions Applications { get; set; }
}
diff --git a/zero.Core/FileStorage/Paths.cs b/zero.Core/FileStorage/Paths.cs
index 435a482c..602ab9de 100644
--- a/zero.Core/FileStorage/Paths.cs
+++ b/zero.Core/FileStorage/Paths.cs
@@ -17,19 +17,17 @@ public class Paths : IPaths
protected IWebHostEnvironment Env { get; set; }
- private bool IsDebug { get; set; }
-
public const string MEDIA_FOLDER = "Uploads";
public const char PATH_SEPARATOR = '/';
- private static char[] InvalidFilenameChars = null;
+ static char[] InvalidFilenameChars = null;
- private const char REPLACEMENT_CHAR = '-';
+ const char REPLACEMENT_CHAR = '-';
- private FileExtensionContentTypeProvider FileExtensionContentTypeProvider { get; set; }
+ FileExtensionContentTypeProvider FileExtensionContentTypeProvider { get; set; }
- private static Dictionary Replacements = new Dictionary()
+ static readonly Dictionary Replacements = new()
{
{ 'ä', "ae" },
{ 'ü', "ue" },
@@ -38,10 +36,9 @@ public class Paths : IPaths
};
- public Paths(IWebHostEnvironment env, bool isDebug)
+ public Paths(IWebHostEnvironment env)
{
Env = env;
- IsDebug = isDebug;
WebRoot = env.WebRootPath;
ContentRoot = env.ContentRootPath;
SecureRoot = Path.Combine(ContentRoot, "wwwroot.secure");
@@ -133,9 +130,9 @@ public class Paths : IPaths
// lowercase for string
value = value.ToLower();
- StringBuilder sb = new StringBuilder(value.Length);
+ StringBuilder sb = new(value.Length);
- var invalids = InvalidFilenameChars ?? (InvalidFilenameChars = Path.GetInvalidFileNameChars());
+ var invalids = InvalidFilenameChars ??= Path.GetInvalidFileNameChars();
bool changed = false;
for (int i = 0; i < value.Length; i++)
diff --git a/zero.Core/Identity/RavenUserStore(TUser).cs b/zero.Core/Identity/RavenUserStore(TUser).cs
index 27f66d50..666994a1 100644
--- a/zero.Core/Identity/RavenUserStore(TUser).cs
+++ b/zero.Core/Identity/RavenUserStore(TUser).cs
@@ -57,7 +57,7 @@ public partial class RavenUserStore :
{
IZeroDocumentSession session = Store.Session(Global);
- if (await IsEmailReserved(session, user))
+ if (await IsEmailReserved(session, user, cancellationToken))
{
return IdentityResult.Failed(new IdentityError
{
@@ -103,7 +103,7 @@ public partial class RavenUserStore :
});
}
- if (source.Email != user.Email && await IsEmailReserved(Store.Session(Global), user))
+ if (source.Email != user.Email && await IsEmailReserved(Store.Session(Global), user, cancellationToken))
{
return IdentityResult.Failed(new IdentityError
{
@@ -337,8 +337,8 @@ public partial class RavenUserStore :
///
public async Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken)
{
- UserClaim userClaim = new UserClaim(claim);
- return await ScopeQuery(Store.Session(Global).Query()).Where(x => x.Claims.Any(c => c.Type == userClaim.Type && c.Value == userClaim.Value)).ToListAsync();
+ UserClaim userClaim = new(claim);
+ return await ScopeQuery(Store.Session(Global).Query()).Where(x => x.Claims.Any(c => c.Type == userClaim.Type && c.Value == userClaim.Value)).ToListAsync(token: cancellationToken);
}
@@ -360,8 +360,8 @@ public partial class RavenUserStore :
public async Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken)
{
IZeroDocumentSession session = Store.Session(Global);
- UserClaim userClaim = new UserClaim(claim);
- UserClaim newUserClaim = new UserClaim(newClaim);
+ UserClaim userClaim = new(claim);
+ UserClaim newUserClaim = new(newClaim);
user.Claims.Remove(userClaim);
user.Claims.Add(newUserClaim);
diff --git a/zero.Core/Identity/Services/AuthenticationService.cs b/zero.Core/Identity/Services/AuthenticationService.cs
index 403b26cf..163b40f1 100644
--- a/zero.Core/Identity/Services/AuthenticationService.cs
+++ b/zero.Core/Identity/Services/AuthenticationService.cs
@@ -22,6 +22,12 @@ public class AuthenticationService : IAuthenticationService
///
public bool IsLoggedIn()
{
+ //ClaimsPrincipal principal = HttpContextAccessor.HttpContext.User;
+ //bool isAuthenticated = principal.Identity.IsAuthenticated;
+ //bool isZeroUser = principal.HasClaim(Constants.Auth.Claims.IsZero, PermissionsValue.True);
+ //bool isSignedIn = SignInManager.IsSignedIn(principal);
+ //return isAuthenticated && isZeroUser && isSignedIn;
+
return SignInManager.IsSignedIn(Context.BackofficeUser);
}
@@ -47,30 +53,10 @@ public class AuthenticationService : IAuthenticationService
}
- ///
- public IList GetPermissions(string prefix = null)
- {
- return new List(); // TODO
- //return Context.BackofficeUser.Claims
- // .Where(claim => claim.Type == Constants.Auth.Claims.Permission && (prefix == null || claim.Value.StartsWith(prefix)))
- // .Select(claim => Permission.FromClaim(claim, prefix))
- // .ToList();
- }
-
-
- ///
- public Permission GetPermission(string key = null)
- {
- return new Permission();
- //Claim claim = Context.BackofficeUser.Claims.FirstOrDefault(claim => claim.Type == Constants.Auth.Claims.Permission && claim.Value.StartsWith(key + ":"));
- //return Permission.FromClaim(claim);
- }
-
-
///
public async Task Login(string email, string password, bool isPersistent)
{
- EntityResult result = new EntityResult();
+ EntityResult result = new();
ZeroUser user = await SignInManager.UserManager.FindByNameAsync(email);
@@ -127,40 +113,6 @@ public class AuthenticationService : IAuthenticationService
{
return SignInManager.UserManager.GetUserId(Context.BackofficeUser);
}
-
-
- ///
- public async Task TrySwitchApp(string appId)
- {
- IZeroDocumentSession session = Store.Session(global: true);
- ZeroUser user = await GetUser();
-
- if (user == null || appId.IsNullOrEmpty())
- {
- return false;
- }
-
- string[] allowedAppIds = user.GetAllowedAppIds();
-
- bool isMainId = appId.Equals(user.AppId, StringComparison.InvariantCultureIgnoreCase);
- bool isAllowedId = allowedAppIds.Contains(appId, StringComparer.InvariantCultureIgnoreCase);
-
- if (user.IsSuper || isMainId || isAllowedId)
- {
- user.CurrentAppId = appId;
-
- //byte[] bytes = new byte[20];
- //RandomNumberGenerator.Fill(bytes);
- //user.SecurityStamp = Base32.ToBase32(bytes); // TODO update security stamp but Base32 is .net core internal
-
- await session.StoreAsync(user);
- await session.SaveChangesAsync();
-
- return true;
- }
-
- return false;
- }
}
@@ -200,19 +152,4 @@ public interface IAuthenticationService
/// Get the ID of the currently logged in user
///
string GetUserId();
-
- ///
- /// Get all permissions for the current user with an optional prefix
- ///
- IList GetPermissions(string prefix = null);
-
- ///
- /// Get a single permissions by key
- ///
- Permission GetPermission(string key = null);
-
- ///
- /// Tries to switch the currently loaded backoffice application for the current user
- ///
- Task TrySwitchApp(string appId);
}
\ No newline at end of file
diff --git a/zero.Core/Identity/Services/AuthorizationService.cs b/zero.Core/Identity/Services/AuthorizationService.cs
index 09f9f899..e7c772dc 100644
--- a/zero.Core/Identity/Services/AuthorizationService.cs
+++ b/zero.Core/Identity/Services/AuthorizationService.cs
@@ -71,7 +71,7 @@ public class AuthorizationService : IAuthorizationService
public EntityPermission GetPermissionForEntity(T model, string permissionKey) where T : ZeroEntity
{
- EntityPermission result = new EntityPermission();
+ EntityPermission result = new();
if (!IsLoggedIn())
{
diff --git a/zero.Core/Identity/Services/UserService.cs b/zero.Core/Identity/Services/UserService.cs
index dc8df408..77692739 100644
--- a/zero.Core/Identity/Services/UserService.cs
+++ b/zero.Core/Identity/Services/UserService.cs
@@ -212,6 +212,40 @@ public class UserService : BackofficeApi, IUserService
return EntityResult.Success(user);
}
+
+
+ ///
+ public async Task TrySwitchApp(string appId)
+ {
+ IZeroDocumentSession session = Store.Session(global: true);
+ ZeroUser user = await GetUser();
+
+ if (user == null || appId.IsNullOrEmpty())
+ {
+ return false;
+ }
+
+ string[] allowedAppIds = user.GetAllowedAppIds();
+
+ bool isMainId = appId.Equals(user.AppId, StringComparison.InvariantCultureIgnoreCase);
+ bool isAllowedId = allowedAppIds.Contains(appId, StringComparer.InvariantCultureIgnoreCase);
+
+ if (user.IsSuper || isMainId || isAllowedId)
+ {
+ user.CurrentAppId = appId;
+
+ //byte[] bytes = new byte[20];
+ //RandomNumberGenerator.Fill(bytes);
+ //user.SecurityStamp = Base32.ToBase32(bytes); // TODO update security stamp but Base32 is .net core internal
+
+ await session.StoreAsync(user);
+ await session.SaveChangesAsync();
+
+ return true;
+ }
+
+ return false;
+ }
}
@@ -272,4 +306,9 @@ public interface IUserService : IBackofficeApi
/// Disables a user
///
Task> Disable(ZeroUser user);
+
+ ///
+ /// Tries to switch the currently loaded backoffice application for the current user
+ ///
+ Task TrySwitchApp(string appId);
}
\ No newline at end of file
diff --git a/zero.Core/Localization/CultureService.cs b/zero.Core/Localization/CultureService.cs
index 18f56d1c..b1a111a4 100644
--- a/zero.Core/Localization/CultureService.cs
+++ b/zero.Core/Localization/CultureService.cs
@@ -10,7 +10,7 @@ public class CultureService : ICultureService
return CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(x => !x.Name.IsNullOrWhiteSpace())
.Select(x => new CultureInfo(x.Name))
- .Where(x => codes.Length > 0 ? codes.Contains(x.Name, StringComparer.InvariantCultureIgnoreCase) : true)
+ .Where(x => codes.Length == 0 || codes.Contains(x.Name, StringComparer.InvariantCultureIgnoreCase))
.OrderBy(x => x.DisplayName)
.Select(x => new Culture()
{
diff --git a/zero.Core/Media/MediaCollection.cs b/zero.Core/Media/MediaCollection.cs
index c8b3c6a6..ff1d1526 100644
--- a/zero.Core/Media/MediaCollection.cs
+++ b/zero.Core/Media/MediaCollection.cs
@@ -137,24 +137,23 @@ namespace zero.Core.Collections
// write additional image data + thumbnail
if (media.Type == MediaType.Image)
{
- using (Image image = Image.Load(filePath))
+ using Image image = Image.Load(filePath);
+
+ media.ImageMeta = GetImageMeta(image);
+
+ Image imageFrame = media.ImageMeta.Frames > 1 ? image.Frames.CloneFrame(0) : image;
+
+ media.PreviewSource = SaveThumbnail(media, imageFrame, PREVIEW_EXTENSION, new ResizeOptions()
{
- media.ImageMeta = GetImageMeta(image);
+ Size = new Size(210, 210),
+ Mode = ResizeMode.Min
+ });
- Image imageFrame = media.ImageMeta.Frames > 1 ? image.Frames.CloneFrame(0) : image;
-
- media.PreviewSource = SaveThumbnail(media, imageFrame, PREVIEW_EXTENSION, new ResizeOptions()
- {
- Size = new Size(210, 210),
- Mode = ResizeMode.Min
- });
-
- media.ThumbnailSource = SaveThumbnail(media, imageFrame, THUMB_EXTENSION, new ResizeOptions()
- {
- Size = new Size(100, 100),
- Mode = ResizeMode.Max
- });
- }
+ media.ThumbnailSource = SaveThumbnail(media, imageFrame, THUMB_EXTENSION, new ResizeOptions()
+ {
+ Size = new Size(100, 100),
+ Mode = ResizeMode.Max
+ });
}
return media;
diff --git a/zero.Core/Pages/Modules/IModuleTypeHandler.cs b/zero.Core/Pages/Modules/IModuleTypeHandler.cs
new file mode 100644
index 00000000..c7ca1700
--- /dev/null
+++ b/zero.Core/Pages/Modules/IModuleTypeHandler.cs
@@ -0,0 +1,6 @@
+namespace zero.Pages;
+
+public interface IModuleTypeHandler : IHandler
+{
+ IEnumerable GetAllowedModuleTypes(Application application, IEnumerable registeredTypes, Page page = default, string[] tags = default);
+}
\ No newline at end of file
diff --git a/zero.Core/Pages/Modules/Module.cs b/zero.Core/Pages/Modules/Module.cs
deleted file mode 100644
index b91a6cee..00000000
--- a/zero.Core/Pages/Modules/Module.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-namespace zero.Core.Entities
-{
- ///
- /// A module can consist of unlimited properties and be rendered as you wish
- /// The backoffice rendering is done by an IRenderer
- ///
- public class Module : ZeroIdEntity
- {
- ///
- /// Sort order
- ///
- public uint Sort { get; set; }
-
- ///
- /// Whether the module is visible in the frontend
- ///
- public bool IsActive { get; set; }
-
- ///
- /// Alias of the used module type
- ///
- public string ModuleTypeAlias { get; set; }
- }
-}
\ No newline at end of file
diff --git a/zero.Core/Pages/Modules/ModulePermissions.cs b/zero.Core/Pages/Modules/ModulePermissions.cs
index 3adccf27..5b37ad4d 100644
--- a/zero.Core/Pages/Modules/ModulePermissions.cs
+++ b/zero.Core/Pages/Modules/ModulePermissions.cs
@@ -1,17 +1,17 @@
-using zero.Core;
-using zero.Core.Identity;
+//using zero.Core;
+//using zero.Core.Identity;
-namespace zero.Web.Defaults
-{
- public class ModulePermissions : PermissionCollection
- {
- public ModulePermissions()
- {
- Alias = Constants.PermissionCollections.Modules;
- Label = "@permission.collections.modules";
- Description = "@permission.collections.modules_description";
+//namespace zero.Web.Defaults
+//{
+// public class ModulePermissions : PermissionCollection
+// {
+// public ModulePermissions()
+// {
+// Alias = Constants.PermissionCollections.Modules;
+// Label = "@permission.collections.modules";
+// Description = "@permission.collections.modules_description";
- // Items get added at runtime
- }
- }
-}
+// // Items get added at runtime
+// }
+// }
+//}
diff --git a/zero.Core/Pages/Modules/ModuleType.cs b/zero.Core/Pages/Modules/ModuleType.cs
deleted file mode 100644
index 0f2cd5c8..00000000
--- a/zero.Core/Pages/Modules/ModuleType.cs
+++ /dev/null
@@ -1,81 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace zero.Core.Entities
-{
- ///
- /// A module type holds information about a Module implementation
- ///
- public class ModuleType : ModuleType where T : Module, new()
- {
- public ModuleType() : base(typeof(T)) { }
- }
-
-
- ///
- /// A module type holds information about a Module implementation
- ///
- public class ModuleType
- {
- ///
- /// Type of the associated module class
- ///
- public Type ContentType { get; private set; }
-
- ///
- /// Alias for querying
- ///
- public string Alias { get; set; }
-
- ///
- /// Name of the module type
- ///
- public string Name { get; set; }
-
- ///
- /// Optional description
- ///
- public string Description { get; set; }
-
- ///
- /// Icon of the module type
- ///
- public string Icon { get; set; }
-
- ///
- /// Optionally group modules together
- ///
- public string Group { get; set; }
-
- ///
- /// Defining tags for a module type allows you to query for them
- ///
- public List Tags { get; set; } = new List();
-
- ///
- /// Page types where this module type is not allowed.
- /// This will only work when operating within the page context.
- ///
- public List DisallowedPageTypes { get; set; } = new List();
-
-
- public ModuleType(Type type)
- {
- ContentType = type;
- }
-
- public static ModuleType Convert(ModuleType model) where T : Module, new()
- {
- return new ModuleType(model.ContentType)
- {
- Alias = model.Alias,
- Name = model.Name,
- Description = model.Description,
- Icon = model.Icon,
- Group = model.Group,
- Tags = model.Tags,
- DisallowedPageTypes = model.DisallowedPageTypes
- };
- }
- }
-}
diff --git a/zero.Core/Pages/Modules/ModulesApi.cs b/zero.Core/Pages/Modules/ModulesApi.cs
index 9f038912..b67dc7b9 100644
--- a/zero.Core/Pages/Modules/ModulesApi.cs
+++ b/zero.Core/Pages/Modules/ModulesApi.cs
@@ -24,10 +24,10 @@ namespace zero.Core.Api
///
- public async Task> GetModuleTypes(string[] tags = default, string pageId = default)
+ public async Task> GetModuleTypes(string[] tags = default, string pageId = default)
{
- IEnumerable types = Options.Modules.GetAllItems();
- List modules = types.ToList();
+ IEnumerable types = Options.Modules.GetAllItems();
+ List modules = types.ToList();
Page page = null;
if (!pageId.IsNullOrEmpty())
@@ -53,7 +53,7 @@ namespace zero.Core.Api
///
- public ModuleType GetModuleType(string alias)
+ public PageModuleType GetModuleType(string alias)
{
return Options.Modules.GetAllItems().FirstOrDefault(x => x.Alias == alias);
}
@@ -65,11 +65,11 @@ namespace zero.Core.Api
///
/// Get all available module types (can be limited to the passed tags)
///
- Task> GetModuleTypes(string[] tags = default, string pageId = default);
+ Task> GetModuleTypes(string[] tags = default, string pageId = default);
///
/// Get a specific module type by alias
///
- ModuleType GetModuleType(string alias);
+ PageModuleType GetModuleType(string alias);
}
}
diff --git a/zero.Core/Pages/Modules/PageModule.cs b/zero.Core/Pages/Modules/PageModule.cs
new file mode 100644
index 00000000..08811191
--- /dev/null
+++ b/zero.Core/Pages/Modules/PageModule.cs
@@ -0,0 +1,23 @@
+namespace zero.Pages;
+
+///
+/// A module can consist of unlimited properties and be rendered as you wish
+/// The backoffice rendering is done by an IRenderer
+///
+public class PageModule : ZeroIdEntity
+{
+ ///
+ /// Sort order
+ ///
+ public uint Sort { get; set; }
+
+ ///
+ /// Whether the module is visible in the frontend
+ ///
+ public bool IsActive { get; set; }
+
+ ///
+ /// Alias of the used module type
+ ///
+ public string ModuleTypeAlias { get; set; }
+}
\ No newline at end of file
diff --git a/zero.Core/Configuration/ConfigurationParts/ModuleOptions.cs b/zero.Core/Pages/Modules/PageModuleOptions.cs
similarity index 64%
rename from zero.Core/Configuration/ConfigurationParts/ModuleOptions.cs
rename to zero.Core/Pages/Modules/PageModuleOptions.cs
index b2682a5c..2b39de7a 100644
--- a/zero.Core/Configuration/ConfigurationParts/ModuleOptions.cs
+++ b/zero.Core/Pages/Modules/PageModuleOptions.cs
@@ -1,20 +1,16 @@
-using System;
-using System.Collections.Generic;
-using zero.Core.Entities;
+namespace zero.Pages;
-namespace zero.Configuration;
-
-public class ModuleOptions : OptionsEnumerable, IOptionsEnumerable
+public class PageModuleOptions : List
{
- public void Add(ModuleType moduleType) where T : Module, new()
+ public void Add(PageModuleType moduleType) where T : PageModule, new()
{
- Items.Add(ModuleType.Convert(moduleType));
+ Add(PageModuleType.Convert(moduleType));
}
- public void Add(string alias, string name, string description, string icon, string group = null, List tags = null, List disallowedPageTypes = null) where T : Module, new()
+ public void Add(string alias, string name, string description, string icon, string group = null, List tags = null, List disallowedPageTypes = null) where T : PageModule, new()
{
- Items.Add(new ModuleType(typeof(T))
+ Add(new PageModuleType(typeof(T))
{
Alias = alias,
Name = name,
@@ -29,7 +25,7 @@ public class ModuleOptions : OptionsEnumerable, IOptionsEnumerable
public void Add(Type type, string alias, string name, string description, string icon, string group = null, List tags = null, List disallowedPageTypes = null)
{
- Items.Add(new ModuleType(type)
+ Add(new PageModuleType(type)
{
Alias = alias,
Name = name,
@@ -40,4 +36,4 @@ public class ModuleOptions : OptionsEnumerable, IOptionsEnumerable
DisallowedPageTypes = disallowedPageTypes ?? new List()
});
}
-}
+}
\ No newline at end of file
diff --git a/zero.Core/Pages/Modules/PageModuleType.cs b/zero.Core/Pages/Modules/PageModuleType.cs
new file mode 100644
index 00000000..6090ae65
--- /dev/null
+++ b/zero.Core/Pages/Modules/PageModuleType.cs
@@ -0,0 +1,77 @@
+namespace zero.Pages;
+
+///
+/// A module type holds information about a Module implementation
+///
+public class PageModuleType : PageModuleType where T : PageModule, new()
+{
+ public PageModuleType() : base(typeof(T)) { }
+}
+
+
+///
+/// A module type holds information about a Module implementation
+///
+public class PageModuleType
+{
+ ///
+ /// Type of the associated module class
+ ///
+ public Type ContentType { get; private set; }
+
+ ///
+ /// Alias for querying
+ ///
+ public string Alias { get; set; }
+
+ ///
+ /// Name of the module type
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Optional description
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// Icon of the module type
+ ///
+ public string Icon { get; set; }
+
+ ///
+ /// Optionally group modules together
+ ///
+ public string Group { get; set; }
+
+ ///
+ /// Defining tags for a module type allows you to query for them
+ ///
+ public List Tags { get; set; } = new List();
+
+ ///
+ /// Page types where this module type is not allowed.
+ /// This will only work when operating within the page context.
+ ///
+ public List DisallowedPageTypes { get; set; } = new List();
+
+
+ public PageModuleType(Type type)
+ {
+ ContentType = type;
+ }
+
+ public static PageModuleType Convert(PageModuleType model) where T : PageModule, new()
+ {
+ return new PageModuleType(model.ContentType)
+ {
+ Alias = model.Alias,
+ Name = model.Name,
+ Description = model.Description,
+ Icon = model.Icon,
+ Group = model.Group,
+ Tags = model.Tags,
+ DisallowedPageTypes = model.DisallowedPageTypes
+ };
+ }
+}
\ No newline at end of file
diff --git a/zero.Core/Configuration/ConfigurationParts/PageOptions.cs b/zero.Core/Pages/PageOptions.cs
similarity index 62%
rename from zero.Core/Configuration/ConfigurationParts/PageOptions.cs
rename to zero.Core/Pages/PageOptions.cs
index 132f1664..6086671a 100644
--- a/zero.Core/Configuration/ConfigurationParts/PageOptions.cs
+++ b/zero.Core/Pages/PageOptions.cs
@@ -1,28 +1,19 @@
-using System;
-using System.Linq;
-using zero.Core.Entities;
+namespace zero.Pages;
-namespace zero.Configuration;
-
-public class PageOptions : OptionsEnumerable, IOptionsEnumerable
+public class PageOptions : List
{
- public PageOptions()
- {
-
- }
-
public string Root { get; set; } = Constants.Pages.DefaultRootPageTypeAlias;
public void Add(PageType pageType) where T : Page, new()
{
- Items.Add(PageType.Convert(pageType));
+ Add(PageType.Convert(pageType));
}
public void Add(string alias, string name, string description, string icon) where T : Page, new()
{
- Items.Add(new PageType(typeof(T))
+ Add(new PageType(typeof(T))
{
Alias = alias,
Name = name,
@@ -34,7 +25,7 @@ public class PageOptions : OptionsEnumerable, IOptionsEnumerable
public void Add(Type type, string alias, string name, string description, string icon)
{
- Items.Add(new PageType(type)
+ Add(new PageType(type)
{
Alias = alias,
Name = name,
@@ -45,6 +36,6 @@ public class PageOptions : OptionsEnumerable, IOptionsEnumerable
public PageType GetByAlias(string alias)
{
- return Items.FirstOrDefault(x => x.Alias == alias);
+ return this.FirstOrDefault(x => x.Alias == alias);
}
}
diff --git a/zero.Core/Pages/ServiceCollectionExtensions.cs b/zero.Core/Pages/ServiceCollectionExtensions.cs
index 6174ef35..8cc88fd6 100644
--- a/zero.Core/Pages/ServiceCollectionExtensions.cs
+++ b/zero.Core/Pages/ServiceCollectionExtensions.cs
@@ -1,14 +1,19 @@
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
namespace zero.Pages;
internal static class ServiceCollectionExtensions
{
- public static IServiceCollection AddZeroPages(this IServiceCollection services)
+ public static IServiceCollection AddZeroPages(this IServiceCollection services, IConfiguration config)
{
services.AddScoped();
services.AddScoped();
+ services.AddOptions().Bind(config.GetSection("Zero:Pages"));
+ services.AddOptions().Bind(config.GetSection("Zero:PageModules"));
+
services.Configure(opts =>
{
RavenOptions raven = opts.For();
diff --git a/zero.Core/Persistence/RavenOptions.cs b/zero.Core/Persistence/RavenOptions.cs
index a45909a2..fb61c851 100644
--- a/zero.Core/Persistence/RavenOptions.cs
+++ b/zero.Core/Persistence/RavenOptions.cs
@@ -9,13 +9,13 @@ public class RavenOptions
public string Database { get; set; }
- public string CollectionPrefix { get; set; }
+ public string CollectionPrefix { get; set; } = String.Empty;
public RavenIndexesOptions Indexes { get; set; } = new();
}
-public class RavenIndexesOptions : OptionsEnumerable, IOptionsEnumerable
+public class RavenIndexesOptions : List
{
public class Map
{
@@ -35,17 +35,17 @@ public class RavenIndexesOptions : OptionsEnumerable, I
public void Add() where T : IZeroIndexDefinition, new()
{
- Items.Add(new(typeof(T), () => new T()));
+ base.Add(new Map(typeof(T), () => new T()));
}
public void Add(Type indexType)
{
- Items.Add(new(indexType, () => (IZeroIndexDefinition)Activator.CreateInstance(indexType)));
+ base.Add(new Map(indexType, () => (IZeroIndexDefinition)Activator.CreateInstance(indexType)));
}
public void Add(T index) where T : IZeroIndexDefinition
{
- Items.Add(new(typeof(T), () => index));
+ base.Add(new Map(typeof(T), () => index));
}
public void AddRange(params Type[] indexes)
@@ -65,17 +65,17 @@ public class RavenIndexesOptions : OptionsEnumerable, I
public void Replace(Type origin, Type replaceWith)
{
- var item = Items.FirstOrDefault(x => x.Type == origin);
+ var item = this.FirstOrDefault(x => x.Type == origin);
if (item != null)
{
- Items.Remove(item);
+ Remove(item);
}
Add(replaceWith);
}
public IEnumerable BuildAll(IZeroOptions options, IDocumentStore store)
{
- foreach (Map map in Items)
+ foreach (Map map in this)
{
IZeroIndexDefinition index = map.CreateIndex.Compile().Invoke();
index.Setup(options, store);
@@ -86,7 +86,7 @@ public class RavenIndexesOptions : OptionsEnumerable, I
}
-public class RavenIndexModifiersOptions : OptionsEnumerable, IOptionsEnumerable
+public class RavenIndexModifiersOptions : List
{
public class Modifier
{
@@ -97,7 +97,7 @@ public class RavenIndexModifiersOptions : OptionsEnumerable(Action modify) where T : IZeroIndexDefinition, new()
{
- Items.Add(new()
+ Add(new()
{
Type = typeof(T),
Modify = x => modify((T)x)
@@ -110,7 +110,7 @@ public class RavenIndexModifiersOptions : OptionsEnumerable GetAllForType(Type type)
{
- foreach (Modifier modifier in Items.Where(x => x.Type.IsAssignableFrom(type)))
+ foreach (Modifier modifier in this.Where(x => x.Type.IsAssignableFrom(type)))
{
yield return modifier;
}
diff --git a/zero.Core/Persistence/ServiceCollectionExtensions.cs b/zero.Core/Persistence/ServiceCollectionExtensions.cs
index c21f0696..442d71f9 100644
--- a/zero.Core/Persistence/ServiceCollectionExtensions.cs
+++ b/zero.Core/Persistence/ServiceCollectionExtensions.cs
@@ -1,4 +1,5 @@
-using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using Raven.Client.Documents;
using Raven.Client.Http;
@@ -6,12 +7,15 @@ namespace zero.Persistence;
internal static class ServiceCollectionExtensions
{
- public static IServiceCollection AddZeroPersistence(this IServiceCollection services)
+ public static IServiceCollection AddZeroPersistence(this IServiceCollection services, IConfiguration config)
{
services.AddSingleton();
services.AddSingleton(CreateRavenStore);
services.AddScoped();
services.AddScoped();
+
+ services.AddOptions().Bind(config.GetSection("Zero:Raven"));
+
return services;
}
diff --git a/zero.Core/Configuration/ConfigurationParts/SpaceOptions.cs b/zero.Core/Spaces/SpaceOptions.cs
similarity index 79%
rename from zero.Core/Configuration/ConfigurationParts/SpaceOptions.cs
rename to zero.Core/Spaces/SpaceOptions.cs
index f0f789ea..62c21151 100644
--- a/zero.Core/Configuration/ConfigurationParts/SpaceOptions.cs
+++ b/zero.Core/Spaces/SpaceOptions.cs
@@ -1,25 +1,18 @@
-using System.Linq;
-using zero.Core.Entities;
+using zero.Core.Entities;
-namespace zero.Configuration;
+namespace zero.Spaces;
-public class SpaceOptions : OptionsEnumerable, IOptionsEnumerable
+public class SpaceOptions : List
{
- public SpaceOptions()
- {
-
- }
-
-
public void Add() where T : Space, new()
{
- Items.Add(new T());
+ Add(new T());
}
public void AddList(string alias, string name, string description, string icon) where T : SpaceContent, new()
{
- Items.Add(new Space()
+ Add(new Space()
{
Alias = alias,
View = SpaceView.List,
@@ -33,7 +26,7 @@ public class SpaceOptions : OptionsEnumerable, IOptionsEnumerable
public void AddEditor(string alias, string name, string description, string icon) where T : SpaceContent, new()
{
- Items.Add(new Space()
+ Add(new Space()
{
Alias = alias,
View = SpaceView.Editor,
@@ -47,7 +40,7 @@ public class SpaceOptions : OptionsEnumerable, IOptionsEnumerable
public void AddSeparator()
{
- Space lastSpace = Items.LastOrDefault();
+ Space lastSpace = this.LastOrDefault();
if (lastSpace != null)
{
@@ -58,7 +51,7 @@ public class SpaceOptions : OptionsEnumerable, IOptionsEnumerable
public void AddCustom(string componentPath, string alias, string name, string description, string icon) where T : SpaceContent, new()
{
- Items.Add(new Space()
+ Add(new Space()
{
Alias = alias,
View = SpaceView.Custom,
@@ -73,7 +66,7 @@ public class SpaceOptions : OptionsEnumerable, IOptionsEnumerable
public void AddCustom(string componentPath, string alias, string name, string description, string icon)
{
- Items.Add(new Space()
+ Add(new Space()
{
Alias = alias,
View = SpaceView.Custom,
diff --git a/zero.Core/Stores/EntityStore.cs b/zero.Core/Stores/EntityStore.cs
index d78e6264..d49750e9 100644
--- a/zero.Core/Stores/EntityStore.cs
+++ b/zero.Core/Stores/EntityStore.cs
@@ -50,9 +50,6 @@ public abstract class EntityStore : IEntityStore where T : ZeroIdEntity, n
///
public virtual Task> LoadAll() => Operations.LoadAll();
- ///