using e_suite.API.Common; using e_suite.API.Common.exceptions; using e_suite.API.Common.repository; using e_suite.Database.Audit; using e_suite.Database.Core.Extensions; using e_suite.Modules.WorkflowTemplatesManager.Repository; using e_suite.Utilities.Pagination; using e_suite.Workflow.Core.Attributes; using e_suite.Workflow.Core.Extensions; using e_suite.Workflow.Core.Interfaces; using eSuite.Core.Miscellaneous; using System.Linq.Expressions; using System.Reflection; using e_suite.Database.Core.Tables.Workflow; using Microsoft.AspNetCore.Mvc; //using WorkflowVersion = e_suite.Workflow.Core.WorkflowVersion; namespace e_suite.Modules.WorkflowTemplatesManager; public class WorkflowTemplateManager : IWorkflowTemplateManager { private readonly IWorkflowTemplateRepository _workflowTemplateRepository; private readonly IWorkflowConverter _workflowConverter; private readonly IDomainRepository _domainRepository; private readonly IPatchFactory _patchFactory; public WorkflowTemplateManager(IWorkflowTemplateRepository workflowTemplateRepository, IPatchFactory patchFactory, IDomainRepository domainRepository, IWorkflowConverter workflowConverter) { _workflowTemplateRepository = workflowTemplateRepository; _patchFactory = patchFactory; _domainRepository = domainRepository; _workflowConverter = workflowConverter; } public async Task> GetWorkflowTemplatesAsync(Paging paging, CancellationToken cancellationToken) { var ssoProviders = _workflowTemplateRepository.GetWorkflows().Where(x => x.Deleted == false); var paginatedData = await PaginatedData.Paginate(ssoProviders, paging, WorkflowKeySelector, cancellationToken); return paginatedData; } private Expression> WorkflowKeySelector(string sortKey) { return sortKey?.ToLowerInvariant() switch { "id" => x => x.Id, "guid" => x => x.Guid, "name" => x => x.Name, "lastupdated" => x => x.LastUpdated, _ => x => x.Id }; } public async Task> GetWorkflowTemplateVersionsAsync(Paging paging, CancellationToken cancellationToken) { var ssoProviders = _workflowTemplateRepository.GetWorkflowVersions().Where(x => x.Deleted == false); var paginatedData = await PaginatedData.Paginate(ssoProviders, paging, KeySelector, cancellationToken); return paginatedData; } private Expression> KeySelector(string sortKey) { return sortKey?.ToLowerInvariant() switch { "id" => x => x.Id, "activitynametemplate" => x => x.ActivityNameTemplate, "description" => x => x.Description, "domain.name" => x => x.Domain.Name, "workflow.name" => x => x.Workflow.Name, _ => x => x.Id }; } public async Task GetWorkflowTemplateVersionAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken) { var dbWorkflowTemplate = await _workflowTemplateRepository.GetWorkflowVersions().FindByGeneralIdRefAsync(generalIdRef, cancellationToken) ?? throw new NotFoundException("Unable to find Workflow Version"); //var workflowTemplate = _workflowConverter.DeserialiseFromDatabase(dbWorkflowTemplate); return new GetWorkflowTemplateVersion(dbWorkflowTemplate); } public async Task EditTemplateVersion( AuditUserDetails auditUserDetails, EditWorkflowTemplateVersion template, CancellationToken cancellationToken ) { await AlterWorkflowTemplateVersionAsync(auditUserDetails, template.ToGeneralIdRef()!, async version => { var domain = await _domainRepository.GetDomainById(template.DomainId!, cancellationToken) ?? throw new NotFoundException("Unable to find Domain with provided id"); version.Domain = domain; version.DomainId = domain.Id; version.Description = template.Description; version.ActivityNameTemplate = template.ActivityNameTemplate; version.Deleted = false; version.Version = template.Version; version.Tasks = template.Tasks; }, cancellationToken); } public async Task PatchTemplateVersion( AuditUserDetails auditUserDetails, IGeneralIdRef templateId, PatchWorkflowTemplateVersion patchTemplate, CancellationToken cancellationToken ) { var patch = _patchFactory.Create(patchTemplate); await AlterWorkflowTemplateVersionAsync(auditUserDetails, templateId, async version => { await patch.ApplyTo(version); }, cancellationToken); } public async Task PostTemplateVersion( AuditUserDetails auditUserDetails, CreateWorkflowTemplateVersion template, CancellationToken cancellationToken ) { await _workflowTemplateRepository.TransactionAsync(async () => { if (_workflowTemplateRepository.GetWorkflows().FirstOrDefault(x => x.Name == template.WorkflowName) != null) { throw new ExistsException("Workflow already exists"); } var workflow = new Database.Core.Tables.Workflow.Workflow { Name = template.WorkflowName, Guid = Guid.NewGuid() }; await _workflowTemplateRepository.AddWorkflow(auditUserDetails, workflow, cancellationToken); var workflowDomain = await _domainRepository.GetDomainById(template.DomainId, cancellationToken); var dbWorkflowTemplate = new WorkflowVersion { Guid = Guid.NewGuid(), ActivityNameTemplate = template.ActivityNameTemplate, Description = template.Description, Domain = workflowDomain, Tasks = template.Tasks, Workflow = workflow, }; Workflow.Core.WorkflowVersion? workflowTemplate = _workflowConverter.DeserialiseFromDatabase(dbWorkflowTemplate); if (workflowTemplate is null) { throw new InvalidDataException("The workflow template is not valid"); } await _workflowTemplateRepository.AddWorkflowVersion(auditUserDetails, dbWorkflowTemplate, cancellationToken); } ); } public async Task DeleteTemplateVersion(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, CancellationToken cancellationToken) { await AlterWorkflowTemplateVersionAsync(auditUserDetails, templateId, async version => { version.Deleted = true; }, cancellationToken); } private async Task AlterWorkflowTemplateVersionAsync( AuditUserDetails auditUserDetails, IGeneralIdRef generalIdRef, Func applyChanges, CancellationToken cancellationToken ) { await _workflowTemplateRepository.TransactionAsync(async () => { var workflowVersion = await _workflowTemplateRepository.GetWorkflowVersions().FindByGeneralIdRefAsync(generalIdRef, cancellationToken) ?? throw new NotFoundException("SsoProvider with this id does not exists"); await applyChanges(workflowVersion); await _workflowTemplateRepository.EditWorkflowVersionAsync(auditUserDetails, workflowVersion, cancellationToken); }); } private static string FormatInterfaceName(Type interfaceType) { if (!interfaceType.IsGenericType) return interfaceType.Name; var genericName = interfaceType.Name; var tickIndex = genericName.IndexOf('`'); if (tickIndex > 0) genericName = genericName.Substring(0, tickIndex); var genericArgs = interfaceType.GetGenericArguments(); var formattedArgs = string.Join(", ", genericArgs.Select(a => a.Name)); return $"{genericName}<{formattedArgs}>"; } public Task> GetAllowedTaskMetadataList(string? taskType, CancellationToken cancellationToken) { var taskTypeAttribute = StageExtensions.GetTaskAttributeType(taskType); var allowedTypes = StageExtensions.GetAllowedTaskTypes(taskTypeAttribute); var result = allowedTypes .Select(t => { var interfaces = t.GetInterfaces(); var capabilities = interfaces .Where(i => i.GetCustomAttribute() != null) .Select(FormatInterfaceName) .ToList(); var newTaskMetadata = new TaskMetadata { TaskType = t.FullName!, DisplayName = t.Name, }; newTaskMetadata.Capabilities.AddRange(capabilities); return newTaskMetadata; }) .ToList(); return Task.FromResult(result); } }