diff --git a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs
index 714b692ff..73205909b 100644
--- a/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs
+++ b/src/clients/Elsa.Api.Client/Resources/WorkflowDefinitions/Contracts/IWorkflowDefinitionsApi.cs
@@ -174,7 +174,7 @@ public interface IWorkflowDefinitionsApi
///
/// The files to import.
/// The cancellation token.
- [Post("/workflow-definitions/import")]
+ [Post("/workflow-definitions/import-files")]
[Multipart]
Task ImportFilesAsync([AliasAs("files")] List files, CancellationToken cancellationToken = default);
diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Import/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Import/Endpoint.cs
index 3849c81c9..d519706af 100644
--- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Import/Endpoint.cs
+++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Import/Endpoint.cs
@@ -39,84 +39,29 @@ internal class Import : ElsaEndpoint
Routes("workflow-definitions/import", "workflow-definitions/{definitionId}/import");
Verbs(FastEndpoints.Http.POST, FastEndpoints.Http.PUT);
ConfigurePermissions("write:workflow-definitions");
- AllowFileUploads();
}
///
public override async Task HandleAsync(WorkflowDefinitionModel model, CancellationToken cancellationToken)
{
- if (Files.Any())
- {
- var count = await ImportFilesAsync(Files, cancellationToken);
-
- if (!ValidationFailed)
- await SendOkAsync(new { Count = count }, cancellationToken);
- }
- else
- {
- var definitionId = model.DefinitionId;
- var isNew = string.IsNullOrWhiteSpace(definitionId);
- var result = await ImportSingleWorkflowDefinitionAsync(model, cancellationToken);
- var definition = result.WorkflowDefinition;
- var updatedModel = await _workflowDefinitionMapper.MapAsync(definition, cancellationToken);
+ var definitionId = model.DefinitionId;
+ var isNew = string.IsNullOrWhiteSpace(definitionId);
+ var result = await ImportSingleWorkflowDefinitionAsync(model, cancellationToken);
+ var definition = result.WorkflowDefinition;
+ var updatedModel = await _workflowDefinitionMapper.MapAsync(definition, cancellationToken);
- if (result.Succeeded)
- {
- if (isNew)
- await SendCreatedAtAsync(new { DefinitionId = definitionId }, updatedModel, cancellation: cancellationToken);
- else
- await SendOkAsync(updatedModel, cancellationToken);
- }
+ if (result.Succeeded)
+ {
+ if (isNew)
+ await SendCreatedAtAsync(new { DefinitionId = definitionId }, updatedModel, cancellation: cancellationToken);
+ else
+ await SendOkAsync(updatedModel, cancellationToken);
}
if (ValidationFailed)
await SendErrorsAsync(400, cancellationToken);
}
- private async Task ImportFilesAsync(IFormFileCollection files, CancellationToken cancellationToken)
- {
- var count = 0;
-
- foreach (var file in files)
- {
- var fileStream = file.OpenReadStream();
-
- // Check if the file is a JSON file or a ZIP file.
- var isJsonFile = file.ContentType == "application/json";
-
- // If the file is a JSON file, read it.
- if (isJsonFile)
- {
- await ImportJsonStreamAsync(fileStream, cancellationToken);
- count++;
- }
- else
- {
- // If the file is a ZIP file, extract the JSON files and read them.
- var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read);
-
- foreach (var entry in zipArchive.Entries)
- {
- if (!entry.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
- continue;
-
- var jsonStream = entry.Open();
- await ImportJsonStreamAsync(jsonStream, cancellationToken);
- count++;
- }
- }
- }
-
- return count;
- }
-
- private async Task ImportJsonStreamAsync(Stream jsonStream, CancellationToken cancellationToken)
- {
- var json = await new StreamReader(jsonStream).ReadToEndAsync();
- var model = _apiSerializer.Deserialize(json);
- await ImportSingleWorkflowDefinitionAsync(model, cancellationToken);
- }
-
private async Task ImportSingleWorkflowDefinitionAsync(WorkflowDefinitionModel model, CancellationToken cancellationToken)
{
// Import workflow
diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/ImportFiles/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/ImportFiles/Endpoint.cs
new file mode 100644
index 000000000..f63519716
--- /dev/null
+++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/ImportFiles/Endpoint.cs
@@ -0,0 +1,122 @@
+using System.IO.Compression;
+using Elsa.Abstractions;
+using Elsa.Workflows.Core.Contracts;
+using Elsa.Workflows.Management.Contracts;
+using Elsa.Workflows.Management.Mappers;
+using Elsa.Workflows.Management.Models;
+using JetBrains.Annotations;
+using Microsoft.AspNetCore.Http;
+
+namespace Elsa.Workflows.Api.Endpoints.WorkflowDefinitions.ImportFiles;
+
+///
+/// Imports JSON and/or ZIP files containing a workflow definitions.
+///
+[PublicAPI]
+internal class ImportFiles : ElsaEndpoint
+{
+ private readonly IWorkflowDefinitionService _workflowDefinitionService;
+ private readonly IWorkflowDefinitionImporter _workflowDefinitionImporter;
+ private readonly WorkflowDefinitionMapper _workflowDefinitionMapper;
+ private readonly IApiSerializer _apiSerializer;
+
+ ///
+ public ImportFiles(
+ IWorkflowDefinitionService workflowDefinitionService,
+ IWorkflowDefinitionImporter workflowDefinitionImporter,
+ WorkflowDefinitionMapper workflowDefinitionMapper,
+ IApiSerializer apiSerializer)
+ {
+ _workflowDefinitionService = workflowDefinitionService;
+ _workflowDefinitionImporter = workflowDefinitionImporter;
+ _workflowDefinitionMapper = workflowDefinitionMapper;
+ _apiSerializer = apiSerializer;
+ }
+
+ ///
+ public override void Configure()
+ {
+ Post("workflow-definitions/import-files");
+ ConfigurePermissions("write:workflow-definitions");
+ AllowFileUploads();
+ }
+
+ ///
+ public override async Task HandleAsync(WorkflowDefinitionModel model, CancellationToken cancellationToken)
+ {
+ if (Files.Any())
+ {
+ var count = await ImportFilesAsync(Files, cancellationToken);
+
+ if (!ValidationFailed)
+ await SendOkAsync(new { Count = count }, cancellationToken);
+ }
+
+ if (ValidationFailed)
+ await SendErrorsAsync(400, cancellationToken);
+ }
+
+ private async Task ImportFilesAsync(IFormFileCollection files, CancellationToken cancellationToken)
+ {
+ var count = 0;
+
+ foreach (var file in files)
+ {
+ var fileStream = file.OpenReadStream();
+
+ // Check if the file is a JSON file or a ZIP file.
+ var isJsonFile = file.ContentType == "application/json";
+
+ // If the file is a JSON file, read it.
+ if (isJsonFile)
+ {
+ await ImportJsonStreamAsync(fileStream, cancellationToken);
+ count++;
+ }
+ else
+ {
+ // If the file is a ZIP file, extract the JSON files and read them.
+ var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read);
+
+ foreach (var entry in zipArchive.Entries)
+ {
+ if (!entry.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
+ continue;
+
+ var jsonStream = entry.Open();
+ await ImportJsonStreamAsync(jsonStream, cancellationToken);
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ private async Task ImportJsonStreamAsync(Stream jsonStream, CancellationToken cancellationToken)
+ {
+ var json = await new StreamReader(jsonStream).ReadToEndAsync();
+ var model = _apiSerializer.Deserialize(json);
+ await ImportSingleWorkflowDefinitionAsync(model, cancellationToken);
+ }
+
+ private async Task ImportSingleWorkflowDefinitionAsync(WorkflowDefinitionModel model, CancellationToken cancellationToken)
+ {
+ // Import workflow
+ var saveWorkflowRequest = new SaveWorkflowDefinitionRequest
+ {
+ Model = model,
+ Publish = false,
+ };
+
+ var result = await _workflowDefinitionImporter.ImportAsync(saveWorkflowRequest, cancellationToken);
+
+ if (result.Succeeded)
+ return result;
+
+ foreach (var validationError in result.ValidationErrors)
+ AddError(validationError.Message);
+
+ return result;
+ }
+}
\ No newline at end of file