using Microsoft.Extensions.Logging; using Raven.Client.Documents; using Raven.Client.Documents.Linq; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using zero.Core.Entities; using zero.Core.Extensions; using zero.Core.Integrations; using zero.Core.Options; namespace zero.Core.Collections { public class IntegrationsCollection : CollectionBase, IIntegrationsCollection { /// public IReadOnlyCollection RegisteredTypes { get; private set; } protected IZeroOptions Options { get; private set; } protected ILogger Logger { get; private set; } public IntegrationsCollection(IZeroContext context, IZeroOptions options, ILogger logger, ICollectionInterceptorHandler interceptorHandler = null) : base(context, interceptorHandler) { Options = options; RegisteredTypes = Options.Integrations.GetAllItems(); Logger = logger; } /// public Integration GetEmpty(string alias) { IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); if (type == null) { return null; } try { Integration model = Activator.CreateInstance(type.ContentType) as Integration; model.TypeAlias = type.Alias; return model; } catch { Logger.LogWarning("Could not create integration with type {alias}", alias); } return null; } /// public async Task GetByAlias(string alias) { IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase)); return await Load(type); } /// public async Task Get(string alias = null) where T : Integration, new() { IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.ContentType == typeof(T) && (alias.IsNullOrEmpty() || x.Alias.Equals(alias, StringComparison.InvariantCultureIgnoreCase))); return await Load(type); } /// public async Task> GetByTag(string tag) { IEnumerable types = RegisteredTypes.Where(x => x.Tags.Contains(tag, StringComparer.InvariantCultureIgnoreCase)); if (!types.Any()) { return new List(); } string[] aliases = types.Select(x => x.Alias).ToArray(); return await Session.Query().Where(x => x.TypeAlias.In(aliases)).ToListAsync(); } /// public async Task Any(string tag) { return (await GetByTag(tag)).Any(x => x.IsActive); } /// public override async Task> GetByQuery(ListQuery query) { List result = new(); List models = await Session.Query().ToListAsync(); foreach (IntegrationType type in RegisteredTypes) { Integration model = models.FirstOrDefault(x => x.TypeAlias == type.Alias); if (model != null) { model.Name = type.Name; result.Add(model); } } return result.ToQueriedList(query); } /// public async Task> GetTypesWithStatus() { List result = new(); List models = await Session.Query().ToListAsync(); foreach (IntegrationType type in RegisteredTypes) { Integration model = models.FirstOrDefault(x => x.TypeAlias == type.Alias); result.Add(new() { Type = type, Id = model?.Id, IsActive = model?.IsActive ?? false, IsConfigured = model != null }); } return result.OrderByDescending(x => x.IsActive).ThenByDescending(x => x.IsConfigured).ThenByDescending(x => x.Type.Name).ToList(); } /// public override async Task> Save(Integration model) { if (model == null) { return EntityResult.Fail("@integration.errors.notfound"); } IntegrationType type = RegisteredTypes.FirstOrDefault(x => x.Alias.Equals(model.TypeAlias, StringComparison.InvariantCultureIgnoreCase)); if (type == null) { return EntityResult.Fail("@integration.errors.typenotfound"); } string existingId = await Session.Query().Where(x => x.TypeAlias == type.Alias).Select(x => x.Id).FirstOrDefaultAsync(); if (!existingId.IsNullOrEmpty() && existingId != model.Id) { return EntityResult.Fail("@integration.errors.multiplenotallowed"); } model.Alias = type.Alias; model.Name = null; EntityResult result = await base.Save(model); if (result.IsSuccess) { result.Model.Name = type.Name; } return result; } /// public async Task> Activate(string alias) { Integration model = await GetByAlias(alias); if (model != null) { model.IsActive = true; } return await Save(model); } /// public async Task> Deactivate(string alias) { Integration model = await GetByAlias(alias); if (model != null) { model.IsActive = false; } return await Save(model); } /// public async Task> Delete(string alias) { return await base.Delete(await GetByAlias(alias)); } /// /// Get integration data from database /// protected async Task Load(IntegrationType type) where T : Integration, new() { if (type == null) { return default; } T entity = await Session.Query().FirstOrDefaultAsync(x => x.TypeAlias == type.Alias); if (entity != null) { entity.Name = type.Name; entity.TypeAlias = type.Alias; } return entity; } } public interface IIntegrationsCollection { /// /// Get all registered integration types /// IReadOnlyCollection RegisteredTypes { get; } /// /// Include entities with IsActive=false for GET queries /// void WithInactive(bool include = true); /// /// Get new integration model for the specified integration type alias /// Integration GetEmpty(string alias); /// /// Get integration by an alias /// Task GetByAlias(string alias); /// /// Get an integration by type and optional alias /// Task Get(string alias = null) where T : Integration, new(); /// /// Get all integrations by a certain tag /// Task> GetByTag(string tag); /// /// Check if any integrations of certain tag are activated /// Task Any(string tag); /// /// Get all integrations with the specified query /// Task> GetByQuery(ListQuery query); /// /// Get all integration types with their configuration status /// Task> GetTypesWithStatus(); /// /// Saves an integration /// Task> Save(Integration model); /// /// Activates a configured integration /// Task> Activate(string alias); /// /// Disables a configured integration /// Task> Deactivate(string alias); /// /// Deletes configuration of an integration and disables it /// Task> Delete(string alias); } }