Work towards implementing a workflow template editor
This commit is contained in:
parent
17aea93370
commit
af02ede4e3
29
e-suite.API.Common/e-suite.API.Common/GetWorkflowTemplate.cs
Normal file
29
e-suite.API.Common/e-suite.API.Common/GetWorkflowTemplate.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using e_suite.Database.Core.Models;
|
||||
using e_suite.Database.Core.Tables.Workflow;
|
||||
|
||||
namespace e_suite.API.Common;
|
||||
|
||||
public class GetWorkflowTemplate : IGeneralId
|
||||
{
|
||||
public GetWorkflowTemplate( Workflow workflow)
|
||||
{
|
||||
Id = workflow.Id;
|
||||
Guid = workflow.Guid;
|
||||
WorkflowName = workflow.Name;
|
||||
Version = workflow.Versions.Max(x => x.Version);
|
||||
Deleted = workflow.Deleted;
|
||||
LastUpdated = workflow.LastUpdated;
|
||||
}
|
||||
|
||||
public long Version { get; set; }
|
||||
|
||||
public DateTimeOffset LastUpdated { get; set; }
|
||||
|
||||
public bool Deleted { get; set; }
|
||||
|
||||
public string WorkflowName { get; set; }
|
||||
|
||||
public Guid Guid { get; set; }
|
||||
|
||||
public long Id { get; set; }
|
||||
}
|
||||
@ -7,43 +7,43 @@ using eSuite.Core.Miscellaneous;
|
||||
|
||||
namespace e_suite.API.Common;
|
||||
|
||||
public class GetWorkflowTemplate : IGeneralId
|
||||
public class GetWorkflowTemplateVersion : IGeneralId
|
||||
{
|
||||
public GetWorkflowTemplate()
|
||||
public GetWorkflowTemplateVersion()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public GetWorkflowTemplate(WorkflowVersion workflowVersion)
|
||||
public GetWorkflowTemplateVersion(WorkflowVersion workflowVersion)
|
||||
{
|
||||
Id = workflowVersion.Id;
|
||||
Guid = workflowVersion.Guid;
|
||||
Deleted = workflowVersion.Deleted;
|
||||
ActivityNameTemplate = workflowVersion.ActivityNameTemplate;
|
||||
Description = workflowVersion.Description;
|
||||
DomainId = workflowVersion.Domain.ToGeneralIdRef();
|
||||
DomainId = workflowVersion.Domain.ToGeneralIdRef()!;
|
||||
LastUpdated = workflowVersion.LastUpdated;
|
||||
Version = workflowVersion.Version;
|
||||
WorkflowId = workflowVersion.Workflow.ToGeneralIdRef();
|
||||
WorkflowId = workflowVersion.Workflow.ToGeneralIdRef()!;
|
||||
WorkflowName = workflowVersion.Workflow.Name;
|
||||
Tasks = workflowVersion.Tasks;
|
||||
}
|
||||
|
||||
public List<TaskDefinition> Tasks { get; set; }
|
||||
public List<TaskDefinition> Tasks { get; set; } = [];
|
||||
|
||||
public string WorkflowName { get; set; }
|
||||
public string WorkflowName { get; set; } = string.Empty;
|
||||
|
||||
public GeneralIdRef? WorkflowId { get; set; }
|
||||
public GeneralIdRef WorkflowId { get; set; } = null!;
|
||||
|
||||
public long Version { get; set; }
|
||||
|
||||
public DateTimeOffset LastUpdated { get; set; }
|
||||
|
||||
public GeneralIdRef? DomainId { get; set; }
|
||||
public GeneralIdRef DomainId { get; set; } = null!;
|
||||
|
||||
public string Description { get; set; }
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public string ActivityNameTemplate { get; set; }
|
||||
public string ActivityNameTemplate { get; set; } = string.Empty;
|
||||
|
||||
public bool Deleted { get; set; }
|
||||
|
||||
@ -51,25 +51,23 @@ public class GetWorkflowTemplate : IGeneralId
|
||||
public Guid Guid { get; set; }
|
||||
}
|
||||
|
||||
public class EditWorkflowTemplate : IGeneralId
|
||||
public class EditWorkflowTemplateVersion : IGeneralId
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public Guid Guid { get; set; }
|
||||
|
||||
public string WorkflowName { get; set; }
|
||||
|
||||
public GeneralIdRef? WorkflowId { get; set; }
|
||||
|
||||
public long Version { get; set; }
|
||||
|
||||
public GeneralIdRef? DomainId { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
public string Description { get; set; } = String.Empty;
|
||||
|
||||
public string ActivityNameTemplate { get; set; }
|
||||
public string ActivityNameTemplate { get; set; } = String.Empty;
|
||||
|
||||
public List<TaskDefinition> Tasks { get; set; } = [];
|
||||
}
|
||||
|
||||
public class PatchWorkflowTemplate
|
||||
public class PatchWorkflowTemplateVersion
|
||||
{
|
||||
|
||||
public string? WorkflowName { get; set; }
|
||||
@ -81,33 +79,29 @@ public class PatchWorkflowTemplate
|
||||
public string? ActivityNameTemplate { get; set; }
|
||||
}
|
||||
|
||||
public class CreateWorkflowTemplate
|
||||
public class CreateWorkflowTemplateVersion
|
||||
{
|
||||
public List<TaskDefinition> Tasks { get; set; }
|
||||
public List<TaskDefinition> Tasks { get; set; } = [];
|
||||
|
||||
public string WorkflowName { get; set; }
|
||||
|
||||
public GeneralIdRef? WorkflowId { get; set; }
|
||||
public required GeneralIdRef WorkflowId { get; set; }
|
||||
|
||||
public long Version { get; set; }
|
||||
|
||||
public DateTimeOffset LastUpdated { get; set; }
|
||||
public required GeneralIdRef DomainId { get; set; }
|
||||
|
||||
public GeneralIdRef? DomainId { get; set; }
|
||||
public string Description { get; set; } = String.Empty;
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string ActivityNameTemplate { get; set; }
|
||||
|
||||
public bool Deleted { get; set; }
|
||||
public string ActivityNameTemplate { get; set; } = String.Empty;
|
||||
}
|
||||
|
||||
public interface IWorkflowTemplateManager
|
||||
{
|
||||
Task<PaginatedData<GetWorkflowTemplate>> GetWorkflowTemplatesAsync(Paging paging, CancellationToken cancellationToken);
|
||||
Task<GetWorkflowTemplate?> GetWorkflowTemplateAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken);
|
||||
Task EditTemplate(AuditUserDetails auditUserDetails, EditWorkflowTemplate template, CancellationToken cancellationToken);
|
||||
Task PatchTemplate(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, PatchWorkflowTemplate patchTemplate, CancellationToken cancellationToken);
|
||||
Task PostTemplate(AuditUserDetails auditUserDetails, CreateWorkflowTemplate template, CancellationToken cancellationToken);
|
||||
Task DeleteTemplate(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, CancellationToken cancellationToken);
|
||||
|
||||
Task<PaginatedData<GetWorkflowTemplateVersion>> GetWorkflowTemplateVersionsAsync(Paging paging, CancellationToken cancellationToken);
|
||||
Task<GetWorkflowTemplateVersion?> GetWorkflowTemplateVersionAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken);
|
||||
Task EditTemplateVersion(AuditUserDetails auditUserDetails, EditWorkflowTemplateVersion template, CancellationToken cancellationToken);
|
||||
Task PatchTemplateVersion(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, PatchWorkflowTemplateVersion patchTemplate, CancellationToken cancellationToken);
|
||||
Task PostTemplateVersion(AuditUserDetails auditUserDetails, CreateWorkflowTemplateVersion template, CancellationToken cancellationToken);
|
||||
Task DeleteTemplateVersion(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, CancellationToken cancellationToken);
|
||||
}
|
||||
@ -6,6 +6,7 @@ namespace e_suite.API.Common.repository;
|
||||
|
||||
public interface IWorkflowTemplateRepository : IRepository
|
||||
{
|
||||
public IQueryable<Workflow> GetWorkflows();
|
||||
IQueryable<WorkflowVersion> GetWorkflowVersions();
|
||||
Task EditWorkflowVersionAsync(AuditUserDetails auditUserDetails, WorkflowVersion workflowVersion, CancellationToken cancellationToken);
|
||||
}
|
||||
@ -27,6 +27,7 @@ public class WorkflowTemplateController : ESuiteControllerBase
|
||||
_workflowTemplateManager = workflowTemplateManager;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of workflow templates
|
||||
/// </summary>
|
||||
@ -37,30 +38,46 @@ public class WorkflowTemplateController : ESuiteControllerBase
|
||||
[Route("templates")]
|
||||
[AccessKey(SecurityAccess.ViewWorkflowTemplates)]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetWorkflowTemplates([FromQuery] Paging paging,CancellationToken cancellationToken = default!)
|
||||
public async Task<IActionResult> GetWorkflowTemplates([FromQuery] Paging paging, CancellationToken cancellationToken = default!)
|
||||
{
|
||||
var result = await _workflowTemplateManager.GetWorkflowTemplatesAsync(paging, cancellationToken);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of workflow templates
|
||||
/// </summary>
|
||||
/// <param name="paging"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
[Route("templateVersions")]
|
||||
[AccessKey(SecurityAccess.ViewWorkflowTemplates)]
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetWorkflowTemplateVersions([FromQuery] Paging paging,CancellationToken cancellationToken = default!)
|
||||
{
|
||||
var result = await _workflowTemplateManager.GetWorkflowTemplateVersionsAsync(paging, cancellationToken);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the details of specific template
|
||||
/// </summary>
|
||||
/// <param name="generalIdRef"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[Route("template")]
|
||||
[Route("templateVersion")]
|
||||
[HttpGet]
|
||||
[AccessKey(SecurityAccess.ViewWorkflowTemplates)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetWorkflowTemplate(
|
||||
public async Task<IActionResult> GetWorkflowTemplateVersion(
|
||||
[FromQuery] GeneralIdRef generalIdRef,
|
||||
CancellationToken cancellationToken = default!
|
||||
)
|
||||
{
|
||||
var result = await _workflowTemplateManager.GetWorkflowTemplateAsync(generalIdRef, cancellationToken);
|
||||
var result = await _workflowTemplateManager.GetWorkflowTemplateVersionAsync(generalIdRef, cancellationToken);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
@ -70,14 +87,14 @@ public class WorkflowTemplateController : ESuiteControllerBase
|
||||
/// <param name="user"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[Route("template")]
|
||||
[Route("templateVersion")]
|
||||
[HttpPut]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[AccessKey(SecurityAccess.EditWorkflowTemplate)]
|
||||
public async Task<IActionResult> EditTemplate(EditWorkflowTemplate template, CancellationToken cancellationToken = default!)
|
||||
public async Task<IActionResult> EditTemplateVersion(EditWorkflowTemplateVersion template, CancellationToken cancellationToken = default!)
|
||||
{
|
||||
await _workflowTemplateManager.EditTemplate(AuditUserDetails, template, cancellationToken);
|
||||
await _workflowTemplateManager.EditTemplateVersion(AuditUserDetails, template, cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -87,14 +104,14 @@ public class WorkflowTemplateController : ESuiteControllerBase
|
||||
/// <param name="user"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[Route("template")]
|
||||
[Route("templateVersion")]
|
||||
[HttpPatch]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[AccessKey(SecurityAccess.EditWorkflowTemplate)]
|
||||
public async Task<IActionResult> PatchWorkflowTemplate([FromQuery] IGeneralIdRef templateId, [FromBody] PatchWorkflowTemplate patchTemplate, CancellationToken cancellationToken = default!)
|
||||
public async Task<IActionResult> PatchWorkflowTemplateVersion([FromQuery] IGeneralIdRef templateId, [FromBody] PatchWorkflowTemplateVersion patchTemplate, CancellationToken cancellationToken = default!)
|
||||
{
|
||||
await _workflowTemplateManager.PatchTemplate(AuditUserDetails, templateId, patchTemplate, cancellationToken);
|
||||
await _workflowTemplateManager.PatchTemplateVersion(AuditUserDetails, templateId, patchTemplate, cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -105,17 +122,17 @@ public class WorkflowTemplateController : ESuiteControllerBase
|
||||
/// <param name="userRegistration">Contains the details that need to be supplied to create the user.</param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
[Route("template")]
|
||||
[Route("templateVersion")]
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
|
||||
[AccessKey(SecurityAccess.AddWorkflowTemplate)]
|
||||
public async Task<IActionResult> CreateWorkflowTemplate(
|
||||
[FromBody] CreateWorkflowTemplate template,
|
||||
public async Task<IActionResult> CreateWorkflowTemplateVersion(
|
||||
[FromBody] CreateWorkflowTemplateVersion template,
|
||||
CancellationToken cancellationToken = default!
|
||||
)
|
||||
{
|
||||
await _workflowTemplateManager.PostTemplate(AuditUserDetails, template, cancellationToken);
|
||||
await _workflowTemplateManager.PostTemplateVersion(AuditUserDetails, template, cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -124,18 +141,18 @@ public class WorkflowTemplateController : ESuiteControllerBase
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
[Route("template")]
|
||||
[Route("templateVersion")]
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound, Type = typeof(ProblemDetails))]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProblemDetails))]
|
||||
[AccessKey(SecurityAccess.DeleteWorkflowTemplate)]
|
||||
public async Task<IActionResult> DeleteWorkflowTemplate(
|
||||
public async Task<IActionResult> DeleteWorkflowTemplateVersion(
|
||||
[FromBody] IGeneralIdRef templateId,
|
||||
CancellationToken cancellationToken = default!
|
||||
)
|
||||
{
|
||||
await _workflowTemplateManager.DeleteTemplate(AuditUserDetails, templateId, cancellationToken);
|
||||
await _workflowTemplateManager.DeleteTemplateVersion(AuditUserDetails, templateId, cancellationToken);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
@ -60,6 +60,7 @@
|
||||
<ProjectReference Include="..\..\e-suite.Modules.SpecificationManager\e-suite.Modules.SpecificationManager\e-suite.Modules.SpecificationManager.csproj" />
|
||||
<ProjectReference Include="..\..\e-suite.Modules.SSOManager\e-suite.Modules.SSOManager\e-suite.Modules.SSOManager.csproj" />
|
||||
<ProjectReference Include="..\..\e-suite.Modules.UserManager\e-suite.Modules.UserManager\e-suite.Modules.UserManager.csproj" />
|
||||
<ProjectReference Include="..\..\e-suite.Modules.WorkflowTemplatesManager\e-suite.Modules.WorkflowTemplatesManager.csproj" />
|
||||
<ProjectReference Include="..\..\e-suite.Service.CustomFieldValidation\e-suite.Service.CustomFieldValidation\e-suite.Service.CustomFieldValidation.csproj" />
|
||||
<ProjectReference Include="..\..\e-suite.Service.Mail\e-suite.Service.Mail\e-suite.Service.Mail.csproj" />
|
||||
<ProjectReference Include="..\..\e-suite.Service.Sentinel\e-suite.Service.Sentinel\e-suite.Service.Sentinel.csproj" />
|
||||
|
||||
@ -3,6 +3,5 @@
|
||||
public class TaskDefinition
|
||||
{
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public int Order { get; set; }
|
||||
public Dictionary<string, object>? Config { get; set; }
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using e_suite.Database.Audit.Attributes;
|
||||
using e_suite.Database.Core.Models;
|
||||
using e_suite.Database.Core.Tables.Forms;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
@ -30,4 +31,6 @@ public class Workflow : IGeneralId, ISoftDeletable
|
||||
|
||||
[AuditLastUpdated]
|
||||
public DateTimeOffset LastUpdated { get; set; }
|
||||
|
||||
public ICollection<WorkflowVersion> Versions { get; set; } = [];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,8 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Style", "IDE0290:Use primary constructor", Justification = "Primary constructors do not create readonly fields, it creates writable properties instead, which is bad practice", Scope = "module")]
|
||||
17
e-suite.Modules.WorkflowTemplatesManager/IocRegistration.cs
Normal file
17
e-suite.Modules.WorkflowTemplatesManager/IocRegistration.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using Autofac;
|
||||
using e_suite.API.Common;
|
||||
using e_suite.API.Common.repository;
|
||||
using e_suite.DependencyInjection;
|
||||
using e_suite.Modules.WorkflowTemplatesManager.Repository;
|
||||
|
||||
namespace e_suite.Modules.WorkflowTemplatesManager;
|
||||
|
||||
public class IocRegistration : IIocRegistration
|
||||
{
|
||||
public void RegisterTypes(ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterType<WorkflowTemplateRepository>().As<IWorkflowTemplateRepository>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<WorkflowTemplateManager>().As<IWorkflowTemplateManager>().InstancePerLifetimeScope();
|
||||
builder.RegisterType<WorkflowConverter>().As<IWorkflowConverter>().InstancePerLifetimeScope();
|
||||
}
|
||||
}
|
||||
@ -1,22 +1,113 @@
|
||||
using e_suite.API.Common.repository;
|
||||
using e_suite.Database.Audit;
|
||||
using e_suite.Database.Core;
|
||||
using e_suite.Database.Core.Tables.Workflow;
|
||||
using e_suite.Database.Core.Extensions;
|
||||
using e_suite.Workflow.Core;
|
||||
using e_suite.Workflow.Core.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace e_suite.Modules.WorkflowTemplatesManager.Repository;
|
||||
|
||||
public interface IWorkflowConverter
|
||||
{
|
||||
WorkflowVersion DeserialiseFromDatabase(e_suite.Database.Core.Tables.Workflow.WorkflowVersion dbVersion);
|
||||
|
||||
Task<e_suite.Database.Core.Tables.Workflow.WorkflowVersion> SerialiseToDatabase(
|
||||
WorkflowVersion runtime,
|
||||
e_suite.Database.Core.Tables.Workflow.WorkflowVersion? dbObject = null,
|
||||
CancellationToken cancellationToken = default
|
||||
);
|
||||
}
|
||||
public class WorkflowConverter : IWorkflowConverter
|
||||
{
|
||||
private readonly IDomainRepository _domainRepository;
|
||||
|
||||
public WorkflowConverter(IDomainRepository domainRepository)
|
||||
{
|
||||
_domainRepository = domainRepository;
|
||||
}
|
||||
|
||||
public WorkflowVersion DeserialiseFromDatabase(e_suite.Database.Core.Tables.Workflow.WorkflowVersion dbVersion)
|
||||
{
|
||||
var runtime = new 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();
|
||||
runtime.Tasks.Add(task);
|
||||
}
|
||||
|
||||
return runtime;
|
||||
}
|
||||
|
||||
public async Task<e_suite.Database.Core.Tables.Workflow.WorkflowVersion> SerialiseToDatabase(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<WorkflowVersion> GetWorkflowVersions()
|
||||
public IQueryable<e_suite.Database.Core.Tables.Workflow.Workflow> GetWorkflows()
|
||||
{
|
||||
return DatabaseDbContext.Workflows
|
||||
.Include( x => x.Versions);
|
||||
}
|
||||
|
||||
public IQueryable<e_suite.Database.Core.Tables.Workflow.WorkflowVersion> GetWorkflowVersions()
|
||||
{
|
||||
return DatabaseDbContext.WorkflowVersions;
|
||||
}
|
||||
|
||||
public async Task EditWorkflowVersionAsync(AuditUserDetails auditUserDetails, WorkflowVersion workflowVersion, CancellationToken cancellationToken)
|
||||
public async Task EditWorkflowVersionAsync(AuditUserDetails auditUserDetails, e_suite.Database.Core.Tables.Workflow.WorkflowVersion workflowVersion, CancellationToken cancellationToken)
|
||||
{
|
||||
await DatabaseDbContext.SaveChangesAsync(auditUserDetails, cancellationToken);
|
||||
}
|
||||
|
||||
@ -3,16 +3,19 @@ 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.Database.Core.Tables.Workflow;
|
||||
using e_suite.Utilities.Pagination;
|
||||
using eSuite.Core.Miscellaneous;
|
||||
using System.Linq.Expressions;
|
||||
using e_suite.Modules.WorkflowTemplatesManager.Repository;
|
||||
|
||||
//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;
|
||||
|
||||
@ -24,16 +27,38 @@ public class WorkflowTemplateManager : IWorkflowTemplateManager
|
||||
}
|
||||
|
||||
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<WorkflowVersion, GetWorkflowTemplate>(ssoProviders, paging,
|
||||
var paginatedData = await PaginatedData.Paginate<e_suite.Database.Core.Tables.Workflow.WorkflowVersion, GetWorkflowTemplateVersion>(ssoProviders, paging,
|
||||
KeySelector, cancellationToken);
|
||||
|
||||
return paginatedData;
|
||||
}
|
||||
|
||||
private Expression<Func<WorkflowVersion, object>> KeySelector(string sortKey)
|
||||
private Expression<Func<e_suite.Database.Core.Tables.Workflow.WorkflowVersion, object>> KeySelector(string sortKey)
|
||||
{
|
||||
return sortKey?.ToLowerInvariant() switch
|
||||
{
|
||||
@ -46,24 +71,23 @@ public class WorkflowTemplateManager : IWorkflowTemplateManager
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<GetWorkflowTemplate?> GetWorkflowTemplateAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken)
|
||||
public async Task<GetWorkflowTemplateVersion?> GetWorkflowTemplateVersionAsync(GeneralIdRef generalIdRef, CancellationToken cancellationToken)
|
||||
{
|
||||
var workflowTemplate = await _workflowTemplateRepository.GetWorkflowVersions().FindByGeneralIdRefAsync(generalIdRef, cancellationToken)
|
||||
?? throw new NotFoundException("Unable to find Workflow Version");
|
||||
return new GetWorkflowTemplate(workflowTemplate);
|
||||
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 EditTemplate(
|
||||
public async Task EditTemplateVersion(
|
||||
AuditUserDetails auditUserDetails,
|
||||
EditWorkflowTemplate template,
|
||||
EditWorkflowTemplateVersion template,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
await AlterWorkflowTemplateVersionAsync(auditUserDetails, template.ToGeneralIdRef()!, async version =>
|
||||
{
|
||||
var domain = await _domainRepository.GetDomainById(template.DomainId, cancellationToken);
|
||||
if (domain is null)
|
||||
throw new NotFoundException("Unable to find Domain with provided id");
|
||||
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;
|
||||
@ -71,34 +95,37 @@ public class WorkflowTemplateManager : IWorkflowTemplateManager
|
||||
version.ActivityNameTemplate = template.ActivityNameTemplate;
|
||||
version.Deleted = false;
|
||||
version.Version = template.Version;
|
||||
//version.WorkflowId
|
||||
version.Tasks = template.Tasks;
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task PatchTemplate(
|
||||
public async Task PatchTemplateVersion(
|
||||
AuditUserDetails auditUserDetails,
|
||||
IGeneralIdRef templateId,
|
||||
PatchWorkflowTemplate patchTemplate,
|
||||
PatchWorkflowTemplateVersion patchTemplate,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
var patch = _patchFactory.Create(patchTemplate);
|
||||
await AlterWorkflowTemplateVersionAsync(auditUserDetails, templateId, async version =>
|
||||
{
|
||||
patch.ApplyTo(version);
|
||||
await patch.ApplyTo(version);
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task PostTemplate(
|
||||
public async Task PostTemplateVersion(
|
||||
AuditUserDetails auditUserDetails,
|
||||
CreateWorkflowTemplate template,
|
||||
CreateWorkflowTemplateVersion template,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
|
||||
//var workflowTemplate = _workflowConverter.DeserialiseFromDatabase(dbWorkflowTemplate);
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public async Task DeleteTemplate(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, CancellationToken cancellationToken)
|
||||
public async Task DeleteTemplateVersion(AuditUserDetails auditUserDetails, IGeneralIdRef templateId, CancellationToken cancellationToken)
|
||||
{
|
||||
await AlterWorkflowTemplateVersionAsync(auditUserDetails, templateId, async version =>
|
||||
{
|
||||
@ -109,15 +136,13 @@ public class WorkflowTemplateManager : IWorkflowTemplateManager
|
||||
private async Task AlterWorkflowTemplateVersionAsync(
|
||||
AuditUserDetails auditUserDetails,
|
||||
IGeneralIdRef generalIdRef,
|
||||
Func<WorkflowVersion, Task> applyChanges,
|
||||
Func<e_suite.Database.Core.Tables.Workflow.WorkflowVersion, Task> applyChanges,
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
await _workflowTemplateRepository.TransactionAsync(async () =>
|
||||
{
|
||||
var workflowVersion = await _workflowTemplateRepository.GetWorkflowVersions().FindByGeneralIdRefAsync(generalIdRef, cancellationToken);
|
||||
if (workflowVersion is null)
|
||||
throw new NotFoundException("SsoProvider with this id does not exists");
|
||||
var workflowVersion = await _workflowTemplateRepository.GetWorkflowVersions().FindByGeneralIdRefAsync(generalIdRef, cancellationToken) ?? throw new NotFoundException("SsoProvider with this id does not exists");
|
||||
|
||||
await applyChanges(workflowVersion);
|
||||
|
||||
|
||||
@ -1,38 +1,105 @@
|
||||
using e_suite.Workflow.Core.Attributes;
|
||||
using e_suite.Workflow.Core.Enums;
|
||||
using e_suite.Database.Core.Models;
|
||||
using e_suite.Workflow.Core.Attributes;
|
||||
using e_suite.Workflow.Core.Interfaces;
|
||||
using e_suite.Workflow.Core.Tasks;
|
||||
using System.Reflection;
|
||||
|
||||
namespace e_suite.Workflow.Core.Extensions;
|
||||
|
||||
//copied from Database.core.
|
||||
public class TaskDefinition
|
||||
{
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public int Order { get; set; }
|
||||
public Dictionary<string, object>? Config { get; set; }
|
||||
}
|
||||
|
||||
public static class TaskExtensions
|
||||
{
|
||||
public static TaskDefinition ToDefinition(this ITask task, int order)
|
||||
private static Dictionary<string, object?> ToConfigDictionary(this ITask task)
|
||||
{
|
||||
if (task is ITemplateValidatable v)
|
||||
var dictionary = new Dictionary<string, object?>();
|
||||
|
||||
var type = task.GetType();
|
||||
var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
var errors = v.ValidateForTemplate().ToList();
|
||||
if (errors.Count != 0)
|
||||
throw new InvalidOperationException(
|
||||
$"Task {task.GetType().Name} is invalid: {string.Join("; ", errors)}");
|
||||
if (!prop.CanRead)
|
||||
continue;
|
||||
|
||||
if (!prop.CanWrite)
|
||||
continue;
|
||||
|
||||
var value = prop.GetValue(task);
|
||||
|
||||
dictionary[prop.Name] = value;
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public static ITask ToTask(this TaskDefinition definition)
|
||||
{
|
||||
var type = Type.GetType(definition.Type);
|
||||
|
||||
if (type == null)
|
||||
throw new InvalidOperationException($"Unknown task type '{definition.Type}'.");
|
||||
|
||||
var instance = Activator.CreateInstance(type) as ITask;
|
||||
|
||||
if (instance == null)
|
||||
throw new InvalidOperationException($"Type '{definition.Type}' does not implement ITask.");
|
||||
|
||||
FromConfigDictionary(instance, definition.Config);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static void FromConfigDictionary(this object obj, Dictionary<string, object?> dict)
|
||||
{
|
||||
var type = obj.GetType();
|
||||
|
||||
foreach (var kvp in dict)
|
||||
{
|
||||
var prop = type.GetProperty(kvp.Key);
|
||||
if (prop == null || !prop.CanWrite)
|
||||
continue;
|
||||
|
||||
var targetType = prop.PropertyType;
|
||||
var value = kvp.Value;
|
||||
|
||||
// Handle enums (the only case where JSON gives you a string)
|
||||
if (value != null && targetType.IsEnum)
|
||||
{
|
||||
value = Enum.Parse(targetType, value.ToString()!, ignoreCase: true);
|
||||
}
|
||||
|
||||
prop.SetValue(obj, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static TaskDefinition ToDefinition(this ITask task)
|
||||
{
|
||||
if (task is null)
|
||||
throw new NullReferenceException();
|
||||
|
||||
|
||||
return new TaskDefinition
|
||||
{
|
||||
Type = task.GetType().AssemblyQualifiedName!,
|
||||
Order = order,
|
||||
Config = ExtractConfig(task)
|
||||
Type = task.GetType().AssemblyQualifiedName,
|
||||
Config = task.ToConfigDictionary()
|
||||
};
|
||||
}
|
||||
|
||||
//public static TaskDefinition ToDefinition(this ITask task)
|
||||
//{
|
||||
// if (task is ITemplateValidatable v)
|
||||
// {
|
||||
// var errors = v.ValidateForTemplate().ToList();
|
||||
// if (errors.Count != 0)
|
||||
// throw new InvalidOperationException(
|
||||
// $"Task {task.GetType().Name} is invalid: {string.Join("; ", errors)}");
|
||||
// }
|
||||
|
||||
// return new TaskDefinition
|
||||
// {
|
||||
// Type = task.GetType().AssemblyQualifiedName!,
|
||||
// Config = ExtractConfig(task)
|
||||
// };
|
||||
//}
|
||||
|
||||
private static Dictionary<string, object> ExtractConfig(object task)
|
||||
{
|
||||
var dict = new Dictionary<string, object>();
|
||||
@ -52,53 +119,53 @@ public static class TaskExtensions
|
||||
return dict;
|
||||
}
|
||||
|
||||
public static ITask ToTask(this TaskDefinition def)
|
||||
{
|
||||
var type = Type.GetType(def.Type, throwOnError: true)!;
|
||||
var task = (ITask)Activator.CreateInstance(type)!;
|
||||
//public static ITask ToTask(this TaskDefinition def)
|
||||
//{
|
||||
// var type = Type.GetType(def.Type, throwOnError: true)!;
|
||||
// var task = (ITask)Activator.CreateInstance(type)!;
|
||||
|
||||
if (def.Config != null)
|
||||
foreach (var kvp in def.Config)
|
||||
{
|
||||
var prop = type.GetProperty(kvp.Key);
|
||||
if (prop == null || !prop.CanWrite) continue;
|
||||
if (prop.IsDefined(typeof(RuntimeOnlyAttribute), inherit: true))
|
||||
continue;
|
||||
// if (def.Config != null)
|
||||
// foreach (var kvp in def.Config)
|
||||
// {
|
||||
// var prop = type.GetProperty(kvp.Key);
|
||||
// if (prop == null || !prop.CanWrite) continue;
|
||||
// if (prop.IsDefined(typeof(RuntimeOnlyAttribute), inherit: true))
|
||||
// continue;
|
||||
|
||||
object? converted = ConvertValue(kvp.Value, prop.PropertyType);
|
||||
prop.SetValue(task, converted);
|
||||
}
|
||||
// object? converted = ConvertValue(kvp.Value, prop.PropertyType);
|
||||
// prop.SetValue(task, converted);
|
||||
// }
|
||||
|
||||
if (task is ITemplateValidatable v)
|
||||
{
|
||||
var errors = v.ValidateForTemplate().ToList();
|
||||
if (errors.Count != 0)
|
||||
throw new InvalidOperationException(
|
||||
$"Task {task.GetType().Name} is invalid: {string.Join("; ", errors)}");
|
||||
}
|
||||
// if (task is ITemplateValidatable v)
|
||||
// {
|
||||
// var errors = v.ValidateForTemplate().ToList();
|
||||
// if (errors.Count != 0)
|
||||
// throw new InvalidOperationException(
|
||||
// $"Task {task.GetType().Name} is invalid: {string.Join("; ", errors)}");
|
||||
// }
|
||||
|
||||
return task;
|
||||
}
|
||||
// return task;
|
||||
//}
|
||||
|
||||
private static object? ConvertValue(object? value, Type targetType)
|
||||
{
|
||||
if (value == null) return null;
|
||||
//private static object? ConvertValue(object? value, Type targetType)
|
||||
//{
|
||||
// if (value == null) return null;
|
||||
|
||||
// Handle enums
|
||||
if (targetType.IsEnum)
|
||||
return Enum.Parse(targetType, value.ToString()!);
|
||||
// // Handle enums
|
||||
// if (targetType.IsEnum)
|
||||
// return Enum.Parse(targetType, value.ToString()!);
|
||||
|
||||
// Handle Guid
|
||||
if (targetType == typeof(Guid))
|
||||
return Guid.Parse(value.ToString()!);
|
||||
// // Handle Guid
|
||||
// if (targetType == typeof(Guid))
|
||||
// return Guid.Parse(value.ToString()!);
|
||||
|
||||
// Handle nullable types
|
||||
var underlying = Nullable.GetUnderlyingType(targetType);
|
||||
if (underlying != null)
|
||||
return Convert.ChangeType(value, underlying);
|
||||
// // Handle nullable types
|
||||
// var underlying = Nullable.GetUnderlyingType(targetType);
|
||||
// if (underlying != null)
|
||||
// return Convert.ChangeType(value, underlying);
|
||||
|
||||
return Convert.ChangeType(value, targetType);
|
||||
}
|
||||
// return Convert.ChangeType(value, targetType);
|
||||
//}
|
||||
|
||||
|
||||
//Todo can only be on a run-time instance
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
using e_suite.Workflow.Core.Interfaces;
|
||||
|
||||
namespace e_suite.Workflow.Core.Extensions;
|
||||
|
||||
public static class WorkflowExtensions
|
||||
public static class WorkflowVersionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true once the workflow has met any requirements that are needed to change the state to active.
|
||||
/// For example, earliest start time has passed.
|
||||
/// Or required starting information is now available.
|
||||
/// </summary>
|
||||
public static bool ReadyToActivate(this IWorkflow workflow)
|
||||
public static bool ReadyToActivate(this IWorkflowVersion workflow)
|
||||
{
|
||||
//todo Check to see if the StartDate has passed.
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -12,7 +12,7 @@ public interface ITask
|
||||
/// <summary>
|
||||
/// ID of the parent of this task. It could be either a Task or a Workflow.
|
||||
/// </summary>
|
||||
ITask Parent { get; }
|
||||
ITask Parent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the task as seen by users, must be unique in the workflow.
|
||||
|
||||
@ -4,7 +4,7 @@ using eSuite.Core.Miscellaneous;
|
||||
|
||||
namespace e_suite.Workflow.Core.Interfaces;
|
||||
|
||||
public interface IWorkflow : IStage<GeneralTaskAttribute>
|
||||
public interface IWorkflowVersion : IStage<GeneralTaskAttribute>
|
||||
{
|
||||
/// <summary>
|
||||
/// Client domain to which the workflow belongs.
|
||||
|
||||
@ -16,7 +16,7 @@ public class WorkflowTemplate: IGeneralId
|
||||
public required string Name { get; set; }
|
||||
}
|
||||
|
||||
public class WorkflowVersion : IGeneralId, IWorkflow
|
||||
public class WorkflowVersion : IGeneralId, IWorkflowVersion
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public Guid Guid { get; set; }
|
||||
@ -25,7 +25,7 @@ public class WorkflowVersion : IGeneralId, IWorkflow
|
||||
|
||||
public required long Version { get; set; }
|
||||
|
||||
public ICollection<ITask> Tasks { get; } = new List<ITask>(); //Serialise to Json.
|
||||
public ICollection<ITask> Tasks { get; } = []; //Serialise to Json.
|
||||
public required IGeneralIdRef Domain { get; set; }
|
||||
public WorkflowState CurrentState { get; set; } = WorkflowState.Pending;
|
||||
public required string ActivityNameTemplate { get; set; }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=authorisation/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Authorised/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Deserialise/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=execption/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=jwks/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=organisation/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user