using FluentValidation; using FluentValidation.Results; using Raven.Client.Documents; using Raven.Client.Documents.Linq; namespace zero.Configuration; public class IntegrationStore : IIntegrationStore { protected IStoreOperations Operations { get; private set; } protected IIntegrationTypeService IntegrationTypes { get; private set; } public IntegrationStore(IStoreOperationsWithInactive operations, IIntegrationTypeService integrationTypes) { IntegrationTypes = integrationTypes; Operations = operations; } /// public virtual async Task Empty(string alias) { return await Operations.Empty(alias); } /// public virtual async Task Load(string alias) { Paged result = await Operations.Load(1, 1, q => q.Where(x => x.Flavor == alias)); return result.Items.FirstOrDefault(); } /// public async Task> LoadByTag(string tag) { IEnumerable types = IntegrationTypes.GetByTag(tag); if (!types.Any()) { return new List(); } string[] aliases = types.Select(x => x.Alias).ToArray(); return await Operations.Session.Query().Where(x => x.Flavor.In(aliases)).ToListAsync(); } /// public async Task Any(string tag) { IEnumerable types = IntegrationTypes.GetByTag(tag); if (!types.Any()) { return false; } string[] aliases = types.Select(x => x.Alias).ToArray(); return await Operations.Session.Query().AnyAsync(x => x.Flavor.In(aliases) && x.IsActive); } /// public virtual string GetChangeToken(Integration model) => Operations.GetChangeToken(model); /// public virtual async Task> Create(Integration model) => await Save(model, true); /// public virtual async Task> Update(Integration model) => await Save(model, false); /// public virtual async Task> Activate(string alias) { Integration model = await Load(alias); if (model != null) { model.IsActive = true; } return await Update(model); } /// public virtual async Task> Deactivate(string alias) { Integration model = await Load(alias); if (model != null) { model.IsActive = false; } return await Update(model); } /// public async Task> Delete(string alias) { Integration integration = await Load(alias); return await Operations.Delete(integration); } // protected virtual async Task Validate(Integration model, bool create = false) { ValidationResult result = new(); if (model == null) { result.Errors.Add(new ValidationFailure("__nofield", "@integration.errors.notfound")); } else { IntegrationType type = IntegrationTypes.GetByAlias(model.Flavor); if (type == null) { result.Errors.Add(new ValidationFailure("__nofield", "@integration.errors.typenotfound")); } if (create && await Operations.Any(q => q.Where(x => x.Flavor == model.Flavor))) { result.Errors.Add(new ValidationFailure("__nofield", "@integration.errors.multiplenotallowed")); } if (!create && await Operations.Any(q => q.Where(x => x.Flavor == model.Flavor && x.Id != model.Id))) { result.Errors.Add(new ValidationFailure("__nofield", "@integration.errors.alreadycreated")); } if (type != null && type.Validator != null) { ValidationResult innerResult = await type.Validator.ValidateAsync(new ValidationContext(model)); result.Errors.AddRange(innerResult.Errors); } } return result; } /// protected virtual async Task> Save(Integration model, bool create = false) { return await Operations.Create(model, async (x, ctx) => await Validate(x, create)); } } public interface IIntegrationStore { /// /// Get new instance of an integration by integration alias /// Task Empty(string alias); /// /// Get an integration by integration alias /// Task Load(string alias); /// /// Get all integrations by a certain tag /// Task> LoadByTag(string tag); /// /// Check if there are any activated integrations for a certain tag /// Task Any(string tag); /// /// Get the change vector for a model (Proxy to IAsyncDocumentSession.GetChangeVectorFor<>) /// string GetChangeToken(Integration model); /// /// Creates a new integration /// Task> Create(Integration model); /// /// Updates an integration /// Task> Update(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); }