| | | 1 | | using System.Text.Json; |
| | | 2 | | using Elsa.Abstractions; |
| | | 3 | | using Elsa.Common.Serialization; |
| | | 4 | | using Elsa.Extensions; |
| | | 5 | | using Elsa.Models; |
| | | 6 | | using Elsa.Workflows.Models; |
| | | 7 | | using JetBrains.Annotations; |
| | | 8 | | using Microsoft.AspNetCore.Http; |
| | | 9 | | |
| | | 10 | | namespace Elsa.Workflows.Api.Endpoints.OutputConverters.List; |
| | | 11 | | |
| | | 12 | | /// <summary> |
| | | 13 | | /// Lists output converters compatible with declared output and destination types. |
| | | 14 | | /// </summary> |
| | | 15 | | [PublicAPI] |
| | | 16 | | internal class List(IOutputConverterRegistry registry, ISerializationTypeRegistry serializationTypeRegistry) : ElsaEndpo |
| | | 17 | | { |
| | | 18 | | /// <inheritdoc /> |
| | | 19 | | public override void Configure() |
| | | 20 | | { |
| | | 21 | | Get("/descriptors/output-converters"); |
| | | 22 | | ConfigurePermissions("read:*", "read:output-converters"); |
| | | 23 | | } |
| | | 24 | | |
| | | 25 | | /// <inheritdoc /> |
| | | 26 | | public override async Task HandleAsync(CancellationToken cancellationToken) |
| | | 27 | | { |
| | | 28 | | var sourceTypeName = Query<string>("sourceType", false); |
| | | 29 | | var destinationTypeName = Query<string>("destinationType", false); |
| | | 30 | | |
| | | 31 | | if (!TryListCompatible(sourceTypeName, destinationTypeName, out var response, out var errors)) |
| | | 32 | | { |
| | | 33 | | foreach (var error in errors) |
| | | 34 | | AddError(error); |
| | | 35 | | |
| | | 36 | | await Send.ErrorsAsync(StatusCodes.Status400BadRequest, cancellationToken); |
| | | 37 | | return; |
| | | 38 | | } |
| | | 39 | | |
| | | 40 | | await Send.OkAsync(response, cancellationToken); |
| | | 41 | | } |
| | | 42 | | |
| | | 43 | | internal bool TryListCompatible( |
| | | 44 | | string? sourceTypeName, |
| | | 45 | | string? destinationTypeName, |
| | | 46 | | out ListResponse<OutputConverterDescriptorModel> response, |
| | | 47 | | out ICollection<string> errors) |
| | | 48 | | { |
| | | 49 | | errors = []; |
| | | 50 | | var hasSourceType = TryResolveType("sourceType", sourceTypeName, out var sourceType, out var sourceTypeError); |
| | | 51 | | var hasDestinationType = TryResolveType("destinationType", destinationTypeName, out var destinationType, out var |
| | | 52 | | |
| | | 53 | | if (!hasSourceType) |
| | | 54 | | errors.Add(sourceTypeError!); |
| | | 55 | | |
| | | 56 | | if (!hasDestinationType) |
| | | 57 | | errors.Add(destinationTypeError!); |
| | | 58 | | |
| | | 59 | | if (errors.Count > 0) |
| | | 60 | | { |
| | | 61 | | response = new ListResponse<OutputConverterDescriptorModel>([]); |
| | | 62 | | return false; |
| | | 63 | | } |
| | | 64 | | |
| | | 65 | | var descriptors = registry.FindCompatible(sourceType, destinationType).Select(Map).ToList(); |
| | | 66 | | |
| | | 67 | | response = new ListResponse<OutputConverterDescriptorModel>(descriptors); |
| | | 68 | | return true; |
| | | 69 | | } |
| | | 70 | | |
| | | 71 | | private bool TryResolveType(string parameterName, string? typeName, out Type type, out string? error) |
| | | 72 | | { |
| | | 73 | | if (string.IsNullOrWhiteSpace(typeName)) |
| | | 74 | | { |
| | | 75 | | type = null!; |
| | | 76 | | error = $"The {parameterName} query parameter is required."; |
| | | 77 | | return false; |
| | | 78 | | } |
| | | 79 | | |
| | | 80 | | if (SerializationTypeResolver.TryResolveType(serializationTypeRegistry, typeName, out type)) |
| | | 81 | | { |
| | | 82 | | error = null; |
| | | 83 | | return true; |
| | | 84 | | } |
| | | 85 | | |
| | | 86 | | type = null!; |
| | | 87 | | error = $"The {parameterName} query parameter must be a registered type alias or resolvable safe type name."; |
| | | 88 | | return false; |
| | | 89 | | } |
| | | 90 | | |
| | | 91 | | private OutputConverterDescriptorModel Map(OutputConverterDescriptor descriptor) => new( |
| | | 92 | | descriptor.Id, |
| | | 93 | | GetTypeName(descriptor.SourceType), |
| | | 94 | | GetTypeName(descriptor.ResultType), |
| | | 95 | | descriptor.DisplayName, |
| | | 96 | | descriptor.Description, |
| | | 97 | | descriptor.SettingsSchema?.Clone()); |
| | | 98 | | |
| | | 99 | | private string GetTypeName(Type type) => SerializationTypeResolver.TryGetAlias(serializationTypeRegistry, type, out |
| | | 100 | | ? alias |
| | | 101 | | : type.GetSimpleAssemblyQualifiedName(); |
| | | 102 | | } |
| | | 103 | | |
| | 1 | 104 | | internal record OutputConverterDescriptorModel( |
| | 1 | 105 | | string Id, |
| | 1 | 106 | | string SourceTypeName, |
| | 1 | 107 | | string ResultTypeName, |
| | 1 | 108 | | string DisplayName, |
| | 1 | 109 | | string? Description, |
| | 2 | 110 | | JsonElement? SettingsSchema); |