using e_suite.API.Common.repository; using e_suite.Database.Audit; using e_suite.Database.Core; using e_suite.Database.Core.Extensions; using e_suite.Database.Core.Tables.Contacts; using e_suite.Database.Core.Tables.Domain; using e_suite.Database.Core.Tables.UserManager; using e_suite.Workflow.Core; using e_suite.Workflow.Core.Extensions; using eSuite.Core.Miscellaneous; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using System.Text.Json; using System.Text.Json.Serialization; namespace e_suite.Modules.WorkflowTemplatesManager.Repository; public class GeneralIdRefConverter : JsonConverter { private readonly Func _lookup; public GeneralIdRefConverter(Func lookup) { _lookup = lookup; } public override bool CanConvert(Type typeToConvert) { // Only convert actual domain types, not enums or primitives return typeToConvert == typeof(T) && !typeToConvert.IsEnum && !typeToConvert.IsPrimitive && typeToConvert != typeof(string); } public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { // Parse the incoming JSON into a GeneralIdRef using var doc = JsonDocument.ParseValue(ref reader); var json = doc.RootElement.GetRawText(); var idRef = JsonSerializer.Deserialize(json, options); if (idRef == null) return default; return _lookup(idRef); } public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { throw new NotImplementedException("Writing not needed."); } } public interface IWorkflowConverter { Workflow.Core.WorkflowVersion DeserialiseFromDatabase(e_suite.Database.Core.Tables.Workflow.WorkflowVersion dbVersion); Task SerialiseToDatabase( Workflow.Core.WorkflowVersion runtime, e_suite.Database.Core.Tables.Workflow.WorkflowVersion? dbObject = null, CancellationToken cancellationToken = default ); } public class WorkflowConverter : IWorkflowConverter { private readonly IDomainRepository _domainRepository; private readonly IRoleManagerRepository _roleManagerRepository; private readonly IUserManagerRepository _userManagerRepository; private readonly JsonSerializerOptions _jsonSerializerOptions; public WorkflowConverter(IDomainRepository domainRepository, IRoleManagerRepository roleManagerRepository, IUserManagerRepository userManagerRepository) { _domainRepository = domainRepository; _roleManagerRepository = roleManagerRepository; _userManagerRepository = userManagerRepository; _jsonSerializerOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; _jsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); _jsonSerializerOptions.Converters.Add(new GeneralIdRefConverter(id => _roleManagerRepository.GetRoleById(id))); _jsonSerializerOptions.Converters.Add(new GeneralIdRefConverter(id => _userManagerRepository.GetUserById(id))); } public Workflow.Core.WorkflowVersion DeserialiseFromDatabase(e_suite.Database.Core.Tables.Workflow.WorkflowVersion dbVersion) { var runtime = new Workflow.Core.WorkflowVersion { Id = dbVersion.Id, Guid = dbVersion.Guid, Version = dbVersion.Version, ActivityNameTemplate = dbVersion.ActivityNameTemplate, Description = dbVersion.Description, Domain = dbVersion.Domain.ToGeneralIdRef()!, Template = new WorkflowTemplate { Name = "Need to fix", Id = 1, Guid = Guid.Empty } // however you load templates }; foreach (var def in dbVersion.Tasks) { var task = def.ToTask(_jsonSerializerOptions); runtime.Tasks.Add(task); } return runtime; } public async Task SerialiseToDatabase(Workflow.Core.WorkflowVersion runtime, e_suite.Database.Core.Tables.Workflow.WorkflowVersion? dbObject = null, CancellationToken cancellationToken = default) { if (runtime is null) throw new NullReferenceException(); var domain = await _domainRepository.GetDomainById(runtime.Domain, cancellationToken); if (domain is null) throw new Exception($"Domain with id {runtime.Domain} not found."); var dbVersion = dbObject ?? new e_suite.Database.Core.Tables.Workflow.WorkflowVersion(); if (dbObject == null) { dbVersion.Id = runtime.Id; dbVersion.Guid = runtime.Guid; } else { //note cannot move a version from one workflow to another, that requires a new version. //todo make sure that the Workflow is populated here. //dbVersion.Workflow = runtime.Template.ToGeneralIdRef() } dbVersion.Version = runtime.Version; //todo make sure that the version number get incremented somewhere logical. dbVersion.ActivityNameTemplate = runtime.ActivityNameTemplate; dbVersion.Description = runtime.Description; dbVersion.DomainId = domain.Id; dbVersion.Tasks = runtime.Tasks .Select(t => t.ToDefinition()) .ToList(); return dbVersion; } } public class WorkflowTemplateRepository : RepositoryBase, IWorkflowTemplateRepository { public WorkflowTemplateRepository(IEsuiteDatabaseDbContext databaseDbContext) : base(databaseDbContext) { } public IQueryable GetWorkflows() { return DatabaseDbContext.Workflows .Include( x => x.Versions); } public IQueryable GetWorkflowVersions() { return DatabaseDbContext.WorkflowVersions.Include( x => x.Domain); } public async Task EditWorkflowVersionAsync(AuditUserDetails auditUserDetails, e_suite.Database.Core.Tables.Workflow.WorkflowVersion workflowVersion, CancellationToken cancellationToken) { await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); } public async Task AddWorkflow(AuditUserDetails auditUserDetails, Database.Core.Tables.Workflow.Workflow workflow, CancellationToken cancellationToken) { DatabaseDbContext.Workflows.Add(workflow); await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); } public async Task AddWorkflowVersion( AuditUserDetails auditUserDetails, Database.Core.Tables.Workflow.WorkflowVersion workflowVersion, CancellationToken cancellationToken ) { DatabaseDbContext.WorkflowVersions.Add(workflowVersion); await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken); } }