V3 Bulk Actions API Endpoints (#3064)

* Add bulk-delete API for workflow instances

* Add bulk-cancel API for workflow instances (stub)

* Add bulk-delete API for workflow definitions

* Add bulk-publish API for workflow definitions

* Add bulk-retract API for workflow definitions
This commit is contained in:
Sipke Schoorstra 2022-05-24 20:51:12 +02:00 committed by GitHub
parent 48443566b9
commit 750320082c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 260 additions and 1 deletions

View file

@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Elsa.AspNetCore;
using Elsa.Persistence.Services;
using Elsa.Serialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Api.Endpoints.WorkflowDefinitions;
[Area(AreaNames.Elsa)]
[ApiEndpoint(ControllerNames.WorkflowDefinitions, "BulkDelete")]
public class BulkDelete : Controller
{
private readonly IWorkflowDefinitionStore _store;
private readonly WorkflowSerializerOptionsProvider _serializerOptionsProvider;
public BulkDelete(IWorkflowDefinitionStore store, WorkflowSerializerOptionsProvider serializerOptionsProvider)
{
_store = store;
_serializerOptionsProvider = serializerOptionsProvider;
}
[HttpPost]
public async Task<IActionResult> HandleAsync(CancellationToken cancellationToken)
{
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
var model = await Request.ReadFromJsonAsync<BulkDeleteWorkflowDefinitionsRequest>(serializerOptions, cancellationToken);
var count = await _store.DeleteManyByDefinitionIdsAsync(model!.DefinitionIds, cancellationToken);
return Json(new BulkDeleteWorkflowDefinitionsResponse(count), serializerOptions);
}
public record BulkDeleteWorkflowDefinitionsRequest(ICollection<string> DefinitionIds);
public record BulkDeleteWorkflowDefinitionsResponse([property: JsonPropertyName("deleted")] int DeletedCount);
}

View file

@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Elsa.AspNetCore;
using Elsa.Management.Services;
using Elsa.Persistence.Models;
using Elsa.Persistence.Services;
using Elsa.Serialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Api.Endpoints.WorkflowDefinitions;
[Area(AreaNames.Elsa)]
[ApiEndpoint(ControllerNames.WorkflowDefinitions, "BulkPublish")]
public class BulkPublish : Controller
{
private readonly IWorkflowDefinitionStore _store;
private readonly IWorkflowPublisher _workflowPublisher;
private readonly WorkflowSerializerOptionsProvider _serializerOptionsProvider;
public BulkPublish(IWorkflowDefinitionStore store, IWorkflowPublisher workflowPublisher, WorkflowSerializerOptionsProvider serializerOptionsProvider)
{
_store = store;
_workflowPublisher = workflowPublisher;
_serializerOptionsProvider = serializerOptionsProvider;
}
[HttpPost]
public async Task<IActionResult> HandleAsync(CancellationToken cancellationToken)
{
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
var model = (await Request.ReadFromJsonAsync<BulkPublishWorkflowDefinitionsRequest>(serializerOptions, cancellationToken))!;
var published = new List<string>();
var notFound = new List<string>();
var alreadyPublished = new List<string>();
foreach (var definitionId in model.DefinitionIds)
{
var definition = await _store.FindByDefinitionIdAsync(definitionId, VersionOptions.Latest, cancellationToken);
if (definition == null)
{
notFound.Add(definitionId);
continue;
}
if (definition.IsPublished)
{
alreadyPublished.Add(definitionId);
continue;
}
await _workflowPublisher.PublishAsync(definition, cancellationToken);
published.Add(definitionId);
}
return Json(new BulkPublishWorkflowDefinitionsResponse(published, alreadyPublished, notFound), serializerOptions);
}
public record BulkPublishWorkflowDefinitionsRequest(ICollection<string> DefinitionIds);
public record BulkPublishWorkflowDefinitionsResponse(ICollection<string> Published, ICollection<string> AlreadyPublished, ICollection<string> NotFound);
}

View file

@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Elsa.AspNetCore;
using Elsa.Management.Services;
using Elsa.Persistence.Models;
using Elsa.Persistence.Services;
using Elsa.Serialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Api.Endpoints.WorkflowDefinitions;
[Area(AreaNames.Elsa)]
[ApiEndpoint(ControllerNames.WorkflowDefinitions, "BulkRetract")]
public class BulkRetract : Controller
{
private readonly IWorkflowDefinitionStore _store;
private readonly IWorkflowPublisher _workflowPublisher;
private readonly WorkflowSerializerOptionsProvider _serializerOptionsProvider;
public BulkRetract(IWorkflowDefinitionStore store, IWorkflowPublisher workflowPublisher, WorkflowSerializerOptionsProvider serializerOptionsProvider)
{
_store = store;
_workflowPublisher = workflowPublisher;
_serializerOptionsProvider = serializerOptionsProvider;
}
[HttpPost]
public async Task<IActionResult> HandleAsync(CancellationToken cancellationToken)
{
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
var model = (await Request.ReadFromJsonAsync<BulkRetractWorkflowDefinitionsRequest>(serializerOptions, cancellationToken))!;
var retracted = new List<string>();
var notFound = new List<string>();
var notPublished = new List<string>();
foreach (var definitionId in model.DefinitionIds)
{
var definition = await _store.FindByDefinitionIdAsync(definitionId, VersionOptions.Latest, cancellationToken);
if (definition == null)
{
notFound.Add(definitionId);
continue;
}
if (!definition.IsPublished)
{
notPublished.Add(definitionId);
continue;
}
await _workflowPublisher.RetractAsync(definition, cancellationToken);
retracted.Add(definitionId);
}
return Json(new BulkRetractWorkflowDefinitionsResponse(retracted, notPublished, notFound), serializerOptions);
}
public record BulkRetractWorkflowDefinitionsRequest(ICollection<string> DefinitionIds);
public record BulkRetractWorkflowDefinitionsResponse(ICollection<string> Retracted, ICollection<string> NotPublished, ICollection<string> NotFound);
}

View file

@ -36,6 +36,12 @@ public class Retract : Controller
if (definition == null)
return NotFound();
if (!definition.IsPublished)
return BadRequest(new
{
Message = $"Workflow with id {definitionId} is not published"
});
await _workflowPublisher.RetractAsync(definition, cancellationToken);
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();

View file

@ -0,0 +1,39 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Elsa.AspNetCore;
using Elsa.Persistence.Services;
using Elsa.Serialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Api.Endpoints.WorkflowInstances;
[Area(AreaNames.Elsa)]
[ApiEndpoint(ControllerNames.WorkflowInstances, "BulkCancel")]
public class BulkCancel : Controller
{
private readonly WorkflowSerializerOptionsProvider _serializerOptionsProvider;
public BulkCancel(WorkflowSerializerOptionsProvider serializerOptionsProvider)
{
_serializerOptionsProvider = serializerOptionsProvider;
}
[HttpPost]
public async Task<IActionResult> HandleAsync(CancellationToken cancellationToken)
{
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
var model = await Request.ReadFromJsonAsync<BulkCancelWorkflowInstancesRequest>(serializerOptions, cancellationToken);
// TODO: Implement workflow cancellation.
var count = -1;
return Json(new BulkCancelWorkflowInstancesResponse(count), serializerOptions);
}
public record BulkCancelWorkflowInstancesRequest(ICollection<string> Ids);
public record BulkCancelWorkflowInstancesResponse([property: JsonPropertyName("cancelled")] int CancelledCount);
}

View file

@ -0,0 +1,40 @@
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Elsa.AspNetCore;
using Elsa.Persistence.Services;
using Elsa.Serialization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Elsa.Api.Endpoints.WorkflowInstances;
[Area(AreaNames.Elsa)]
[ApiEndpoint(ControllerNames.WorkflowInstances, "BulkDelete")]
public class BulkDelete : Controller
{
private readonly IWorkflowInstanceStore _store;
private readonly WorkflowSerializerOptionsProvider _serializerOptionsProvider;
public BulkDelete(IWorkflowInstanceStore store, WorkflowSerializerOptionsProvider serializerOptionsProvider)
{
_store = store;
_serializerOptionsProvider = serializerOptionsProvider;
}
[HttpPost]
public async Task<IActionResult> HandleAsync(CancellationToken cancellationToken)
{
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
var model = await Request.ReadFromJsonAsync<BulkDeleteWorkflowInstancesRequest>(serializerOptions, cancellationToken);
var count = await _store.DeleteManyAsync(model!.Ids, cancellationToken);
return Json(new BulkDeleteWorkflowInstancesResponse(count), serializerOptions);
}
public record BulkDeleteWorkflowInstancesRequest(ICollection<string> Ids);
public record BulkDeleteWorkflowInstancesResponse([property: JsonPropertyName("deleted")] int DeletedCount);
}

View file

@ -30,8 +30,13 @@ public static class EndpointRouteBuilderExtensions
Map("WorkflowDefinitions.Dispatch", "workflow-definitions/{definitionId}/dispatch", new { Controller = ControllerNames.WorkflowDefinitions, Action = "Dispatch" });
Map("WorkflowDefinitions.Execute", "workflow-definitions/{definitionId}/execute", new { Controller = ControllerNames.WorkflowDefinitions, Action = "Execute" });
Map("WorkflowDefinitions.Export", "workflow-definitions/{definitionId}/export", new { Controller = ControllerNames.WorkflowDefinitions, Action = "Export" });
Map("WorkflowDefinitions.BulkDelete", "bulk-actions/delete/workflow-definitions/by-definition-id", new { Controller = ControllerNames.WorkflowDefinitions, Action = "BulkDelete" });
Map("WorkflowDefinitions.BulkPublish", "bulk-actions/publish/workflow-definitions/by-definition-id", new { Controller = ControllerNames.WorkflowDefinitions, Action = "BulkPublish" });
Map("WorkflowDefinitions.BulkRetract", "bulk-actions/retract/workflow-definitions/by-definition-id", new { Controller = ControllerNames.WorkflowDefinitions, Action = "BulkRetract" });
// Workflow Instances.
Map("WorkflowInstances.BulkDelete", "bulk-actions/delete/workflow-instances/by-id", new { Controller = ControllerNames.WorkflowInstances, Action = "BulkDelete" });
Map("WorkflowInstances.BulkCancel", "bulk-actions/cancel/workflow-instances/by-id", new { Controller = ControllerNames.WorkflowInstances, Action = "BulkCancel" });
Map("WorkflowInstances.Get", "workflow-instances/{id}", new { Controller = ControllerNames.WorkflowInstances, Action = "Get" });
Map("WorkflowInstances.Delete", "workflow-instances/{id}", new { Controller = ControllerNames.WorkflowInstances, Action = "Delete" });
Map("WorkflowInstances.List", "workflow-instances", new { Controller = ControllerNames.WorkflowInstances, Action = "List" });
@ -42,7 +47,7 @@ public static class EndpointRouteBuilderExtensions
Map("Labels.Get", "labels/{id}", new { Controller = ControllerNames.Labels, Action = "Get" });
Map("Labels.Delete", "labels/{id}", new { Controller = ControllerNames.Labels, Action = "Delete" });
Map("Labels.List", "labels", new { Controller = ControllerNames.Labels, Action = "List" });
// Workflow Definition Labels
Map("WorkflowDefinitions.Labels.Update", "workflow-definitions/{id}/labels", new { Controller = ControllerNames.WorkflowDefinitionLabels, Action = "Update" });
Map("WorkflowDefinitions.Labels.Get", "workflow-definitions/{id}/labels", new { Controller = ControllerNames.WorkflowDefinitionLabels, Action = "Get" });