< Summary

Information
Class: Elsa.Workflows.Api.Endpoints.WorkflowInstances.Import.Import
Assembly: Elsa.Workflows.Api
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Import/Endpoint.cs
Line coverage
26%
Covered lines: 22
Uncovered lines: 62
Coverable lines: 84
Total lines: 160
Line coverage: 26.1%
Branch coverage
0%
Covered branches: 0
Total branches: 14
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
Configure()100%11100%
HandleAsync()100%210%
ImportFilesAsync()0%7280%
ImportJsonStreamAsync()100%210%
ImportSingleWorkflowInstanceAsync()0%4260%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Import/Endpoint.cs

#LineLine coverage
 1using System.IO.Compression;
 2using System.Text.Json;
 3using Elsa.Abstractions;
 4using Elsa.Workflows.Api.Models;
 5using Elsa.Workflows.Management;
 6using Elsa.Workflows.Runtime;
 7using Elsa.Workflows.Runtime.Entities;
 8using JetBrains.Annotations;
 9using Microsoft.AspNetCore.Http;
 10
 11namespace Elsa.Workflows.Api.Endpoints.WorkflowInstances.Import;
 12
 13/// <summary>
 14/// Imports JSON and/or ZIP files containing a workflow instances.
 15/// </summary>
 16[PublicAPI]
 17internal class Import : ElsaEndpointWithoutRequest<Response>
 18{
 19    private readonly IWorkflowInstanceManager _workflowInstanceManager;
 20    private readonly IWorkflowInstanceStore _workflowInstanceStore;
 21    private readonly IActivityExecutionStore _activityExecutionStore;
 22    private readonly IWorkflowExecutionLogStore _workflowExecutionLogStore;
 23    private readonly IBookmarkStore _bookmarkStore;
 24    private readonly IWorkflowStateSerializer _workflowStateSerializer;
 25    private readonly IPayloadSerializer _payloadSerializer;
 26    private readonly ISafeSerializer _safeSerializer;
 27
 28    /// <inheritdoc />
 129    public Import(
 130        IWorkflowInstanceManager workflowInstanceManager,
 131        IWorkflowInstanceStore workflowInstanceStore,
 132        IActivityExecutionStore activityExecutionStore,
 133        IWorkflowExecutionLogStore workflowExecutionLogStore,
 134        IBookmarkStore bookmarkStore,
 135        IWorkflowStateSerializer workflowStateSerializer,
 136        IPayloadSerializer payloadSerializer,
 137        ISafeSerializer safeSerializer)
 38    {
 139        _workflowInstanceManager = workflowInstanceManager;
 140        _workflowInstanceStore = workflowInstanceStore;
 141        _activityExecutionStore = activityExecutionStore;
 142        _workflowExecutionLogStore = workflowExecutionLogStore;
 143        _bookmarkStore = bookmarkStore;
 144        _workflowStateSerializer = workflowStateSerializer;
 145        _payloadSerializer = payloadSerializer;
 146        _safeSerializer = safeSerializer;
 147    }
 48
 49    /// <inheritdoc />
 50    public override void Configure()
 51    {
 152        Post("/bulk-actions/import/workflow-instances");
 153        ConfigurePermissions("write:workflow-instances");
 154        AllowFileUploads();
 155    }
 56
 57    /// <inheritdoc />
 58    public override async Task HandleAsync(CancellationToken cancellationToken)
 59    {
 060        var count = await ImportFilesAsync(Files, cancellationToken);
 061        var response = new Response { Imported = count };
 62
 063        await Send.OkAsync(response, cancellationToken);
 064    }
 65
 66    private async Task<int> ImportFilesAsync(IFormFileCollection files, CancellationToken cancellationToken)
 67    {
 068        var count = 0;
 69
 070        foreach (var file in files)
 71        {
 072            var fileStream = file.OpenReadStream();
 73
 74            // Check if the file is a JSON file or a ZIP file.
 075            var isJsonFile = file.ContentType == "application/json";
 76
 77            // If the file is a JSON file, read it.
 078            if (isJsonFile)
 79            {
 080                await ImportJsonStreamAsync(fileStream, cancellationToken);
 081                count++;
 82            }
 83            else
 84            {
 85                // If the file is a ZIP file, extract the JSON files and read them.
 086                var zipArchive = new ZipArchive(fileStream, ZipArchiveMode.Read);
 87
 088                foreach (var entry in zipArchive.Entries)
 89                {
 090                    if (!entry.FullName.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
 91                        continue;
 92
 093                    var jsonStream = entry.Open();
 094                    await ImportJsonStreamAsync(jsonStream, cancellationToken);
 095                    count++;
 96                }
 97            }
 98        }
 99
 0100        return count;
 0101    }
 102
 103    private async Task ImportJsonStreamAsync(Stream jsonStream, CancellationToken cancellationToken)
 104    {
 0105        var json = await new StreamReader(jsonStream).ReadToEndAsync();
 0106        var model = JsonSerializer.Deserialize<ExportedWorkflowState>(json)!;
 0107        await ImportSingleWorkflowInstanceAsync(model, cancellationToken);
 0108    }
 109
 110    private async Task ImportSingleWorkflowInstanceAsync(ExportedWorkflowState model, CancellationToken cancellationToke
 111    {
 0112        var workflowState = _workflowStateSerializer.Deserialize(model.WorkflowState);
 0113        await _workflowInstanceManager.SaveAsync(workflowState, cancellationToken);
 114
 0115        if (model.Bookmarks != null)
 116        {
 0117            var bookmarksElement = model.Bookmarks.Value.EnumerateArray().ToList();
 0118            var bookmarks = bookmarksElement.Select(x =>
 0119            {
 0120                var bookmarkId = x.GetProperty("id").GetString()!;
 0121                var activityTypeName = x.GetProperty("activityTypeName").GetString()!;
 0122                var workflowInstanceId = x.GetProperty("workflowInstanceId").GetString()!;
 0123                var activityInstanceId = x.GetProperty("activityInstanceId").GetString();
 0124                var hash = x.GetProperty("hash").GetString()!;
 0125                var correlationId = x.GetProperty("correlationId").GetString();
 0126                var createdAt = x.GetProperty("createdAt").GetDateTimeOffset();
 0127                var payloadElement = x.GetProperty("payload");
 0128                var metadataElement = x.GetProperty("metadata");
 0129                var payload = _payloadSerializer.Deserialize<object>(payloadElement);
 0130                var metadata = _payloadSerializer.Deserialize<IDictionary<string, string>>(metadataElement);
 0131
 0132                return new StoredBookmark
 0133                {
 0134                    Id = bookmarkId,
 0135                    Name = activityTypeName,
 0136                    Hash = hash,
 0137                    WorkflowInstanceId = workflowInstanceId,
 0138                    CreatedAt = createdAt,
 0139                    ActivityInstanceId = activityInstanceId,
 0140                    CorrelationId = correlationId,
 0141                    Payload = payload,
 0142                    Metadata = metadata
 0143                };
 0144            }).ToList();
 0145            await _bookmarkStore.SaveManyAsync(bookmarks, cancellationToken);
 146        }
 147
 0148        if (model.ActivityExecutionRecords != null)
 149        {
 0150            var activityExecutionRecords = _safeSerializer.Deserialize<ICollection<ActivityExecutionRecord>>(model.Activ
 0151            await _activityExecutionStore.SaveManyAsync(activityExecutionRecords, cancellationToken);
 152        }
 153
 0154        if (model.WorkflowExecutionLogRecords != null)
 155        {
 0156            var workflowExecutionLogRecords = _safeSerializer.Deserialize<ICollection<WorkflowExecutionLogRecord>>(model
 0157            await _workflowExecutionLogStore.SaveManyAsync(workflowExecutionLogRecords, cancellationToken);
 158        }
 0159    }
 160}