diff --git a/zero.Backoffice/Abstractions/BackofficeController.cs b/zero.Backoffice/Abstractions/BackofficeController.cs new file mode 100644 index 00000000..b1eedd4c --- /dev/null +++ b/zero.Backoffice/Abstractions/BackofficeController.cs @@ -0,0 +1,252 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.StaticFiles; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using zero.Core.Api; +using zero.Core.Entities; +using zero.Core.Identity; +using zero.Core.Options; + +namespace zero.Backoffice; + +[ZeroAuthorize] +//[ServiceFilter(typeof(ModelStateValidationFilterAttribute))] +[ApiController] +[Route("getsreplaced/[controller]/[action]")] +//[ServiceFilter(typeof(BackofficeFilterAttribute))] +public abstract class ZeroBackofficeController : ControllerBase +{ + IZeroOptions _options; + + public bool IsCoreDatabase { get; protected set; } + + protected IZeroOptions Options => _options ?? (_options = HttpContext?.RequestServices?.GetService()); + + + /// + /// Is execuated when the scope changes. + /// The scope is evaluated by the BackofficeFilterAttribute. + /// + public virtual void OnScopeChanged(string scope) { } + + + /// + /// Creates an edit model with appropriate options and permissions + /// + public EditModel Edit(T data, bool typed = true, Action> transform = null) where T : ZeroIdEntity + { + Type type = typeof(T); + + //ControllerContext.ActionDescriptor.FilterDescriptors[0]. + + if (data == null) + { + return null; + } + + EditModel model = new EditModel(); + model.Entity = data; + model.Meta.Token = null; // Token.Get(data); + //model.Meta.IsAppAware = AppAwareType.IsAssignableFrom(type); // TODO appx + //model.Meta.CanBeShared = canBeShared; + model.Meta.CanCreate = true; + //model.Meta.CanCreateShared = canBeShared; + model.Meta.CanEdit = true; + model.Meta.CanDelete = true; + model.Meta.IsShared = IsCoreDatabase; + + transform?.Invoke(model); + + return model; + } + + + /// + /// Creates an edit model with appropriate options and permissions + /// + public TWrapper Edit(TWrapper data, bool typed = true, Action> transform = null) + where T : ZeroIdEntity + where TWrapper : EditModel, new() + { + Type type = typeof(T); + + //ControllerContext.ActionDescriptor.FilterDescriptors[0]. + + data.Meta.Token = null; // Token.Get(data.Entity); + //data.Meta.IsAppAware = AppAwareType.IsAssignableFrom(type); // TODO appx + //data.Meta.CanBeShared = canBeShared; + data.Meta.CanCreate = true; + //data.Meta.CanCreateShared = canBeShared; + data.Meta.CanEdit = true; + data.Meta.CanDelete = true; + data.Meta.IsShared = IsCoreDatabase; + + transform?.Invoke(data); + + return data; + } + + + public IList Previews(Dictionary items, Func transform) + { + IList previews = new List(); + + foreach (var item in items) + { + bool exists = item.Value != null; + + if (!exists) + { + previews.Add(new PreviewModel() + { + HasError = true, + Icon = "fth-alert-circle color-red", + Id = item.Key, + Name = "@errors.preview.notfound", + Text = "@errors.preview.notfound_text" + }); + } + else + { + previews.Add(transform(item.Value)); + } + } + + return previews; + } + + + public IList Previews(Dictionary items, Action transform = null) where T : ZeroIdEntity + { + IList previews = new List(); + + foreach (var item in items) + { + if (item.Value == null) + { + previews.Add(new PreviewModel() + { + HasError = true, + Icon = "fth-alert-circle color-red", + Id = item.Key, + Name = "@errors.preview.notfound", + Text = "@errors.preview.notfound_text" + }); + } + else + { + PreviewModel model = new() + { + Id = item.Value.Id + }; + + if (item.Value is ZeroEntity) + { + model.Name = (item.Value as ZeroEntity).Name; + } + + transform?.Invoke(item.Value, model); + + previews.Add(model); + } + } + + return previews; + } + + + + public async Task> SelectList(IAsyncEnumerable enumerable, Action transform = null) where T : ZeroIdEntity + { + List items = new List(); + + await foreach (T item in enumerable) + { + SelectModel model = new() + { + Id = item.Id + }; + + if (item is ZeroEntity) + { + model.Name = (item as ZeroEntity).Name; + model.IsActive = (item as ZeroEntity).IsActive; + } + + transform?.Invoke(item, model); + + items.Add(model); + } + + return items; + } + + + + public async Task> Previews(Dictionary items, Func> transform) + { + IList previews = new List(); + + foreach (var item in items) + { + bool exists = item.Value != null; + + if (!exists) + { + previews.Add(new PreviewModel() + { + HasError = true, + Icon = "fth-alert-circle color-red", + Id = item.Key, + Name = "@errors.preview.notfound", + Text = "@errors.preview.notfound_text" + }); + } + else + { + previews.Add(await transform(item.Value)); + } + } + + return previews; + } + + + protected IActionResult Download(Stream stream, string filename) + { + if (stream == null) + { + // TODO add success property + return error response + } + + if (filename.Contains("{date}")) + { + filename = filename.Replace("{date}", DateTimeOffset.Now.ToString("yyyy-MM-dd")); + } + + var provider = new FileExtensionContentTypeProvider(); + if (filename == null || !provider.TryGetContentType(Path.GetFileName(filename), out string contentType)) + { + contentType = "application/octet-stream"; + } + + Response.Headers.Add("zero-filename", filename); + + return base.File(stream, contentType, filename, true); + } + + + protected IActionResult File(Core.Entities.FileResult file) + { + if (file == null) + { + return NotFound(); + } + + FileStream stream = System.IO.File.OpenRead(file.Path); + return File(stream, file.ContentType, file.Filename); + } +} \ No newline at end of file diff --git a/zero.Backoffice/Abstractions/ZeroBackofficeCollectionController.cs b/zero.Backoffice/Abstractions/ZeroBackofficeCollectionController.cs new file mode 100644 index 00000000..dce5a86c --- /dev/null +++ b/zero.Backoffice/Abstractions/ZeroBackofficeCollectionController.cs @@ -0,0 +1,71 @@ +using Microsoft.AspNetCore.Mvc; +using Raven.Client.Documents.Linq; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using zero.Core; +using zero.Core.Entities; + + +namespace zero.Backoffice; + +public abstract class ZeroBackofficeCollectionController : ZeroBackofficeController + where TEntity : ZeroIdEntity, new() + where TCollection : IEntityCollection +{ + protected TCollection Collection { get; private set; } + + [Obsolete] + protected Func, IRavenQueryable> DefaultQuery { get; set; } + + protected Action PreviewTransform { get; set; } + + protected Action PickerTransform { get; set; } + + + public ZeroBackofficeCollectionController(TCollection collection) + { + Collection = collection; + } + + public override void OnScopeChanged(string scope) + { + //Collection.ApplyScope(scope); + } + + + public virtual async Task> GetById([FromQuery] string id, [FromQuery] string changeVector = null) => Edit(await Collection.Load(id, changeVector)); + + + public virtual async Task> GetByIds([FromQuery] string[] ids) => await Collection.Load(ids); + + + public virtual async Task> GetEmpty() => Edit(await Collection.Empty()); + + + public virtual async Task> GetByQuery([FromQuery] ListBackofficeQuery query) + { + return await Collection.Load(query); + } + + + public virtual async Task> GetRevisions([FromQuery] string id, [FromQuery] ListBackofficeQuery query) + { + return null; // TODO + //return await Collection.GetRevisions(id, query.Page, query.PageSize); + } + + + public virtual async Task> GetForPicker() => await SelectList(Collection.Stream(), PickerTransform); + + + public virtual async Task> GetPreviews([FromQuery] List ids) => Previews(await Collection.Load(ids), PreviewTransform); + + + [HttpPost] + public virtual async Task> Save([FromBody] TEntity model) => await Collection.Save(model); + + + [HttpDelete] + public virtual async Task> Delete([FromQuery] string id) => await Collection.Delete(id); +} \ No newline at end of file diff --git a/zero.Backoffice/Endpoints/Countries.cs b/zero.Backoffice/Endpoints/Countries.cs new file mode 100644 index 00000000..962d0d3d --- /dev/null +++ b/zero.Backoffice/Endpoints/Countries.cs @@ -0,0 +1,23 @@ +//using Microsoft.AspNetCore.Mvc; +//using Raven.Client.Documents; +//using Raven.Client.Documents.Linq; +//using System.Threading.Tasks; +//using zero; + +//namespace zero.Backoffice +//{ +// [ZeroAuthorize(Permissions.Settings.Countries, PermissionsValue.Read)] +// public class CountriesController : ZeroBackofficeCollectionController +// { +// public CountriesController(ICountriesCollection collection) : base(collection) +// { +// PreviewTransform = (item, model) => model.Icon = "flag-" + item.Code.ToLowerInvariant(); +// } + +// public override Task> GetByQuery([FromQuery] ListBackofficeQuery query) +// { +// query.OrderQuery = q => q.OrderByDescending(x => x.IsPreferred).ThenBy(x => x.Name); +// return Collection.Load(query); +// } +// } +//} diff --git a/zero.Backoffice/Models/EditModel.cs b/zero.Backoffice/Models/EditModel.cs new file mode 100644 index 00000000..7d910902 --- /dev/null +++ b/zero.Backoffice/Models/EditModel.cs @@ -0,0 +1,61 @@ +using System; + +namespace zero.Backoffice; + +public class EditModel : EditModel { } + +public class EditModel +{ + /// + /// Model + /// + public T Entity { get; set; } + + /// + /// Meta data + /// + public EditMetaModel Meta { get; set; } = new(); +} + + +public class EditMetaModel +{ + /// + /// Whether an entity of this type can be created + /// + public bool CanCreate { get; set; } + + /// + /// Whether an entity of this type can be created in the shared app space + /// + public bool CanCreateShared { get; set; } + + /// + /// Whether this entity can be edited or only viewed + /// + public bool CanEdit { get; set; } + + /// + /// Whether this entity can be deleted + /// + public bool CanDelete { get; set; } + + /// + /// Wehther this entity is application aware + /// + public bool IsAppAware { get; set; } + + /// + /// Whether this entity can be shared across applications (only for IsAppAware=true) + /// + public bool CanBeShared { get; set; } + + public bool IsShared { get; set; } + + /// + /// The change token maps to a database entity which holds ID and collection of the model to edit + /// If these values do not match the entity on save it is rejected + /// // TODO expiration expiry session.Advanced.GetMetadataFor(user)[Raven.Client.Constants.Documents.Metadata.Expires] = DateTime.UtcNow.AddMinutes(60); + /// + public string Token { get; set; } +} diff --git a/zero.Backoffice/Module.cs b/zero.Backoffice/Module.cs new file mode 100644 index 00000000..cfa0ba0f --- /dev/null +++ b/zero.Backoffice/Module.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Options; + +namespace zero.Backoffice; + +internal class BackofficeModule : ZeroModule +{ + /// + public override void Register(IZeroModuleConfiguration config) + { + config.Services.TryAddEnumerable(ServiceDescriptor.Transient, ZeroBackofficeMvcOptions>()); + } +} \ No newline at end of file diff --git a/zero.Backoffice/ZeroBackofficeControllerModelConvention.cs b/zero.Backoffice/ZeroBackofficeControllerModelConvention.cs new file mode 100644 index 00000000..39f6bfb4 --- /dev/null +++ b/zero.Backoffice/ZeroBackofficeControllerModelConvention.cs @@ -0,0 +1,32 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApplicationModels; +using System; + +namespace zero.Backoffice; + +public class ZeroBackofficeControllerModelConvention : IControllerModelConvention +{ + readonly AttributeRouteModel RouteModel; + + readonly Type BaseClass = typeof(ZeroBackofficeController); + + + public ZeroBackofficeControllerModelConvention(string backofficePath) + { + RouteModel = new AttributeRouteModel(new RouteAttribute(backofficePath + "/api/[controller]/[action]")); + } + + + public void Apply(ControllerModel controller) + { + if (!controller.ControllerType.IsSubclassOf(BaseClass)) + { + return; + } + + foreach (var selector in controller.Selectors) + { + selector.AttributeRouteModel = RouteModel; + } + } +} \ No newline at end of file diff --git a/zero.Backoffice/ZeroBackofficeMvcOptions.cs b/zero.Backoffice/ZeroBackofficeMvcOptions.cs new file mode 100644 index 00000000..d310df82 --- /dev/null +++ b/zero.Backoffice/ZeroBackofficeMvcOptions.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; + +namespace zero.Backoffice; + +class ZeroBackofficeMvcOptions : IConfigureOptions +{ + IZeroOptions Options { get; set; } + + public ZeroBackofficeMvcOptions(IZeroOptions options) + { + Options = options; + } + + public void Configure(MvcOptions options) + { + //options.Conventions.Add(new ZeroBackofficeControllerModelConvention(Options.BackofficePath)); + } +} \ No newline at end of file diff --git a/zero.Backoffice/zero.Backoffice.csproj b/zero.Backoffice/zero.Backoffice.csproj new file mode 100644 index 00000000..3ce542aa --- /dev/null +++ b/zero.Backoffice/zero.Backoffice.csproj @@ -0,0 +1,14 @@ + + + + zero.Backoffice + 0.1.0 + preview + net6.0 + true + + + + + + \ No newline at end of file diff --git a/zero.Core/Abstractions/IZeroRouteEntity.cs b/zero.Core/Abstractions/IZeroRouteEntity.cs new file mode 100644 index 00000000..6528b5ac --- /dev/null +++ b/zero.Core/Abstractions/IZeroRouteEntity.cs @@ -0,0 +1,14 @@ +namespace zero; + +public interface IZeroRouteEntity +{ + /// + /// Id of the entity + /// + string Id { get; set; } + + /// + /// Unique hash for this entity (primarily used for routing) + /// + string Hash { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Abstractions/ZeroEntity.cs b/zero.Core/Abstractions/ZeroEntity.cs new file mode 100644 index 00000000..5c0c20c3 --- /dev/null +++ b/zero.Core/Abstractions/ZeroEntity.cs @@ -0,0 +1,76 @@ +using Newtonsoft.Json; +using System; +using System.Diagnostics; + +namespace zero; + +[DebuggerDisplay("Id = {Id,nq}, Name = {Name}, Alias = {Alias}")] +public class ZeroEntity : ZeroIdEntity, IZeroDbConventions, IZeroRouteEntity +{ + /// + /// Full name of the entity + /// + public string Name { get; set; } + + /// + /// Alias (non-unique) which can be used in the frontend and URLs + /// + public string Alias { get; set; } + + /// + /// A key which can be used to query this entity in code + /// + public string Key { get; set; } + + /// + /// Sort order + /// + public uint Sort { get; set; } + + /// + /// Whether the entity is visible in the frontend + /// + public bool IsActive { get; set; } + + /// + /// Unique hash for this entity (primarily used for routing) + /// + public string Hash { get; set; } + + /// + /// Backoffice user who last modified this content + /// + public string LastModifiedById { get; set; } + + /// + /// Date of last modification + /// + public DateTimeOffset LastModifiedDate { get; set; } + + /// + /// Backoffice user who created this content + /// + public string CreatedById { get; set; } + + /// + /// Date of creation + /// + public DateTimeOffset CreatedDate { get; set; } + + /// + /// Configuration of the base entity (which this one inherits from) + /// + public BlueprintConfiguration Blueprint { get; set; } + + /// + /// Language of the entity + /// + public string LanguageId { get; set; } + + /// + /// [Warning] This field is always empty when bound to the database. + /// It is only filled in the app-code for routing. + /// + [JsonIgnore] + public string Url { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Abstractions/ZeroIdEntity.cs b/zero.Core/Abstractions/ZeroIdEntity.cs new file mode 100644 index 00000000..0efadec4 --- /dev/null +++ b/zero.Core/Abstractions/ZeroIdEntity.cs @@ -0,0 +1,9 @@ +namespace zero; + +public class ZeroIdEntity +{ + /// + /// Id of the entity + /// + public string Id { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Application/Application.cs b/zero.Core/Application/Application.cs new file mode 100644 index 00000000..6526b40a --- /dev/null +++ b/zero.Core/Application/Application.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace zero; + +/// +/// An application is a website. zero can host multiple websites at once which share common assets +/// +[RavenCollection("Applications")] +public class Application : ZeroEntity +{ + /// + /// 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/Application/ApplicationOptions.cs b/zero.Core/Application/ApplicationOptions.cs new file mode 100644 index 00000000..ff1098c0 --- /dev/null +++ b/zero.Core/Application/ApplicationOptions.cs @@ -0,0 +1,12 @@ +namespace zero; + +public class ApplicationOptions +{ + public ApplicationOptions() + { + EnableMultiple = false; + } + + + public bool EnableMultiple { get; set; } +} diff --git a/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscovery.cs b/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscovery.cs new file mode 100644 index 00000000..89ab072b --- /dev/null +++ b/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscovery.cs @@ -0,0 +1,164 @@ +using Microsoft.AspNetCore.Mvc.ApplicationParts; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace zero; + +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 new file mode 100644 index 00000000..51386f58 --- /dev/null +++ b/zero.Core/Architecture/AssemblyDiscovery/AssemblyDiscoveryContext.cs @@ -0,0 +1,26 @@ +using System.Reflection; + +namespace zero; + +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 new file mode 100644 index 00000000..16bde55c --- /dev/null +++ b/zero.Core/Architecture/AssemblyDiscovery/IAssemblyDiscoveryRule.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.DependencyModel; + +namespace zero; + +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/Blueprints/BlueprintConfiguration.cs b/zero.Core/Architecture/Blueprints/BlueprintConfiguration.cs new file mode 100644 index 00000000..30dcf344 --- /dev/null +++ b/zero.Core/Architecture/Blueprints/BlueprintConfiguration.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace zero; + +/// +/// 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 Id { 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/BlueprintOptions.cs b/zero.Core/Architecture/Blueprints/BlueprintOptions.cs new file mode 100644 index 00000000..17e642e5 --- /dev/null +++ b/zero.Core/Architecture/Blueprints/BlueprintOptions.cs @@ -0,0 +1,33 @@ +using System; +using zero.Core.Blueprints; + +namespace zero; + +public class BlueprintOptions : ZeroBackofficeCollection, IZeroCollectionOptions +{ + public BlueprintOptions() + { + Enabled = false; + } + + + public bool Enabled { get; set; } + + + public void Add() where T : Blueprint, new() + { + Items.Add(new T()); + } + + + public void Add(Blueprint implementation) where T : ZeroEntity, new() + { + Items.Add(implementation); + } + + + public void Add(Action> createExpression = null) where T : ZeroEntity, new() + { + Items.Add(new DefaultBlueprint(createExpression)); + } +} diff --git a/zero.Core/Architecture/ZeroModule.cs b/zero.Core/Architecture/ZeroModule.cs new file mode 100644 index 00000000..ee1adf77 --- /dev/null +++ b/zero.Core/Architecture/ZeroModule.cs @@ -0,0 +1,8 @@ +namespace zero; + +public class ZeroModule +{ + public virtual void Register(IZeroModuleConfiguration config) { } + + public virtual void Configure(IZeroOptions options) { } +} diff --git a/zero.Core/Architecture/ZeroModuleConfiguration.cs b/zero.Core/Architecture/ZeroModuleConfiguration.cs new file mode 100644 index 00000000..5ba47b57 --- /dev/null +++ b/zero.Core/Architecture/ZeroModuleConfiguration.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace zero; + +public class ZeroModuleConfiguration : IZeroModuleConfiguration +{ + public IServiceCollection Services { get; } + + public IConfiguration Configuration { get; } + + internal ZeroModuleConfiguration(IServiceCollection servicse, IConfiguration configuration) + { + Services = servicse; + Configuration = configuration; + } +} + + +public interface IZeroModuleConfiguration +{ + IServiceCollection Services { get; } + + IConfiguration Configuration { get; } +} diff --git a/zero.Core/Configuration/ConfigurationParts/FeatureOptions.cs b/zero.Core/Configuration/ConfigurationParts/FeatureOptions.cs new file mode 100644 index 00000000..ed683b7a --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/FeatureOptions.cs @@ -0,0 +1,21 @@ +using zero.Core.Entities; + +namespace zero; + +public class FeatureOptions : OptionsEnumerable, IOptionsEnumerable +{ + public void Add() where T : Feature, new() + { + Items.Add(new T()); + } + + public void Add(string alias, string name, string description) + { + Items.Add(new Feature() + { + Alias = alias, + Name = name, + Description = description + }); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/IconOptions.cs b/zero.Core/Configuration/ConfigurationParts/IconOptions.cs new file mode 100644 index 00000000..922ce6dc --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/IconOptions.cs @@ -0,0 +1,24 @@ +using zero.Core.Entities; + +namespace zero; + +public class IconOptions : OptionsEnumerable, IOptionsEnumerable +{ + /// + /// Add a new backoffice icon set + /// + /// Alias for reference + /// Name of the icon set + /// Path to the SVG sprite containing addressable symbols + /// Optional symbol identifier prefix (by default the alias is used) + public void AddSet(string alias, string name, string spritePath, string prefix = null) + { + Items.Add(new IconSet() + { + Alias = alias, + Name = name, + SpritePath = spritePath, + Prefix = prefix ?? alias + }); + } +} \ No newline at end of file diff --git a/zero.Core/Configuration/ConfigurationParts/IntegrationOptions.cs b/zero.Core/Configuration/ConfigurationParts/IntegrationOptions.cs new file mode 100644 index 00000000..dc342225 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/IntegrationOptions.cs @@ -0,0 +1,42 @@ +using FluentValidation; +using System; +using System.Collections.Generic; +using zero.Core.Integrations; + +namespace zero; + +public class IntegrationOptions : OptionsEnumerable, IOptionsEnumerable +{ + public void Add(IntegrationType integration) where T : Integration, new() + { + Items.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)) + { + Alias = alias, + Name = name, + Description = description, + ImagePath = imagePath, + Tags = tags, + Validator = validator + }); + } + + + 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) + { + Alias = alias, + Name = name, + Description = description, + ImagePath = imagePath, + Tags = tags, + Validator = validator + }); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/InterceptorOptions.cs b/zero.Core/Configuration/ConfigurationParts/InterceptorOptions.cs new file mode 100644 index 00000000..65ce2710 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/InterceptorOptions.cs @@ -0,0 +1,65 @@ +using System; +using zero.Core.Collections; + +namespace zero; + +public class InterceptorOptions : OptionsEnumerable, IOptionsEnumerable +{ + public void Add(int gravity = 0, Func canHandle = null) where T : ICollectionInterceptor + { + Type type = typeof(T); + + if (canHandle == null) + { + canHandle = _ => true; + } + + Items.Add(new InterceptorRegistration() + { + Hash = IdGenerator.Create(), + Name = type.Name, + Gravity = gravity, + CanHandle = canHandle, + InterceptorType = type + }); + } + + + public void Add(int gravity = 0, Func canHandle = null) + where T : ICollectionInterceptor + where TBoxed : ZeroEntity + { + Type type = typeof(T); + Type boxedType = typeof(TBoxed); + Func finalCanHandle = requestedType => + { + return boxedType.IsAssignableFrom(requestedType) && (canHandle == null || canHandle.Invoke(requestedType)); + }; + + Items.Add(new InterceptorRegistration() + { + Hash = IdGenerator.Create(), + Name = type.Name, + Gravity = gravity, + CanHandle = finalCanHandle, + InterceptorType = type, + IsInterceptorBoxed = true + }); + } +} + + +public class InterceptorRegistration +{ + public int Gravity { get; set; } + + public Type InterceptorType { get; set; } + + public string Hash { get; set; } + + public string Name { get; set; } + + public Func CanHandle { get; set; } + + public bool IsInterceptorBoxed { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Configuration/ConfigurationParts/ModuleOptions.cs b/zero.Core/Configuration/ConfigurationParts/ModuleOptions.cs new file mode 100644 index 00000000..ea216547 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/ModuleOptions.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using zero.Core.Entities; + +namespace zero; + +public class ModuleOptions : OptionsEnumerable, IOptionsEnumerable +{ + public void Add(ModuleType moduleType) where T : Module, new() + { + Items.Add(ModuleType.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() + { + Items.Add(new ModuleType(typeof(T)) + { + Alias = alias, + Name = name, + Description = description, + Icon = icon, + Group = group, + Tags = tags ?? new List(), + DisallowedPageTypes = disallowedPageTypes ?? new List() + }); + } + + + 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) + { + Alias = alias, + Name = name, + Description = description, + Icon = icon, + Group = group, + Tags = tags ?? new List(), + DisallowedPageTypes = disallowedPageTypes ?? new List() + }); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/PageOptions.cs b/zero.Core/Configuration/ConfigurationParts/PageOptions.cs new file mode 100644 index 00000000..ecca8e2d --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/PageOptions.cs @@ -0,0 +1,50 @@ +using System; +using System.Linq; +using zero.Core.Entities; + +namespace zero; + +public class PageOptions : OptionsEnumerable, IOptionsEnumerable +{ + public PageOptions() + { + + } + + public string Root { get; set; } = Constants.Pages.DefaultRootPageTypeAlias; + + + public void Add(PageType pageType) where T : Page, new() + { + Items.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)) + { + Alias = alias, + Name = name, + Description = description, + Icon = icon + }); + } + + + public void Add(Type type, string alias, string name, string description, string icon) + { + Items.Add(new PageType(type) + { + Alias = alias, + Name = name, + Description = description, + Icon = icon + }); + } + + public PageType GetByAlias(string alias) + { + return Items.FirstOrDefault(x => x.Alias == alias); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/PermissionOptions.cs b/zero.Core/Configuration/ConfigurationParts/PermissionOptions.cs new file mode 100644 index 00000000..0a3bc928 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/PermissionOptions.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using zero.Core.Identity; + +namespace zero; + +public class PermissionOptions : OptionsEnumerable, IOptionsEnumerable +{ + public void AddCollection(PermissionCollection collection, int index = -1) + { + if (index > -1 && index < Items.Count) + { + Items.Insert(index, collection); + } + else + { + Items.Add(collection); + } + } + + + public void AddCollection(int index = -1) where T : PermissionCollection, new() + { + if (index > -1 && index < Items.Count) + { + Items.Insert(index, new T()); + } + else + { + Items.Add(new T()); + } + } + + + public void Add(string collectionAlias, Permission permission, int index = -1) + { + PermissionCollection collection = Items.FirstOrDefault(x => x.Alias.Equals(collectionAlias, StringComparison.InvariantCultureIgnoreCase)); + + if (collection == null) + { + // TODO handle error + return; + } + + IList items = collection.Items; + + if (index > -1 && index < items.Count) + { + items.Insert(index, permission); + } + else + { + items.Add(permission); + } + } +} \ No newline at end of file diff --git a/zero.Core/Configuration/ConfigurationParts/RoutingEndpointOptions.cs b/zero.Core/Configuration/ConfigurationParts/RoutingEndpointOptions.cs new file mode 100644 index 00000000..421d8724 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/RoutingEndpointOptions.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using zero.Core.Routing; + +namespace zero; + +public class RoutingEndpointOptions +{ + HashSet Resolvers { get; set; } = new(); + + class ResolverMap + { + public Type Type { get; set; } + public Func Impl { get; set; } + } + + + public void Add(Func resolver) where T : class, IRouteModel + { + Resolvers.Add(new() + { + Type = typeof(T), + Impl = obj => resolver(obj as T) + }); + } + + public void Replace(Func resolver) where T : class, IRouteModel + { + Remove(); + Add(resolver); + } + + public void Remove() where T : IRouteModel + { + Type type = typeof(T); + Resolvers.RemoveWhere(x => x.Type == type); + } + + public Func Get() where T : IRouteModel => Get(typeof(T)); + + public IEnumerable> GetAll() where T : IRouteModel => GetAll(typeof(T)); + + public Func Get(Type type) + { + ResolverMap map = Resolvers.LastOrDefault(x => x.Type == type); + return map?.Impl; + } + + public IEnumerable> GetAll(Type type) + { + IEnumerable maps = Resolvers.Where(x => x.Type == type); + return maps.Select(map => map.Impl).Where(x => x != null); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/RoutingOptions.cs b/zero.Core/Configuration/ConfigurationParts/RoutingOptions.cs new file mode 100644 index 00000000..9eba3d62 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/RoutingOptions.cs @@ -0,0 +1,40 @@ +using zero.Core.Routing; + +namespace zero; + +public class RoutingOptions +{ + public RoutingOptions() + { + PageRouteIdBuilder = new PageRouteIdBuilder(); + DefaultEndpoint = new("ZeroFrontend", "Index"); + EndpointResolvers = new(); + PageResolvers = new(); + //ErrorReexecutionPath = "/error"; + NotFoundEndpoint = null; + } + + + public IPageRouteIdBuilder PageRouteIdBuilder { get; set; } + + + public RouteEndpoint NotFoundEndpoint { get; set; } + + + public RouteEndpoint DefaultEndpoint { get; set; } + + /// + /// + /// + public RoutingEndpointOptions EndpointResolvers { get; set; } + + /// + /// + /// + public RoutingPageResolverOptions PageResolvers { get; set; } + + /// + /// + /// + public string ErrorReexecutionPath { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Configuration/ConfigurationParts/RoutingPageResolverOptions.cs b/zero.Core/Configuration/ConfigurationParts/RoutingPageResolverOptions.cs new file mode 100644 index 00000000..f9e75e2c --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/RoutingPageResolverOptions.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using zero.Core.Entities; + +namespace zero; + +public class RoutingPageResolverOptions +{ + HashSet Resolvers { get; set; } = new(); + + class ResolverMap + { + public Type Type { get; set; } + public Expression> Impl { get; set; } + } + + + public void Add(Expression> resolver) + { + Resolvers.Add(new() + { + Type = typeof(T), + Impl = resolver + }); + } + + public void Replace(Expression> resolver) + { + Remove(); + Add(resolver); + } + + public void Remove() + { + Type type = typeof(T); + Resolvers.RemoveWhere(x => x.Type == type); + } + + public Expression> Get() => Get(typeof(T)); + + public IEnumerable>> GetAll() => GetAll(typeof(T)); + + public Expression> Get(Type type) + { + ResolverMap map = Resolvers.LastOrDefault(x => x.Type == type); + return map?.Impl; + } + + public IEnumerable>> GetAll(Type type) + { + IEnumerable maps = Resolvers.Where(x => x.Type == type); + return maps.Select(map => map.Impl).Where(x => x != null); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/SearchOptions.cs b/zero.Core/Configuration/ConfigurationParts/SearchOptions.cs new file mode 100644 index 00000000..5be917b1 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/SearchOptions.cs @@ -0,0 +1,147 @@ +using Raven.Client.Documents; +using System; +using System.Linq; +using System.Threading.Tasks; +using zero.Core.Models; +using zero.Core.Renderer; + +namespace zero; + +public class SearchOptions : OptionsEnumerable, IOptionsEnumerable +{ + public bool IsEnabled { get; set; } + + + public SearchOptions() + { + IsEnabled = true; + //Map().Display((x, res, opts) => + //{ + // PageType pageType = opts.Pages.GetByAlias(x.PageTypeAlias); + // if (pageType != null) + // { + // res.Icon = pageType.Icon; + // } + // res.Url = "/pages/edit/" + x.Id; + //}); + //Map("fth-image"); + } + + + public SearchIndexMap Map(string icon = null) where T : ZeroEntity, new() + { + SearchIndexMap map = new(icon); + Items.Add(map); + return map; + } +} + + +public class SearchIndexMap +{ + internal Type Type; + internal string _Icon; + protected string _group; + protected string[] _fields; + protected Func _modify; + + const string mapTemplate = @"map('{collection}', function (x) { + return { + Id: x.Id, + Group: '{group}', + Name: x.Name, + IsActive: x.IsActive, + Fields: [{fields}] + }; + });"; + + internal SearchIndexMap(Type type, string icon = null) + { + Type = type; + _group = "__TODO"; + _Icon = icon; + } + + internal string BuildInstruction(IDocumentStore store) + { + return TokenReplacement.Apply(mapTemplate, new() + { + { "collection", store.Conventions.GetCollectionName(Type) }, + { "group", _group }, + { "fields", BuildFieldArray(_fields) } + }); + } + + internal string BuildFieldArray(string[] fields) + { + if (fields == null || !fields.Any()) + { + return String.Empty; + } + + return "x." + String.Join(", x.", fields); + } + + internal bool CanModify(Type type) + { + return Type.IsAssignableFrom(type); + } + + internal async Task Modify(ZeroEntity entity, SearchResult result, IZeroOptions options) + { + if (_modify != null) + { + await _modify(entity, result, options); + } + } +} + + +public class SearchIndexMap : SearchIndexMap where T : ZeroEntity +{ + internal SearchIndexMap(string icon = null) : base(typeof(T), icon) {} + + public SearchIndexMap Icon(string icon) + { + _Icon = icon; + return this; + } + + public SearchIndexMap Display(Action modify = null) + { + _modify = (x, res, opts) => + { + modify?.Invoke(x as T, res); + return Task.CompletedTask; + }; + return this; + } + + public SearchIndexMap Display(Func modify = null) + { + _modify = (x, res, opts) => modify?.Invoke(x as T, res); + return this; + } + + public SearchIndexMap Display(Action modify = null) + { + _modify = (x, res, opts) => + { + modify?.Invoke(x as T, res, opts); + return Task.CompletedTask; + }; + return this; + } + + public SearchIndexMap Display(Func modify = null) + { + _modify = (x, res, opts) => modify?.Invoke(x as T, res, opts); + return this; + } + + public SearchIndexMap Fields(params string[] fieldNames) + { + _fields = fieldNames; + return this; + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/SectionOptions.cs b/zero.Core/Configuration/ConfigurationParts/SectionOptions.cs new file mode 100644 index 00000000..ec02e450 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/SectionOptions.cs @@ -0,0 +1,29 @@ +using zero.Core.Entities; + +namespace zero; + +public class SectionOptions : OptionsEnumerable, IOptionsEnumerable +{ + public SectionOptions() + { + + } + + + public void Add(int index = -1) where T : ISection, new() + { + if (index > -1 && index < Items.Count) + { + Items.Insert(index, new T()); + } + else + { + Items.Add(new T()); + } + } + + public void Add(string alias, string name, string icon) + { + Items.Add(new Section(alias, name, icon)); + } +} diff --git a/zero.Core/Configuration/ConfigurationParts/ServiceOptions.cs b/zero.Core/Configuration/ConfigurationParts/ServiceOptions.cs new file mode 100644 index 00000000..0861d1b6 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/ServiceOptions.cs @@ -0,0 +1,9 @@ +namespace zero; + +public class ServiceOptions +{ + /// + /// Define a YouTube API Key so the zero videopicker can display previews + /// + public string YouTubeApiKey { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Configuration/ConfigurationParts/SettingsOptions.cs b/zero.Core/Configuration/ConfigurationParts/SettingsOptions.cs new file mode 100644 index 00000000..17c1f6b1 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/SettingsOptions.cs @@ -0,0 +1,52 @@ +using System.Linq; +using zero.Core.Entities; + +namespace zero; + +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/ConfigurationParts/SpaceOptions.cs b/zero.Core/Configuration/ConfigurationParts/SpaceOptions.cs new file mode 100644 index 00000000..ab457712 --- /dev/null +++ b/zero.Core/Configuration/ConfigurationParts/SpaceOptions.cs @@ -0,0 +1,86 @@ +using System.Linq; +using zero.Core.Entities; + +namespace zero; + +public class SpaceOptions : OptionsEnumerable, IOptionsEnumerable +{ + public SpaceOptions() + { + + } + + + public void Add() where T : Space, new() + { + Items.Add(new T()); + } + + + public void AddList(string alias, string name, string description, string icon) where T : SpaceContent, new() + { + Items.Add(new Space() + { + Alias = alias, + View = SpaceView.List, + Name = name, + Description = description, + Icon = icon, + Type = typeof(T) + }); + } + + + public void AddEditor(string alias, string name, string description, string icon) where T : SpaceContent, new() + { + Items.Add(new Space() + { + Alias = alias, + View = SpaceView.Editor, + Name = name, + Description = description, + Icon = icon, + Type = typeof(T) + }); + } + + + public void AddSeparator() + { + Space lastSpace = Items.LastOrDefault(); + + if (lastSpace != null) + { + lastSpace.LineBelow = true; + } + } + + + public void AddCustom(string componentPath, string alias, string name, string description, string icon) where T : SpaceContent, new() + { + Items.Add(new Space() + { + Alias = alias, + View = SpaceView.Custom, + ComponentPath = componentPath, + Name = name, + Description = description, + Icon = icon, + Type = typeof(T) + }); + } + + + public void AddCustom(string componentPath, string alias, string name, string description, string icon) + { + Items.Add(new Space() + { + Alias = alias, + View = SpaceView.Custom, + ComponentPath = componentPath, + Name = name, + Description = description, + Icon = icon + }); + } +} diff --git a/zero.Core/Configuration/Constants.cs b/zero.Core/Configuration/Constants.cs new file mode 100644 index 00000000..540e57ed --- /dev/null +++ b/zero.Core/Configuration/Constants.cs @@ -0,0 +1,89 @@ +namespace zero; + +public static class Constants +{ + public const string ErrorFieldNone = "__zero_no_field"; + + public static class Tabs + { + public const string General = "general"; + } + + public static class Auth + { + public const string SystemUser = "system"; + public const string DefaultScheme = "zeroScheme"; + public const string BackofficeDisplayName = "Zero Bacckoffice"; + public const string BackofficeScheme = "zeroBackoffice"; + public const string BackofficeCookieName = "zero.be.session"; + public const string DefaultCookieName = "zero.session"; + + public static class Claims + { + public const string IsZero = "zero.claim.iszero"; + public const string IsSuper = "zero.claim.issuper"; + public const string UserId = "zero.claim.userid"; + public const string UserName = "zero.claim.username"; + public const string Role = "zero.claim.rolealias"; + public const string SecurityStamp = "zero.claim.securitystamp"; + public const string Email = "zero.claim.email"; + public const string Permission = "zero.claim.permission"; + public const string DefaultAppId = "zero.claim.defaultAppId"; + public const string AppId = "zero.claim.appId"; + public const string TicketExpires = "zero.claim.ticketExpires"; + } + } + + public static class Database + { + public const string ReservationPrefix = "zero."; + public const string CoreIdPrefix = "core."; + public const string Expires = Raven.Client.Constants.Documents.Metadata.Expires; + } + + public static class Sections + { + public const string Dashboard = "dashboard"; + public const string Pages = "pages"; + public const string Spaces = "spaces"; + public const string Media = "media"; + public const string Settings = "settings"; + } + + public static class Settings + { + public const string Updates = "updates"; + public const string Applications = "applications"; + public const string Users = "users"; + public const string Languages = "languages"; + public const string Translations = "translations"; + public const string Countries = "countries"; + public const string Mails = "mailTemplates"; + public const string Integrations = "integrations"; + public const string Logging = "logs"; + public const string Plugins = "plugins"; + public const string CreatePlugin = "createplugin"; + } + + public static class PermissionCollections + { + public const string Sections = "permissionCollectionSections"; + public const string Spaces = "permissionCollectionSpaces"; + public const string Settings = "permisssionCollectionSettings"; + public const string Modules = "permissionCollectionModules"; + } + + public static class Pages + { + public const string FolderAlias = "zero.folder"; + public const string DefaultRootPageTypeAlias = "root"; + public const string PageRouteProviderAlias = "zero.pages"; + } + + public static class Routing + { + public const string InternalRoutePrefix = "/__zero/"; + + public const string ErrorRoute = InternalRoutePrefix + "error"; + } +} diff --git a/zero.Core/Options/IZeroCollectionOptions.cs b/zero.Core/Configuration/IZeroCollectionOptions.cs similarity index 100% rename from zero.Core/Options/IZeroCollectionOptions.cs rename to zero.Core/Configuration/IZeroCollectionOptions.cs diff --git a/zero.Core/Configuration/Module.cs b/zero.Core/Configuration/Module.cs new file mode 100644 index 00000000..f7dabe21 --- /dev/null +++ b/zero.Core/Configuration/Module.cs @@ -0,0 +1,17 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; + +namespace zero; + +internal class ConfigurationModule : ZeroModule +{ + /// + public override void Register(IZeroModuleConfiguration config) + { + config.Services.AddOptions() + .Bind(config.Configuration.GetSection("Zero")) + .Configure(opts => opts.ZeroVersion = "0.0.1.0" /*// TODO*/); + + config.Services.AddTransient(factory => factory.GetService>().CurrentValue); + } +} \ No newline at end of file diff --git a/zero.Core/Configuration/OptionsEnumerable.cs b/zero.Core/Configuration/OptionsEnumerable.cs new file mode 100644 index 00000000..4d0382dd --- /dev/null +++ b/zero.Core/Configuration/OptionsEnumerable.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace zero; + +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/OptionsType.cs b/zero.Core/Configuration/OptionsType.cs new file mode 100644 index 00000000..4ea088e4 --- /dev/null +++ b/zero.Core/Configuration/OptionsType.cs @@ -0,0 +1,27 @@ +using FluentValidation; +using System; + +namespace zero; + +public abstract class OptionsType +{ + /// + /// Type of the associated model class + /// + public Type ContentType { get; set; } + + /// + /// The alias + /// + public string Alias { get; set; } + + /// + /// The name of the options type + /// + public string Name { get; set; } + + /// + /// Set a validator for the editor + /// + public IValidator Validator { get; set; } +} \ No newline at end of file diff --git a/zero.Core/Configuration/ZeroOptions.cs b/zero.Core/Configuration/ZeroOptions.cs new file mode 100644 index 00000000..a3343d86 --- /dev/null +++ b/zero.Core/Configuration/ZeroOptions.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; + +namespace zero; + +public class ZeroOptions : IZeroOptions +{ + public ZeroOptions() + { + SupportedLanguages = new string[2] { "en-US", "de-DE" }; + DefaultLanguage = SupportedLanguages[0]; + TokenExpiration = 60 * 3; + BackofficePath = "/zero"; + ExcludedPaths = new() { }; + Raven = new() + { + CollectionPrefix = String.Empty + }; + Sections = new(); + Features = new(); + Pages = new(); + Modules = new(); + Permissions = new(); + Settings = new(); + Spaces = new(); + Integrations = new(); + Icons = new(); + Services = new(); + Blueprints = new(); + Routing = new(); + Interceptors = new(); + Applications = new(); + + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + //Raven.Indexes.Add(); + + Search = new(); + } + + /// + public bool SetupCompleted => !String.IsNullOrEmpty(Raven?.Database); + + /// + public string ZeroVersion { 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 string BackofficePath { get; set; } + + /// + /// Paths in the backoffice which are not handled by zero + /// + public List ExcludedPaths { get; private set; } + + /// + //public IZeroPluginConfiguration Backoffice { get; set; } + + /// + public SectionOptions Sections { get; private set; } + + /// + public FeatureOptions Features { get; private set; } + + /// + public PageOptions Pages { get; private set; } + + /// + public ModuleOptions Modules { get; private set; } + + /// + public PermissionOptions Permissions { get; private set; } + + /// + public SettingsOptions Settings { get; private set; } + + /// + public SpaceOptions Spaces { get; private set; } + + /// + public IntegrationOptions Integrations { get; private set; } + + /// + public IconOptions Icons { get; private set; } + + /// + public ServiceOptions Services { get; private set; } + + /// + public BlueprintOptions Blueprints { get; private set; } + + /// + public RoutingOptions Routing { get; private set; } + + /// + public InterceptorOptions Interceptors { get; private set; } + + /// + public SearchOptions Search { get; private set; } +} + + +public interface IZeroOptions +{ + /// + /// Whether the zero setup has already been completed and the instance is ready for use + /// + bool SetupCompleted { get; } + + /// + /// The currently active version + /// This should not be set manually, as it is used for setup and migrations and incremented automatically + /// + string ZeroVersion { get; set; } + + /// + /// 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; } + + /// + /// URL path to the backoffice (defaults to /zero) + /// + string BackofficePath { get; set; } + + /// + /// Paths in the backoffice which are not handled by zero + /// + List ExcludedPaths { get; } + + /// + /// + /// + SectionOptions Sections { get; } + + /// + /// + /// + FeatureOptions Features { get; } + + /// + /// + /// + PageOptions Pages { get; } + + /// + /// + /// + ModuleOptions Modules { get; } + + /// + /// + /// + PermissionOptions Permissions { get; } + + /// + /// + /// + SettingsOptions Settings { get; } + + /// + /// + /// + SpaceOptions Spaces { get; } + + /// + /// + /// + IntegrationOptions Integrations { get; } + + /// + /// + /// + IconOptions Icons { get; } + + /// + /// + /// + ServiceOptions Services { get; } + + /// + /// + /// + BlueprintOptions Blueprints { get; } + + /// + /// + /// + RoutingOptions Routing { get; } + + /// + /// + /// + InterceptorOptions Interceptors { get; } + + /// + /// + /// + SearchOptions Search { get; } +} diff --git a/zero.Core/Configuration/ZeroStartupOptions.cs b/zero.Core/Configuration/ZeroStartupOptions.cs new file mode 100644 index 00000000..63e94723 --- /dev/null +++ b/zero.Core/Configuration/ZeroStartupOptions.cs @@ -0,0 +1,24 @@ +using Microsoft.Extensions.DependencyInjection; +using System.Collections.Generic; + +namespace zero; + +public class ZeroStartupOptions : IZeroStartupOptions +{ + public IList AssemblyDiscoveryRules { get; private set; } = new List(); + + public IMvcBuilder Mvc { get; private set; } + + + public ZeroStartupOptions(IMvcBuilder mvc) + { + Mvc = mvc; + } +} + +public interface IZeroStartupOptions +{ + IList AssemblyDiscoveryRules { get; } + + IMvcBuilder Mvc { get; } +} \ No newline at end of file diff --git a/zero.Core/Extensions/StringExtensions.cs b/zero.Core/Extensions/StringExtensions.cs index 881d1613..16dba42b 100644 --- a/zero.Core/Extensions/StringExtensions.cs +++ b/zero.Core/Extensions/StringExtensions.cs @@ -3,186 +3,185 @@ using System.Globalization; using System.Linq; using System.Text.RegularExpressions; -namespace zero.Core.Extensions +namespace zero; + +public static class StringExtensions { - public static class StringExtensions + const string SPACE = " "; + + static Regex replaceMultipleSpacesRegex { get; } = new Regex("[ ]{2,}", RegexOptions.None); + + static Regex newLineCharsRegex { get; } = new Regex("\t|\n|\r", RegexOptions.None); + + + public static string FullTrim(this string value) { - const string SPACE = " "; - - static Regex replaceMultipleSpacesRegex { get; } = new Regex("[ ]{2,}", RegexOptions.None); - - static Regex newLineCharsRegex { get; } = new Regex("\t|\n|\r", RegexOptions.None); - - - public static string FullTrim(this string value) + if (String.IsNullOrEmpty(value)) { - if (String.IsNullOrEmpty(value)) - { - return value; - } - - return replaceMultipleSpacesRegex.Replace(value, SPACE).Trim(); - } - - - public static string EnsureStartsWith(this string input, string toStartWith) - { - if (input.StartsWith(toStartWith)) return input; - return toStartWith + input.TrimStart(toStartWith); - } - - - public static string EnsureStartsWith(this string input, char value) - { - return input.StartsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : value + input; - } - - - public static string EnsureEndsWith(this string input, char value) - { - return input.EndsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : input + value; - } - - - public static string EnsureEndsWith(this string input, string toEndWith) - { - return input.EndsWith(toEndWith.ToString(CultureInfo.InvariantCulture)) ? input : input + toEndWith; - } - - - public static string EnsureSurroundedWith(this string input, char toSurroundWith) - { - return input.EnsureStartsWith(toSurroundWith).EnsureEndsWith(toSurroundWith); - } - - - public static string Or(this string value, string fallback) - { - return String.IsNullOrWhiteSpace(value) ? fallback : value; - } - - - public static string TrimEnd(this string value, string forRemoving) - { - if (String.IsNullOrEmpty(value)) return value; - if (String.IsNullOrEmpty(forRemoving)) return value; - - while (value.EndsWith(forRemoving, StringComparison.InvariantCultureIgnoreCase)) - { - value = value.Remove(value.LastIndexOf(forRemoving, StringComparison.InvariantCultureIgnoreCase)); - } return value; } + return replaceMultipleSpacesRegex.Replace(value, SPACE).Trim(); + } - public static string TrimStart(this string value, string forRemoving) + + public static string EnsureStartsWith(this string input, string toStartWith) + { + if (input.StartsWith(toStartWith)) return input; + return toStartWith + input.TrimStart(toStartWith); + } + + + public static string EnsureStartsWith(this string input, char value) + { + return input.StartsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : value + input; + } + + + public static string EnsureEndsWith(this string input, char value) + { + return input.EndsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : input + value; + } + + + public static string EnsureEndsWith(this string input, string toEndWith) + { + return input.EndsWith(toEndWith.ToString(CultureInfo.InvariantCulture)) ? input : input + toEndWith; + } + + + public static string EnsureSurroundedWith(this string input, char toSurroundWith) + { + return input.EnsureStartsWith(toSurroundWith).EnsureEndsWith(toSurroundWith); + } + + + public static string Or(this string value, string fallback) + { + return String.IsNullOrWhiteSpace(value) ? fallback : value; + } + + + public static string TrimEnd(this string value, string forRemoving) + { + if (String.IsNullOrEmpty(value)) return value; + if (String.IsNullOrEmpty(forRemoving)) return value; + + while (value.EndsWith(forRemoving, StringComparison.InvariantCultureIgnoreCase)) { - if (String.IsNullOrEmpty(value)) return value; - if (String.IsNullOrEmpty(forRemoving)) return value; - - while (value.StartsWith(forRemoving, StringComparison.InvariantCultureIgnoreCase)) - { - value = value.Substring(forRemoving.Length); - } - return value; + value = value.Remove(value.LastIndexOf(forRemoving, StringComparison.InvariantCultureIgnoreCase)); } + return value; + } - public static bool HasValue(this string input) + public static string TrimStart(this string value, string forRemoving) + { + if (String.IsNullOrEmpty(value)) return value; + if (String.IsNullOrEmpty(forRemoving)) return value; + + while (value.StartsWith(forRemoving, StringComparison.InvariantCultureIgnoreCase)) { - return !String.IsNullOrWhiteSpace(input); + value = value.Substring(forRemoving.Length); } + return value; + } - public static bool IsNullOrEmpty(this string input) + public static bool HasValue(this string input) + { + return !String.IsNullOrWhiteSpace(input); + } + + + public static bool IsNullOrEmpty(this string input) + { + return String.IsNullOrEmpty(input); + } + + + public static bool IsNullOrWhiteSpace(this string input) + { + return String.IsNullOrWhiteSpace(input); + } + + public static string ToCamelCase(this string input) + { + if (!String.IsNullOrEmpty(input) && input.Length > 1) { - return String.IsNullOrEmpty(input); + return Char.ToLowerInvariant(input[0]) + input.Substring(1); } + return input; + } - - public static bool IsNullOrWhiteSpace(this string input) + public static string ToPascalCase(this string input) + { + if (!String.IsNullOrEmpty(input) && input.Length > 1) { - return String.IsNullOrWhiteSpace(input); + return Char.ToUpperInvariant(input[0]) + input.Substring(1); } + return input; + } - public static string ToCamelCase(this string input) + public static string ToCamelCaseId(this string input) + { + if (String.IsNullOrEmpty(input)) { - if (!String.IsNullOrEmpty(input) && input.Length > 1) - { - return Char.ToLowerInvariant(input[0]) + input.Substring(1); - } return input; } - public static string ToPascalCase(this string input) + if (input.Length < 2) + { + return input.ToLowerInvariant(); + } + + string[] parts = input.Split('.'); + + return String.Join(".", parts.Select(x => x.ToCamelCase())); + } + + + public static string ToPascalCaseId(this string input) + { + if (String.IsNullOrEmpty(input)) { - if (!String.IsNullOrEmpty(input) && input.Length > 1) - { - return Char.ToUpperInvariant(input[0]) + input.Substring(1); - } return input; } - public static string ToCamelCaseId(this string input) + if (input.Length < 2) { - if (String.IsNullOrEmpty(input)) - { - return input; - } - - if (input.Length < 2) - { - return input.ToLowerInvariant(); - } - - string[] parts = input.Split('.'); - - return String.Join(".", parts.Select(x => x.ToCamelCase())); + return input.ToUpperInvariant(); } + string[] parts = input.Split('.'); - public static string ToPascalCaseId(this string input) + return String.Join(".", parts.Select(x => x.ToPascalCase())); + } + + + public static string RemoveNewLines(this string input) + { + if (String.IsNullOrEmpty(input)) { - if (String.IsNullOrEmpty(input)) - { - return input; - } - - if (input.Length < 2) - { - return input.ToUpperInvariant(); - } - - string[] parts = input.Split('.'); - - return String.Join(".", parts.Select(x => x.ToPascalCase())); + return input; } + return newLineCharsRegex.Replace(input, String.Empty).Trim(); + } - public static string RemoveNewLines(this string input) + + public static string Shorten(this string input, int maxLength) + { + if (maxLength < 4) { - if (String.IsNullOrEmpty(input)) - { - return input; - } - - return newLineCharsRegex.Replace(input, String.Empty).Trim(); + throw new ArgumentOutOfRangeException("maxLength", "Has to be at least 4 characters long"); } - - public static string Shorten(this string input, int maxLength) + if (String.IsNullOrEmpty(input) || input.Length <= maxLength) { - if (maxLength < 4) - { - throw new ArgumentOutOfRangeException("maxLength", "Has to be at least 4 characters long"); - } - - if (String.IsNullOrEmpty(input) || input.Length <= maxLength) - { - return input; - } - - return input.Substring(0, maxLength - 3) + "..."; + return input; } + + return input.Substring(0, maxLength - 3) + "..."; } } diff --git a/zero.Core/Persistence/IZeroDbConventions.cs b/zero.Core/Persistence/IZeroDbConventions.cs new file mode 100644 index 00000000..3b8650f1 --- /dev/null +++ b/zero.Core/Persistence/IZeroDbConventions.cs @@ -0,0 +1,6 @@ +namespace zero; + +/// +/// Triggers custom Raven conventions for database operations +/// +public interface IZeroDbConventions { } \ No newline at end of file diff --git a/zero.Core/Persistence/IdGenerator.cs b/zero.Core/Persistence/IdGenerator.cs new file mode 100644 index 00000000..759572a5 --- /dev/null +++ b/zero.Core/Persistence/IdGenerator.cs @@ -0,0 +1,36 @@ +using System; +using System.Linq; + +namespace zero; + +public class IdGenerator +{ + const string CHARS = "abcdefghijklmnopqrstuvwxyz0123456789"; + + private static Random random = new(); + + /// + /// Create a new unique Id + /// + public static string Create(int length = -1) + { + if (length < 1) + { + length = 12; + } + + return new string(Enumerable.Repeat(CHARS, length).Select(s => s[random.Next(s.Length)]).ToArray()); + + //if (length > 0) + //{ + //return Convert.ToBase64String(Guid.NewGuid().ToByteArray()) + // .Replace("/", String.Empty) + // .Replace("+", String.Empty) + // .Replace("-", String.Empty) + // .ToLowerInvariant() + // .Substring(0, length); + //} + + //return Guid.NewGuid().ToString(); + } +} diff --git a/zero.Core/Persistence/Module.cs b/zero.Core/Persistence/Module.cs new file mode 100644 index 00000000..c16fd888 --- /dev/null +++ b/zero.Core/Persistence/Module.cs @@ -0,0 +1,61 @@ +using Microsoft.Extensions.DependencyInjection; +using Raven.Client.Documents; +using Raven.Client.Http; +using System; + +namespace zero; + +internal class PersistenceModule : ZeroModule +{ + /// + public override void Register(IZeroModuleConfiguration config) + { + config.Services.AddSingleton(); + config.Services.AddSingleton(CreateRavenStore); + config.Services.AddScoped(); + config.Services.AddScoped(); + } + + + /// + public override void Configure(IZeroOptions options) + { + base.Configure(options); + } + + + /// + /// Creates and configures the raven store + /// + protected ZeroDocumentStore CreateRavenStore(IServiceProvider services) + { + IZeroOptions options = services.GetService(); + IZeroDocumentConventionsBuilder conventionsBuilder = services.GetService(); + + IZeroDocumentStore store = new ZeroDocumentStore(options) + { + Urls = new string[1] { options.Raven.Url }, + Conventions = // TODO activate and test this + { + AggressiveCache = + { + Duration = TimeSpan.FromHours(1), + Mode = AggressiveCacheMode.TrackChanges + } + } + }; + + conventionsBuilder.Run(store.Conventions); + + IDocumentStore raven = store.Initialize(); + + // create all indexes + if (options.SetupCompleted) + { + //var indexes = options.Raven.Indexes.BuildAll(options, store); + //IndexCreation.CreateIndexes(indexes, store, database: options.Raven.Database); + } + + return (ZeroDocumentStore)raven; + } +} \ No newline at end of file diff --git a/zero.Core/Persistence/RavenCollectionAttribute.cs b/zero.Core/Persistence/RavenCollectionAttribute.cs new file mode 100644 index 00000000..3fd83500 --- /dev/null +++ b/zero.Core/Persistence/RavenCollectionAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace zero; + +/// +/// This attribute will allow the usage of custom collection names for Raven collections +/// +[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = false)] +public class RavenCollectionAttribute : Attribute +{ + public string Name { get; set; } + + public RavenCollectionAttribute(string name) + { + Name = name; + } +} diff --git a/zero.Core/Persistence/RavenOptions.cs b/zero.Core/Persistence/RavenOptions.cs new file mode 100644 index 00000000..5ea0790c --- /dev/null +++ b/zero.Core/Persistence/RavenOptions.cs @@ -0,0 +1,121 @@ +using Raven.Client.Documents; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace zero; + +public class RavenOptions +{ + public string Url { get; set; } + + public string Database { get; set; } + + public string CollectionPrefix { get; set; } + + public RavenIndexesOptions Indexes { get; set; } = new(); +} + + +public class RavenIndexesOptions : OptionsEnumerable, IOptionsEnumerable +{ + public class Map + { + internal Type Type { get; set; } + + internal Expression> CreateIndex { get; set; } + + internal Map(Type type, Expression> create) + { + Type = type; + CreateIndex = create; + } + } + + + public RavenIndexModifiersOptions Modifiers { get; private set; } = new(); + + public void Add() where T : IZeroIndexDefinition, new() + { + Items.Add(new(typeof(T), () => new T())); + } + + public void Add(Type indexType) + { + Items.Add(new(indexType, () => (IZeroIndexDefinition)Activator.CreateInstance(indexType))); + } + + public void Add(T index) where T : IZeroIndexDefinition + { + Items.Add(new(typeof(T), () => index)); + } + + public void AddRange(params Type[] indexes) + { + foreach (Type type in indexes) + { + Add(type); + } + } + + public void Replace() + where T : IZeroIndexDefinition, new() + where TReplaceWith : IZeroIndexDefinition, new() + { + Replace(typeof(T), typeof(TReplaceWith)); + } + + public void Replace(Type origin, Type replaceWith) + { + var item = Items.FirstOrDefault(x => x.Type == origin); + if (item != null) + { + Items.Remove(item); + } + Add(replaceWith); + } + + public IEnumerable BuildAll(IZeroOptions options, IDocumentStore store) + { + foreach (Map map in Items) + { + IZeroIndexDefinition index = map.CreateIndex.Compile().Invoke(); + index.Setup(options, store); + index.RunModifiers(options); + yield return index; + } + } +} + + +public class RavenIndexModifiersOptions : OptionsEnumerable, IOptionsEnumerable +{ + public class Modifier + { + public Type Type { get; set; } + + public Expression> Modify { get; set; } + } + + public void Add(Action modify) where T : IZeroIndexDefinition, new() + { + Items.Add(new() + { + Type = typeof(T), + Modify = x => modify((T)x) + }); + } + + + public IEnumerable GetAllForType() where T : IZeroIndexDefinition, new() => GetAllForType(typeof(T)); + + + public IEnumerable GetAllForType(Type type) + { + foreach (Modifier modifier in Items.Where(x => x.Type.IsAssignableFrom(type))) + { + yield return modifier; + } + } +} diff --git a/zero.Core/Persistence/RavenQueryableExtensions.cs b/zero.Core/Persistence/RavenQueryableExtensions.cs new file mode 100644 index 00000000..73cfe399 --- /dev/null +++ b/zero.Core/Persistence/RavenQueryableExtensions.cs @@ -0,0 +1,194 @@ +//using Raven.Client.Documents; +//using Raven.Client.Documents.Linq; +//using Raven.Client.Documents.Session; +//using System.Collections.Generic; +//using System.Linq; +//using System.Threading.Tasks; + +//namespace zero; + +//public static class RavenQueryableExtensions +//{ +// // TODO we need to simplify these extensions methods. +// // ToQueriedListAsyncX is used in MediaCollection for the Media_ByParent index, which produces MediaListItem (which is no ZeroEntity) +// /// +// /// +// /// +// public static async Task> ToQueriedListAsyncX(this IRavenQueryable queryable, ListQuery query) +// { +// queryable = queryable.Statistics(out QueryStatistics stats); + +// IQueryable rawQuery = queryable; + +// if (query != null) +// { +// if (!query.Search.IsNullOrEmpty() && query.SearchSelector != null) +// { +// rawQuery = rawQuery.SearchIf(query.SearchSelector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); +// } +// if (!query.Search.IsNullOrEmpty() && query.SearchSelectors.Length > 0) +// { +// foreach (var selector in query.SearchSelectors) +// { +// rawQuery = rawQuery.SearchIf(selector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); +// } +// } + +// if (query.OrderQuery != null) +// { +// rawQuery = query.OrderQuery(rawQuery); +// } +// else if (!query.OrderBy.IsNullOrEmpty()) +// { +// rawQuery = rawQuery.OrderBy(query.OrderBy, query.OrderIsDescending, query.OrderType == ListQueryOrderType.String ? OrderingType.String : OrderingType.Double); +// } + +// if (query.PageSize > 0) +// { +// rawQuery = rawQuery.Paging(query.Page, query.PageSize); +// } +// } + +// List items = await rawQuery.ToListAsync(); + +// return new ListResult(items, stats.TotalResults, query.Page, query.PageSize); +// } + + +// /// +// /// +// /// +// public static async Task> ToQueriedListAsync(this IRavenQueryable queryable, ListQuery query) where T : ZeroEntity +// { +// queryable = queryable.Statistics(out QueryStatistics stats); + +// IQueryable rawQuery = queryable; + +// if (query != null) +// { +// if (!query.IncludeInactive) +// { +// rawQuery = rawQuery.Where(x => x.IsActive); +// } + +// if (!query.Search.IsNullOrEmpty() && query.SearchSelectors.Length > 0) +// { +// foreach (var selector in query.SearchSelectors) +// { +// rawQuery = rawQuery.SearchIf(selector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); +// } +// } +// else if (!query.Search.IsNullOrEmpty() && query.SearchSelector != null) +// { +// rawQuery = rawQuery.SearchIf(query.SearchSelector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.And); +// } + +// if (query.OrderQuery != null) +// { +// rawQuery = query.OrderQuery(rawQuery); +// } +// else if (!query.OrderBy.IsNullOrEmpty()) +// { +// rawQuery = rawQuery.OrderBy(query.OrderBy, query.OrderIsDescending, query.OrderType == ListQueryOrderType.String ? OrderingType.String : OrderingType.Double); +// } +// else +// { +// rawQuery = rawQuery.OrderByDescending(x => x.CreatedDate); +// } + +// if (query.PageSize > 0) +// { +// rawQuery = rawQuery.Paging(query.Page, query.PageSize); +// } +// } + +// List items = await rawQuery.ToListAsync(); + +// return new ListResult(items, stats.TotalResults, query.Page, query.PageSize); +// } + + +// /// +// /// +// /// +// public static async Task> ToQueriedListAsyncX(this IRavenQueryable queryable, ListQuery query) where TFilter : IListSpecificQuery +// { +// queryable = queryable.Statistics(out QueryStatistics stats); + +// IQueryable rawQuery = queryable; + +// if (query != null) +// { +// if (!query.Search.IsNullOrEmpty() && query.SearchSelector != null) +// { +// rawQuery = rawQuery.SearchIf(query.SearchSelector, query.Search, "*", "*"); +// } +// if (!query.Search.IsNullOrEmpty() && query.SearchSelectors.Length > 0) +// { +// foreach (var selector in query.SearchSelectors) +// { +// rawQuery = rawQuery.SearchIf(selector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.Or); +// } +// } + +// if (!query.OrderBy.IsNullOrEmpty()) +// { +// rawQuery = rawQuery.OrderBy(query.OrderBy, query.OrderIsDescending, query.OrderType == ListQueryOrderType.String ? OrderingType.String : OrderingType.Double); +// } + +// if (query.PageSize > 0) +// { +// rawQuery = rawQuery.Paging(query.Page, query.PageSize); +// } +// } + +// List items = await rawQuery.ToListAsync(); + +// return new ListResult(items, stats.TotalResults, query.Page, query.PageSize); +// } + + +// /// +// /// +// /// +// public static async Task> ToQueriedListAsync(this IRavenQueryable queryable, ListQuery query) where T : ZeroEntity where TFilter : IListSpecificQuery +// { +// queryable = queryable.Statistics(out QueryStatistics stats); + +// IQueryable rawQuery = queryable; + +// if (query != null) +// { +// if (!query.IncludeInactive) +// { +// rawQuery = rawQuery.Where(x => x.IsActive); +// } + +// if (!query.Search.IsNullOrEmpty() && query.SearchSelector != null) +// { +// rawQuery = rawQuery.SearchIf(query.SearchSelector, query.Search, "*", "*"); +// } +// if (!query.Search.IsNullOrEmpty() && query.SearchSelectors.Length > 0) +// { +// foreach (var selector in query.SearchSelectors) +// { +// rawQuery = rawQuery.SearchIf(selector, query.Search, "*", "*", Raven.Client.Documents.Queries.SearchOperator.Or); +// } +// } + +// if (!query.OrderBy.IsNullOrEmpty()) +// { +// rawQuery = rawQuery.OrderBy(query.OrderBy, query.OrderIsDescending, query.OrderType == ListQueryOrderType.String ? OrderingType.String : OrderingType.Double); +// } + +// if (query.PageSize > 0) +// { +// rawQuery = rawQuery.Paging(query.Page, query.PageSize); +// } +// } + +// List items = await rawQuery.ToListAsync(); + +// return new ListResult(items, stats.TotalResults, query.Page, query.PageSize); +// } +//} diff --git a/zero.Core/Persistence/Tokens/Rfc6238AuthenticationService.cs b/zero.Core/Persistence/Tokens/Rfc6238AuthenticationService.cs new file mode 100644 index 00000000..5c444884 --- /dev/null +++ b/zero.Core/Persistence/Tokens/Rfc6238AuthenticationService.cs @@ -0,0 +1,107 @@ +using System; +using System.Diagnostics; +using System.Net; +using System.Security.Cryptography; +using System.Text; + +namespace zero; + +/// +/// Replicates the Rfc6238AuthenticationService from ASP.NET Core internals as it isn't part of the public API +/// (see: https://github.com/dotnet/aspnetcore/blob/release/5.0/src/Identity/Extensions.Core/src/Rfc6238AuthenticationService.cs) +/// +public static class Rfc6238AuthenticationService +{ + private static readonly TimeSpan _timestep = TimeSpan.FromMinutes(3); + private static readonly Encoding _encoding = new UTF8Encoding(false, true); + + // Generates a new 80-bit security token + public static byte[] GenerateRandomKey() + { + byte[] bytes = new byte[20]; + RandomNumberGenerator.Fill(bytes); + return bytes; + } + + internal static int ComputeTotp(HashAlgorithm hashAlgorithm, ulong timestepNumber, string modifier) + { + // # of 0's = length of pin + const int Mod = 1000000; + + // See https://tools.ietf.org/html/rfc4226 + // We can add an optional modifier + var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber)); + var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifier)); + + // Generate DT string + var offset = hash[hash.Length - 1] & 0xf; + Debug.Assert(offset + 4 < hash.Length); + var binaryCode = (hash[offset] & 0x7f) << 24 + | (hash[offset + 1] & 0xff) << 16 + | (hash[offset + 2] & 0xff) << 8 + | (hash[offset + 3] & 0xff); + + return binaryCode % Mod; + } + + private static byte[] ApplyModifier(byte[] input, string modifier) + { + if (String.IsNullOrEmpty(modifier)) + { + return input; + } + + var modifierBytes = _encoding.GetBytes(modifier); + var combined = new byte[checked(input.Length + modifierBytes.Length)]; + Buffer.BlockCopy(input, 0, combined, 0, input.Length); + Buffer.BlockCopy(modifierBytes, 0, combined, input.Length, modifierBytes.Length); + return combined; + } + + // More info: https://tools.ietf.org/html/rfc6238#section-4 + private static ulong GetCurrentTimeStepNumber() + { + var delta = DateTimeOffset.UtcNow - DateTimeOffset.UnixEpoch; + return (ulong)(delta.Ticks / _timestep.Ticks); + } + + public static int GenerateCode(byte[] securityToken, string modifier = null) + { + if (securityToken == null) + { + throw new ArgumentNullException(nameof(securityToken)); + } + + // Allow a variance of no greater than 9 minutes in either direction + var currentTimeStep = GetCurrentTimeStepNumber(); + using (var hashAlgorithm = new HMACSHA1(securityToken)) + { + return ComputeTotp(hashAlgorithm, currentTimeStep, modifier); + } + } + + public static bool ValidateCode(byte[] securityToken, int code, string modifier = null) + { + if (securityToken == null) + { + throw new ArgumentNullException(nameof(securityToken)); + } + + // Allow a variance of no greater than 9 minutes in either direction + var currentTimeStep = GetCurrentTimeStepNumber(); + using (var hashAlgorithm = new HMACSHA1(securityToken)) + { + for (var i = -2; i <= 2; i++) + { + var computedTotp = ComputeTotp(hashAlgorithm, (ulong)((long)currentTimeStep + i), modifier); + if (computedTotp == code) + { + return true; + } + } + } + + // No match + return false; + } +} \ No newline at end of file diff --git a/zero.Core/Persistence/Tokens/Token.cs b/zero.Core/Persistence/Tokens/Token.cs new file mode 100644 index 00000000..ba9cb0a0 --- /dev/null +++ b/zero.Core/Persistence/Tokens/Token.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; + +namespace zero; + +[RavenCollection("Tokens")] +public class SecurityToken : IZeroDbConventions +{ + public string Id { get; set; } + + public string Key { get; set; } + + public string Token { get; set; } + + public Dictionary Metadata { get; set; } = new(); +} \ No newline at end of file diff --git a/zero.Core/Persistence/Tokens/ZeroTokenProvider.cs b/zero.Core/Persistence/Tokens/ZeroTokenProvider.cs new file mode 100644 index 00000000..e5c77515 --- /dev/null +++ b/zero.Core/Persistence/Tokens/ZeroTokenProvider.cs @@ -0,0 +1,278 @@ +using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using Raven.Client.Documents.Session; +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace zero; + +public class ZeroTokenProvider : IZeroTokenProvider +{ + readonly char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-".ToCharArray(); + + readonly RandomNumberGenerator randonNumberGenerator; + + protected IZeroStore Store { get; private set; } + + + public ZeroTokenProvider(IZeroStore store) + { + Store = store; + randonNumberGenerator = RandomNumberGenerator.Create(); + } + + + /// + public virtual async Task Create(string key, TimeSpan expires, int length = 82, Dictionary metadata = default) + { + if (key.IsNullOrWhiteSpace()) + { + throw new ArgumentException("Key cannot be empty"); + } + if (length < 16) + { + throw new ArgumentOutOfRangeException("Use at least a length of 16 for the token"); + } + + string tokenKey = Random(length); + + SecurityToken securityToken = new SecurityToken() + { + Id = TokenToId(tokenKey), + Token = tokenKey, + Key = HashKey(key), + Metadata = metadata ?? new() + }; + + IZeroDocumentSession session = Store.Session(); + + // saves the token + await session.StoreAsync(securityToken); + + // set the expires flag for the token + IMetadataDictionary tokenMetadata = session.Advanced.GetMetadataFor(securityToken); + tokenMetadata[Constants.Database.Expires] = DateTime.UtcNow.AddSeconds(expires.TotalSeconds); + await session.SaveChangesAsync(); + + return tokenKey; + } + + + /// + public virtual async Task Verify(string key, string token) + { + if (token.IsNullOrWhiteSpace() || key.IsNullOrWhiteSpace()) + { + return false; + } + + IZeroDocumentSession session = Store.Session(); + + // try to find a valid token + SecurityToken securityToken = await session.LoadAsync(TokenToId(token)); + bool isValid = securityToken != null && VerifyKey(securityToken.Key, key); + + // remove token from DB if it is valid + if (isValid) + { + session.Delete(securityToken); + await session.SaveChangesAsync(); + } + + return isValid; + } + + + /// + public virtual async Task VerifyAndReturn(string key, string token) + { + if (token.IsNullOrWhiteSpace() || key.IsNullOrWhiteSpace()) + { + return null; + } + + IZeroDocumentSession session = Store.Session(); + + // try to find a valid token + SecurityToken securityToken = await session.LoadAsync(TokenToId(token)); + bool isValid = securityToken != null && VerifyKey(securityToken.Key, key); + + // remove token from DB if it is valid + if (isValid) + { + session.Delete(securityToken); + await session.SaveChangesAsync(); + return securityToken; + } + + return null; + } + + + /// + public string Random(int length) + { + byte[] data = new byte[4 * length]; + randonNumberGenerator.GetBytes(data); + + StringBuilder result = new(length); + + for (int i = 0; i < length; i++) + { + var rnd = BitConverter.ToUInt32(data, i * 4); + var idx = rnd % chars.Length; + + result.Append(chars[idx]); + } + + return result.ToString(); + } + + + /// + /// Converts the token to a database id + /// + string TokenToId(string token) + { + string collection = Store.Raven.Conventions.GetCollectionName(typeof(SecurityToken)); + string idPrefix = Store.Raven.Conventions.TransformTypeCollectionNameToDocumentIdPrefix(collection); + return idPrefix + Store.Raven.Conventions.IdentityPartsSeparator + token; + } + + + /// + /// Creates a hash for the security token key. + /// Borrowed from the .NET Core PasswordHasher + /// (see: https://github.com/dotnet/aspnetcore/blob/release/5.0/src/Identity/Extensions.Core/src/PasswordHasher.cs) + /// + string HashKey(string key) + { + key = key.ToLowerInvariant(); + + KeyDerivationPrf prf = KeyDerivationPrf.HMACSHA256; + int iterationCount = 10000; + int saltSize = 128 / 8; + int numBytesRequested = 256 / 8; + + byte[] salt = new byte[saltSize]; + randonNumberGenerator.GetBytes(salt); + byte[] subkey = KeyDerivation.Pbkdf2(key, salt, prf, iterationCount, numBytesRequested); + + var outputBytes = new byte[13 + salt.Length + subkey.Length]; + outputBytes[0] = 0x01; + WriteNetworkByteOrder(outputBytes, 1, (uint)prf); + WriteNetworkByteOrder(outputBytes, 5, (uint)iterationCount); + WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize); + Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length); + Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length); + return Convert.ToBase64String(outputBytes); + } + + + /// + /// Verifies the given key. + /// Borrowed from the .NET Core PasswordHasher + /// (see: https://github.com/dotnet/aspnetcore/blob/release/5.0/src/Identity/Extensions.Core/src/PasswordHasher.cs) + /// + bool VerifyKey(string storedKey, string key) + { + byte[] decodedStoredKey = Convert.FromBase64String(storedKey); + + try + { + KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(decodedStoredKey, 1); + int embeddedIterCount = (int)ReadNetworkByteOrder(decodedStoredKey, 5); + int saltLength = (int)ReadNetworkByteOrder(decodedStoredKey, 9); + + // Read the salt: must be >= 128 bits + if (saltLength < 128 / 8) + { + return false; + } + + byte[] salt = new byte[saltLength]; + Buffer.BlockCopy(decodedStoredKey, 13, salt, 0, salt.Length); + + // Read the subkey (the rest of the payload): must be >= 128 bits + int subkeyLength = decodedStoredKey.Length - 13 - salt.Length; + if (subkeyLength < 128 / 8) + { + return false; + } + byte[] expectedSubkey = new byte[subkeyLength]; + Buffer.BlockCopy(decodedStoredKey, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); + + // Hash the incoming key and verify it + byte[] actualSubkey = KeyDerivation.Pbkdf2(key, salt, prf, embeddedIterCount, subkeyLength); + + return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey); + } + catch + { + return false; + } + } + + + static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value) + { + buffer[offset + 0] = (byte)(value >> 24); + buffer[offset + 1] = (byte)(value >> 16); + buffer[offset + 2] = (byte)(value >> 8); + buffer[offset + 3] = (byte)(value >> 0); + } + + static uint ReadNetworkByteOrder(byte[] buffer, int offset) + { + return ((uint)(buffer[offset + 0]) << 24) + | ((uint)(buffer[offset + 1]) << 16) + | ((uint)(buffer[offset + 2]) << 8) + | ((uint)(buffer[offset + 3])); + } +} + + +public interface IZeroTokenProvider +{ + /// + /// Generates a token for a with a specified lifespan. + /// + /// The purpose the token will be used for. The key must match when verifying the token and should always be hidden from the user. + /// The token will automatically expire after this timespan. + /// Length of the geneated token. + /// Additional metadata to store with the token. This data can be retrieved on verification with + /// + /// The generated token with the specified . + /// + Task Create(string key, TimeSpan expires, int length = 82, Dictionary metadata = default); + + /// + /// Validates the passed for the specified . + /// + /// The purpose the token was used for. + /// The previously generated token. + /// + /// False, if the token could not be found or it has already expired. + /// + Task Verify(string key, string token); + + /// + /// Validates the passed for the specified . + /// + /// The purpose the token was used for. + /// The previously generated token. + /// + /// Null, if the token could not be found or it has already expired. + /// + Task VerifyAndReturn(string key, string token); + + /// + /// Generates a random token with the specified using the RNGCryptoServiceProvider. + /// + /// + /// This method won't store the token in the database and can't be used for verification. Use instead. + /// + string Random(int length); +} diff --git a/zero.Core/Persistence/ZeroDocumentConventionsBuilder.cs b/zero.Core/Persistence/ZeroDocumentConventionsBuilder.cs new file mode 100644 index 00000000..a600d42c --- /dev/null +++ b/zero.Core/Persistence/ZeroDocumentConventionsBuilder.cs @@ -0,0 +1,145 @@ +using Raven.Client.Documents.Conventions; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace zero; + +public class ZeroDocumentConventionsBuilder : IZeroDocumentConventionsBuilder +{ + protected HashSet PolymorphTypes { get; private set; } = new(); + + protected Type AcceptsZeroConventionsType { get; set; } = typeof(IZeroDbConventions); + + protected char IdentityPartsSeparator { get; set; } = '.'; + + protected IZeroOptions Options { get; private set; } + + protected static ConcurrentDictionary CachedTypeCollectionNameMap = new(); + + + public ZeroDocumentConventionsBuilder(IZeroOptions options) + { + Options = options; + } + + + /// + public void Run(DocumentConventions conventions) + { + conventions.MaxNumberOfRequestsPerSession = 1000; + conventions.IdentityPartsSeparator = IdentityPartsSeparator; + conventions.TransformTypeCollectionNameToDocumentIdPrefix = TransformTypeCollectionNameToDocumentIdPrefix; + conventions.FindCollectionName = FindCollectionName; + conventions.RegisterAsyncIdConvention((_, entity) => GetDocumentId(conventions, entity)); + } + + + /// + /// Get a document ID from an entity + /// + protected virtual Task GetDocumentId(DocumentConventions conventions, T entity) + { + string collection = conventions.GetCollectionName(entity); + + StringBuilder documentId = new(); + documentId.Append(conventions.TransformTypeCollectionNameToDocumentIdPrefix(collection)); + documentId.Append(IdentityPartsSeparator); + documentId.Append(IdGenerator.Create()); + + return Task.FromResult(documentId.ToString()); + } + + + /// + /// Finds the collection name for a certain type based on internal rules + /// + protected virtual string FindCollectionName(Type originalType) + { + string collection = null; + + Type type = originalType; + + Func cache = name => + { + CachedTypeCollectionNameMap.TryAdd(type, name); + return name; + }; + + // get inner type for revisions + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Raven.Client.Documents.Subscriptions.Revision<>)) + { + type = type.GetGenericArguments().FirstOrDefault(); + } + + // try to resolve from cache + if (CachedTypeCollectionNameMap.TryGetValue(type, out collection)) + { + return collection; + } + + // do not alter non-internal entities + if (!AcceptsZeroConventionsType.IsAssignableFrom(type)) + { + return cache(DocumentConventions.DefaultGetCollectionName(type)); + } + + // use name from attribute if available + RavenCollectionAttribute collectionAttribute = type.GetCustomAttribute(true); + + if (collectionAttribute != null) + { + return cache(collectionAttribute.Name); + } + + // use base interface if available + Type interfaceBaseType = type.GetInterfaces().FirstOrDefault(x => x.IsInterface && AcceptsZeroConventionsType.IsAssignableFrom(x) && x.Name != AcceptsZeroConventionsType.Name); + + if (interfaceBaseType != null) + { + // use name from attribute if available + collectionAttribute = interfaceBaseType.GetCustomAttribute(true); + if (collectionAttribute != null) + { + return cache(collectionAttribute.Name); + } + } + + // use base type for polymorphism + Type polymorphBaseType = PolymorphTypes.FirstOrDefault(x => type.IsSubclassOf(x)); + + if (polymorphBaseType != null) + { + return cache(DocumentConventions.DefaultGetCollectionName(polymorphBaseType)); + } + + return cache(DocumentConventions.DefaultGetCollectionName(type)); + } + + + /// + /// Translates the types collection name to the document id prefix + /// + protected virtual string TransformTypeCollectionNameToDocumentIdPrefix(string name) + { + if (!Options.Raven.CollectionPrefix.IsNullOrWhiteSpace()) + { + name = Options.Raven.CollectionPrefix.EnsureEndsWith(IdentityPartsSeparator) + name.TrimStart(Options.Raven.CollectionPrefix); + } + + return name.ToCamelCaseId(); + } +} + + +public interface IZeroDocumentConventionsBuilder +{ + /// + /// Applies internal rules to the RavenDB document conventions + /// + void Run(DocumentConventions conventions); +} \ No newline at end of file diff --git a/zero.Core/Persistence/ZeroDocumentSession.cs b/zero.Core/Persistence/ZeroDocumentSession.cs new file mode 100644 index 00000000..b5c0b31c --- /dev/null +++ b/zero.Core/Persistence/ZeroDocumentSession.cs @@ -0,0 +1,40 @@ +using Raven.Client.Documents; +using Raven.Client.Documents.Session; +using System; + +namespace zero; + +public class ZeroDocumentSession : AsyncDocumentSession, IZeroDocumentSession +{ + public IZeroDocumentSession Core { get; private set; } + + public ZeroDocumentSession(DocumentStore documentStore, Guid id, SessionOptions options, string coreDatabase = null) : base(documentStore, id, options) + { + if (coreDatabase.HasValue()) + { + Core = new ZeroDocumentSession(documentStore, id, new SessionOptions() + { + Database = coreDatabase, + DisableAtomicDocumentWritesInClusterWideTransaction = options.DisableAtomicDocumentWritesInClusterWideTransaction, + NoCaching = options.NoCaching, + NoTracking = options.NoTracking, + RequestExecutor = options.RequestExecutor, + TransactionMode = options.TransactionMode + }); + } + else + { + Core = this; + } + } + + public bool IsDisposed { get; set; } +} + + +public interface IZeroDocumentSession : IAsyncDocumentSession +{ + IZeroDocumentSession Core { get; } + + bool IsDisposed { get; } +} diff --git a/zero.Core/Persistence/ZeroDocumentStore.cs b/zero.Core/Persistence/ZeroDocumentStore.cs new file mode 100644 index 00000000..3e537406 --- /dev/null +++ b/zero.Core/Persistence/ZeroDocumentStore.cs @@ -0,0 +1,150 @@ +using Raven.Client; +using Raven.Client.Documents; +using Raven.Client.Documents.BulkInsert; +using Raven.Client.Documents.Operations; +using Raven.Client.Documents.Queries; +using Raven.Client.Documents.Session; +using System; +using System.Threading; +using System.Threading.Tasks; +using zero.Core.Options; + +namespace zero; + +public class ZeroDocumentStore : DocumentStore, IZeroDocumentStore +{ + public ZeroDocumentStore(IZeroOptions options) : base() + { + Options = options; + Database = null; + } + + protected IZeroOptions Options { get; set; } + + /// + public string ResolvedDatabase { get; set; } + + + /// + public OperationExecutor GetOperationExecutor(string database = null) + { + return Operations.ForDatabase(database ?? ResolvedDatabase); + } + + /// + public override IAsyncDocumentSession OpenAsyncSession(string database) + { + return OpenAsyncSession(new SessionOptions() + { + Database = database + }); + } + + /// + public override IAsyncDocumentSession OpenAsyncSession(SessionOptions options) + { + options.Database = options.Database ?? ResolvedDatabase; + + AssertInitialized(); + EnsureNotClosed(); + + var sessionId = Guid.NewGuid(); + var session = new ZeroDocumentSession(this, sessionId, options, Options.Raven.Database); + RegisterEvents(session); + AfterSessionCreated(session); + session.OnSessionDisposing += (sender, args) => + { + session.IsDisposed = true; + }; + + session.Advanced.WaitForIndexesAfterSaveChanges(); + session.Advanced.DocumentStore.AggressivelyCacheFor(TimeSpan.FromHours(1), options.Database); + + return session; + } + + /// + public override IAsyncDocumentSession OpenAsyncSession() + { + return OpenAsyncSession(new SessionOptions() + { + Database = ResolvedDatabase + }); + } + + /// + public override IDocumentSession OpenSession(SessionOptions options) + { + options.Database = options.Database ?? ResolvedDatabase; + + AssertInitialized(); + EnsureNotClosed(); + + var sessionId = Guid.NewGuid(); + var session = new DocumentSession(this, sessionId, options); + RegisterEvents(session); + AfterSessionCreated(session); + + session.Advanced.DocumentStore.AggressivelyCacheFor(TimeSpan.FromHours(1), options.Database); + + return session; + } + + /// + public override IDocumentSession OpenSession(string database) + { + return OpenSession(new SessionOptions() + { + Database = database + }); + } + + /// + public override IDocumentSession OpenSession() + { + return OpenSession(new SessionOptions() + { + Database = ResolvedDatabase + }); + } + + /// + public override BulkInsertOperation BulkInsert(string database = null, CancellationToken token = default) + { + return base.BulkInsert(database ?? ResolvedDatabase, token); + } + + /// + public async Task PurgeAsync(string database = null, string querySuffix = null, Parameters parameters = null) + { + var collectionName = Conventions.FindCollectionName(typeof(T)); + var operationQuery = new DeleteByQueryOperation(new IndexQuery() + { + Query = $"from {collectionName} c {querySuffix ?? String.Empty}", + QueryParameters = parameters + }, new QueryOperationOptions { AllowStale = true }); + + Operation operation = await GetOperationExecutor(database ?? ResolvedDatabase).SendAsync(operationQuery); + + await operation.WaitForCompletionAsync(); + } +} + + +public interface IZeroDocumentStore : IDocumentStore +{ + /// + /// The database which has been resolved from the current application + /// + string ResolvedDatabase { get; set; } + + /// + /// Get operation executor + /// + OperationExecutor GetOperationExecutor(string database = null); + + /// + /// Purges a collection + /// + Task PurgeAsync(string database = null, string querySuffix = null, Parameters parameters = null); +} \ No newline at end of file diff --git a/zero.Core/Persistence/ZeroIndex.cs b/zero.Core/Persistence/ZeroIndex.cs new file mode 100644 index 00000000..2cc322bd --- /dev/null +++ b/zero.Core/Persistence/ZeroIndex.cs @@ -0,0 +1,291 @@ +using Raven.Client.Documents; +using Raven.Client.Documents.Indexes; +using Raven.Client.Documents.Indexes.Spatial; +using Raven.Client.Documents.Operations.Attachments; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq.Expressions; +using zero.Core.Options; + +namespace zero; + +public abstract class ZeroJavascriptIndex : AbstractJavaScriptIndexCreationTask, IZeroIndexDefinition +{ + public ZeroJavascriptIndex() { Create(); } + protected virtual void Create() { } + + public virtual void Setup(IZeroOptions options, IDocumentStore store) { } + + public new string Reduce { get => base.Reduce; set => base.Reduce = value; } + public new string OutputReduceToCollection { get => base.OutputReduceToCollection; set => base.OutputReduceToCollection = value; } + public new string PatternReferencesCollectionName { get => base.PatternReferencesCollectionName; set => base.PatternReferencesCollectionName = value; } + public new string PatternForOutputReduceToCollectionReferences { get => base.PatternForOutputReduceToCollectionReferences; set => base.PatternForOutputReduceToCollectionReferences = value; } + + // AbstractIndexCreationTask + public new IJsonObject AsJson(object doc) => base.AsJson(doc); + public new IEnumerable AttachmentsFor(object doc) => base.AttachmentsFor(doc); + public new IEnumerable CounterNamesFor(object doc) => base.CounterNamesFor(doc); + public new IJsonObject.IMetadata MetadataFor(object doc) => base.MetadataFor(doc); + public new IEnumerable TimeSeriesNamesFor(object doc) => base.TimeSeriesNamesFor(doc); + + // AbstractIndexCreationTaskBase + public new object CreateField(string name, object value, CreateFieldOptions options) => base.CreateField(name, value, options); + public new object CreateField(string name, object value, bool stored, bool analyzed) => base.CreateField(name, value, stored, analyzed); + public new object CreateField(string name, object value) => base.CreateField(name, value); + + // AbstractCommonApiForIndexes + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new T? TryConvert(object value) where T : struct => base.TryConvert(value); +} + +public abstract class ZeroMultiMapIndex : AbstractMultiMapIndexCreationTask, IZeroIndexDefinition +{ + public ZeroMultiMapIndex() { Create(); } + protected virtual void Create() { } + + public virtual void Setup(IZeroOptions options, IDocumentStore store) { } + + // AbstractMultiMapIndexCreationTask + public new void AddMap(Expression, IEnumerable>> map) => base.AddMap(map); + public new void AddMapForAll(Expression, IEnumerable>> map) => base.AddMapForAll(map); + + // AbstractGenericIndexCreationTask + public new Expression, IEnumerable>> Reduce { get => base.Reduce; set => base.Reduce = value; } + public new string OutputReduceToCollection { get => base.OutputReduceToCollection; set => base.OutputReduceToCollection = value; } + public new IDictionary IndexesStrings { get => base.IndexesStrings; set => base.IndexesStrings = value; } + public new IDictionary>, FieldIndexing> Indexes { get => base.Indexes; set => base.Indexes = value; } + public new IDictionary SpatialIndexesStrings { get => base.SpatialIndexesStrings; set => base.SpatialIndexesStrings = value; } + public new IDictionary>, SpatialOptions> SpatialIndexes { get => base.SpatialIndexes; set => base.SpatialIndexes = value; } + public new IDictionary TermVectorsStrings { get => base.TermVectorsStrings; set => base.TermVectorsStrings = value; } + public new IDictionary>, FieldTermVector> TermVectors { get => base.TermVectors; set => base.TermVectors = value; } + public new IDictionary AnalyzersStrings { get => base.AnalyzersStrings; set => base.AnalyzersStrings = value; } + public new IDictionary>, string> Analyzers { get => base.Analyzers; set => base.Analyzers = value; } + public new ISet>> IndexSuggestions { get => base.IndexSuggestions; set => base.IndexSuggestions = value; } + public new IDictionary StoresStrings { get => base.StoresStrings; set => base.StoresStrings = value; } + public new IDictionary>, FieldStorage> Stores { get => base.Stores; set => base.Stores = value; } + public new string PatternReferencesCollectionName { get => base.PatternReferencesCollectionName; set => base.PatternReferencesCollectionName = value; } + public new Expression> PatternForOutputReduceToCollectionReferences { get => base.PatternForOutputReduceToCollectionReferences; set => base.PatternForOutputReduceToCollectionReferences = value; } + public new void AddAssembly(AdditionalAssembly assembly) => base.AddAssembly(assembly); + public new void Analyze(string field, string analyzer) => base.Analyze(field, analyzer); + public new void Analyze(Expression> field, string analyzer) => base.Analyze(field, analyzer); + public new void Index(Expression> field, FieldIndexing indexing) => base.Index(field, indexing); + public new void Index(string field, FieldIndexing indexing) => base.Index(field, indexing); + public new void Spatial(string field, Func indexing) => base.Spatial(field, indexing); + public new void Spatial(Expression> field, Func indexing) => base.Spatial(field, indexing); + public new void Store(string field, FieldStorage storage) => base.Store(field, storage); + public new void Store(Expression> field, FieldStorage storage) => base.Store(field, storage); + public new void StoreAllFields(FieldStorage storage) => base.StoreAllFields(storage); + public new void Suggestion(Expression> field) => base.Suggestion(field); + public new void TermVector(string field, FieldTermVector termVector) => base.TermVector(field, termVector); + public new void TermVector(Expression> field, FieldTermVector termVector) => base.TermVector(field, termVector); + + // AbstractIndexCreationTask + public new IJsonObject AsJson(object doc) => base.AsJson(doc); + public new IEnumerable AttachmentsFor(object doc) => base.AttachmentsFor(doc); + public new IEnumerable CounterNamesFor(object doc) => base.CounterNamesFor(doc); + public new IJsonObject.IMetadata MetadataFor(object doc) => base.MetadataFor(doc); + public new IEnumerable TimeSeriesNamesFor(object doc) => base.TimeSeriesNamesFor(doc); + + // AbstractIndexCreationTaskBase + public new object CreateField(string name, object value, CreateFieldOptions options) => base.CreateField(name, value, options); + public new object CreateField(string name, object value, bool stored, bool analyzed) => base.CreateField(name, value, stored, analyzed); + public new object CreateField(string name, object value) => base.CreateField(name, value); + + // AbstractCommonApiForIndexes + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new T? TryConvert(object value) where T : struct => base.TryConvert(value); +} + + +public abstract class ZeroMultiMapIndex : AbstractMultiMapIndexCreationTask, IZeroIndexDefinition +{ + public ZeroMultiMapIndex() { Create(); } + protected virtual void Create() { } + + public virtual void Setup(IZeroOptions options, IDocumentStore store) { } + + // AbstractMultiMapIndexCreationTask + public new void AddMap(Expression, IEnumerable>> map) => base.AddMap(map); + public new void AddMapForAll(Expression, IEnumerable>> map) => base.AddMapForAll(map); + + // AbstractGenericIndexCreationTask + public new Expression, IEnumerable>> Reduce { get => base.Reduce; set => base.Reduce = value; } + public new string OutputReduceToCollection { get => base.OutputReduceToCollection; set => base.OutputReduceToCollection = value; } + public new IDictionary IndexesStrings { get => base.IndexesStrings; set => base.IndexesStrings = value; } + public new IDictionary>, FieldIndexing> Indexes { get => base.Indexes; set => base.Indexes = value; } + public new IDictionary SpatialIndexesStrings { get => base.SpatialIndexesStrings; set => base.SpatialIndexesStrings = value; } + public new IDictionary>, SpatialOptions> SpatialIndexes { get => base.SpatialIndexes; set => base.SpatialIndexes = value; } + public new IDictionary TermVectorsStrings { get => base.TermVectorsStrings; set => base.TermVectorsStrings = value; } + public new IDictionary>, FieldTermVector> TermVectors { get => base.TermVectors; set => base.TermVectors = value; } + public new IDictionary AnalyzersStrings { get => base.AnalyzersStrings; set => base.AnalyzersStrings = value; } + public new IDictionary>, string> Analyzers { get => base.Analyzers; set => base.Analyzers = value; } + public new ISet>> IndexSuggestions { get => base.IndexSuggestions; set => base.IndexSuggestions = value; } + public new IDictionary StoresStrings { get => base.StoresStrings; set => base.StoresStrings = value; } + public new IDictionary>, FieldStorage> Stores { get => base.Stores; set => base.Stores = value; } + public new string PatternReferencesCollectionName { get => base.PatternReferencesCollectionName; set => base.PatternReferencesCollectionName = value; } + public new Expression> PatternForOutputReduceToCollectionReferences { get => base.PatternForOutputReduceToCollectionReferences; set => base.PatternForOutputReduceToCollectionReferences = value; } + public new void AddAssembly(AdditionalAssembly assembly) => base.AddAssembly(assembly); + public new void Analyze(string field, string analyzer) => base.Analyze(field, analyzer); + public new void Analyze(Expression> field, string analyzer) => base.Analyze(field, analyzer); + public new void Index(Expression> field, FieldIndexing indexing) => base.Index(field, indexing); + public new void Index(string field, FieldIndexing indexing) => base.Index(field, indexing); + public new void Spatial(string field, Func indexing) => base.Spatial(field, indexing); + public new void Spatial(Expression> field, Func indexing) => base.Spatial(field, indexing); + public new void Store(string field, FieldStorage storage) => base.Store(field, storage); + public new void Store(Expression> field, FieldStorage storage) => base.Store(field, storage); + public new void StoreAllFields(FieldStorage storage) => base.StoreAllFields(storage); + public new void Suggestion(Expression> field) => base.Suggestion(field); + public new void TermVector(string field, FieldTermVector termVector) => base.TermVector(field, termVector); + public new void TermVector(Expression> field, FieldTermVector termVector) => base.TermVector(field, termVector); + + // AbstractIndexCreationTask + public new IJsonObject AsJson(object doc) => base.AsJson(doc); + public new IEnumerable AttachmentsFor(object doc) => base.AttachmentsFor(doc); + public new IEnumerable CounterNamesFor(object doc) => base.CounterNamesFor(doc); + public new IJsonObject.IMetadata MetadataFor(object doc) => base.MetadataFor(doc); + public new IEnumerable TimeSeriesNamesFor(object doc) => base.TimeSeriesNamesFor(doc); + + // AbstractIndexCreationTaskBase + public new object CreateField(string name, object value, CreateFieldOptions options) => base.CreateField(name, value, options); + public new object CreateField(string name, object value, bool stored, bool analyzed) => base.CreateField(name, value, stored, analyzed); + public new object CreateField(string name, object value) => base.CreateField(name, value); + + // AbstractCommonApiForIndexes + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new T? TryConvert(object value) where T : struct => base.TryConvert(value); +} + + +public abstract class ZeroIndex : AbstractIndexCreationTask, IZeroIndexDefinition +{ + public ZeroIndex() { Create(); } + protected virtual void Create() { } + + public virtual void Setup(IZeroOptions options, IDocumentStore store) { } + + // AbstractIndexCreationTask + public new Expression, IEnumerable>> Map { get => base.Map; set => base.Map = value; } + + // AbstractGenericIndexCreationTask + public new Expression, IEnumerable>> Reduce { get => base.Reduce; set => base.Reduce = value; } + public new string OutputReduceToCollection { get => base.OutputReduceToCollection; set => base.OutputReduceToCollection = value; } + public new IDictionary IndexesStrings { get => base.IndexesStrings; set => base.IndexesStrings = value; } + public new IDictionary>, FieldIndexing> Indexes { get => base.Indexes; set => base.Indexes = value; } + public new IDictionary SpatialIndexesStrings { get => base.SpatialIndexesStrings; set => base.SpatialIndexesStrings = value; } + public new IDictionary>, SpatialOptions> SpatialIndexes { get => base.SpatialIndexes; set => base.SpatialIndexes = value; } + public new IDictionary TermVectorsStrings { get => base.TermVectorsStrings; set => base.TermVectorsStrings = value; } + public new IDictionary>, FieldTermVector> TermVectors { get => base.TermVectors; set => base.TermVectors = value; } + public new IDictionary AnalyzersStrings { get => base.AnalyzersStrings; set => base.AnalyzersStrings = value; } + public new IDictionary>, string> Analyzers { get => base.Analyzers; set => base.Analyzers = value; } + public new ISet>> IndexSuggestions { get => base.IndexSuggestions; set => base.IndexSuggestions = value; } + public new IDictionary StoresStrings { get => base.StoresStrings; set => base.StoresStrings = value; } + public new IDictionary>, FieldStorage> Stores { get => base.Stores; set => base.Stores = value; } + public new string PatternReferencesCollectionName { get => base.PatternReferencesCollectionName; set => base.PatternReferencesCollectionName = value; } + public new Expression> PatternForOutputReduceToCollectionReferences { get => base.PatternForOutputReduceToCollectionReferences; set => base.PatternForOutputReduceToCollectionReferences = value; } + public new void AddAssembly(AdditionalAssembly assembly) => base.AddAssembly(assembly); + public new void Analyze(string field, string analyzer) => base.Analyze(field, analyzer); + public new void Analyze(Expression> field, string analyzer) => base.Analyze(field, analyzer); + public new void Index(Expression> field, FieldIndexing indexing) => base.Index(field, indexing); + public new void Index(string field, FieldIndexing indexing) => base.Index(field, indexing); + public new void Spatial(string field, Func indexing) => base.Spatial(field, indexing); + public new void Spatial(Expression> field, Func indexing) => base.Spatial(field, indexing); + public new void Store(string field, FieldStorage storage) => base.Store(field, storage); + public new void Store(Expression> field, FieldStorage storage) => base.Store(field, storage); + public new void StoreAllFields(FieldStorage storage) => base.StoreAllFields(storage); + public new void Suggestion(Expression> field) => base.Suggestion(field); + public new void TermVector(string field, FieldTermVector termVector) => base.TermVector(field, termVector); + public new void TermVector(Expression> field, FieldTermVector termVector) => base.TermVector(field, termVector); + + // AbstractIndexCreationTask + public new IJsonObject AsJson(object doc) => base.AsJson(doc); + public new IEnumerable AttachmentsFor(object doc) => base.AttachmentsFor(doc); + public new IEnumerable CounterNamesFor(object doc) => base.CounterNamesFor(doc); + public new IJsonObject.IMetadata MetadataFor(object doc) => base.MetadataFor(doc); + public new IEnumerable TimeSeriesNamesFor(object doc) => base.TimeSeriesNamesFor(doc); + + // AbstractIndexCreationTaskBase + public new object CreateField(string name, object value, CreateFieldOptions options) => base.CreateField(name, value, options); + public new object CreateField(string name, object value, bool stored, bool analyzed) => base.CreateField(name, value, stored, analyzed); + public new object CreateField(string name, object value) => base.CreateField(name, value); + + // AbstractCommonApiForIndexes + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new T? TryConvert(object value) where T : struct => base.TryConvert(value); +} + + +public abstract class ZeroIndex : ZeroIndex +{ +} + + +public abstract class ZeroIndex : AbstractIndexCreationTask, IZeroIndexDefinition +{ + public ZeroIndex() { Create(); } + protected virtual void Create() { } + + public virtual void Setup(IZeroOptions options, IDocumentStore store) { } + + // AbstractIndexCreationTask + public new IJsonObject AsJson(object doc) => base.AsJson(doc); + public new IEnumerable AttachmentsFor(object doc) => base.AttachmentsFor(doc); + public new IEnumerable CounterNamesFor(object doc) => base.CounterNamesFor(doc); + public new IJsonObject.IMetadata MetadataFor(object doc) => base.MetadataFor(doc); + public new IEnumerable TimeSeriesNamesFor(object doc) => base.TimeSeriesNamesFor(doc); + + // AbstractIndexCreationTaskBase + public new object CreateField(string name, object value, CreateFieldOptions options) => base.CreateField(name, value, options); + public new object CreateField(string name, object value, bool stored, bool analyzed) => base.CreateField(name, value, stored, analyzed); + public new object CreateField(string name, object value) => base.CreateField(name, value); + + // AbstractCommonApiForIndexes + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func func) => base.Recurse(source, func); + public new IEnumerable Recurse(TSource source, Func> func) => base.Recurse(source, func); + public new T? TryConvert(object value) where T : struct => base.TryConvert(value); +} + + +public interface IZeroIndexDefinition : IAbstractIndexCreationTask +{ + void Setup(IZeroOptions options, IDocumentStore store); +} diff --git a/zero.Core/Persistence/ZeroIndexExtensions.cs b/zero.Core/Persistence/ZeroIndexExtensions.cs new file mode 100644 index 00000000..ac6721ac --- /dev/null +++ b/zero.Core/Persistence/ZeroIndexExtensions.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace zero; + +public static class ZeroIndexExtensions +{ + internal static void RunModifiers(this T index, IZeroOptions options) where T : IZeroIndexDefinition + { + IEnumerable modifiers = options.Raven.Indexes.Modifiers.GetAllForType(index.GetType()); + + foreach (RavenIndexModifiersOptions.Modifier modifier in modifiers) + { + Action action = modifier.Modify.Compile(); + action.Invoke(index); + } + } +} diff --git a/zero.Core/Persistence/ZeroStore.cs b/zero.Core/Persistence/ZeroStore.cs new file mode 100644 index 00000000..48df510f --- /dev/null +++ b/zero.Core/Persistence/ZeroStore.cs @@ -0,0 +1,91 @@ +using Raven.Client.Documents.Session; +using System.Collections.Generic; +using zero.Core.Options; + +namespace zero; + +public class ZeroStore : IZeroStore +{ + public ZeroStore(IZeroDocumentStore raven, IZeroOptions options) : base() + { + Options = options; + Raven = raven; + //Database = null; + } + + protected IZeroOptions Options { get; set; } + protected Dictionary ScopedSessions { get; set; } = new(); + + /// + public string ResolvedDatabase { get; set; } + + + /// + public IZeroDocumentStore Raven { get; private set; } + + + /// + public IZeroDocumentSession Session(string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null) + { + database ??= ResolvedDatabase; + options ??= new SessionOptions() { Database = database }; + + if (resolution == ZeroSessionResolution.Create) + { + return Raven.OpenAsyncSession(options) as IZeroDocumentSession; + } + + if (!ScopedSessions.TryGetValue(database, out IZeroDocumentSession session)) + { + session = Raven.OpenAsyncSession(options) as IZeroDocumentSession; + ScopedSessions.TryAdd(database, session); + } + + if (session.IsDisposed) + { + session = Raven.OpenAsyncSession(options) as IZeroDocumentSession; + ScopedSessions.Remove(database); + ScopedSessions.TryAdd(database, session); + } + + return session; + } + + + /// + public IZeroDocumentSession Session(bool global, string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null) + { + return Session(global ? Options.Raven.Database : database, resolution, options); + } +} + + +public enum ZeroSessionResolution +{ + Reuse = 0, + Create = 1 +} + + +public interface IZeroStore +{ + /// + /// The database which has been resolved from the current application + /// + string ResolvedDatabase { get; set; } + + /// + /// Get underlying raven document store + /// + IZeroDocumentStore Raven { get; } + + /// + /// Use a specific session + /// + IZeroDocumentSession Session(string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null); + + /// + /// Use a session for the core database + /// + IZeroDocumentSession Session(bool global, string database = null, ZeroSessionResolution resolution = ZeroSessionResolution.Reuse, SessionOptions options = null); +} \ No newline at end of file diff --git a/zero.Core/Tokens/Rfc6238AuthenticationService.cs b/zero.Core/Tokens/Rfc6238AuthenticationService.cs deleted file mode 100644 index b5d68d3d..00000000 --- a/zero.Core/Tokens/Rfc6238AuthenticationService.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System; -using System.Diagnostics; -using System.Net; -using System.Security.Cryptography; -using System.Text; - -namespace zero.Core.Tokens -{ - /// - /// Replicates the Rfc6238AuthenticationService from ASP.NET Core internals as it isn't part of the public API - /// (see: https://github.com/dotnet/aspnetcore/blob/release/5.0/src/Identity/Extensions.Core/src/Rfc6238AuthenticationService.cs) - /// - public static class Rfc6238AuthenticationService - { - private static readonly TimeSpan _timestep = TimeSpan.FromMinutes(3); - private static readonly Encoding _encoding = new UTF8Encoding(false, true); - - // Generates a new 80-bit security token - public static byte[] GenerateRandomKey() - { - byte[] bytes = new byte[20]; - RandomNumberGenerator.Fill(bytes); - return bytes; - } - - internal static int ComputeTotp(HashAlgorithm hashAlgorithm, ulong timestepNumber, string modifier) - { - // # of 0's = length of pin - const int Mod = 1000000; - - // See https://tools.ietf.org/html/rfc4226 - // We can add an optional modifier - var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber)); - var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifier)); - - // Generate DT string - var offset = hash[hash.Length - 1] & 0xf; - Debug.Assert(offset + 4 < hash.Length); - var binaryCode = (hash[offset] & 0x7f) << 24 - | (hash[offset + 1] & 0xff) << 16 - | (hash[offset + 2] & 0xff) << 8 - | (hash[offset + 3] & 0xff); - - return binaryCode % Mod; - } - - private static byte[] ApplyModifier(byte[] input, string modifier) - { - if (String.IsNullOrEmpty(modifier)) - { - return input; - } - - var modifierBytes = _encoding.GetBytes(modifier); - var combined = new byte[checked(input.Length + modifierBytes.Length)]; - Buffer.BlockCopy(input, 0, combined, 0, input.Length); - Buffer.BlockCopy(modifierBytes, 0, combined, input.Length, modifierBytes.Length); - return combined; - } - - // More info: https://tools.ietf.org/html/rfc6238#section-4 - private static ulong GetCurrentTimeStepNumber() - { - var delta = DateTimeOffset.UtcNow - DateTimeOffset.UnixEpoch; - return (ulong)(delta.Ticks / _timestep.Ticks); - } - - public static int GenerateCode(byte[] securityToken, string modifier = null) - { - if (securityToken == null) - { - throw new ArgumentNullException(nameof(securityToken)); - } - - // Allow a variance of no greater than 9 minutes in either direction - var currentTimeStep = GetCurrentTimeStepNumber(); - using (var hashAlgorithm = new HMACSHA1(securityToken)) - { - return ComputeTotp(hashAlgorithm, currentTimeStep, modifier); - } - } - - public static bool ValidateCode(byte[] securityToken, int code, string modifier = null) - { - if (securityToken == null) - { - throw new ArgumentNullException(nameof(securityToken)); - } - - // Allow a variance of no greater than 9 minutes in either direction - var currentTimeStep = GetCurrentTimeStepNumber(); - using (var hashAlgorithm = new HMACSHA1(securityToken)) - { - for (var i = -2; i <= 2; i++) - { - var computedTotp = ComputeTotp(hashAlgorithm, (ulong)((long)currentTimeStep + i), modifier); - if (computedTotp == code) - { - return true; - } - } - } - - // No match - return false; - } - } -} \ No newline at end of file diff --git a/zero.Core/Tokens/Token.cs b/zero.Core/Tokens/Token.cs deleted file mode 100644 index a15d8d83..00000000 --- a/zero.Core/Tokens/Token.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Collections.Generic; -using zero.Core.Attributes; -using zero.Core.Entities; - -namespace zero.Core.Tokens -{ - [Collection("Tokens")] - public class SecurityToken : IZeroDbConventions - { - public string Id { get; set; } - - public string Key { get; set; } - - public string Token { get; set; } - - public Dictionary Metadata { get; set; } = new Dictionary(); - } -} diff --git a/zero.Core/Tokens/ZeroTokenProvider.cs b/zero.Core/Tokens/ZeroTokenProvider.cs deleted file mode 100644 index b7e33b73..00000000 --- a/zero.Core/Tokens/ZeroTokenProvider.cs +++ /dev/null @@ -1,281 +0,0 @@ -using Microsoft.AspNetCore.Cryptography.KeyDerivation; -using Raven.Client.Documents.Session; -using System; -using System.Collections.Generic; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using zero.Core.Database; -using zero.Core.Extensions; - -namespace zero.Core.Tokens -{ - public class ZeroTokenProvider : IZeroTokenProvider - { - readonly char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-".ToCharArray(); - - readonly RandomNumberGenerator randonNumberGenerator; - - protected IZeroStore Store { get; private set; } - - - public ZeroTokenProvider(IZeroStore store) - { - Store = store; - randonNumberGenerator = RandomNumberGenerator.Create(); - } - - - /// - public virtual async Task Create(string key, TimeSpan expires, int length = 82, Dictionary metadata = default) - { - if (key.IsNullOrWhiteSpace()) - { - throw new ArgumentException("Key cannot be empty"); - } - if (length < 16) - { - throw new ArgumentOutOfRangeException("Use at least a length of 16 for the token"); - } - - string tokenKey = Random(length); - - SecurityToken securityToken = new SecurityToken() - { - Id = TokenToId(tokenKey), - Token = tokenKey, - Key = HashKey(key), - Metadata = metadata ?? new() - }; - - IZeroDocumentSession session = Store.Session(); - - // saves the token - await session.StoreAsync(securityToken); - - // set the expires flag for the token - IMetadataDictionary tokenMetadata = session.Advanced.GetMetadataFor(securityToken); - tokenMetadata[Constants.Database.Expires] = DateTime.UtcNow.AddSeconds(expires.TotalSeconds); - await session.SaveChangesAsync(); - - return tokenKey; - } - - - /// - public virtual async Task Verify(string key, string token) - { - if (token.IsNullOrWhiteSpace() || key.IsNullOrWhiteSpace()) - { - return false; - } - - IZeroDocumentSession session = Store.Session(); - - // try to find a valid token - SecurityToken securityToken = await session.LoadAsync(TokenToId(token)); - bool isValid = securityToken != null && VerifyKey(securityToken.Key, key); - - // remove token from DB if it is valid - if (isValid) - { - session.Delete(securityToken); - await session.SaveChangesAsync(); - } - - return isValid; - } - - - /// - public virtual async Task VerifyAndReturn(string key, string token) - { - if (token.IsNullOrWhiteSpace() || key.IsNullOrWhiteSpace()) - { - return null; - } - - IZeroDocumentSession session = Store.Session(); - - // try to find a valid token - SecurityToken securityToken = await session.LoadAsync(TokenToId(token)); - bool isValid = securityToken != null && VerifyKey(securityToken.Key, key); - - // remove token from DB if it is valid - if (isValid) - { - session.Delete(securityToken); - await session.SaveChangesAsync(); - return securityToken; - } - - return null; - } - - - /// - public string Random(int length) - { - byte[] data = new byte[4 * length]; - randonNumberGenerator.GetBytes(data); - - StringBuilder result = new(length); - - for (int i = 0; i < length; i++) - { - var rnd = BitConverter.ToUInt32(data, i * 4); - var idx = rnd % chars.Length; - - result.Append(chars[idx]); - } - - return result.ToString(); - } - - - /// - /// Converts the token to a database id - /// - string TokenToId(string token) - { - string collection = Store.Raven.Conventions.GetCollectionName(typeof(SecurityToken)); - string idPrefix = Store.Raven.Conventions.TransformTypeCollectionNameToDocumentIdPrefix(collection); - return idPrefix + Store.Raven.Conventions.IdentityPartsSeparator + token; - } - - - /// - /// Creates a hash for the security token key. - /// Borrowed from the .NET Core PasswordHasher - /// (see: https://github.com/dotnet/aspnetcore/blob/release/5.0/src/Identity/Extensions.Core/src/PasswordHasher.cs) - /// - string HashKey(string key) - { - key = key.ToLowerInvariant(); - - KeyDerivationPrf prf = KeyDerivationPrf.HMACSHA256; - int iterationCount = 10000; - int saltSize = 128 / 8; - int numBytesRequested = 256 / 8; - - byte[] salt = new byte[saltSize]; - randonNumberGenerator.GetBytes(salt); - byte[] subkey = KeyDerivation.Pbkdf2(key, salt, prf, iterationCount, numBytesRequested); - - var outputBytes = new byte[13 + salt.Length + subkey.Length]; - outputBytes[0] = 0x01; - WriteNetworkByteOrder(outputBytes, 1, (uint)prf); - WriteNetworkByteOrder(outputBytes, 5, (uint)iterationCount); - WriteNetworkByteOrder(outputBytes, 9, (uint)saltSize); - Buffer.BlockCopy(salt, 0, outputBytes, 13, salt.Length); - Buffer.BlockCopy(subkey, 0, outputBytes, 13 + saltSize, subkey.Length); - return Convert.ToBase64String(outputBytes); - } - - - /// - /// Verifies the given key. - /// Borrowed from the .NET Core PasswordHasher - /// (see: https://github.com/dotnet/aspnetcore/blob/release/5.0/src/Identity/Extensions.Core/src/PasswordHasher.cs) - /// - bool VerifyKey(string storedKey, string key) - { - byte[] decodedStoredKey = Convert.FromBase64String(storedKey); - - try - { - KeyDerivationPrf prf = (KeyDerivationPrf)ReadNetworkByteOrder(decodedStoredKey, 1); - int embeddedIterCount = (int)ReadNetworkByteOrder(decodedStoredKey, 5); - int saltLength = (int)ReadNetworkByteOrder(decodedStoredKey, 9); - - // Read the salt: must be >= 128 bits - if (saltLength < 128 / 8) - { - return false; - } - - byte[] salt = new byte[saltLength]; - Buffer.BlockCopy(decodedStoredKey, 13, salt, 0, salt.Length); - - // Read the subkey (the rest of the payload): must be >= 128 bits - int subkeyLength = decodedStoredKey.Length - 13 - salt.Length; - if (subkeyLength < 128 / 8) - { - return false; - } - byte[] expectedSubkey = new byte[subkeyLength]; - Buffer.BlockCopy(decodedStoredKey, 13 + salt.Length, expectedSubkey, 0, expectedSubkey.Length); - - // Hash the incoming key and verify it - byte[] actualSubkey = KeyDerivation.Pbkdf2(key, salt, prf, embeddedIterCount, subkeyLength); - - return CryptographicOperations.FixedTimeEquals(actualSubkey, expectedSubkey); - } - catch - { - return false; - } - } - - - static void WriteNetworkByteOrder(byte[] buffer, int offset, uint value) - { - buffer[offset + 0] = (byte)(value >> 24); - buffer[offset + 1] = (byte)(value >> 16); - buffer[offset + 2] = (byte)(value >> 8); - buffer[offset + 3] = (byte)(value >> 0); - } - - static uint ReadNetworkByteOrder(byte[] buffer, int offset) - { - return ((uint)(buffer[offset + 0]) << 24) - | ((uint)(buffer[offset + 1]) << 16) - | ((uint)(buffer[offset + 2]) << 8) - | ((uint)(buffer[offset + 3])); - } - } - - - public interface IZeroTokenProvider - { - /// - /// Generates a token for a with a specified lifespan. - /// - /// The purpose the token will be used for. The key must match when verifying the token and should always be hidden from the user. - /// The token will automatically expire after this timespan. - /// Length of the geneated token. - /// Additional metadata to store with the token. This data can be retrieved on verification with - /// - /// The generated token with the specified . - /// - Task Create(string key, TimeSpan expires, int length = 82, Dictionary metadata = default); - - /// - /// Validates the passed for the specified . - /// - /// The purpose the token was used for. - /// The previously generated token. - /// - /// False, if the token could not be found or it has already expired. - /// - Task Verify(string key, string token); - - /// - /// Validates the passed for the specified . - /// - /// The purpose the token was used for. - /// The previously generated token. - /// - /// Null, if the token could not be found or it has already expired. - /// - Task VerifyAndReturn(string key, string token); - - /// - /// Generates a random token with the specified using the RNGCryptoServiceProvider. - /// - /// - /// This method won't store the token in the database and can't be used for verification. Use instead. - /// - string Random(int length); - } -} diff --git a/zero.Core/Usings.cs b/zero.Core/Usings.cs deleted file mode 100644 index 3481f0d4..00000000 --- a/zero.Core/Usings.cs +++ /dev/null @@ -1,16 +0,0 @@ - -global using zero; -global using zero.Core; -global using zero.Core.Api; -global using zero.Core.Assemblies; -global using zero.Core.Collections; -global using zero.Core.Cultures; -global using zero.Core.Database; -global using zero.Core.Entities; -global using zero.Core.Extensions; -global using zero.Core.Handlers; -global using zero.Core.Identity; -global using zero.Core.Options; -global using zero.Core.Plugins; -global using zero.Core.Security; -global using zero.Core.Validation; \ No newline at end of file diff --git a/zero.Core/Api/ApplicationsApi.cs b/zero.Core/old/Api/ApplicationsApi.cs similarity index 100% rename from zero.Core/Api/ApplicationsApi.cs rename to zero.Core/old/Api/ApplicationsApi.cs diff --git a/zero.Core/Api/AuthenticationApi.cs b/zero.Core/old/Api/AuthenticationApi.cs similarity index 100% rename from zero.Core/Api/AuthenticationApi.cs rename to zero.Core/old/Api/AuthenticationApi.cs diff --git a/zero.Core/Api/AuthorizationApi.cs b/zero.Core/old/Api/AuthorizationApi.cs similarity index 100% rename from zero.Core/Api/AuthorizationApi.cs rename to zero.Core/old/Api/AuthorizationApi.cs diff --git a/zero.Core/Api/BackofficeApi.cs b/zero.Core/old/Api/BackofficeApi.cs similarity index 100% rename from zero.Core/Api/BackofficeApi.cs rename to zero.Core/old/Api/BackofficeApi.cs diff --git a/zero.Core/Api/BackofficeStore.cs b/zero.Core/old/Api/BackofficeStore.cs similarity index 100% rename from zero.Core/Api/BackofficeStore.cs rename to zero.Core/old/Api/BackofficeStore.cs diff --git a/zero.Core/Api/ModulesApi.cs b/zero.Core/old/Api/ModulesApi.cs similarity index 100% rename from zero.Core/Api/ModulesApi.cs rename to zero.Core/old/Api/ModulesApi.cs diff --git a/zero.Core/Api/PermissionsApi.cs b/zero.Core/old/Api/PermissionsApi.cs similarity index 100% rename from zero.Core/Api/PermissionsApi.cs rename to zero.Core/old/Api/PermissionsApi.cs diff --git a/zero.Core/Api/PreviewApi.cs b/zero.Core/old/Api/PreviewApi.cs similarity index 100% rename from zero.Core/Api/PreviewApi.cs rename to zero.Core/old/Api/PreviewApi.cs diff --git a/zero.Core/Api/RecycleBinApi.cs b/zero.Core/old/Api/RecycleBinApi.cs similarity index 100% rename from zero.Core/Api/RecycleBinApi.cs rename to zero.Core/old/Api/RecycleBinApi.cs diff --git a/zero.Core/Api/RevisionsApi.cs b/zero.Core/old/Api/RevisionsApi.cs similarity index 100% rename from zero.Core/Api/RevisionsApi.cs rename to zero.Core/old/Api/RevisionsApi.cs diff --git a/zero.Core/Api/Safenames.cs b/zero.Core/old/Api/Safenames.cs similarity index 100% rename from zero.Core/Api/Safenames.cs rename to zero.Core/old/Api/Safenames.cs diff --git a/zero.Core/Api/SectionsApi.cs b/zero.Core/old/Api/SectionsApi.cs similarity index 100% rename from zero.Core/Api/SectionsApi.cs rename to zero.Core/old/Api/SectionsApi.cs diff --git a/zero.Core/Api/SettingsApi.cs b/zero.Core/old/Api/SettingsApi.cs similarity index 100% rename from zero.Core/Api/SettingsApi.cs rename to zero.Core/old/Api/SettingsApi.cs diff --git a/zero.Core/Api/SetupApi.cs b/zero.Core/old/Api/SetupApi.cs similarity index 100% rename from zero.Core/Api/SetupApi.cs rename to zero.Core/old/Api/SetupApi.cs diff --git a/zero.Core/Api/SpacesApi.cs b/zero.Core/old/Api/SpacesApi.cs similarity index 100% rename from zero.Core/Api/SpacesApi.cs rename to zero.Core/old/Api/SpacesApi.cs diff --git a/zero.Core/Api/Token.cs b/zero.Core/old/Api/Token.cs similarity index 100% rename from zero.Core/Api/Token.cs rename to zero.Core/old/Api/Token.cs diff --git a/zero.Core/Api/UserApi.cs b/zero.Core/old/Api/UserApi.cs similarity index 100% rename from zero.Core/Api/UserApi.cs rename to zero.Core/old/Api/UserApi.cs diff --git a/zero.Core/Api/UserRolesApi.cs b/zero.Core/old/Api/UserRolesApi.cs similarity index 100% rename from zero.Core/Api/UserRolesApi.cs rename to zero.Core/old/Api/UserRolesApi.cs diff --git a/zero.Core/ApplicationResolver.cs b/zero.Core/old/ApplicationResolver.cs similarity index 100% rename from zero.Core/ApplicationResolver.cs rename to zero.Core/old/ApplicationResolver.cs diff --git a/zero.Core/Assemblies/AssemblyDiscovery.cs b/zero.Core/old/Assemblies/AssemblyDiscovery.cs similarity index 100% rename from zero.Core/Assemblies/AssemblyDiscovery.cs rename to zero.Core/old/Assemblies/AssemblyDiscovery.cs diff --git a/zero.Core/Assemblies/AssemblyDiscoveryContext.cs b/zero.Core/old/Assemblies/AssemblyDiscoveryContext.cs similarity index 100% rename from zero.Core/Assemblies/AssemblyDiscoveryContext.cs rename to zero.Core/old/Assemblies/AssemblyDiscoveryContext.cs diff --git a/zero.Core/Assemblies/IAssemblyDiscoveryRule.cs b/zero.Core/old/Assemblies/IAssemblyDiscoveryRule.cs similarity index 100% rename from zero.Core/Assemblies/IAssemblyDiscoveryRule.cs rename to zero.Core/old/Assemblies/IAssemblyDiscoveryRule.cs diff --git a/zero.Core/Attributes/CollectionAttribute.cs b/zero.Core/old/Attributes/CollectionAttribute.cs similarity index 100% rename from zero.Core/Attributes/CollectionAttribute.cs rename to zero.Core/old/Attributes/CollectionAttribute.cs diff --git a/zero.Core/Attributes/GenerateIdAttribute.cs b/zero.Core/old/Attributes/GenerateIdAttribute.cs similarity index 100% rename from zero.Core/Attributes/GenerateIdAttribute.cs rename to zero.Core/old/Attributes/GenerateIdAttribute.cs diff --git a/zero.Core/Attributes/LocalizeAttribute.cs b/zero.Core/old/Attributes/LocalizeAttribute.cs similarity index 100% rename from zero.Core/Attributes/LocalizeAttribute.cs rename to zero.Core/old/Attributes/LocalizeAttribute.cs diff --git a/zero.Core/Attributes/OperationCancelledExceptionFilterAttribute.cs b/zero.Core/old/Attributes/OperationCancelledExceptionFilterAttribute.cs similarity index 100% rename from zero.Core/Attributes/OperationCancelledExceptionFilterAttribute.cs rename to zero.Core/old/Attributes/OperationCancelledExceptionFilterAttribute.cs diff --git a/zero.Core/Blueprints/Blueprint.cs b/zero.Core/old/Blueprints/Blueprint.cs similarity index 100% rename from zero.Core/Blueprints/Blueprint.cs rename to zero.Core/old/Blueprints/Blueprint.cs diff --git a/zero.Core/Blueprints/BlueprintChildInterceptor.cs b/zero.Core/old/Blueprints/BlueprintChildInterceptor.cs similarity index 100% rename from zero.Core/Blueprints/BlueprintChildInterceptor.cs rename to zero.Core/old/Blueprints/BlueprintChildInterceptor.cs diff --git a/zero.Core/Blueprints/BlueprintField.cs b/zero.Core/old/Blueprints/BlueprintField.cs similarity index 100% rename from zero.Core/Blueprints/BlueprintField.cs rename to zero.Core/old/Blueprints/BlueprintField.cs diff --git a/zero.Core/Blueprints/BlueprintInterceptor.cs b/zero.Core/old/Blueprints/BlueprintInterceptor.cs similarity index 100% rename from zero.Core/Blueprints/BlueprintInterceptor.cs rename to zero.Core/old/Blueprints/BlueprintInterceptor.cs diff --git a/zero.Core/Blueprints/BlueprintService.cs b/zero.Core/old/Blueprints/BlueprintService.cs similarity index 100% rename from zero.Core/Blueprints/BlueprintService.cs rename to zero.Core/old/Blueprints/BlueprintService.cs diff --git a/zero.Core/Collections/CollectionBase.cs b/zero.Core/old/Collections/CollectionBase.cs similarity index 100% rename from zero.Core/Collections/CollectionBase.cs rename to zero.Core/old/Collections/CollectionBase.cs diff --git a/zero.Core/Collections/CollectionContext.cs b/zero.Core/old/Collections/CollectionContext.cs similarity index 100% rename from zero.Core/Collections/CollectionContext.cs rename to zero.Core/old/Collections/CollectionContext.cs diff --git a/zero.Core/Collections/CollectionScope.cs b/zero.Core/old/Collections/CollectionScope.cs similarity index 100% rename from zero.Core/Collections/CollectionScope.cs rename to zero.Core/old/Collections/CollectionScope.cs diff --git a/zero.Core/Collections/Countries/CountriesCollection.cs b/zero.Core/old/Collections/Countries/CountriesCollection.cs similarity index 100% rename from zero.Core/Collections/Countries/CountriesCollection.cs rename to zero.Core/old/Collections/Countries/CountriesCollection.cs diff --git a/zero.Core/Collections/EntityCollection/EntityCollection.Delete.cs b/zero.Core/old/Collections/EntityCollection/EntityCollection.Delete.cs similarity index 100% rename from zero.Core/Collections/EntityCollection/EntityCollection.Delete.cs rename to zero.Core/old/Collections/EntityCollection/EntityCollection.Delete.cs diff --git a/zero.Core/Collections/EntityCollection/EntityCollection.Read.cs b/zero.Core/old/Collections/EntityCollection/EntityCollection.Read.cs similarity index 100% rename from zero.Core/Collections/EntityCollection/EntityCollection.Read.cs rename to zero.Core/old/Collections/EntityCollection/EntityCollection.Read.cs diff --git a/zero.Core/Collections/EntityCollection/EntityCollection.Write.cs b/zero.Core/old/Collections/EntityCollection/EntityCollection.Write.cs similarity index 100% rename from zero.Core/Collections/EntityCollection/EntityCollection.Write.cs rename to zero.Core/old/Collections/EntityCollection/EntityCollection.Write.cs diff --git a/zero.Core/Collections/EntityCollection/EntityCollection.cs b/zero.Core/old/Collections/EntityCollection/EntityCollection.cs similarity index 100% rename from zero.Core/Collections/EntityCollection/EntityCollection.cs rename to zero.Core/old/Collections/EntityCollection/EntityCollection.cs diff --git a/zero.Core/Collections/EntityCollection/EntityCollectionProxy.cs b/zero.Core/old/Collections/EntityCollection/EntityCollectionProxy.cs similarity index 100% rename from zero.Core/Collections/EntityCollection/EntityCollectionProxy.cs rename to zero.Core/old/Collections/EntityCollection/EntityCollectionProxy.cs diff --git a/zero.Core/Collections/Integrations/IntegrationsCollection.cs b/zero.Core/old/Collections/Integrations/IntegrationsCollection.cs similarity index 100% rename from zero.Core/Collections/Integrations/IntegrationsCollection.cs rename to zero.Core/old/Collections/Integrations/IntegrationsCollection.cs diff --git a/zero.Core/Collections/Interceptors/CollectionInterceptor.cs b/zero.Core/old/Collections/Interceptors/CollectionInterceptor.cs similarity index 100% rename from zero.Core/Collections/Interceptors/CollectionInterceptor.cs rename to zero.Core/old/Collections/Interceptors/CollectionInterceptor.cs diff --git a/zero.Core/Collections/Interceptors/CollectionInterceptorHandler.cs b/zero.Core/old/Collections/Interceptors/CollectionInterceptorHandler.cs similarity index 100% rename from zero.Core/Collections/Interceptors/CollectionInterceptorHandler.cs rename to zero.Core/old/Collections/Interceptors/CollectionInterceptorHandler.cs diff --git a/zero.Core/Collections/Interceptors/CollectionInterceptorShim.cs b/zero.Core/old/Collections/Interceptors/CollectionInterceptorShim.cs similarity index 100% rename from zero.Core/Collections/Interceptors/CollectionInterceptorShim.cs rename to zero.Core/old/Collections/Interceptors/CollectionInterceptorShim.cs diff --git a/zero.Core/Collections/Interceptors/InterceptorInstruction.cs b/zero.Core/old/Collections/Interceptors/InterceptorInstruction.cs similarity index 100% rename from zero.Core/Collections/Interceptors/InterceptorInstruction.cs rename to zero.Core/old/Collections/Interceptors/InterceptorInstruction.cs diff --git a/zero.Core/Collections/Interceptors/InterceptorInstructionProxy.cs b/zero.Core/old/Collections/Interceptors/InterceptorInstructionProxy.cs similarity index 100% rename from zero.Core/Collections/Interceptors/InterceptorInstructionProxy.cs rename to zero.Core/old/Collections/Interceptors/InterceptorInstructionProxy.cs diff --git a/zero.Core/Collections/Interceptors/InterceptorParameters.cs b/zero.Core/old/Collections/Interceptors/InterceptorParameters.cs similarity index 100% rename from zero.Core/Collections/Interceptors/InterceptorParameters.cs rename to zero.Core/old/Collections/Interceptors/InterceptorParameters.cs diff --git a/zero.Core/Collections/Interceptors/InterceptorResult.cs b/zero.Core/old/Collections/Interceptors/InterceptorResult.cs similarity index 100% rename from zero.Core/Collections/Interceptors/InterceptorResult.cs rename to zero.Core/old/Collections/Interceptors/InterceptorResult.cs diff --git a/zero.Core/Collections/Interceptors/InterceptorRunner.cs b/zero.Core/old/Collections/Interceptors/InterceptorRunner.cs similarity index 100% rename from zero.Core/Collections/Interceptors/InterceptorRunner.cs rename to zero.Core/old/Collections/Interceptors/InterceptorRunner.cs diff --git a/zero.Core/Collections/Interceptors/InterceptorType.cs b/zero.Core/old/Collections/Interceptors/InterceptorType.cs similarity index 100% rename from zero.Core/Collections/Interceptors/InterceptorType.cs rename to zero.Core/old/Collections/Interceptors/InterceptorType.cs diff --git a/zero.Core/Collections/Languages/LanguagesCollection.cs b/zero.Core/old/Collections/Languages/LanguagesCollection.cs similarity index 100% rename from zero.Core/Collections/Languages/LanguagesCollection.cs rename to zero.Core/old/Collections/Languages/LanguagesCollection.cs diff --git a/zero.Core/Collections/MailTemplates/MailTemplatesCollection.cs b/zero.Core/old/Collections/MailTemplates/MailTemplatesCollection.cs similarity index 100% rename from zero.Core/Collections/MailTemplates/MailTemplatesCollection.cs rename to zero.Core/old/Collections/MailTemplates/MailTemplatesCollection.cs diff --git a/zero.Core/Collections/Media/MediaCollection.cs b/zero.Core/old/Collections/Media/MediaCollection.cs similarity index 100% rename from zero.Core/Collections/Media/MediaCollection.cs rename to zero.Core/old/Collections/Media/MediaCollection.cs diff --git a/zero.Core/Collections/Media/MediaFolderCollection.cs b/zero.Core/old/Collections/Media/MediaFolderCollection.cs similarity index 100% rename from zero.Core/Collections/Media/MediaFolderCollection.cs rename to zero.Core/old/Collections/Media/MediaFolderCollection.cs diff --git a/zero.Core/Collections/Pages/PagesCollection.cs b/zero.Core/old/Collections/Pages/PagesCollection.cs similarity index 100% rename from zero.Core/Collections/Pages/PagesCollection.cs rename to zero.Core/old/Collections/Pages/PagesCollection.cs diff --git a/zero.Core/Collections/Translations/TranslationValidator.cs b/zero.Core/old/Collections/Translations/TranslationValidator.cs similarity index 100% rename from zero.Core/Collections/Translations/TranslationValidator.cs rename to zero.Core/old/Collections/Translations/TranslationValidator.cs diff --git a/zero.Core/Collections/Translations/TranslationsCollection.cs b/zero.Core/old/Collections/Translations/TranslationsCollection.cs similarity index 100% rename from zero.Core/Collections/Translations/TranslationsCollection.cs rename to zero.Core/old/Collections/Translations/TranslationsCollection.cs diff --git a/zero.Core/Constants.cs b/zero.Core/old/Constants.cs similarity index 100% rename from zero.Core/Constants.cs rename to zero.Core/old/Constants.cs diff --git a/zero.Core/Cultures/CultureResolver.cs b/zero.Core/old/Cultures/CultureResolver.cs similarity index 100% rename from zero.Core/Cultures/CultureResolver.cs rename to zero.Core/old/Cultures/CultureResolver.cs diff --git a/zero.Core/Database/Indexes/Backoffice/zero_Countries.cs b/zero.Core/old/Database/Indexes/Backoffice/zero_Countries.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice/zero_Countries.cs rename to zero.Core/old/Database/Indexes/Backoffice/zero_Countries.cs diff --git a/zero.Core/Database/Indexes/Backoffice/zero_Languages.cs b/zero.Core/old/Database/Indexes/Backoffice/zero_Languages.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice/zero_Languages.cs rename to zero.Core/old/Database/Indexes/Backoffice/zero_Languages.cs diff --git a/zero.Core/Database/Indexes/Backoffice/zero_MailTemplates.cs b/zero.Core/old/Database/Indexes/Backoffice/zero_MailTemplates.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice/zero_MailTemplates.cs rename to zero.Core/old/Database/Indexes/Backoffice/zero_MailTemplates.cs diff --git a/zero.Core/Database/Indexes/Backoffice/zero_RecycledEntities.cs b/zero.Core/old/Database/Indexes/Backoffice/zero_RecycledEntities.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice/zero_RecycledEntities.cs rename to zero.Core/old/Database/Indexes/Backoffice/zero_RecycledEntities.cs diff --git a/zero.Core/Database/Indexes/Backoffice/zero_Spaces.cs b/zero.Core/old/Database/Indexes/Backoffice/zero_Spaces.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice/zero_Spaces.cs rename to zero.Core/old/Database/Indexes/Backoffice/zero_Spaces.cs diff --git a/zero.Core/Database/Indexes/Backoffice/zero_Translations.cs b/zero.Core/old/Database/Indexes/Backoffice/zero_Translations.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice/zero_Translations.cs rename to zero.Core/old/Database/Indexes/Backoffice/zero_Translations.cs diff --git a/zero.Core/Database/Indexes/Backoffice_Search.cs b/zero.Core/old/Database/Indexes/Backoffice_Search.cs similarity index 100% rename from zero.Core/Database/Indexes/Backoffice_Search.cs rename to zero.Core/old/Database/Indexes/Backoffice_Search.cs diff --git a/zero.Core/Database/Indexes/MediaFolder_ByHierarchy.cs b/zero.Core/old/Database/Indexes/MediaFolder_ByHierarchy.cs similarity index 100% rename from zero.Core/Database/Indexes/MediaFolder_ByHierarchy.cs rename to zero.Core/old/Database/Indexes/MediaFolder_ByHierarchy.cs diff --git a/zero.Core/Database/Indexes/MediaFolders_WithChildren.cs b/zero.Core/old/Database/Indexes/MediaFolders_WithChildren.cs similarity index 100% rename from zero.Core/Database/Indexes/MediaFolders_WithChildren.cs rename to zero.Core/old/Database/Indexes/MediaFolders_WithChildren.cs diff --git a/zero.Core/Database/Indexes/Media_ByChildren.cs b/zero.Core/old/Database/Indexes/Media_ByChildren.cs similarity index 100% rename from zero.Core/Database/Indexes/Media_ByChildren.cs rename to zero.Core/old/Database/Indexes/Media_ByChildren.cs diff --git a/zero.Core/Database/Indexes/Media_ByParent.cs b/zero.Core/old/Database/Indexes/Media_ByParent.cs similarity index 100% rename from zero.Core/Database/Indexes/Media_ByParent.cs rename to zero.Core/old/Database/Indexes/Media_ByParent.cs diff --git a/zero.Core/Database/Indexes/Pages_AsHistory.cs b/zero.Core/old/Database/Indexes/Pages_AsHistory.cs similarity index 100% rename from zero.Core/Database/Indexes/Pages_AsHistory.cs rename to zero.Core/old/Database/Indexes/Pages_AsHistory.cs diff --git a/zero.Core/Database/Indexes/Pages_ByHierarchy.cs b/zero.Core/old/Database/Indexes/Pages_ByHierarchy.cs similarity index 100% rename from zero.Core/Database/Indexes/Pages_ByHierarchy.cs rename to zero.Core/old/Database/Indexes/Pages_ByHierarchy.cs diff --git a/zero.Core/Database/Indexes/Pages_ByType.cs b/zero.Core/old/Database/Indexes/Pages_ByType.cs similarity index 100% rename from zero.Core/Database/Indexes/Pages_ByType.cs rename to zero.Core/old/Database/Indexes/Pages_ByType.cs diff --git a/zero.Core/Database/Indexes/Pages_WithChildren.cs b/zero.Core/old/Database/Indexes/Pages_WithChildren.cs similarity index 100% rename from zero.Core/Database/Indexes/Pages_WithChildren.cs rename to zero.Core/old/Database/Indexes/Pages_WithChildren.cs diff --git a/zero.Core/Database/Indexes/RouteRedirects_ByUrl.cs b/zero.Core/old/Database/Indexes/RouteRedirects_ByUrl.cs similarity index 100% rename from zero.Core/Database/Indexes/RouteRedirects_ByUrl.cs rename to zero.Core/old/Database/Indexes/RouteRedirects_ByUrl.cs diff --git a/zero.Core/Database/Indexes/Routes_ByDependencies.cs b/zero.Core/old/Database/Indexes/Routes_ByDependencies.cs similarity index 100% rename from zero.Core/Database/Indexes/Routes_ByDependencies.cs rename to zero.Core/old/Database/Indexes/Routes_ByDependencies.cs diff --git a/zero.Core/Database/Indexes/Routes_ForResolver.cs b/zero.Core/old/Database/Indexes/Routes_ForResolver.cs similarity index 100% rename from zero.Core/Database/Indexes/Routes_ForResolver.cs rename to zero.Core/old/Database/Indexes/Routes_ForResolver.cs diff --git a/zero.Core/Database/ZeroDocumentConventionsBuilder.cs b/zero.Core/old/Database/ZeroDocumentConventionsBuilder.cs similarity index 100% rename from zero.Core/Database/ZeroDocumentConventionsBuilder.cs rename to zero.Core/old/Database/ZeroDocumentConventionsBuilder.cs diff --git a/zero.Core/Database/ZeroDocumentSession.cs b/zero.Core/old/Database/ZeroDocumentSession.cs similarity index 100% rename from zero.Core/Database/ZeroDocumentSession.cs rename to zero.Core/old/Database/ZeroDocumentSession.cs diff --git a/zero.Core/Database/ZeroDocumentStore.cs b/zero.Core/old/Database/ZeroDocumentStore.cs similarity index 100% rename from zero.Core/Database/ZeroDocumentStore.cs rename to zero.Core/old/Database/ZeroDocumentStore.cs diff --git a/zero.Core/Database/ZeroIndex.cs b/zero.Core/old/Database/ZeroIndex.cs similarity index 100% rename from zero.Core/Database/ZeroIndex.cs rename to zero.Core/old/Database/ZeroIndex.cs diff --git a/zero.Core/Database/ZeroStore.cs b/zero.Core/old/Database/ZeroStore.cs similarity index 100% rename from zero.Core/Database/ZeroStore.cs rename to zero.Core/old/Database/ZeroStore.cs diff --git a/zero.Core/Entities/Applications/Application.cs b/zero.Core/old/Entities/Applications/Application.cs similarity index 100% rename from zero.Core/Entities/Applications/Application.cs rename to zero.Core/old/Entities/Applications/Application.cs diff --git a/zero.Core/Entities/Blueprints/BlueprintConfiguration.cs b/zero.Core/old/Entities/Blueprints/BlueprintConfiguration.cs similarity index 100% rename from zero.Core/Entities/Blueprints/BlueprintConfiguration.cs rename to zero.Core/old/Entities/Blueprints/BlueprintConfiguration.cs diff --git a/zero.Core/Entities/ChangeToken.cs b/zero.Core/old/Entities/ChangeToken.cs similarity index 100% rename from zero.Core/Entities/ChangeToken.cs rename to zero.Core/old/Entities/ChangeToken.cs diff --git a/zero.Core/Entities/Country.cs b/zero.Core/old/Entities/Country.cs similarity index 100% rename from zero.Core/Entities/Country.cs rename to zero.Core/old/Entities/Country.cs diff --git a/zero.Core/Entities/Culture.cs b/zero.Core/old/Entities/Culture.cs similarity index 100% rename from zero.Core/Entities/Culture.cs rename to zero.Core/old/Entities/Culture.cs diff --git a/zero.Core/Entities/DateRange.cs b/zero.Core/old/Entities/DateRange.cs similarity index 100% rename from zero.Core/Entities/DateRange.cs rename to zero.Core/old/Entities/DateRange.cs diff --git a/zero.Core/Entities/EntityResult.cs b/zero.Core/old/Entities/EntityResult.cs similarity index 100% rename from zero.Core/Entities/EntityResult.cs rename to zero.Core/old/Entities/EntityResult.cs diff --git a/zero.Core/Entities/Features/Feature.cs b/zero.Core/old/Entities/Features/Feature.cs similarity index 100% rename from zero.Core/Entities/Features/Feature.cs rename to zero.Core/old/Entities/Features/Feature.cs diff --git a/zero.Core/Entities/FileResult.cs b/zero.Core/old/Entities/FileResult.cs similarity index 100% rename from zero.Core/Entities/FileResult.cs rename to zero.Core/old/Entities/FileResult.cs diff --git a/zero.Core/Entities/FileSizeNotation.cs b/zero.Core/old/Entities/FileSizeNotation.cs similarity index 100% rename from zero.Core/Entities/FileSizeNotation.cs rename to zero.Core/old/Entities/FileSizeNotation.cs diff --git a/zero.Core/Entities/Gender.cs b/zero.Core/old/Entities/Gender.cs similarity index 100% rename from zero.Core/Entities/Gender.cs rename to zero.Core/old/Entities/Gender.cs diff --git a/zero.Core/Entities/IZeroDbConventions.cs b/zero.Core/old/Entities/IZeroDbConventions.cs similarity index 100% rename from zero.Core/Entities/IZeroDbConventions.cs rename to zero.Core/old/Entities/IZeroDbConventions.cs diff --git a/zero.Core/Entities/IconSet.cs b/zero.Core/old/Entities/IconSet.cs similarity index 100% rename from zero.Core/Entities/IconSet.cs rename to zero.Core/old/Entities/IconSet.cs diff --git a/zero.Core/Entities/Language.cs b/zero.Core/old/Entities/Language.cs similarity index 100% rename from zero.Core/Entities/Language.cs rename to zero.Core/old/Entities/Language.cs diff --git a/zero.Core/Entities/Links/Link.cs b/zero.Core/old/Entities/Links/Link.cs similarity index 100% rename from zero.Core/Entities/Links/Link.cs rename to zero.Core/old/Entities/Links/Link.cs diff --git a/zero.Core/Entities/ListQuery.cs b/zero.Core/old/Entities/ListQuery.cs similarity index 100% rename from zero.Core/Entities/ListQuery.cs rename to zero.Core/old/Entities/ListQuery.cs diff --git a/zero.Core/Entities/ListResult.cs b/zero.Core/old/Entities/ListResult.cs similarity index 100% rename from zero.Core/Entities/ListResult.cs rename to zero.Core/old/Entities/ListResult.cs diff --git a/zero.Core/Entities/MailTemplate.cs b/zero.Core/old/Entities/MailTemplate.cs similarity index 100% rename from zero.Core/Entities/MailTemplate.cs rename to zero.Core/old/Entities/MailTemplate.cs diff --git a/zero.Core/Entities/Media/Media.cs b/zero.Core/old/Entities/Media/Media.cs similarity index 100% rename from zero.Core/Entities/Media/Media.cs rename to zero.Core/old/Entities/Media/Media.cs diff --git a/zero.Core/Entities/Media/MediaFocalPoint.cs b/zero.Core/old/Entities/Media/MediaFocalPoint.cs similarity index 100% rename from zero.Core/Entities/Media/MediaFocalPoint.cs rename to zero.Core/old/Entities/Media/MediaFocalPoint.cs diff --git a/zero.Core/Entities/Media/MediaFolder.cs b/zero.Core/old/Entities/Media/MediaFolder.cs similarity index 100% rename from zero.Core/Entities/Media/MediaFolder.cs rename to zero.Core/old/Entities/Media/MediaFolder.cs diff --git a/zero.Core/Entities/Media/MediaImageMeta.cs b/zero.Core/old/Entities/Media/MediaImageMeta.cs similarity index 100% rename from zero.Core/Entities/Media/MediaImageMeta.cs rename to zero.Core/old/Entities/Media/MediaImageMeta.cs diff --git a/zero.Core/Entities/Media/MediaListItem.cs b/zero.Core/old/Entities/Media/MediaListItem.cs similarity index 100% rename from zero.Core/Entities/Media/MediaListItem.cs rename to zero.Core/old/Entities/Media/MediaListItem.cs diff --git a/zero.Core/Entities/Media/MediaListQuery.cs b/zero.Core/old/Entities/Media/MediaListQuery.cs similarity index 100% rename from zero.Core/Entities/Media/MediaListQuery.cs rename to zero.Core/old/Entities/Media/MediaListQuery.cs diff --git a/zero.Core/Entities/Media/MediaType.cs b/zero.Core/old/Entities/Media/MediaType.cs similarity index 100% rename from zero.Core/Entities/Media/MediaType.cs rename to zero.Core/old/Entities/Media/MediaType.cs diff --git a/zero.Core/Entities/Modules/Module.cs b/zero.Core/old/Entities/Modules/Module.cs similarity index 100% rename from zero.Core/Entities/Modules/Module.cs rename to zero.Core/old/Entities/Modules/Module.cs diff --git a/zero.Core/Entities/Modules/ModuleType.cs b/zero.Core/old/Entities/Modules/ModuleType.cs similarity index 100% rename from zero.Core/Entities/Modules/ModuleType.cs rename to zero.Core/old/Entities/Modules/ModuleType.cs diff --git a/zero.Core/Entities/Pages/Page.cs b/zero.Core/old/Entities/Pages/Page.cs similarity index 100% rename from zero.Core/Entities/Pages/Page.cs rename to zero.Core/old/Entities/Pages/Page.cs diff --git a/zero.Core/Entities/Pages/PageFolder.cs b/zero.Core/old/Entities/Pages/PageFolder.cs similarity index 100% rename from zero.Core/Entities/Pages/PageFolder.cs rename to zero.Core/old/Entities/Pages/PageFolder.cs diff --git a/zero.Core/Entities/Pages/PageType.cs b/zero.Core/old/Entities/Pages/PageType.cs similarity index 100% rename from zero.Core/Entities/Pages/PageType.cs rename to zero.Core/old/Entities/Pages/PageType.cs diff --git a/zero.Core/Entities/Preset.cs b/zero.Core/old/Entities/Preset.cs similarity index 100% rename from zero.Core/Entities/Preset.cs rename to zero.Core/old/Entities/Preset.cs diff --git a/zero.Core/Entities/Preview.cs b/zero.Core/old/Entities/Preview.cs similarity index 100% rename from zero.Core/Entities/Preview.cs rename to zero.Core/old/Entities/Preview.cs diff --git a/zero.Core/Entities/PreviewModel.cs b/zero.Core/old/Entities/PreviewModel.cs similarity index 100% rename from zero.Core/Entities/PreviewModel.cs rename to zero.Core/old/Entities/PreviewModel.cs diff --git a/zero.Core/Entities/PriceRange.cs b/zero.Core/old/Entities/PriceRange.cs similarity index 100% rename from zero.Core/Entities/PriceRange.cs rename to zero.Core/old/Entities/PriceRange.cs diff --git a/zero.Core/Entities/RecycleBin/RecycleBinListQuery.cs b/zero.Core/old/Entities/RecycleBin/RecycleBinListQuery.cs similarity index 100% rename from zero.Core/Entities/RecycleBin/RecycleBinListQuery.cs rename to zero.Core/old/Entities/RecycleBin/RecycleBinListQuery.cs diff --git a/zero.Core/Entities/RecycleBin/RecycledEntity.cs b/zero.Core/old/Entities/RecycleBin/RecycledEntity.cs similarity index 100% rename from zero.Core/Entities/RecycleBin/RecycledEntity.cs rename to zero.Core/old/Entities/RecycleBin/RecycledEntity.cs diff --git a/zero.Core/Entities/Refs/MediaRef.cs b/zero.Core/old/Entities/Refs/MediaRef.cs similarity index 100% rename from zero.Core/Entities/Refs/MediaRef.cs rename to zero.Core/old/Entities/Refs/MediaRef.cs diff --git a/zero.Core/Entities/Refs/Ref.cs b/zero.Core/old/Entities/Refs/Ref.cs similarity index 100% rename from zero.Core/Entities/Refs/Ref.cs rename to zero.Core/old/Entities/Refs/Ref.cs diff --git a/zero.Core/Entities/Refs/ValueRef.cs b/zero.Core/old/Entities/Refs/ValueRef.cs similarity index 100% rename from zero.Core/Entities/Refs/ValueRef.cs rename to zero.Core/old/Entities/Refs/ValueRef.cs diff --git a/zero.Core/Entities/Revision.cs b/zero.Core/old/Entities/Revision.cs similarity index 100% rename from zero.Core/Entities/Revision.cs rename to zero.Core/old/Entities/Revision.cs diff --git a/zero.Core/Entities/SearchResult.cs b/zero.Core/old/Entities/SearchResult.cs similarity index 100% rename from zero.Core/Entities/SearchResult.cs rename to zero.Core/old/Entities/SearchResult.cs diff --git a/zero.Core/Entities/Sections/IChildSection.cs b/zero.Core/old/Entities/Sections/IChildSection.cs similarity index 100% rename from zero.Core/Entities/Sections/IChildSection.cs rename to zero.Core/old/Entities/Sections/IChildSection.cs diff --git a/zero.Core/Entities/Sections/ISection.cs b/zero.Core/old/Entities/Sections/ISection.cs similarity index 100% rename from zero.Core/Entities/Sections/ISection.cs rename to zero.Core/old/Entities/Sections/ISection.cs diff --git a/zero.Core/Entities/Sections/Section.cs b/zero.Core/old/Entities/Sections/Section.cs similarity index 100% rename from zero.Core/Entities/Sections/Section.cs rename to zero.Core/old/Entities/Sections/Section.cs diff --git a/zero.Core/Entities/SelectModel.cs b/zero.Core/old/Entities/SelectModel.cs similarity index 100% rename from zero.Core/Entities/SelectModel.cs rename to zero.Core/old/Entities/SelectModel.cs diff --git a/zero.Core/Entities/Settings/SettingsArea.cs b/zero.Core/old/Entities/Settings/SettingsArea.cs similarity index 100% rename from zero.Core/Entities/Settings/SettingsArea.cs rename to zero.Core/old/Entities/Settings/SettingsArea.cs diff --git a/zero.Core/Entities/Settings/SettingsGroup.cs b/zero.Core/old/Entities/Settings/SettingsGroup.cs similarity index 100% rename from zero.Core/Entities/Settings/SettingsGroup.cs rename to zero.Core/old/Entities/Settings/SettingsGroup.cs diff --git a/zero.Core/Entities/Setup/SetupModel.cs b/zero.Core/old/Entities/Setup/SetupModel.cs similarity index 100% rename from zero.Core/Entities/Setup/SetupModel.cs rename to zero.Core/old/Entities/Setup/SetupModel.cs diff --git a/zero.Core/Entities/Spaces/Space.cs b/zero.Core/old/Entities/Spaces/Space.cs similarity index 100% rename from zero.Core/Entities/Spaces/Space.cs rename to zero.Core/old/Entities/Spaces/Space.cs diff --git a/zero.Core/Entities/Spaces/SpaceContent.cs b/zero.Core/old/Entities/Spaces/SpaceContent.cs similarity index 100% rename from zero.Core/Entities/Spaces/SpaceContent.cs rename to zero.Core/old/Entities/Spaces/SpaceContent.cs diff --git a/zero.Core/Entities/Spaces/SpaceView.cs b/zero.Core/old/Entities/Spaces/SpaceView.cs similarity index 100% rename from zero.Core/Entities/Spaces/SpaceView.cs rename to zero.Core/old/Entities/Spaces/SpaceView.cs diff --git a/zero.Core/Entities/Translation.cs b/zero.Core/old/Entities/Translation.cs similarity index 100% rename from zero.Core/Entities/Translation.cs rename to zero.Core/old/Entities/Translation.cs diff --git a/zero.Core/Entities/Tree/TreeItem.cs b/zero.Core/old/Entities/Tree/TreeItem.cs similarity index 100% rename from zero.Core/Entities/Tree/TreeItem.cs rename to zero.Core/old/Entities/Tree/TreeItem.cs diff --git a/zero.Core/Entities/User/BackofficeUser.cs b/zero.Core/old/Entities/User/BackofficeUser.cs similarity index 100% rename from zero.Core/Entities/User/BackofficeUser.cs rename to zero.Core/old/Entities/User/BackofficeUser.cs diff --git a/zero.Core/Entities/User/BackofficeUserRole.cs b/zero.Core/old/Entities/User/BackofficeUserRole.cs similarity index 100% rename from zero.Core/Entities/User/BackofficeUserRole.cs rename to zero.Core/old/Entities/User/BackofficeUserRole.cs diff --git a/zero.Core/Entities/User/UserClaim.cs b/zero.Core/old/Entities/User/UserClaim.cs similarity index 100% rename from zero.Core/Entities/User/UserClaim.cs rename to zero.Core/old/Entities/User/UserClaim.cs diff --git a/zero.Core/Entities/User/ZeroIdentityRole.cs b/zero.Core/old/Entities/User/ZeroIdentityRole.cs similarity index 100% rename from zero.Core/Entities/User/ZeroIdentityRole.cs rename to zero.Core/old/Entities/User/ZeroIdentityRole.cs diff --git a/zero.Core/Entities/User/ZeroIdentityUser.cs b/zero.Core/old/Entities/User/ZeroIdentityUser.cs similarity index 100% rename from zero.Core/Entities/User/ZeroIdentityUser.cs rename to zero.Core/old/Entities/User/ZeroIdentityUser.cs diff --git a/zero.Core/Entities/Video.cs b/zero.Core/old/Entities/Video.cs similarity index 100% rename from zero.Core/Entities/Video.cs rename to zero.Core/old/Entities/Video.cs diff --git a/zero.Core/Entities/ZeroEntity.cs b/zero.Core/old/Entities/ZeroEntity.cs similarity index 100% rename from zero.Core/Entities/ZeroEntity.cs rename to zero.Core/old/Entities/ZeroEntity.cs diff --git a/zero.Core/Entities/ZeroReference.cs b/zero.Core/old/Entities/ZeroReference.cs similarity index 100% rename from zero.Core/Entities/ZeroReference.cs rename to zero.Core/old/Entities/ZeroReference.cs diff --git a/zero.Core/Extensions/BackofficeUserExtensions.cs b/zero.Core/old/Extensions/BackofficeUserExtensions.cs similarity index 100% rename from zero.Core/Extensions/BackofficeUserExtensions.cs rename to zero.Core/old/Extensions/BackofficeUserExtensions.cs diff --git a/zero.Core/Extensions/CharExtensions.cs b/zero.Core/old/Extensions/CharExtensions.cs similarity index 100% rename from zero.Core/Extensions/CharExtensions.cs rename to zero.Core/old/Extensions/CharExtensions.cs diff --git a/zero.Core/Extensions/CollectionExtensions.cs b/zero.Core/old/Extensions/CollectionExtensions.cs similarity index 100% rename from zero.Core/Extensions/CollectionExtensions.cs rename to zero.Core/old/Extensions/CollectionExtensions.cs diff --git a/zero.Core/Extensions/ColorExtensions.cs b/zero.Core/old/Extensions/ColorExtensions.cs similarity index 100% rename from zero.Core/Extensions/ColorExtensions.cs rename to zero.Core/old/Extensions/ColorExtensions.cs diff --git a/zero.Core/Extensions/DictionaryExtensions.cs b/zero.Core/old/Extensions/DictionaryExtensions.cs similarity index 100% rename from zero.Core/Extensions/DictionaryExtensions.cs rename to zero.Core/old/Extensions/DictionaryExtensions.cs diff --git a/zero.Core/Extensions/EnumerableExtensions.cs b/zero.Core/old/Extensions/EnumerableExtensions.cs similarity index 100% rename from zero.Core/Extensions/EnumerableExtensions.cs rename to zero.Core/old/Extensions/EnumerableExtensions.cs diff --git a/zero.Core/Extensions/ExpressionExtensions.cs b/zero.Core/old/Extensions/ExpressionExtensions.cs similarity index 100% rename from zero.Core/Extensions/ExpressionExtensions.cs rename to zero.Core/old/Extensions/ExpressionExtensions.cs diff --git a/zero.Core/Extensions/HttpContextExtensions.cs b/zero.Core/old/Extensions/HttpContextExtensions.cs similarity index 100% rename from zero.Core/Extensions/HttpContextExtensions.cs rename to zero.Core/old/Extensions/HttpContextExtensions.cs diff --git a/zero.Core/Extensions/LinkTargetExtensions.cs b/zero.Core/old/Extensions/LinkTargetExtensions.cs similarity index 100% rename from zero.Core/Extensions/LinkTargetExtensions.cs rename to zero.Core/old/Extensions/LinkTargetExtensions.cs diff --git a/zero.Core/Extensions/MailExtensions.cs b/zero.Core/old/Extensions/MailExtensions.cs similarity index 100% rename from zero.Core/Extensions/MailExtensions.cs rename to zero.Core/old/Extensions/MailExtensions.cs diff --git a/zero.Core/Extensions/NumberExtensions.cs b/zero.Core/old/Extensions/NumberExtensions.cs similarity index 100% rename from zero.Core/Extensions/NumberExtensions.cs rename to zero.Core/old/Extensions/NumberExtensions.cs diff --git a/zero.Core/Extensions/ObjectExtensions.cs b/zero.Core/old/Extensions/ObjectExtensions.cs similarity index 100% rename from zero.Core/Extensions/ObjectExtensions.cs rename to zero.Core/old/Extensions/ObjectExtensions.cs diff --git a/zero.Core/Extensions/QueryableExtensions.cs b/zero.Core/old/Extensions/QueryableExtensions.cs similarity index 100% rename from zero.Core/Extensions/QueryableExtensions.cs rename to zero.Core/old/Extensions/QueryableExtensions.cs diff --git a/zero.Core/Extensions/RavenQueryableExtensions.cs b/zero.Core/old/Extensions/RavenQueryableExtensions.cs similarity index 100% rename from zero.Core/Extensions/RavenQueryableExtensions.cs rename to zero.Core/old/Extensions/RavenQueryableExtensions.cs diff --git a/zero.Core/Extensions/RouteExtensions.cs b/zero.Core/old/Extensions/RouteExtensions.cs similarity index 100% rename from zero.Core/Extensions/RouteExtensions.cs rename to zero.Core/old/Extensions/RouteExtensions.cs diff --git a/zero.Core/Extensions/ServiceCollectionExtensions.cs b/zero.Core/old/Extensions/ServiceCollectionExtensions.cs similarity index 100% rename from zero.Core/Extensions/ServiceCollectionExtensions.cs rename to zero.Core/old/Extensions/ServiceCollectionExtensions.cs diff --git a/zero.Core/old/Extensions/StringExtensions.cs b/zero.Core/old/Extensions/StringExtensions.cs new file mode 100644 index 00000000..881d1613 --- /dev/null +++ b/zero.Core/old/Extensions/StringExtensions.cs @@ -0,0 +1,188 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; + +namespace zero.Core.Extensions +{ + public static class StringExtensions + { + const string SPACE = " "; + + static Regex replaceMultipleSpacesRegex { get; } = new Regex("[ ]{2,}", RegexOptions.None); + + static Regex newLineCharsRegex { get; } = new Regex("\t|\n|\r", RegexOptions.None); + + + public static string FullTrim(this string value) + { + if (String.IsNullOrEmpty(value)) + { + return value; + } + + return replaceMultipleSpacesRegex.Replace(value, SPACE).Trim(); + } + + + public static string EnsureStartsWith(this string input, string toStartWith) + { + if (input.StartsWith(toStartWith)) return input; + return toStartWith + input.TrimStart(toStartWith); + } + + + public static string EnsureStartsWith(this string input, char value) + { + return input.StartsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : value + input; + } + + + public static string EnsureEndsWith(this string input, char value) + { + return input.EndsWith(value.ToString(CultureInfo.InvariantCulture)) ? input : input + value; + } + + + public static string EnsureEndsWith(this string input, string toEndWith) + { + return input.EndsWith(toEndWith.ToString(CultureInfo.InvariantCulture)) ? input : input + toEndWith; + } + + + public static string EnsureSurroundedWith(this string input, char toSurroundWith) + { + return input.EnsureStartsWith(toSurroundWith).EnsureEndsWith(toSurroundWith); + } + + + public static string Or(this string value, string fallback) + { + return String.IsNullOrWhiteSpace(value) ? fallback : value; + } + + + public static string TrimEnd(this string value, string forRemoving) + { + if (String.IsNullOrEmpty(value)) return value; + if (String.IsNullOrEmpty(forRemoving)) return value; + + while (value.EndsWith(forRemoving, StringComparison.InvariantCultureIgnoreCase)) + { + value = value.Remove(value.LastIndexOf(forRemoving, StringComparison.InvariantCultureIgnoreCase)); + } + return value; + } + + + public static string TrimStart(this string value, string forRemoving) + { + if (String.IsNullOrEmpty(value)) return value; + if (String.IsNullOrEmpty(forRemoving)) return value; + + while (value.StartsWith(forRemoving, StringComparison.InvariantCultureIgnoreCase)) + { + value = value.Substring(forRemoving.Length); + } + return value; + } + + + public static bool HasValue(this string input) + { + return !String.IsNullOrWhiteSpace(input); + } + + + public static bool IsNullOrEmpty(this string input) + { + return String.IsNullOrEmpty(input); + } + + + public static bool IsNullOrWhiteSpace(this string input) + { + return String.IsNullOrWhiteSpace(input); + } + + public static string ToCamelCase(this string input) + { + if (!String.IsNullOrEmpty(input) && input.Length > 1) + { + return Char.ToLowerInvariant(input[0]) + input.Substring(1); + } + return input; + } + + public static string ToPascalCase(this string input) + { + if (!String.IsNullOrEmpty(input) && input.Length > 1) + { + return Char.ToUpperInvariant(input[0]) + input.Substring(1); + } + return input; + } + + public static string ToCamelCaseId(this string input) + { + if (String.IsNullOrEmpty(input)) + { + return input; + } + + if (input.Length < 2) + { + return input.ToLowerInvariant(); + } + + string[] parts = input.Split('.'); + + return String.Join(".", parts.Select(x => x.ToCamelCase())); + } + + + public static string ToPascalCaseId(this string input) + { + if (String.IsNullOrEmpty(input)) + { + return input; + } + + if (input.Length < 2) + { + return input.ToUpperInvariant(); + } + + string[] parts = input.Split('.'); + + return String.Join(".", parts.Select(x => x.ToPascalCase())); + } + + + public static string RemoveNewLines(this string input) + { + if (String.IsNullOrEmpty(input)) + { + return input; + } + + return newLineCharsRegex.Replace(input, String.Empty).Trim(); + } + + + public static string Shorten(this string input, int maxLength) + { + if (maxLength < 4) + { + throw new ArgumentOutOfRangeException("maxLength", "Has to be at least 4 characters long"); + } + + if (String.IsNullOrEmpty(input) || input.Length <= maxLength) + { + return input; + } + + return input.Substring(0, maxLength - 3) + "..."; + } + } +} diff --git a/zero.Core/Extensions/ValidatorExtensions.cs b/zero.Core/old/Extensions/ValidatorExtensions.cs similarity index 100% rename from zero.Core/Extensions/ValidatorExtensions.cs rename to zero.Core/old/Extensions/ValidatorExtensions.cs diff --git a/zero.Core/Extensions/ZeroIndexExtensions.cs b/zero.Core/old/Extensions/ZeroIndexExtensions.cs similarity index 100% rename from zero.Core/Extensions/ZeroIndexExtensions.cs rename to zero.Core/old/Extensions/ZeroIndexExtensions.cs diff --git a/zero.Core/Handlers/IApplicationResolverHandler.cs b/zero.Core/old/Handlers/IApplicationResolverHandler.cs similarity index 100% rename from zero.Core/Handlers/IApplicationResolverHandler.cs rename to zero.Core/old/Handlers/IApplicationResolverHandler.cs diff --git a/zero.Core/Handlers/IHandler.cs b/zero.Core/old/Handlers/IHandler.cs similarity index 100% rename from zero.Core/Handlers/IHandler.cs rename to zero.Core/old/Handlers/IHandler.cs diff --git a/zero.Core/Handlers/IHandlerHolder.cs b/zero.Core/old/Handlers/IHandlerHolder.cs similarity index 100% rename from zero.Core/Handlers/IHandlerHolder.cs rename to zero.Core/old/Handlers/IHandlerHolder.cs diff --git a/zero.Core/Handlers/IModuleTypeHandler.cs b/zero.Core/old/Handlers/IModuleTypeHandler.cs similarity index 100% rename from zero.Core/Handlers/IModuleTypeHandler.cs rename to zero.Core/old/Handlers/IModuleTypeHandler.cs diff --git a/zero.Core/Handlers/IPageTypeHandler.cs b/zero.Core/old/Handlers/IPageTypeHandler.cs similarity index 100% rename from zero.Core/Handlers/IPageTypeHandler.cs rename to zero.Core/old/Handlers/IPageTypeHandler.cs diff --git a/zero.Core/Identity/Base32.cs b/zero.Core/old/Identity/Base32.cs similarity index 100% rename from zero.Core/Identity/Base32.cs rename to zero.Core/old/Identity/Base32.cs diff --git a/zero.Core/Identity/Permissions/EntityPermission.cs b/zero.Core/old/Identity/Permissions/EntityPermission.cs similarity index 100% rename from zero.Core/Identity/Permissions/EntityPermission.cs rename to zero.Core/old/Identity/Permissions/EntityPermission.cs diff --git a/zero.Core/Identity/Permissions/Permission.cs b/zero.Core/old/Identity/Permissions/Permission.cs similarity index 100% rename from zero.Core/Identity/Permissions/Permission.cs rename to zero.Core/old/Identity/Permissions/Permission.cs diff --git a/zero.Core/Identity/Permissions/PermissionCollection.cs b/zero.Core/old/Identity/Permissions/PermissionCollection.cs similarity index 100% rename from zero.Core/Identity/Permissions/PermissionCollection.cs rename to zero.Core/old/Identity/Permissions/PermissionCollection.cs diff --git a/zero.Core/Identity/Permissions/PermissionGroupCollection.cs b/zero.Core/old/Identity/Permissions/PermissionGroupCollection.cs similarity index 100% rename from zero.Core/Identity/Permissions/PermissionGroupCollection.cs rename to zero.Core/old/Identity/Permissions/PermissionGroupCollection.cs diff --git a/zero.Core/Identity/Permissions/PermissionValueType.cs b/zero.Core/old/Identity/Permissions/PermissionValueType.cs similarity index 100% rename from zero.Core/Identity/Permissions/PermissionValueType.cs rename to zero.Core/old/Identity/Permissions/PermissionValueType.cs diff --git a/zero.Core/Identity/Permissions/Permissions.cs b/zero.Core/old/Identity/Permissions/Permissions.cs similarity index 100% rename from zero.Core/Identity/Permissions/Permissions.cs rename to zero.Core/old/Identity/Permissions/Permissions.cs diff --git a/zero.Core/Identity/RavenRoleStore(TRole).cs b/zero.Core/old/Identity/RavenRoleStore(TRole).cs similarity index 100% rename from zero.Core/Identity/RavenRoleStore(TRole).cs rename to zero.Core/old/Identity/RavenRoleStore(TRole).cs diff --git a/zero.Core/Identity/RavenScopedStores.cs b/zero.Core/old/Identity/RavenScopedStores.cs similarity index 100% rename from zero.Core/Identity/RavenScopedStores.cs rename to zero.Core/old/Identity/RavenScopedStores.cs diff --git a/zero.Core/Identity/RavenUserStore(TUser).cs b/zero.Core/old/Identity/RavenUserStore(TUser).cs similarity index 100% rename from zero.Core/Identity/RavenUserStore(TUser).cs rename to zero.Core/old/Identity/RavenUserStore(TUser).cs diff --git a/zero.Core/Identity/RavenUserStore(TUser,TRole).cs b/zero.Core/old/Identity/RavenUserStore(TUser,TRole).cs similarity index 100% rename from zero.Core/Identity/RavenUserStore(TUser,TRole).cs rename to zero.Core/old/Identity/RavenUserStore(TUser,TRole).cs diff --git a/zero.Core/Identity/UserIdentity.cs b/zero.Core/old/Identity/UserIdentity.cs similarity index 100% rename from zero.Core/Identity/UserIdentity.cs rename to zero.Core/old/Identity/UserIdentity.cs diff --git a/zero.Core/Identity/ZeroIdentityExtensions.cs b/zero.Core/old/Identity/ZeroIdentityExtensions.cs similarity index 100% rename from zero.Core/Identity/ZeroIdentityExtensions.cs rename to zero.Core/old/Identity/ZeroIdentityExtensions.cs diff --git a/zero.Core/Integrations/Integration.cs b/zero.Core/old/Integrations/Integration.cs similarity index 100% rename from zero.Core/Integrations/Integration.cs rename to zero.Core/old/Integrations/Integration.cs diff --git a/zero.Core/Integrations/IntegrationService.cs b/zero.Core/old/Integrations/IntegrationService.cs similarity index 93% rename from zero.Core/Integrations/IntegrationService.cs rename to zero.Core/old/Integrations/IntegrationService.cs index ebae4feb..a6c00f78 100644 --- a/zero.Core/Integrations/IntegrationService.cs +++ b/zero.Core/old/Integrations/IntegrationService.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Logging; +using zero.Core.Collections; namespace zero.Core.Integrations { diff --git a/zero.Core/Integrations/IntegrationType.cs b/zero.Core/old/Integrations/IntegrationType.cs similarity index 100% rename from zero.Core/Integrations/IntegrationType.cs rename to zero.Core/old/Integrations/IntegrationType.cs diff --git a/zero.Core/Integrations/IntegrationTypeWithStatus.cs b/zero.Core/old/Integrations/IntegrationTypeWithStatus.cs similarity index 100% rename from zero.Core/Integrations/IntegrationTypeWithStatus.cs rename to zero.Core/old/Integrations/IntegrationTypeWithStatus.cs diff --git a/zero.Core/Mails/FileMailDispatcher.cs b/zero.Core/old/Mails/FileMailDispatcher.cs similarity index 100% rename from zero.Core/Mails/FileMailDispatcher.cs rename to zero.Core/old/Mails/FileMailDispatcher.cs diff --git a/zero.Core/Mails/IMailDispatcher.cs b/zero.Core/old/Mails/IMailDispatcher.cs similarity index 100% rename from zero.Core/Mails/IMailDispatcher.cs rename to zero.Core/old/Mails/IMailDispatcher.cs diff --git a/zero.Core/Mails/LoggerMailDispatcher.cs b/zero.Core/old/Mails/LoggerMailDispatcher.cs similarity index 100% rename from zero.Core/Mails/LoggerMailDispatcher.cs rename to zero.Core/old/Mails/LoggerMailDispatcher.cs diff --git a/zero.Core/Mails/Mail.cs b/zero.Core/old/Mails/Mail.cs similarity index 100% rename from zero.Core/Mails/Mail.cs rename to zero.Core/old/Mails/Mail.cs diff --git a/zero.Core/Mails/MailMetadata.cs b/zero.Core/old/Mails/MailMetadata.cs similarity index 100% rename from zero.Core/Mails/MailMetadata.cs rename to zero.Core/old/Mails/MailMetadata.cs diff --git a/zero.Core/Mails/MailPlaceholders.cs b/zero.Core/old/Mails/MailPlaceholders.cs similarity index 100% rename from zero.Core/Mails/MailPlaceholders.cs rename to zero.Core/old/Mails/MailPlaceholders.cs diff --git a/zero.Core/Mails/MailProvider.cs b/zero.Core/old/Mails/MailProvider.cs similarity index 100% rename from zero.Core/Mails/MailProvider.cs rename to zero.Core/old/Mails/MailProvider.cs diff --git a/zero.Core/Mails/MailSendResult.cs b/zero.Core/old/Mails/MailSendResult.cs similarity index 100% rename from zero.Core/Mails/MailSendResult.cs rename to zero.Core/old/Mails/MailSendResult.cs diff --git a/zero.Core/Mapper/Mappable.cs b/zero.Core/old/Mapper/Mappable.cs similarity index 100% rename from zero.Core/Mapper/Mappable.cs rename to zero.Core/old/Mapper/Mappable.cs diff --git a/zero.Core/Messages/IMessage.cs b/zero.Core/old/Messages/IMessage.cs similarity index 100% rename from zero.Core/Messages/IMessage.cs rename to zero.Core/old/Messages/IMessage.cs diff --git a/zero.Core/Messages/IMessageHandler.cs b/zero.Core/old/Messages/IMessageHandler.cs similarity index 100% rename from zero.Core/Messages/IMessageHandler.cs rename to zero.Core/old/Messages/IMessageHandler.cs diff --git a/zero.Core/Messages/MessageAggregator.cs b/zero.Core/old/Messages/MessageAggregator.cs similarity index 100% rename from zero.Core/Messages/MessageAggregator.cs rename to zero.Core/old/Messages/MessageAggregator.cs diff --git a/zero.Core/Messages/MessageSubscription.cs b/zero.Core/old/Messages/MessageSubscription.cs similarity index 100% rename from zero.Core/Messages/MessageSubscription.cs rename to zero.Core/old/Messages/MessageSubscription.cs diff --git a/zero.Core/Options/ApplicationOptions.cs b/zero.Core/old/Options/ApplicationOptions.cs similarity index 100% rename from zero.Core/Options/ApplicationOptions.cs rename to zero.Core/old/Options/ApplicationOptions.cs diff --git a/zero.Core/Options/BackofficeJsonSerlializerSettings.cs b/zero.Core/old/Options/BackofficeJsonSerlializerSettings.cs similarity index 100% rename from zero.Core/Options/BackofficeJsonSerlializerSettings.cs rename to zero.Core/old/Options/BackofficeJsonSerlializerSettings.cs diff --git a/zero.Core/Options/BlueprintOptions.cs b/zero.Core/old/Options/BlueprintOptions.cs similarity index 100% rename from zero.Core/Options/BlueprintOptions.cs rename to zero.Core/old/Options/BlueprintOptions.cs diff --git a/zero.Core/Options/FeatureOptions.cs b/zero.Core/old/Options/FeatureOptions.cs similarity index 100% rename from zero.Core/Options/FeatureOptions.cs rename to zero.Core/old/Options/FeatureOptions.cs diff --git a/zero.Core/old/Options/IZeroCollectionOptions.cs b/zero.Core/old/Options/IZeroCollectionOptions.cs new file mode 100644 index 00000000..e4ecc6c5 --- /dev/null +++ b/zero.Core/old/Options/IZeroCollectionOptions.cs @@ -0,0 +1,7 @@ +namespace zero.Core.Options +{ + public interface IZeroCollectionOptions + { + + } +} diff --git a/zero.Core/Options/IconOptions.cs b/zero.Core/old/Options/IconOptions.cs similarity index 100% rename from zero.Core/Options/IconOptions.cs rename to zero.Core/old/Options/IconOptions.cs diff --git a/zero.Core/Options/IntegrationOptions.cs b/zero.Core/old/Options/IntegrationOptions.cs similarity index 100% rename from zero.Core/Options/IntegrationOptions.cs rename to zero.Core/old/Options/IntegrationOptions.cs diff --git a/zero.Core/Options/InterceptorOptions.cs b/zero.Core/old/Options/InterceptorOptions.cs similarity index 100% rename from zero.Core/Options/InterceptorOptions.cs rename to zero.Core/old/Options/InterceptorOptions.cs diff --git a/zero.Core/Options/ModuleOptions.cs b/zero.Core/old/Options/ModuleOptions.cs similarity index 100% rename from zero.Core/Options/ModuleOptions.cs rename to zero.Core/old/Options/ModuleOptions.cs diff --git a/zero.Core/Options/OptionsType.cs b/zero.Core/old/Options/OptionsType.cs similarity index 100% rename from zero.Core/Options/OptionsType.cs rename to zero.Core/old/Options/OptionsType.cs diff --git a/zero.Core/Options/PageOptions.cs b/zero.Core/old/Options/PageOptions.cs similarity index 100% rename from zero.Core/Options/PageOptions.cs rename to zero.Core/old/Options/PageOptions.cs diff --git a/zero.Core/Options/PermissionOptions.cs b/zero.Core/old/Options/PermissionOptions.cs similarity index 100% rename from zero.Core/Options/PermissionOptions.cs rename to zero.Core/old/Options/PermissionOptions.cs diff --git a/zero.Core/Options/RavenOptions.cs b/zero.Core/old/Options/RavenOptions.cs similarity index 100% rename from zero.Core/Options/RavenOptions.cs rename to zero.Core/old/Options/RavenOptions.cs diff --git a/zero.Core/Options/RoleOptions.cs b/zero.Core/old/Options/RoleOptions.cs similarity index 100% rename from zero.Core/Options/RoleOptions.cs rename to zero.Core/old/Options/RoleOptions.cs diff --git a/zero.Core/Options/RoutingEndpointOptions.cs b/zero.Core/old/Options/RoutingEndpointOptions.cs similarity index 100% rename from zero.Core/Options/RoutingEndpointOptions.cs rename to zero.Core/old/Options/RoutingEndpointOptions.cs diff --git a/zero.Core/Options/RoutingOptions.cs b/zero.Core/old/Options/RoutingOptions.cs similarity index 100% rename from zero.Core/Options/RoutingOptions.cs rename to zero.Core/old/Options/RoutingOptions.cs diff --git a/zero.Core/Options/RoutingPageResolverOptions.cs b/zero.Core/old/Options/RoutingPageResolverOptions.cs similarity index 100% rename from zero.Core/Options/RoutingPageResolverOptions.cs rename to zero.Core/old/Options/RoutingPageResolverOptions.cs diff --git a/zero.Core/Options/SearchOptions.cs b/zero.Core/old/Options/SearchOptions.cs similarity index 100% rename from zero.Core/Options/SearchOptions.cs rename to zero.Core/old/Options/SearchOptions.cs diff --git a/zero.Core/Options/SectionOptions.cs b/zero.Core/old/Options/SectionOptions.cs similarity index 100% rename from zero.Core/Options/SectionOptions.cs rename to zero.Core/old/Options/SectionOptions.cs diff --git a/zero.Core/Options/ServiceOptions.cs b/zero.Core/old/Options/ServiceOptions.cs similarity index 100% rename from zero.Core/Options/ServiceOptions.cs rename to zero.Core/old/Options/ServiceOptions.cs diff --git a/zero.Core/Options/SettingsOptions.cs b/zero.Core/old/Options/SettingsOptions.cs similarity index 100% rename from zero.Core/Options/SettingsOptions.cs rename to zero.Core/old/Options/SettingsOptions.cs diff --git a/zero.Core/Options/SpaceOptions.cs b/zero.Core/old/Options/SpaceOptions.cs similarity index 100% rename from zero.Core/Options/SpaceOptions.cs rename to zero.Core/old/Options/SpaceOptions.cs diff --git a/zero.Core/Options/ZeroBackofficeCollection.cs b/zero.Core/old/Options/ZeroBackofficeCollection.cs similarity index 100% rename from zero.Core/Options/ZeroBackofficeCollection.cs rename to zero.Core/old/Options/ZeroBackofficeCollection.cs diff --git a/zero.Core/Options/ZeroOptions.cs b/zero.Core/old/Options/ZeroOptions.cs similarity index 100% rename from zero.Core/Options/ZeroOptions.cs rename to zero.Core/old/Options/ZeroOptions.cs diff --git a/zero.Core/Options/ZeroStartupOptions.cs b/zero.Core/old/Options/ZeroStartupOptions.cs similarity index 100% rename from zero.Core/Options/ZeroStartupOptions.cs rename to zero.Core/old/Options/ZeroStartupOptions.cs diff --git a/zero.Core/Paths.cs b/zero.Core/old/Paths.cs similarity index 100% rename from zero.Core/Paths.cs rename to zero.Core/old/Paths.cs diff --git a/zero.Core/Plugins/IZeroBuiltInPlugin.cs b/zero.Core/old/Plugins/IZeroBuiltInPlugin.cs similarity index 100% rename from zero.Core/Plugins/IZeroBuiltInPlugin.cs rename to zero.Core/old/Plugins/IZeroBuiltInPlugin.cs diff --git a/zero.Core/Plugins/IZeroPlugin.cs b/zero.Core/old/Plugins/IZeroPlugin.cs similarity index 100% rename from zero.Core/Plugins/IZeroPlugin.cs rename to zero.Core/old/Plugins/IZeroPlugin.cs diff --git a/zero.Core/Plugins/ZeroPluginOptions.cs b/zero.Core/old/Plugins/ZeroPluginOptions.cs similarity index 100% rename from zero.Core/Plugins/ZeroPluginOptions.cs rename to zero.Core/old/Plugins/ZeroPluginOptions.cs diff --git a/zero.Core/Renderer/RazorRenderer.cs b/zero.Core/old/Renderer/RazorRenderer.cs similarity index 100% rename from zero.Core/Renderer/RazorRenderer.cs rename to zero.Core/old/Renderer/RazorRenderer.cs diff --git a/zero.Core/Renderer/TokenReplacement.cs b/zero.Core/old/Renderer/TokenReplacement.cs similarity index 100% rename from zero.Core/Renderer/TokenReplacement.cs rename to zero.Core/old/Renderer/TokenReplacement.cs diff --git a/zero.Core/Routing/Entities/IRouteModel.cs b/zero.Core/old/Routing/Entities/IRouteModel.cs similarity index 100% rename from zero.Core/Routing/Entities/IRouteModel.cs rename to zero.Core/old/Routing/Entities/IRouteModel.cs diff --git a/zero.Core/Routing/Entities/Route.cs b/zero.Core/old/Routing/Entities/Route.cs similarity index 100% rename from zero.Core/Routing/Entities/Route.cs rename to zero.Core/old/Routing/Entities/Route.cs diff --git a/zero.Core/Routing/Entities/RouteEndpoint.cs b/zero.Core/old/Routing/Entities/RouteEndpoint.cs similarity index 100% rename from zero.Core/Routing/Entities/RouteEndpoint.cs rename to zero.Core/old/Routing/Entities/RouteEndpoint.cs diff --git a/zero.Core/Routing/Entities/RouteRedirect.cs b/zero.Core/old/Routing/Entities/RouteRedirect.cs similarity index 100% rename from zero.Core/Routing/Entities/RouteRedirect.cs rename to zero.Core/old/Routing/Entities/RouteRedirect.cs diff --git a/zero.Core/Routing/Entities/RouteResponse.cs b/zero.Core/old/Routing/Entities/RouteResponse.cs similarity index 100% rename from zero.Core/Routing/Entities/RouteResponse.cs rename to zero.Core/old/Routing/Entities/RouteResponse.cs diff --git a/zero.Core/Routing/Entities/RoutingContext.cs b/zero.Core/old/Routing/Entities/RoutingContext.cs similarity index 100% rename from zero.Core/Routing/Entities/RoutingContext.cs rename to zero.Core/old/Routing/Entities/RoutingContext.cs diff --git a/zero.Core/Routing/Links/ILinkProvider.cs b/zero.Core/old/Routing/Links/ILinkProvider.cs similarity index 100% rename from zero.Core/Routing/Links/ILinkProvider.cs rename to zero.Core/old/Routing/Links/ILinkProvider.cs diff --git a/zero.Core/Routing/Links/Links.cs b/zero.Core/old/Routing/Links/Links.cs similarity index 100% rename from zero.Core/Routing/Links/Links.cs rename to zero.Core/old/Routing/Links/Links.cs diff --git a/zero.Core/Routing/Links/RawLinkProvider.cs b/zero.Core/old/Routing/Links/RawLinkProvider.cs similarity index 100% rename from zero.Core/Routing/Links/RawLinkProvider.cs rename to zero.Core/old/Routing/Links/RawLinkProvider.cs diff --git a/zero.Core/Routing/Links/RequestUrlResolver.cs b/zero.Core/old/Routing/Links/RequestUrlResolver.cs similarity index 100% rename from zero.Core/Routing/Links/RequestUrlResolver.cs rename to zero.Core/old/Routing/Links/RequestUrlResolver.cs diff --git a/zero.Core/Routing/NotFoundMatcherPolicy.cs b/zero.Core/old/Routing/NotFoundMatcherPolicy.cs similarity index 100% rename from zero.Core/Routing/NotFoundMatcherPolicy.cs rename to zero.Core/old/Routing/NotFoundMatcherPolicy.cs diff --git a/zero.Core/Routing/Page/BasePageRoute.cs b/zero.Core/old/Routing/Page/BasePageRoute.cs similarity index 100% rename from zero.Core/Routing/Page/BasePageRoute.cs rename to zero.Core/old/Routing/Page/BasePageRoute.cs diff --git a/zero.Core/Routing/Page/PageLinkProvider.cs b/zero.Core/old/Routing/Page/PageLinkProvider.cs similarity index 100% rename from zero.Core/Routing/Page/PageLinkProvider.cs rename to zero.Core/old/Routing/Page/PageLinkProvider.cs diff --git a/zero.Core/Routing/Page/PageRoute.cs b/zero.Core/old/Routing/Page/PageRoute.cs similarity index 100% rename from zero.Core/Routing/Page/PageRoute.cs rename to zero.Core/old/Routing/Page/PageRoute.cs diff --git a/zero.Core/Routing/Page/PageRouteIdBuilder.cs b/zero.Core/old/Routing/Page/PageRouteIdBuilder.cs similarity index 100% rename from zero.Core/Routing/Page/PageRouteIdBuilder.cs rename to zero.Core/old/Routing/Page/PageRouteIdBuilder.cs diff --git a/zero.Core/Routing/Page/PageRouteProvider.cs b/zero.Core/old/Routing/Page/PageRouteProvider.cs similarity index 100% rename from zero.Core/Routing/Page/PageRouteProvider.cs rename to zero.Core/old/Routing/Page/PageRouteProvider.cs diff --git a/zero.Core/Routing/Page/PageRouteResolverHelper.cs b/zero.Core/old/Routing/Page/PageRouteResolverHelper.cs similarity index 100% rename from zero.Core/Routing/Page/PageRouteResolverHelper.cs rename to zero.Core/old/Routing/Page/PageRouteResolverHelper.cs diff --git a/zero.Core/Routing/Page/PageUrlBuilder.cs b/zero.Core/old/Routing/Page/PageUrlBuilder.cs similarity index 100% rename from zero.Core/Routing/Page/PageUrlBuilder.cs rename to zero.Core/old/Routing/Page/PageUrlBuilder.cs diff --git a/zero.Core/Routing/RedirectAutomation.cs b/zero.Core/old/Routing/RedirectAutomation.cs similarity index 100% rename from zero.Core/Routing/RedirectAutomation.cs rename to zero.Core/old/Routing/RedirectAutomation.cs diff --git a/zero.Core/Routing/RouteBulkRefresher.cs b/zero.Core/old/Routing/RouteBulkRefresher.cs similarity index 100% rename from zero.Core/Routing/RouteBulkRefresher.cs rename to zero.Core/old/Routing/RouteBulkRefresher.cs diff --git a/zero.Core/Routing/RouteRedirectCollection.cs b/zero.Core/old/Routing/RouteRedirectCollection.cs similarity index 100% rename from zero.Core/Routing/RouteRedirectCollection.cs rename to zero.Core/old/Routing/RouteRedirectCollection.cs diff --git a/zero.Core/Routing/RouteResolver.cs b/zero.Core/old/Routing/RouteResolver.cs similarity index 100% rename from zero.Core/Routing/RouteResolver.cs rename to zero.Core/old/Routing/RouteResolver.cs diff --git a/zero.Core/Routing/Routes.cs b/zero.Core/old/Routing/Routes.cs similarity index 100% rename from zero.Core/Routing/Routes.cs rename to zero.Core/old/Routing/Routes.cs diff --git a/zero.Core/Routing/ZeroEntityRouteInterceptor.cs b/zero.Core/old/Routing/ZeroEntityRouteInterceptor.cs similarity index 100% rename from zero.Core/Routing/ZeroEntityRouteInterceptor.cs rename to zero.Core/old/Routing/ZeroEntityRouteInterceptor.cs diff --git a/zero.Core/Routing/ZeroRouteProvider.cs b/zero.Core/old/Routing/ZeroRouteProvider.cs similarity index 100% rename from zero.Core/Routing/ZeroRouteProvider.cs rename to zero.Core/old/Routing/ZeroRouteProvider.cs diff --git a/zero.Core/Routing/ZeroRoutesTransformer.cs b/zero.Core/old/Routing/ZeroRoutesTransformer.cs similarity index 100% rename from zero.Core/Routing/ZeroRoutesTransformer.cs rename to zero.Core/old/Routing/ZeroRoutesTransformer.cs diff --git a/zero.Core/Security/ContextualCookieManager.cs b/zero.Core/old/Security/ContextualCookieManager.cs similarity index 100% rename from zero.Core/Security/ContextualCookieManager.cs rename to zero.Core/old/Security/ContextualCookieManager.cs diff --git a/zero.Core/Security/SchemedSignInManager.cs b/zero.Core/old/Security/SchemedSignInManager.cs similarity index 100% rename from zero.Core/Security/SchemedSignInManager.cs rename to zero.Core/old/Security/SchemedSignInManager.cs diff --git a/zero.Core/Security/ZeroAuthOptions.cs b/zero.Core/old/Security/ZeroAuthOptions.cs similarity index 100% rename from zero.Core/Security/ZeroAuthOptions.cs rename to zero.Core/old/Security/ZeroAuthOptions.cs diff --git a/zero.Core/Security/ZeroAuthorizeAttribute.cs b/zero.Core/old/Security/ZeroAuthorizeAttribute.cs similarity index 100% rename from zero.Core/Security/ZeroAuthorizeAttribute.cs rename to zero.Core/old/Security/ZeroAuthorizeAttribute.cs diff --git a/zero.Core/Security/ZeroBackofficeClaimsPrincipalFactory.cs b/zero.Core/old/Security/ZeroBackofficeClaimsPrincipalFactory.cs similarity index 100% rename from zero.Core/Security/ZeroBackofficeClaimsPrincipalFactory.cs rename to zero.Core/old/Security/ZeroBackofficeClaimsPrincipalFactory.cs diff --git a/zero.Core/Security/ZeroClaimsPrinicipalFactory.cs b/zero.Core/old/Security/ZeroClaimsPrinicipalFactory.cs similarity index 100% rename from zero.Core/Security/ZeroClaimsPrinicipalFactory.cs rename to zero.Core/old/Security/ZeroClaimsPrinicipalFactory.cs diff --git a/zero.Core/Services/BackofficeSearchService.cs b/zero.Core/old/Services/BackofficeSearchService.cs similarity index 100% rename from zero.Core/Services/BackofficeSearchService.cs rename to zero.Core/old/Services/BackofficeSearchService.cs diff --git a/zero.Core/Services/GuidCreator.cs b/zero.Core/old/Services/GuidCreator.cs similarity index 100% rename from zero.Core/Services/GuidCreator.cs rename to zero.Core/old/Services/GuidCreator.cs diff --git a/zero.Core/Services/Localizer.cs b/zero.Core/old/Services/Localizer.cs similarity index 100% rename from zero.Core/Services/Localizer.cs rename to zero.Core/old/Services/Localizer.cs diff --git a/zero.Core/Utils/IdGenerator.cs b/zero.Core/old/Utils/IdGenerator.cs similarity index 100% rename from zero.Core/Utils/IdGenerator.cs rename to zero.Core/old/Utils/IdGenerator.cs diff --git a/zero.Core/Utils/ObjectCloner.cs b/zero.Core/old/Utils/ObjectCloner.cs similarity index 100% rename from zero.Core/Utils/ObjectCloner.cs rename to zero.Core/old/Utils/ObjectCloner.cs diff --git a/zero.Core/Utils/ObjectTraverser.cs b/zero.Core/old/Utils/ObjectTraverser.cs similarity index 100% rename from zero.Core/Utils/ObjectTraverser.cs rename to zero.Core/old/Utils/ObjectTraverser.cs diff --git a/zero.Core/Utils/PrimitiveTypeCollection.cs b/zero.Core/old/Utils/PrimitiveTypeCollection.cs similarity index 100% rename from zero.Core/Utils/PrimitiveTypeCollection.cs rename to zero.Core/old/Utils/PrimitiveTypeCollection.cs diff --git a/zero.Core/Utils/RefJsonConverter.cs b/zero.Core/old/Utils/RefJsonConverter.cs similarity index 100% rename from zero.Core/Utils/RefJsonConverter.cs rename to zero.Core/old/Utils/RefJsonConverter.cs diff --git a/zero.Core/Utils/TableBuilder/CsvCreator.cs b/zero.Core/old/Utils/TableBuilder/CsvCreator.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/CsvCreator.cs rename to zero.Core/old/Utils/TableBuilder/CsvCreator.cs diff --git a/zero.Core/Utils/TableBuilder/ExcelCreator.cs b/zero.Core/old/Utils/TableBuilder/ExcelCreator.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/ExcelCreator.cs rename to zero.Core/old/Utils/TableBuilder/ExcelCreator.cs diff --git a/zero.Core/Utils/TableBuilder/ITableCreator.cs b/zero.Core/old/Utils/TableBuilder/ITableCreator.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/ITableCreator.cs rename to zero.Core/old/Utils/TableBuilder/ITableCreator.cs diff --git a/zero.Core/Utils/TableBuilder/TableBuilder.cs b/zero.Core/old/Utils/TableBuilder/TableBuilder.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/TableBuilder.cs rename to zero.Core/old/Utils/TableBuilder/TableBuilder.cs diff --git a/zero.Core/Utils/TableBuilder/TableColumn.cs b/zero.Core/old/Utils/TableBuilder/TableColumn.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/TableColumn.cs rename to zero.Core/old/Utils/TableBuilder/TableColumn.cs diff --git a/zero.Core/Utils/TableBuilder/TableExport.cs b/zero.Core/old/Utils/TableBuilder/TableExport.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/TableExport.cs rename to zero.Core/old/Utils/TableBuilder/TableExport.cs diff --git a/zero.Core/Utils/TableBuilder/TableFormat.cs b/zero.Core/old/Utils/TableBuilder/TableFormat.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/TableFormat.cs rename to zero.Core/old/Utils/TableBuilder/TableFormat.cs diff --git a/zero.Core/Utils/TableBuilder/TableResult.cs b/zero.Core/old/Utils/TableBuilder/TableResult.cs similarity index 100% rename from zero.Core/Utils/TableBuilder/TableResult.cs rename to zero.Core/old/Utils/TableBuilder/TableResult.cs diff --git a/zero.Core/Utils/ZeroEntityJsonConverter.cs b/zero.Core/old/Utils/ZeroEntityJsonConverter.cs similarity index 100% rename from zero.Core/Utils/ZeroEntityJsonConverter.cs rename to zero.Core/old/Utils/ZeroEntityJsonConverter.cs diff --git a/zero.Core/Utils/ZeroInterfaceBinder.cs b/zero.Core/old/Utils/ZeroInterfaceBinder.cs similarity index 100% rename from zero.Core/Utils/ZeroInterfaceBinder.cs rename to zero.Core/old/Utils/ZeroInterfaceBinder.cs diff --git a/zero.Core/Utils/ZeroJsonContractResolver.cs b/zero.Core/old/Utils/ZeroJsonContractResolver.cs similarity index 100% rename from zero.Core/Utils/ZeroJsonContractResolver.cs rename to zero.Core/old/Utils/ZeroJsonContractResolver.cs diff --git a/zero.Core/Validation/ApplicationValidator.cs b/zero.Core/old/Validation/ApplicationValidator.cs similarity index 100% rename from zero.Core/Validation/ApplicationValidator.cs rename to zero.Core/old/Validation/ApplicationValidator.cs diff --git a/zero.Core/Validation/BackofficeUserValidator.cs b/zero.Core/old/Validation/BackofficeUserValidator.cs similarity index 100% rename from zero.Core/Validation/BackofficeUserValidator.cs rename to zero.Core/old/Validation/BackofficeUserValidator.cs diff --git a/zero.Core/Validation/PageValidator.cs b/zero.Core/old/Validation/PageValidator.cs similarity index 100% rename from zero.Core/Validation/PageValidator.cs rename to zero.Core/old/Validation/PageValidator.cs diff --git a/zero.Core/Validation/SetupModelValidator.cs b/zero.Core/old/Validation/SetupModelValidator.cs similarity index 100% rename from zero.Core/Validation/SetupModelValidator.cs rename to zero.Core/old/Validation/SetupModelValidator.cs diff --git a/zero.Core/Validation/UserRoleValidator.cs b/zero.Core/old/Validation/UserRoleValidator.cs similarity index 100% rename from zero.Core/Validation/UserRoleValidator.cs rename to zero.Core/old/Validation/UserRoleValidator.cs diff --git a/zero.Core/Validation/ValidatorCamelCasePropertyResolver.cs b/zero.Core/old/Validation/ValidatorCamelCasePropertyResolver.cs similarity index 100% rename from zero.Core/Validation/ValidatorCamelCasePropertyResolver.cs rename to zero.Core/old/Validation/ValidatorCamelCasePropertyResolver.cs diff --git a/zero.Core/Validation/ZeroValidator.cs b/zero.Core/old/Validation/ZeroValidator.cs similarity index 100% rename from zero.Core/Validation/ZeroValidator.cs rename to zero.Core/old/Validation/ZeroValidator.cs diff --git a/zero.Core/ZeroContext.cs b/zero.Core/old/ZeroContext.cs similarity index 100% rename from zero.Core/ZeroContext.cs rename to zero.Core/old/ZeroContext.cs diff --git a/zero.Core/zero.Core.csproj b/zero.Core/zero.Core.csproj index 06623581..74634b9c 100644 --- a/zero.Core/zero.Core.csproj +++ b/zero.Core/zero.Core.csproj @@ -9,13 +9,13 @@ - + - + - + diff --git a/zero.Web.UI/app/core/editor-blueprint.ts b/zero.Web.UI/app/core/editor-blueprint.ts index ee204095..5d7c2d58 100644 --- a/zero.Web.UI/app/core/editor-blueprint.ts +++ b/zero.Web.UI/app/core/editor-blueprint.ts @@ -81,8 +81,9 @@ function unlock(config, model, field) export function createBlueprintConfig(zero, editor, model) { let blueprintAlias = editor.blueprintAlias; + let config = zero.config.blueprints.find(x => x.alias == blueprintAlias); - if (!blueprintAlias) + if (!blueprintAlias || !config) { return { alias: blueprintAlias, @@ -96,7 +97,7 @@ export function createBlueprintConfig(zero, editor, model) }; } - let config = zero.config.blueprints.find(x => x.alias == blueprintAlias); + // check for blueprint availability //config.isParent = this.value && this.$route.query.scope === 'shared'; diff --git a/zero.Web/Controllers/ApplicationsController.cs b/zero.Web/old/Controllers/ApplicationsController.cs similarity index 100% rename from zero.Web/Controllers/ApplicationsController.cs rename to zero.Web/old/Controllers/ApplicationsController.cs diff --git a/zero.Web/Controllers/AuthenticationController.cs b/zero.Web/old/Controllers/AuthenticationController.cs similarity index 100% rename from zero.Web/Controllers/AuthenticationController.cs rename to zero.Web/old/Controllers/AuthenticationController.cs diff --git a/zero.Web/Controllers/BackofficeCollectionController.cs b/zero.Web/old/Controllers/BackofficeCollectionController.cs similarity index 100% rename from zero.Web/Controllers/BackofficeCollectionController.cs rename to zero.Web/old/Controllers/BackofficeCollectionController.cs diff --git a/zero.Web/Controllers/BackofficeController.cs b/zero.Web/old/Controllers/BackofficeController.cs similarity index 100% rename from zero.Web/Controllers/BackofficeController.cs rename to zero.Web/old/Controllers/BackofficeController.cs diff --git a/zero.Web/Controllers/BlueprintController.cs b/zero.Web/old/Controllers/BlueprintController.cs similarity index 100% rename from zero.Web/Controllers/BlueprintController.cs rename to zero.Web/old/Controllers/BlueprintController.cs diff --git a/zero.Web/Controllers/CountriesController.cs b/zero.Web/old/Controllers/CountriesController.cs similarity index 100% rename from zero.Web/Controllers/CountriesController.cs rename to zero.Web/old/Controllers/CountriesController.cs diff --git a/zero.Web/Controllers/IntegrationsController.cs b/zero.Web/old/Controllers/IntegrationsController.cs similarity index 100% rename from zero.Web/Controllers/IntegrationsController.cs rename to zero.Web/old/Controllers/IntegrationsController.cs diff --git a/zero.Web/Controllers/LanguagesController.cs b/zero.Web/old/Controllers/LanguagesController.cs similarity index 100% rename from zero.Web/Controllers/LanguagesController.cs rename to zero.Web/old/Controllers/LanguagesController.cs diff --git a/zero.Web/Controllers/LinksController.cs b/zero.Web/old/Controllers/LinksController.cs similarity index 100% rename from zero.Web/Controllers/LinksController.cs rename to zero.Web/old/Controllers/LinksController.cs diff --git a/zero.Web/Controllers/MailTemplatesController.cs b/zero.Web/old/Controllers/MailTemplatesController.cs similarity index 100% rename from zero.Web/Controllers/MailTemplatesController.cs rename to zero.Web/old/Controllers/MailTemplatesController.cs diff --git a/zero.Web/Controllers/MediaController.cs b/zero.Web/old/Controllers/MediaController.cs similarity index 100% rename from zero.Web/Controllers/MediaController.cs rename to zero.Web/old/Controllers/MediaController.cs diff --git a/zero.Web/Controllers/MediaFolderController.cs b/zero.Web/old/Controllers/MediaFolderController.cs similarity index 100% rename from zero.Web/Controllers/MediaFolderController.cs rename to zero.Web/old/Controllers/MediaFolderController.cs diff --git a/zero.Web/Controllers/ModulesController.cs b/zero.Web/old/Controllers/ModulesController.cs similarity index 100% rename from zero.Web/Controllers/ModulesController.cs rename to zero.Web/old/Controllers/ModulesController.cs diff --git a/zero.Web/Controllers/PagesController.cs b/zero.Web/old/Controllers/PagesController.cs similarity index 100% rename from zero.Web/Controllers/PagesController.cs rename to zero.Web/old/Controllers/PagesController.cs diff --git a/zero.Web/Controllers/PreviewController.cs b/zero.Web/old/Controllers/PreviewController.cs similarity index 100% rename from zero.Web/Controllers/PreviewController.cs rename to zero.Web/old/Controllers/PreviewController.cs diff --git a/zero.Web/Controllers/RecycleBinController.cs b/zero.Web/old/Controllers/RecycleBinController.cs similarity index 100% rename from zero.Web/Controllers/RecycleBinController.cs rename to zero.Web/old/Controllers/RecycleBinController.cs diff --git a/zero.Web/Controllers/SearchController.cs b/zero.Web/old/Controllers/SearchController.cs similarity index 100% rename from zero.Web/Controllers/SearchController.cs rename to zero.Web/old/Controllers/SearchController.cs diff --git a/zero.Web/Controllers/SectionsController.cs b/zero.Web/old/Controllers/SectionsController.cs similarity index 100% rename from zero.Web/Controllers/SectionsController.cs rename to zero.Web/old/Controllers/SectionsController.cs diff --git a/zero.Web/Controllers/SettingsController.cs b/zero.Web/old/Controllers/SettingsController.cs similarity index 100% rename from zero.Web/Controllers/SettingsController.cs rename to zero.Web/old/Controllers/SettingsController.cs diff --git a/zero.Web/Controllers/SpacesController.cs b/zero.Web/old/Controllers/SpacesController.cs similarity index 100% rename from zero.Web/Controllers/SpacesController.cs rename to zero.Web/old/Controllers/SpacesController.cs diff --git a/zero.Web/Controllers/TranslationsController.cs b/zero.Web/old/Controllers/TranslationsController.cs similarity index 100% rename from zero.Web/Controllers/TranslationsController.cs rename to zero.Web/old/Controllers/TranslationsController.cs diff --git a/zero.Web/Controllers/UserRolesController.cs b/zero.Web/old/Controllers/UserRolesController.cs similarity index 100% rename from zero.Web/Controllers/UserRolesController.cs rename to zero.Web/old/Controllers/UserRolesController.cs diff --git a/zero.Web/Controllers/UsersController.cs b/zero.Web/old/Controllers/UsersController.cs similarity index 100% rename from zero.Web/Controllers/UsersController.cs rename to zero.Web/old/Controllers/UsersController.cs diff --git a/zero.Web/Controllers/UtilsController.cs b/zero.Web/old/Controllers/UtilsController.cs similarity index 100% rename from zero.Web/Controllers/UtilsController.cs rename to zero.Web/old/Controllers/UtilsController.cs diff --git a/zero.Web/Controllers/ZeroBackofficeCollectionController.cs b/zero.Web/old/Controllers/ZeroBackofficeCollectionController.cs similarity index 100% rename from zero.Web/Controllers/ZeroBackofficeCollectionController.cs rename to zero.Web/old/Controllers/ZeroBackofficeCollectionController.cs diff --git a/zero.Web/Controllers/ZeroBackofficeController.cs b/zero.Web/old/Controllers/ZeroBackofficeController.cs similarity index 100% rename from zero.Web/Controllers/ZeroBackofficeController.cs rename to zero.Web/old/Controllers/ZeroBackofficeController.cs diff --git a/zero.Web/Controllers/ZeroBackofficeControllerModelConvention.cs b/zero.Web/old/Controllers/ZeroBackofficeControllerModelConvention.cs similarity index 100% rename from zero.Web/Controllers/ZeroBackofficeControllerModelConvention.cs rename to zero.Web/old/Controllers/ZeroBackofficeControllerModelConvention.cs diff --git a/zero.Web/Controllers/ZeroController.cs b/zero.Web/old/Controllers/ZeroController.cs similarity index 100% rename from zero.Web/Controllers/ZeroController.cs rename to zero.Web/old/Controllers/ZeroController.cs diff --git a/zero.Web/Controllers/ZeroFrontendController.cs b/zero.Web/old/Controllers/ZeroFrontendController.cs similarity index 100% rename from zero.Web/Controllers/ZeroFrontendController.cs rename to zero.Web/old/Controllers/ZeroFrontendController.cs diff --git a/zero.Web/Controllers/ZeroSetupController.cs b/zero.Web/old/Controllers/ZeroSetupController.cs similarity index 100% rename from zero.Web/Controllers/ZeroSetupController.cs rename to zero.Web/old/Controllers/ZeroSetupController.cs diff --git a/zero.Web/Controllers/ZeroVueController.cs b/zero.Web/old/Controllers/ZeroVueController.cs similarity index 100% rename from zero.Web/Controllers/ZeroVueController.cs rename to zero.Web/old/Controllers/ZeroVueController.cs diff --git a/zero.Web/Defaults/ApplicationSettings.cs b/zero.Web/old/Defaults/ApplicationSettings.cs similarity index 100% rename from zero.Web/Defaults/ApplicationSettings.cs rename to zero.Web/old/Defaults/ApplicationSettings.cs diff --git a/zero.Web/Defaults/ModulePermissions.cs b/zero.Web/old/Defaults/ModulePermissions.cs similarity index 100% rename from zero.Web/Defaults/ModulePermissions.cs rename to zero.Web/old/Defaults/ModulePermissions.cs diff --git a/zero.Web/Defaults/SectionPermissions.cs b/zero.Web/old/Defaults/SectionPermissions.cs similarity index 100% rename from zero.Web/Defaults/SectionPermissions.cs rename to zero.Web/old/Defaults/SectionPermissions.cs diff --git a/zero.Web/Defaults/SettingsPermissions.cs b/zero.Web/old/Defaults/SettingsPermissions.cs similarity index 100% rename from zero.Web/Defaults/SettingsPermissions.cs rename to zero.Web/old/Defaults/SettingsPermissions.cs diff --git a/zero.Web/Defaults/SpacePermissions.cs b/zero.Web/old/Defaults/SpacePermissions.cs similarity index 100% rename from zero.Web/Defaults/SpacePermissions.cs rename to zero.Web/old/Defaults/SpacePermissions.cs diff --git a/zero.Web/Defaults/SystemSettings.cs b/zero.Web/old/Defaults/SystemSettings.cs similarity index 100% rename from zero.Web/Defaults/SystemSettings.cs rename to zero.Web/old/Defaults/SystemSettings.cs diff --git a/zero.Web/Defaults/ZeroAssemblyDiscoveryRule.cs b/zero.Web/old/Defaults/ZeroAssemblyDiscoveryRule.cs similarity index 100% rename from zero.Web/Defaults/ZeroAssemblyDiscoveryRule.cs rename to zero.Web/old/Defaults/ZeroAssemblyDiscoveryRule.cs diff --git a/zero.Web/Defaults/ZeroBackofficePlugin.cs b/zero.Web/old/Defaults/ZeroBackofficePlugin.cs similarity index 100% rename from zero.Web/Defaults/ZeroBackofficePlugin.cs rename to zero.Web/old/Defaults/ZeroBackofficePlugin.cs diff --git a/zero.Web/DevServer/EventedStreamReader.cs b/zero.Web/old/DevServer/EventedStreamReader.cs similarity index 100% rename from zero.Web/DevServer/EventedStreamReader.cs rename to zero.Web/old/DevServer/EventedStreamReader.cs diff --git a/zero.Web/DevServer/PidUtils.cs b/zero.Web/old/DevServer/PidUtils.cs similarity index 100% rename from zero.Web/DevServer/PidUtils.cs rename to zero.Web/old/DevServer/PidUtils.cs diff --git a/zero.Web/DevServer/PluginResolver.cs b/zero.Web/old/DevServer/PluginResolver.cs similarity index 100% rename from zero.Web/DevServer/PluginResolver.cs rename to zero.Web/old/DevServer/PluginResolver.cs diff --git a/zero.Web/DevServer/ProcessProxy.cs b/zero.Web/old/DevServer/ProcessProxy.cs similarity index 100% rename from zero.Web/DevServer/ProcessProxy.cs rename to zero.Web/old/DevServer/ProcessProxy.cs diff --git a/zero.Web/DevServer/ZeroDevOptions.cs b/zero.Web/old/DevServer/ZeroDevOptions.cs similarity index 100% rename from zero.Web/DevServer/ZeroDevOptions.cs rename to zero.Web/old/DevServer/ZeroDevOptions.cs diff --git a/zero.Web/DevServer/ZeroDevService.cs b/zero.Web/old/DevServer/ZeroDevService.cs similarity index 100% rename from zero.Web/DevServer/ZeroDevService.cs rename to zero.Web/old/DevServer/ZeroDevService.cs diff --git a/zero.Web/Extensions/LocalizerExtensions.cs b/zero.Web/old/Extensions/LocalizerExtensions.cs similarity index 100% rename from zero.Web/Extensions/LocalizerExtensions.cs rename to zero.Web/old/Extensions/LocalizerExtensions.cs diff --git a/zero.Web/Filters/AddTokenAttribute.cs b/zero.Web/old/Filters/AddTokenAttribute.cs similarity index 100% rename from zero.Web/Filters/AddTokenAttribute.cs rename to zero.Web/old/Filters/AddTokenAttribute.cs diff --git a/zero.Web/Filters/BackofficeFilterAttribute.cs b/zero.Web/old/Filters/BackofficeFilterAttribute.cs similarity index 100% rename from zero.Web/Filters/BackofficeFilterAttribute.cs rename to zero.Web/old/Filters/BackofficeFilterAttribute.cs diff --git a/zero.Web/Filters/CanEditAttribute.cs b/zero.Web/old/Filters/CanEditAttribute.cs similarity index 100% rename from zero.Web/Filters/CanEditAttribute.cs rename to zero.Web/old/Filters/CanEditAttribute.cs diff --git a/zero.Web/Filters/ModelStateValidationFilterAttribute.cs b/zero.Web/old/Filters/ModelStateValidationFilterAttribute.cs similarity index 100% rename from zero.Web/Filters/ModelStateValidationFilterAttribute.cs rename to zero.Web/old/Filters/ModelStateValidationFilterAttribute.cs diff --git a/zero.Web/Filters/VerifyTokenAttribute.cs b/zero.Web/old/Filters/VerifyTokenAttribute.cs similarity index 100% rename from zero.Web/Filters/VerifyTokenAttribute.cs rename to zero.Web/old/Filters/VerifyTokenAttribute.cs diff --git a/zero.Web/Filters/ZeroBackofficeAttribute.cs b/zero.Web/old/Filters/ZeroBackofficeAttribute.cs similarity index 100% rename from zero.Web/Filters/ZeroBackofficeAttribute.cs rename to zero.Web/old/Filters/ZeroBackofficeAttribute.cs diff --git a/zero.Web/Formatters/RawJsonBodyInputFormatter.cs b/zero.Web/old/Formatters/RawJsonBodyInputFormatter.cs similarity index 100% rename from zero.Web/Formatters/RawJsonBodyInputFormatter.cs rename to zero.Web/old/Formatters/RawJsonBodyInputFormatter.cs diff --git a/zero.Web/Middlewares/ZeroContextMiddleware.cs b/zero.Web/old/Middlewares/ZeroContextMiddleware.cs similarity index 100% rename from zero.Web/Middlewares/ZeroContextMiddleware.cs rename to zero.Web/old/Middlewares/ZeroContextMiddleware.cs diff --git a/zero.Web/Models/ActionCopyModel.cs b/zero.Web/old/Models/ActionCopyModel.cs similarity index 100% rename from zero.Web/Models/ActionCopyModel.cs rename to zero.Web/old/Models/ActionCopyModel.cs diff --git a/zero.Web/Models/ApplicationEditModel.cs b/zero.Web/old/Models/ApplicationEditModel.cs similarity index 100% rename from zero.Web/Models/ApplicationEditModel.cs rename to zero.Web/old/Models/ApplicationEditModel.cs diff --git a/zero.Web/Models/ApplicationListModel.cs b/zero.Web/old/Models/ApplicationListModel.cs similarity index 100% rename from zero.Web/Models/ApplicationListModel.cs rename to zero.Web/old/Models/ApplicationListModel.cs diff --git a/zero.Web/Models/CountryEditModel.cs b/zero.Web/old/Models/CountryEditModel.cs similarity index 100% rename from zero.Web/Models/CountryEditModel.cs rename to zero.Web/old/Models/CountryEditModel.cs diff --git a/zero.Web/Models/CountryListModel.cs b/zero.Web/old/Models/CountryListModel.cs similarity index 100% rename from zero.Web/Models/CountryListModel.cs rename to zero.Web/old/Models/CountryListModel.cs diff --git a/zero.Web/Models/LanguageEditModel.cs b/zero.Web/old/Models/LanguageEditModel.cs similarity index 100% rename from zero.Web/Models/LanguageEditModel.cs rename to zero.Web/old/Models/LanguageEditModel.cs diff --git a/zero.Web/Models/LanguageListModel.cs b/zero.Web/old/Models/LanguageListModel.cs similarity index 100% rename from zero.Web/Models/LanguageListModel.cs rename to zero.Web/old/Models/LanguageListModel.cs diff --git a/zero.Web/Models/ListItemModel.cs b/zero.Web/old/Models/ListItemModel.cs similarity index 100% rename from zero.Web/Models/ListItemModel.cs rename to zero.Web/old/Models/ListItemModel.cs diff --git a/zero.Web/Models/ListModel.cs b/zero.Web/old/Models/ListModel.cs similarity index 100% rename from zero.Web/Models/ListModel.cs rename to zero.Web/old/Models/ListModel.cs diff --git a/zero.Web/Models/LoginModel.cs b/zero.Web/old/Models/LoginModel.cs similarity index 100% rename from zero.Web/Models/LoginModel.cs rename to zero.Web/old/Models/LoginModel.cs diff --git a/zero.Web/Models/MediaEditModel.cs b/zero.Web/old/Models/MediaEditModel.cs similarity index 100% rename from zero.Web/Models/MediaEditModel.cs rename to zero.Web/old/Models/MediaEditModel.cs diff --git a/zero.Web/Models/MediaFolderEditModel.cs b/zero.Web/old/Models/MediaFolderEditModel.cs similarity index 100% rename from zero.Web/Models/MediaFolderEditModel.cs rename to zero.Web/old/Models/MediaFolderEditModel.cs diff --git a/zero.Web/Models/MediaListModel.cs b/zero.Web/old/Models/MediaListModel.cs similarity index 100% rename from zero.Web/Models/MediaListModel.cs rename to zero.Web/old/Models/MediaListModel.cs diff --git a/zero.Web/Models/MediaListResultModel.cs b/zero.Web/old/Models/MediaListResultModel.cs similarity index 100% rename from zero.Web/Models/MediaListResultModel.cs rename to zero.Web/old/Models/MediaListResultModel.cs diff --git a/zero.Web/Models/ObsoleteEditModel.cs b/zero.Web/old/Models/ObsoleteEditModel.cs similarity index 100% rename from zero.Web/Models/ObsoleteEditModel.cs rename to zero.Web/old/Models/ObsoleteEditModel.cs diff --git a/zero.Web/Models/PageEditModel.cs b/zero.Web/old/Models/PageEditModel.cs similarity index 100% rename from zero.Web/Models/PageEditModel.cs rename to zero.Web/old/Models/PageEditModel.cs diff --git a/zero.Web/Models/SpaceContentEditModel.cs b/zero.Web/old/Models/SpaceContentEditModel.cs similarity index 100% rename from zero.Web/Models/SpaceContentEditModel.cs rename to zero.Web/old/Models/SpaceContentEditModel.cs diff --git a/zero.Web/Models/TranslationEditModel.cs b/zero.Web/old/Models/TranslationEditModel.cs similarity index 100% rename from zero.Web/Models/TranslationEditModel.cs rename to zero.Web/old/Models/TranslationEditModel.cs diff --git a/zero.Web/Models/TranslationListModel.cs b/zero.Web/old/Models/TranslationListModel.cs similarity index 100% rename from zero.Web/Models/TranslationListModel.cs rename to zero.Web/old/Models/TranslationListModel.cs diff --git a/zero.Web/Models/UserEditModel.cs b/zero.Web/old/Models/UserEditModel.cs similarity index 100% rename from zero.Web/Models/UserEditModel.cs rename to zero.Web/old/Models/UserEditModel.cs diff --git a/zero.Web/Models/UserListModel.cs b/zero.Web/old/Models/UserListModel.cs similarity index 100% rename from zero.Web/Models/UserListModel.cs rename to zero.Web/old/Models/UserListModel.cs diff --git a/zero.Web/Models/UserPasswordEditModel.cs b/zero.Web/old/Models/UserPasswordEditModel.cs similarity index 100% rename from zero.Web/Models/UserPasswordEditModel.cs rename to zero.Web/old/Models/UserPasswordEditModel.cs diff --git a/zero.Web/Models/UserRoleEditModel.cs b/zero.Web/old/Models/UserRoleEditModel.cs similarity index 100% rename from zero.Web/Models/UserRoleEditModel.cs rename to zero.Web/old/Models/UserRoleEditModel.cs diff --git a/zero.Web/Models/UserRoleListModel.cs b/zero.Web/old/Models/UserRoleListModel.cs similarity index 100% rename from zero.Web/Models/UserRoleListModel.cs rename to zero.Web/old/Models/UserRoleListModel.cs diff --git a/zero.Web/Models/ZeroBackofficeModel.cs b/zero.Web/old/Models/ZeroBackofficeModel.cs similarity index 100% rename from zero.Web/Models/ZeroBackofficeModel.cs rename to zero.Web/old/Models/ZeroBackofficeModel.cs diff --git a/zero.Web/Resources/Countries/countries.de-de.json b/zero.Web/old/Resources/Countries/countries.de-de.json similarity index 100% rename from zero.Web/Resources/Countries/countries.de-de.json rename to zero.Web/old/Resources/Countries/countries.de-de.json diff --git a/zero.Web/Resources/Countries/countries.en-us.json b/zero.Web/old/Resources/Countries/countries.en-us.json similarity index 100% rename from zero.Web/Resources/Countries/countries.en-us.json rename to zero.Web/old/Resources/Countries/countries.en-us.json diff --git a/zero.Web/Resources/Localization/zero.de-de.json b/zero.Web/old/Resources/Localization/zero.de-de.json similarity index 100% rename from zero.Web/Resources/Localization/zero.de-de.json rename to zero.Web/old/Resources/Localization/zero.de-de.json diff --git a/zero.Web/Resources/Localization/zero.en-us.json b/zero.Web/old/Resources/Localization/zero.en-us.json similarity index 100% rename from zero.Web/Resources/Localization/zero.en-us.json rename to zero.Web/old/Resources/Localization/zero.en-us.json diff --git a/zero.Web/Sections/DashboardSection.cs b/zero.Web/old/Sections/DashboardSection.cs similarity index 100% rename from zero.Web/Sections/DashboardSection.cs rename to zero.Web/old/Sections/DashboardSection.cs diff --git a/zero.Web/Sections/MediaSection.cs b/zero.Web/old/Sections/MediaSection.cs similarity index 100% rename from zero.Web/Sections/MediaSection.cs rename to zero.Web/old/Sections/MediaSection.cs diff --git a/zero.Web/Sections/PagesSection.cs b/zero.Web/old/Sections/PagesSection.cs similarity index 100% rename from zero.Web/Sections/PagesSection.cs rename to zero.Web/old/Sections/PagesSection.cs diff --git a/zero.Web/Sections/SettingsSection.cs b/zero.Web/old/Sections/SettingsSection.cs similarity index 100% rename from zero.Web/Sections/SettingsSection.cs rename to zero.Web/old/Sections/SettingsSection.cs diff --git a/zero.Web/Sections/SpacesSection.cs b/zero.Web/old/Sections/SpacesSection.cs similarity index 100% rename from zero.Web/Sections/SpacesSection.cs rename to zero.Web/old/Sections/SpacesSection.cs diff --git a/zero.Web/Security/AuthenticationBuilderExtensions.cs b/zero.Web/old/Security/AuthenticationBuilderExtensions.cs similarity index 100% rename from zero.Web/Security/AuthenticationBuilderExtensions.cs rename to zero.Web/old/Security/AuthenticationBuilderExtensions.cs diff --git a/zero.Web/ViewHelpers/ZeroMediaHelper.cs b/zero.Web/old/ViewHelpers/ZeroMediaHelper.cs similarity index 100% rename from zero.Web/ViewHelpers/ZeroMediaHelper.cs rename to zero.Web/old/ViewHelpers/ZeroMediaHelper.cs diff --git a/zero.Web/ViewHelpers/ZeroPageHelper.cs b/zero.Web/old/ViewHelpers/ZeroPageHelper.cs similarity index 100% rename from zero.Web/ViewHelpers/ZeroPageHelper.cs rename to zero.Web/old/ViewHelpers/ZeroPageHelper.cs diff --git a/zero.Web/Views/Zero/Index.cshtml b/zero.Web/old/Views/Zero/Index.cshtml similarity index 100% rename from zero.Web/Views/Zero/Index.cshtml rename to zero.Web/old/Views/Zero/Index.cshtml diff --git a/zero.Web/Views/Zero/Setup.cshtml b/zero.Web/old/Views/Zero/Setup.cshtml similarity index 100% rename from zero.Web/Views/Zero/Setup.cshtml rename to zero.Web/old/Views/Zero/Setup.cshtml diff --git a/zero.Web/Views/index.tpl.html b/zero.Web/old/Views/index.tpl.html similarity index 100% rename from zero.Web/Views/index.tpl.html rename to zero.Web/old/Views/index.tpl.html diff --git a/zero.Web/ZeroApplicationBuilder.cs b/zero.Web/old/ZeroApplicationBuilder.cs similarity index 100% rename from zero.Web/ZeroApplicationBuilder.cs rename to zero.Web/old/ZeroApplicationBuilder.cs diff --git a/zero.Web/ZeroApplicationBuilderExtensions.cs b/zero.Web/old/ZeroApplicationBuilderExtensions.cs similarity index 100% rename from zero.Web/ZeroApplicationBuilderExtensions.cs rename to zero.Web/old/ZeroApplicationBuilderExtensions.cs diff --git a/zero.Web/ZeroBuilder.cs b/zero.Web/old/ZeroBuilder.cs similarity index 100% rename from zero.Web/ZeroBuilder.cs rename to zero.Web/old/ZeroBuilder.cs diff --git a/zero.Web/ZeroClaimsPrinicipalFactory.cs b/zero.Web/old/ZeroClaimsPrinicipalFactory.cs similarity index 100% rename from zero.Web/ZeroClaimsPrinicipalFactory.cs rename to zero.Web/old/ZeroClaimsPrinicipalFactory.cs diff --git a/zero.Web/ZeroEndpointRouteBuilder.cs b/zero.Web/old/ZeroEndpointRouteBuilder.cs similarity index 100% rename from zero.Web/ZeroEndpointRouteBuilder.cs rename to zero.Web/old/ZeroEndpointRouteBuilder.cs diff --git a/zero.Web/ZeroEnpointRouteBuilderExtensions.cs b/zero.Web/old/ZeroEnpointRouteBuilderExtensions.cs similarity index 100% rename from zero.Web/ZeroEnpointRouteBuilderExtensions.cs rename to zero.Web/old/ZeroEnpointRouteBuilderExtensions.cs diff --git a/zero.Web/ZeroServiceCollectionExtensions.cs b/zero.Web/old/ZeroServiceCollectionExtensions.cs similarity index 100% rename from zero.Web/ZeroServiceCollectionExtensions.cs rename to zero.Web/old/ZeroServiceCollectionExtensions.cs diff --git a/zero.Web/ZeroVue.cs b/zero.Web/old/ZeroVue.cs similarity index 100% rename from zero.Web/ZeroVue.cs rename to zero.Web/old/ZeroVue.cs diff --git a/zero.Web/zero.Web.targets b/zero.Web/old/zero.Web.targets similarity index 100% rename from zero.Web/zero.Web.targets rename to zero.Web/old/zero.Web.targets diff --git a/zero.Web/zero.Web.csproj b/zero.Web/zero.Web.csproj index 37511627..0f49553e 100644 --- a/zero.Web/zero.Web.csproj +++ b/zero.Web/zero.Web.csproj @@ -21,14 +21,4 @@ - - - - - \ No newline at end of file diff --git a/zero.sln b/zero.sln index 8f3b8879..0612bee3 100644 --- a/zero.sln +++ b/zero.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31912.275 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zero.Core", "zero.Core\zero.Core.csproj", "{7BFF3DDE-F910-4CE1-9B94-846059CE80DA}" EndProject @@ -39,10 +39,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{1CE271AD EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zero.Stories", "zero.Stories\zero.Stories.csproj", "{C23CF90A-DB90-427F-816C-0E2FE20E29D0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zero.Forms", "zero.Forms\zero.Forms.csproj", "{A8E5F34F-5400-4F92-96C6-7F91645BC220}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "zero.Forms", "zero.Forms\zero.Forms.csproj", "{A8E5F34F-5400-4F92-96C6-7F91645BC220}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{6FAA92A8-CA1A-48EA-9857-C9092971B4D1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "zero.Backoffice", "zero.Backoffice\zero.Backoffice.csproj", "{355432DA-01AF-4E1E-B87F-8A8D99E52411}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -73,6 +75,10 @@ Global {A8E5F34F-5400-4F92-96C6-7F91645BC220}.Debug|Any CPU.Build.0 = Debug|Any CPU {A8E5F34F-5400-4F92-96C6-7F91645BC220}.Release|Any CPU.ActiveCfg = Release|Any CPU {A8E5F34F-5400-4F92-96C6-7F91645BC220}.Release|Any CPU.Build.0 = Release|Any CPU + {355432DA-01AF-4E1E-B87F-8A8D99E52411}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {355432DA-01AF-4E1E-B87F-8A8D99E52411}.Debug|Any CPU.Build.0 = Debug|Any CPU + {355432DA-01AF-4E1E-B87F-8A8D99E52411}.Release|Any CPU.ActiveCfg = Release|Any CPU + {355432DA-01AF-4E1E-B87F-8A8D99E52411}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE