Backend/e-suite.Modules.WorkflowTemplatesManager/WorkflowTemplateManager.cs

260 lines
11 KiB
C#

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<PaginatedData<GetWorkflowTemplate>> GetWorkflowTemplatesAsync(Paging paging, CancellationToken cancellationToken)
{
var ssoProviders = _workflowTemplateRepository.GetWorkflows().Where(x => x.Deleted == false);
var paginatedData = await PaginatedData.Paginate<e_suite.Database.Core.Tables.Workflow.Workflow, GetWorkflowTemplate>(ssoProviders, paging,
WorkflowKeySelector, cancellationToken);
return paginatedData;
}
private Expression<Func<e_suite.Database.Core.Tables.Workflow.Workflow, object>> 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<PaginatedData<GetWorkflowTemplateVersion>> GetWorkflowTemplateVersionsAsync(Paging paging, CancellationToken cancellationToken)
{
var ssoProviders = _workflowTemplateRepository.GetWorkflowVersions().Where(x => x.Deleted == false);
var paginatedData = await PaginatedData.Paginate<e_suite.Database.Core.Tables.Workflow.WorkflowVersion, GetWorkflowTemplateVersion>(ssoProviders, paging,
KeySelector, cancellationToken);
return paginatedData;
}
private Expression<Func<e_suite.Database.Core.Tables.Workflow.WorkflowVersion, object>> 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<GetWorkflowTemplateVersion?> GetWorkflowTemplateAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken)
{
var workflow = await _workflowTemplateRepository.GetWorkflows().FindByGeneralIdRefAsync(generalIdRef, cancellationToken) ?? throw new NotFoundException("Unable to find Workflow");
var dbWorkflowTemplate = _workflowTemplateRepository.GetWorkflowVersions().Where(x => x.WorkflowId == workflow.Id).OrderByDescending( x => x.Version).First();
//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,
GetWorkflowTemplateVersion 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");
var workflow = version.Workflow;
workflow.Name = template.WorkflowName;
var newVersion = new e_suite.Database.Core.Tables.Workflow.WorkflowVersion
{
Domain = domain,
DomainId = domain.Id,
Description = template.Description,
ActivityNameTemplate = template.ActivityNameTemplate,
Deleted = false,
Version = template.Version + 1,
Tasks = template.Tasks,
Workflow = workflow
};
return newVersion;
}, 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);
return 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) ?? throw new NotFoundException("Unable to find domain");
var dbWorkflowTemplate = new WorkflowVersion
{
ActivityNameTemplate = template.ActivityNameTemplate,
Description = template.Description,
Domain = workflowDomain,
Tasks = template.Tasks,
Workflow = workflow,
};
//This will attempt to parse the data onto the internal workflow structure.
//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;
return version;
}, cancellationToken);
}
private async Task AlterWorkflowTemplateVersionAsync(
AuditUserDetails auditUserDetails,
IGeneralIdRef generalIdRef,
Func<e_suite.Database.Core.Tables.Workflow.WorkflowVersion,
Task<e_suite.Database.Core.Tables.Workflow.WorkflowVersion?>> 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");
var newVersion = await applyChanges(workflowVersion);
if (newVersion != workflowVersion)
await _workflowTemplateRepository.AddWorkflowVersion(auditUserDetails, newVersion, cancellationToken);
else
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<List<TaskMetadata>> 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<TaskCapabilityAttribute>() != 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);
}
}