Implement API to delete specific workflow definition version

This commit is contained in:
Sipke Schoorstra 2023-07-18 22:33:59 +02:00
parent 06c332389a
commit 07c9783363
6 changed files with 107 additions and 34 deletions

View file

@ -69,10 +69,18 @@ public interface IWorkflowDefinitionsApi
/// <summary>
/// Deletes a workflow definition.
/// </summary>
/// <param name="definitionId">The ID of the workflow definition to delete.</param>
/// <param name="definitionId">The definition ID of the workflow definition, and all of its versions, to delete.</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Delete("/workflow-definitions/{definitionId}")]
Task DeleteAsync(string definitionId, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a workflow definition version.
/// </summary>
/// <param name="id">The ID of a specific workflow definition version to delete.</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Delete("/workflow-definition-versions/{id}")]
Task DeleteVersionAsync(string id, CancellationToken cancellationToken = default);
/// <summary>
/// Publishes a workflow definition.

View file

@ -0,0 +1,32 @@
using Elsa.Abstractions;
using Elsa.Workflows.Management.Contracts;
using JetBrains.Annotations;
namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.DeleteVersion;
[PublicAPI]
internal class DeleteVersion : ElsaEndpoint<Request>
{
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
public DeleteVersion(IWorkflowDefinitionManager workflowDefinitionManager)
{
_workflowDefinitionManager = workflowDefinitionManager;
}
public override void Configure()
{
Delete("/workflow-definition-versions/{id}");
ConfigurePermissions("delete:workflow-definitions");
}
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
{
var deleted = await _workflowDefinitionManager.DeleteByIdAsync(request.Id, cancellationToken);
if (!deleted)
await SendNotFoundAsync(cancellationToken);
else
await SendNoContentAsync(cancellationToken);
}
}

View file

@ -0,0 +1,6 @@
namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.DeleteVersion;
internal class Request
{
public string Id { get; set; } = default!;
}

View file

@ -15,6 +15,13 @@ public interface IWorkflowDefinitionManager
/// <returns>The number of deleted workflow definitions.</returns>
Task<int> DeleteByDefinitionIdAsync(string definitionId, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a specific version of a workflow definition.
/// </summary>
/// <param name="id">The ID of the workflow definition version.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>True if the workflow definition version was deleted, otherwise false.</returns>
Task<bool> DeleteByIdAsync(string id, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a specific workflow definition version.

View file

@ -1,4 +1,5 @@
using Elsa.Mediator.Contracts;
using Elsa.Workflows.Management.Entities;
using JetBrains.Annotations;
namespace Elsa.Workflows.Management.Notifications;
@ -6,7 +7,5 @@ namespace Elsa.Workflows.Management.Notifications;
/// <summary>
/// A notification that is sent when a workflow definition version is deleted.
/// </summary>
/// <param name="DefinitionId">The ID of the workflow definition.</param>
/// <param name="Version">The version number of the workflow definition.</param>
[PublicAPI]
public record WorkflowDefinitionVersionDeleted(string DefinitionId, int Version) : INotification;
public record WorkflowDefinitionVersionDeleted(WorkflowDefinition WorkflowDefinition) : INotification;

View file

@ -48,6 +48,18 @@ public class WorkflowDefinitionManager : IWorkflowDefinitionManager
return count;
}
/// <inheritdoc />
public async Task<bool> DeleteByIdAsync(string id, CancellationToken cancellationToken = default)
{
var filter = new WorkflowDefinitionFilter { Id = id};
var definition = await _store.FindAsync(filter, cancellationToken);
if (definition == null)
return false;
return await DeleteVersionAsync(definition, cancellationToken);
}
/// <inheritdoc />
public async Task<int> BulkDeleteByDefinitionIdsAsync(IEnumerable<string> definitionIds, CancellationToken cancellationToken = default)
{
@ -61,37 +73,13 @@ public class WorkflowDefinitionManager : IWorkflowDefinitionManager
/// <inheritdoc />
public async Task<bool> DeleteVersionAsync(string definitionId, int versionToDelete, CancellationToken cancellationToken = default)
{
var filter = new WorkflowDefinitionFilter { DefinitionId = definitionId, VersionOptions = VersionOptions.LatestAndPublished };
var workflows = (await _store.FindManyAsync(filter, cancellationToken)).ToList();
var latestVersion = workflows.WithVersion(VersionOptions.Latest).First();
var publishedVersion = workflows.WithVersion(VersionOptions.Published).FirstOrDefault();
if (versionToDelete == publishedVersion?.Version)
{
throw new Exception("Published version cannot be deleted");
}
filter = new WorkflowDefinitionFilter { DefinitionId = definitionId, VersionOptions = VersionOptions.SpecificVersion(versionToDelete) };
var isDeleted = await _store.DeleteAsync(filter, cancellationToken) > 0;
if (!isDeleted)
var filter = new WorkflowDefinitionFilter { DefinitionId = definitionId, VersionOptions = VersionOptions.SpecificVersion(versionToDelete) };
var definitionToDelete = await _store.FindAsync(filter, cancellationToken);
if (definitionToDelete == null)
return false;
await _notificationSender.SendAsync(new WorkflowDefinitionVersionDeleted(definitionId, versionToDelete), cancellationToken);
if (latestVersion.Version != versionToDelete)
return isDeleted;
filter = new WorkflowDefinitionFilter { DefinitionId = definitionId };
var lastVersion = await _store.FindLastVersionAsync(filter, cancellationToken);
if (lastVersion is null)
return isDeleted;
lastVersion.IsLatest = true;
await _store.SaveAsync(lastVersion, cancellationToken);
return isDeleted;
return await DeleteVersionAsync(definitionToDelete, cancellationToken);
}
/// <inheritdoc />
@ -159,4 +147,37 @@ public class WorkflowDefinitionManager : IWorkflowDefinitionManager
return updatedWorkflowDefinitions;
}
private async Task<bool> DeleteVersionAsync(WorkflowDefinition definitionToDelete, CancellationToken cancellationToken)
{
if (definitionToDelete.IsPublished)
{
throw new Exception("Published version cannot be deleted before retracting it");
}
var filter = new WorkflowDefinitionFilter { Id = definitionToDelete.Id };
var isDeleted = await _store.DeleteAsync(filter, cancellationToken) > 0;
if (!isDeleted)
return false;
await _notificationSender.SendAsync(new WorkflowDefinitionVersionDeleted(definitionToDelete), cancellationToken);
if (!definitionToDelete.IsLatest)
return isDeleted;
// The deleted version was also the latest version, so we need to update the current latest version to "IsLatest = true".
filter = new WorkflowDefinitionFilter { DefinitionId = definitionToDelete.DefinitionId };
var lastVersion = await _store.FindLastVersionAsync(filter, cancellationToken);
// If there are no more versions left, then we're done.
if (lastVersion is null)
return isDeleted;
// Otherwise, we need to update the latest version.
lastVersion.IsLatest = true;
await _store.SaveAsync(lastVersion, cancellationToken);
return isDeleted;
}
}