From 4e2dbee4eb2317534bb4290a90ccd178c1e3b5ae Mon Sep 17 00:00:00 2001 From: Tobias Klika Date: Wed, 16 Dec 2020 13:22:18 +0100 Subject: [PATCH] collection for integrations --- zero.Core/Collections/CollectionCacheBase.cs | 132 ++++++++++++++ .../{IIntegration.cs => IIntegrationType.cs} | 2 +- zero.Core/Integrations/Integration.cs | 41 ++--- zero.Core/Integrations/IntegrationService.cs | 170 ------------------ zero.Core/Integrations/IntegrationSettings.cs | 26 --- zero.Core/Integrations/IntegrationType.cs | 35 ++++ .../Integrations/IntegrationTypeService.cs | 97 ++++++++++ .../Integrations/IntegrationsCollection.cs | 76 ++++++++ zero.Core/Options/IntegrationOptions.cs | 4 +- .../Controllers/IntegrationsController.cs | 22 +-- zero.Web/Defaults/ZeroBackofficePlugin.cs | 3 +- 11 files changed, 373 insertions(+), 235 deletions(-) create mode 100644 zero.Core/Collections/CollectionCacheBase.cs rename zero.Core/Integrations/{IIntegration.cs => IIntegrationType.cs} (97%) delete mode 100644 zero.Core/Integrations/IntegrationService.cs delete mode 100644 zero.Core/Integrations/IntegrationSettings.cs create mode 100644 zero.Core/Integrations/IntegrationType.cs create mode 100644 zero.Core/Integrations/IntegrationTypeService.cs create mode 100644 zero.Core/Integrations/IntegrationsCollection.cs diff --git a/zero.Core/Collections/CollectionCacheBase.cs b/zero.Core/Collections/CollectionCacheBase.cs new file mode 100644 index 00000000..dae285ba --- /dev/null +++ b/zero.Core/Collections/CollectionCacheBase.cs @@ -0,0 +1,132 @@ +using FluentValidation; +using Raven.Client; +using Raven.Client.Documents; +using Raven.Client.Documents.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using zero.Core.Entities; +using zero.Core.Extensions; + +namespace zero.Core.Collections +{ + public abstract class CollectionCacheBase : CollectionBase, ICollectionBase, IDisposable where T : IZeroEntity + { + public CollectionCacheBase(IZeroContext context, ICollectionInterceptorHandler interceptorHandler, IValidator validator = null) : base(context, interceptorHandler, validator) { } + + + protected List Items { get; set; } + + + protected async Task Preload() + { + if (Items == null || !Items.Any()) + { + Items = await Session.Query().ToListAsync(); + } + } + + + /// + public override void ApplyScope(string scope) + { + Items = null; + base.ApplyScope(scope); + } + + + /// + public override async Task GetById(string id) + { + await Preload(); + + if (id.IsNullOrWhiteSpace()) + { + return default; + } + + return Items.FirstOrDefault(x => x.Id == id); + } + + + /// + public override async Task> GetByIds(params string[] ids) + { + await Preload(); + + Dictionary models = Items.Where(x => ids.Contains(x.Id)).ToDictionary(x => x.Id, x => x); + Dictionary result = new Dictionary(); + + foreach (string id in ids) + { + models.TryGetValue(id, out T model); + result.Add(id, model); + } + + return result; + } + + + /// + public override async Task> GetByQuery(ListQuery query) + { + return await Session.Query().OrderByDescending(x => x.CreatedDate).ToQueriedListAsync(query); + } + + + /// + public override async Task> GetAll() + { + await Preload(); + return Items; + } + + + /// + public override async Task> Save(T model) + { + EntityResult result = await Save(model); + if (result.IsSuccess) + { + Items = null; + } + return result; + } + + + /// + public override async Task> DeleteById(string id) + { + EntityResult result = await DeleteById(id); + if (result.IsSuccess) + { + Items = null; + } + return result; + } + + /// + public override async Task DeleteByIds(params string[] ids) + { + int successCount = await DeleteByIds(ids); + if (successCount > 0) + { + Items = null; + } + return successCount; + } + + + /// + public override async Task> Purge(string querySuffix = null, Parameters parameters = null) + { + EntityResult result = await Purge(querySuffix, parameters); + if (result.IsSuccess) + { + Items = null; + } + return result; + } + } +} diff --git a/zero.Core/Integrations/IIntegration.cs b/zero.Core/Integrations/IIntegrationType.cs similarity index 97% rename from zero.Core/Integrations/IIntegration.cs rename to zero.Core/Integrations/IIntegrationType.cs index 34e34ac6..4a22e3d5 100644 --- a/zero.Core/Integrations/IIntegration.cs +++ b/zero.Core/Integrations/IIntegrationType.cs @@ -7,7 +7,7 @@ namespace zero.Core.Integrations /// An integration is an application part which has a public configuration per app. /// It's up to the user to provide functionality. /// - public interface IIntegration + public interface IIntegrationType { /// /// The alias diff --git a/zero.Core/Integrations/Integration.cs b/zero.Core/Integrations/Integration.cs index 5ea87faf..ca845ef5 100644 --- a/zero.Core/Integrations/Integration.cs +++ b/zero.Core/Integrations/Integration.cs @@ -1,35 +1,26 @@ -using System; +using zero.Core.Attributes; +using zero.Core.Entities; namespace zero.Core.Integrations { - /// - /// An integration is an application part which has a public configuration per app. - /// It's up to the user to provide functionality. - /// - public class Integration : IIntegration + public abstract class Integration : ZeroEntity, IIntegration { - /// - public string Alias { get; set; } + public Integration() + { + IsActive = true; + } /// - public string Name { get; set; } + public string IntegrationAlias { get; set; } + } - /// - public string Description { get; set; } - /// - public string ImagePath { get; set; } - - /// - public string Color { get; set; } - - /// - public Type SettingsType { get; set; } - - /// - public bool AllowMultiple { get; set; } - - /// - public bool IsAutoActivated { get; set; } + [Collection("Integrations")] + public interface IIntegration : IZeroEntity, IZeroDbConventions + { + /// + /// Preferred countries are displayed on top in lists + /// + string IntegrationAlias { get; set; } } } diff --git a/zero.Core/Integrations/IntegrationService.cs b/zero.Core/Integrations/IntegrationService.cs deleted file mode 100644 index e41570f3..00000000 --- a/zero.Core/Integrations/IntegrationService.cs +++ /dev/null @@ -1,170 +0,0 @@ -using Raven.Client.Documents; -using Raven.Client.Documents.Linq; -using Raven.Client.Documents.Session; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using zero.Core.Api; -using zero.Core.Database; -using zero.Core.Entities; -using zero.Core.Extensions; -using zero.Core.Options; - -namespace zero.Core.Integrations -{ - public class IntegrationService : BackofficeApi, IIntegrationService - { - protected IZeroOptions Options { get; private set; } - - - public IntegrationService(IZeroOptions options, IBackofficeStore bstore) : base(bstore) - { - Options = options; - } - - - /// - public IIntegration GetByAlias(string alias) - { - return GetAll().FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); - } - - - /// - public IIntegration GetBy() where T : class, IIntegrationSettings - { - Type type = typeof(T); - return GetAll().FirstOrDefault(x => x.SettingsType == type); - } - - - /// - public IReadOnlyCollection GetAll() - { - return Options.Integrations.GetAllItems(); - } - - - /// - public async Task> GetActivated() - { - using IAsyncDocumentSession session = Store.OpenAsyncSession(); - string[] activated = await session.Query().Where(x => x.IsActive).Select(x => x.IntegrationAlias).ToArrayAsync(); - - return GetAll().Where(x => x.IsAutoActivated || activated.Contains(x.Alias)).ToList(); - } - - - /// - public async Task> GetAvailable() - { - using IAsyncDocumentSession session = Store.OpenAsyncSession(); - string[] activated = await session.Query().Where(x => x.IsActive).Select(x => x.IntegrationAlias).ToArrayAsync(); - - return GetAll().Where(x => x.IsAutoActivated || !activated.Contains(x.Alias)).ToList(); - } - - - /// - public async Task GetSettingsByAlias(string alias) - { - IIntegration integration = GetByAlias(alias); - - if (integration == null) - { - return default; - } - - using IAsyncDocumentSession session = Store.OpenAsyncSession(); - - return await session.Query() - .Where(x => x.IntegrationAlias == integration.Alias) - .FirstOrDefaultAsync(); - } - - - /// - public async Task GetSettingsById(string id) - { - using IAsyncDocumentSession session = Store.OpenAsyncSession(); - return await session.LoadAsync(id); - } - - - /// - public async Task GetSettingsById(string id) where T : class, IIntegrationSettings - { - using IAsyncDocumentSession session = Store.OpenAsyncSession(); - return await session.LoadAsync(id); - } - - - /// - public async Task> Save(IIntegrationSettings model) - { - return await SaveModel(model, null); - } - - - /// - public async Task> Delete(string id) - { - return await DeleteById(id); - } - } - - - public interface IIntegrationService - { - /// - /// Get an integration by the specified alias - /// - IIntegration GetByAlias(string alias); - - /// - /// Get an integration by the settings type - /// - IIntegration GetBy() where T : class, IIntegrationSettings; - - /// - /// Get all available app integrations - /// - IReadOnlyCollection GetAll(); - - /// - /// Get already activated app integrations - /// - Task> GetActivated(); - - /// - /// Get available app integrations - /// - Task> GetAvailable(); - - /// - /// Get settings for a specific integration - /// - Task GetSettingsByAlias(string alias); - - /// - /// Get settings for a specific integration - /// - Task GetSettingsById(string id); - - /// - /// Get settings for a specific integration - /// - Task GetSettingsById(string id) where T : class, IIntegrationSettings; - - /// - /// Saves settings for an integration - /// - Task> Save(IIntegrationSettings model); - - /// - /// Deletes an integration (therefore its settings) - /// - Task> Delete(string id); - } -} diff --git a/zero.Core/Integrations/IntegrationSettings.cs b/zero.Core/Integrations/IntegrationSettings.cs deleted file mode 100644 index 2d352b36..00000000 --- a/zero.Core/Integrations/IntegrationSettings.cs +++ /dev/null @@ -1,26 +0,0 @@ -using zero.Core.Attributes; -using zero.Core.Entities; - -namespace zero.Core.Integrations -{ - public abstract class IntegrationSettings : ZeroEntity, IIntegrationSettings - { - public IntegrationSettings() - { - IsActive = true; - } - - /// - public string IntegrationAlias { get; set; } - } - - - [Collection("Integrations")] - public interface IIntegrationSettings : IZeroEntity, IZeroDbConventions - { - /// - /// Preferred countries are displayed on top in lists - /// - string IntegrationAlias { get; set; } - } -} diff --git a/zero.Core/Integrations/IntegrationType.cs b/zero.Core/Integrations/IntegrationType.cs new file mode 100644 index 00000000..7a40149e --- /dev/null +++ b/zero.Core/Integrations/IntegrationType.cs @@ -0,0 +1,35 @@ +using System; + +namespace zero.Core.Integrations +{ + /// + /// An integration is an application part which has a public configuration per app. + /// It's up to the user to provide functionality. + /// + public class IntegrationType : IIntegrationType + { + /// + public string Alias { get; set; } + + /// + public string Name { get; set; } + + /// + public string Description { get; set; } + + /// + public string ImagePath { get; set; } + + /// + public string Color { get; set; } + + /// + public Type SettingsType { get; set; } + + /// + public bool AllowMultiple { get; set; } + + /// + public bool IsAutoActivated { get; set; } + } +} diff --git a/zero.Core/Integrations/IntegrationTypeService.cs b/zero.Core/Integrations/IntegrationTypeService.cs new file mode 100644 index 00000000..c5f26def --- /dev/null +++ b/zero.Core/Integrations/IntegrationTypeService.cs @@ -0,0 +1,97 @@ +using Raven.Client.Documents; +using Raven.Client.Documents.Linq; +using Raven.Client.Documents.Session; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using zero.Core.Database; +using zero.Core.Options; + +namespace zero.Core.Integrations +{ + public class IntegrationTypeService : IIntegrationTypeService + { + protected IZeroOptions Options { get; private set; } + + protected IZeroStore Store { get; private set; } + + + public IntegrationTypeService(IZeroOptions options, IZeroStore store) + { + Options = options; + Store = store; + } + + + /// + public IIntegrationType GetByAlias(string alias) + { + return GetAll().FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); + } + + + /// + public IIntegrationType GetBy() where T : class, IIntegration + { + Type type = typeof(T); + return GetAll().FirstOrDefault(x => x.SettingsType == type); + } + + + /// + public IReadOnlyCollection GetAll() + { + return Options.Integrations.GetAllItems(); + } + + + /// + public async Task> GetActivated() + { + using IAsyncDocumentSession session = Store.OpenAsyncSession(); + string[] activated = await session.Query().Where(x => x.IsActive).Select(x => x.IntegrationAlias).ToArrayAsync(); + + return GetAll().Where(x => x.IsAutoActivated || activated.Contains(x.Alias)).ToList(); + } + + + /// + public async Task> GetAvailable() + { + using IAsyncDocumentSession session = Store.OpenAsyncSession(); + string[] activated = await session.Query().Where(x => x.IsActive).Select(x => x.IntegrationAlias).ToArrayAsync(); + + return GetAll().Where(x => x.IsAutoActivated || !activated.Contains(x.Alias)).ToList(); + } + } + + + public interface IIntegrationTypeService + { + /// + /// Get an integration by the specified alias + /// + IIntegrationType GetByAlias(string alias); + + /// + /// Get an integration by the settings type + /// + IIntegrationType GetBy() where T : class, IIntegration; + + /// + /// Get all available app integrations + /// + IReadOnlyCollection GetAll(); + + /// + /// Get already activated app integrations + /// + Task> GetActivated(); + + /// + /// Get available app integrations + /// + Task> GetAvailable(); + } +} diff --git a/zero.Core/Integrations/IntegrationsCollection.cs b/zero.Core/Integrations/IntegrationsCollection.cs new file mode 100644 index 00000000..9247be73 --- /dev/null +++ b/zero.Core/Integrations/IntegrationsCollection.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using zero.Core.Collections; + +namespace zero.Core.Integrations +{ + public class IntegrationsCollection : CollectionCacheBase, IIntegrationsCollection + { + public IReadOnlyCollection RegisteredTypes { get; private set; } + + + public IntegrationsCollection(IZeroContext context, ICollectionInterceptorHandler interceptorHandler) : base(context, interceptorHandler) + { + RegisteredTypes = context.Options.Integrations.GetAllItems(); + } + + + /// + public async Task Get() where T : class, IIntegration + { + Type type = typeof(T); + IIntegrationType integration = RegisteredTypes.FirstOrDefault(x => x.SettingsType == type); + + if (integration == null) + { + return default; + } + + await Preload(); + return Items.FirstOrDefault(x => x.IntegrationAlias == integration.Alias) as T; + } + + + /// + public async Task GetByAlias(string alias) + { + IIntegrationType integration = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); + + if (integration == null) + { + return default; + } + + await Preload(); + return Items.FirstOrDefault(x => x.IntegrationAlias == integration.Alias); + } + + + /// + public async Task GetById(string id) where T : class, IIntegration + { + return await GetById(id) as T; + } + } + + + public interface IIntegrationsCollection : ICollectionBase + { + /// + /// Get settings for a specific integration + /// + Task Get() where T : class, IIntegration; + + /// + /// Get settings for a specific integration + /// + Task GetByAlias(string alias); + + /// + /// Get settings for a specific integration + /// + Task GetById(string id) where T : class, IIntegration; + } +} diff --git a/zero.Core/Options/IntegrationOptions.cs b/zero.Core/Options/IntegrationOptions.cs index 865a620c..7241319c 100644 --- a/zero.Core/Options/IntegrationOptions.cs +++ b/zero.Core/Options/IntegrationOptions.cs @@ -3,9 +3,9 @@ using zero.Core.Integrations; namespace zero.Core.Options { - public class IntegrationOptions : ZeroBackofficeCollection, IZeroCollectionOptions + public class IntegrationOptions : ZeroBackofficeCollection, IZeroCollectionOptions { - public void Add() where T : IIntegration, new() + public void Add() where T : IIntegrationType, new() { Items.Add(new T()); } diff --git a/zero.Web/Controllers/IntegrationsController.cs b/zero.Web/Controllers/IntegrationsController.cs index 304c8d31..de813b62 100644 --- a/zero.Web/Controllers/IntegrationsController.cs +++ b/zero.Web/Controllers/IntegrationsController.cs @@ -8,11 +8,13 @@ namespace zero.Web.Controllers //[ZeroAuthorize(Permissions.Sections.Spaces, PermissionsValue.True)] public class IntegrationsController : BackofficeController { - IIntegrationService Integrations; + IIntegrationsCollection Integrations; + IIntegrationTypeService Types; - public IntegrationsController(IIntegrationService integrations) + public IntegrationsController(IIntegrationsCollection integrations, IIntegrationTypeService types) { Integrations = integrations; + Types = types; } @@ -20,16 +22,16 @@ namespace zero.Web.Controllers { return Ok(new { - available = await Integrations.GetAvailable(), - activated = await Integrations.GetActivated() + available = await Types.GetAvailable(), + activated = await Types.GetActivated() }); } public IActionResult GetEmptySettings([FromQuery] string alias) { - IIntegration integration = Integrations.GetByAlias(alias); - IIntegrationSettings model = integration != null ? Activator.CreateInstance(integration.SettingsType) as IIntegrationSettings : null; + IIntegrationType integration = Types.GetByAlias(alias); + IIntegration model = integration != null ? Activator.CreateInstance(integration.SettingsType) as IIntegration : null; if (model != null) { @@ -42,26 +44,26 @@ namespace zero.Web.Controllers public async Task GetSettingsByAlias([FromQuery] string alias) { - IIntegrationSettings content = await Integrations.GetSettingsByAlias(alias); + IIntegration content = await Integrations.GetByAlias(alias); return Ok(Edit(content)); } public async Task GetSettingsById([FromQuery] string id) { - IIntegrationSettings content = await Integrations.GetSettingsById(id); + IIntegration content = await Integrations.GetById(id); return Ok(Edit(content)); } - public async Task Save([FromBody] IIntegrationSettings model) + public async Task Save([FromBody] IIntegration model) { return Ok(await Integrations.Save(model)); } public async Task Delete([FromQuery] string id) { - return Ok(await Integrations.Delete(id)); + return Ok(await Integrations.DeleteById(id)); } } } diff --git a/zero.Web/Defaults/ZeroBackofficePlugin.cs b/zero.Web/Defaults/ZeroBackofficePlugin.cs index d57bbb80..bcf4e623 100644 --- a/zero.Web/Defaults/ZeroBackofficePlugin.cs +++ b/zero.Web/Defaults/ZeroBackofficePlugin.cs @@ -117,7 +117,8 @@ namespace zero.Web.Defaults services.AddScoped(); - services.AddScoped(); + services.AddScoped(); + services.AddScoped(); } } } \ No newline at end of file