Incremental work on tests, API endpoint, versioning and cleanup
This commit is contained in:
parent
bd3b41440a
commit
400b4f827a
|
|
@ -50,8 +50,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Scripting.Liquid", "sr
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "server", "server", "{468E498C-59DB-4541-8D8A-0D89DE9083AB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Core", "src\server\Elsa.Server.Core\Elsa.Server.Core.csproj", "{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Server.Host", "src\server\Elsa.Server.Host\Elsa.Server.Host.csproj", "{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{AB1AE008-6FD6-414C-8E88-D735F42E1FA6}"
|
||||
|
|
@ -152,10 +150,6 @@ Global
|
|||
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{01DC21DD-C6E2-4B21-864E-97D29448F777}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -251,7 +245,6 @@ Global
|
|||
{18BE8F72-E528-4617-B1B1-07BD35337DFC} = {9C3C685E-3D7D-4638-A031-24F71CF74B52}
|
||||
{01DC21DD-C6E2-4B21-864E-97D29448F777} = {9C3C685E-3D7D-4638-A031-24F71CF74B52}
|
||||
{468E498C-59DB-4541-8D8A-0D89DE9083AB} = {DA71CDAA-8DD3-4D5F-9FBD-8E4B37A2D925}
|
||||
{D91E2F7B-D5B7-4D1C-A3F0-B0475C33F539} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
|
||||
{FC54EDBA-71FB-4A87-8FD5-54759DF77CCE} = {468E498C-59DB-4541-8D8A-0D89DE9083AB}
|
||||
{0A3C36AB-2ACF-4175-A512-66B4C3DB9371} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
|
||||
{0A6747EA-7AC6-4B6F-BC0C-C40C8A80C44D} = {AB1AE008-6FD6-414C-8E88-D735F42E1FA6}
|
||||
|
|
|
|||
|
|
@ -27,5 +27,7 @@ namespace Elsa
|
|||
}
|
||||
|
||||
public static void SetState(this JObject state, string key, object? value) => state[key] = value != null ? JToken.FromObject(value, Serializer) : null;
|
||||
|
||||
public static bool HasKey(this JObject state, string key) => state.ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
using Elsa.Serialization.Extensions;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Models
|
||||
{
|
||||
public class Variables
|
||||
public class Variables
|
||||
{
|
||||
public Variables()
|
||||
{
|
||||
|
|
@ -19,8 +19,8 @@ namespace Elsa.Models
|
|||
Data = data;
|
||||
}
|
||||
|
||||
public JObject Data { get; set; }
|
||||
|
||||
[JsonExtensionData] public JObject Data { get; set; }
|
||||
|
||||
public JToken? Get(string name) => Has(name) ? Data[name] : default;
|
||||
public T Get<T>(string name) => Has(name) ? Data.Value<T>(name) : default!;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Serialization.Extensions
|
||||
{
|
||||
public static class JTokenExtensions
|
||||
{
|
||||
public static T GetValue<T>(this JToken token, string key)
|
||||
{
|
||||
var value = ((JObject)token).GetValue(key, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
return value != null ? value.Value<T>() : default;
|
||||
}
|
||||
|
||||
public static bool HasKey(this JToken token, string key) => ((JObject)token).ContainsKey(key);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Elsa.Serialization.Extensions
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static Stream ToStream(this string text)
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(text);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
|
||||
public static byte[] ToBytes(this string text)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Serialization.Formatters
|
||||
{
|
||||
public interface ITokenFormatter
|
||||
{
|
||||
string Format { get; }
|
||||
string ContentType { get; }
|
||||
string ToString(JObject token);
|
||||
JObject FromString(string data);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Serialization.Handlers
|
||||
{
|
||||
public interface IValueHandler
|
||||
{
|
||||
int Priority { get; }
|
||||
bool CanSerialize(JToken token, Type type, object value);
|
||||
bool CanDeserialize(JToken token);
|
||||
object? Deserialize(JsonSerializer serializer, JToken token);
|
||||
void Serialize(JsonWriter writer, JsonSerializer serializer, Type type, JToken token, object value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Elsa.Serialization.Extensions;
|
||||
|
||||
namespace Elsa.Serialization.Handlers
|
||||
{
|
||||
public abstract class PrimitiveValueHandler<T> : IValueHandler
|
||||
{
|
||||
public virtual int Priority => 0;
|
||||
public bool CanSerialize(JToken token, Type type, object value) => type == typeof(T);
|
||||
public bool CanDeserialize(JToken token) => token.Type == JTokenType.Object && token.GetValue<string>("Type") == TypeName;
|
||||
protected virtual string TypeName => typeof(T).Name;
|
||||
|
||||
public virtual object Deserialize(JsonSerializer serializer, JToken token)
|
||||
{
|
||||
var valueToken = token["Value"];
|
||||
|
||||
return valueToken == null ? null! : ParseValue(valueToken);
|
||||
}
|
||||
|
||||
public virtual void Serialize(JsonWriter writer, JsonSerializer serializer, Type type, JToken token, object? value)
|
||||
{
|
||||
var objectToken = new JObject
|
||||
{
|
||||
["Type"] = TypeName,
|
||||
["Value"] = token
|
||||
};
|
||||
objectToken.WriteTo(writer, serializer.Converters.ToArray());
|
||||
}
|
||||
|
||||
protected abstract object ParseValue(JToken value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
using Elsa.Services;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Serialization
|
||||
{
|
||||
public interface IActivitySerializer
|
||||
{
|
||||
JObject Serialize<T>(T activity) where T : IActivity;
|
||||
T Deserialize<T>(JObject data) where T : IActivity;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,9 @@ namespace Elsa.Serialization
|
|||
{
|
||||
public interface IContentSerializer
|
||||
{
|
||||
JObject Serialize<T>(T value);
|
||||
string Serialize<T>(T value);
|
||||
T Deserialize<T>(JToken token);
|
||||
T Deserialize<T>(string json);
|
||||
object GetSettings();
|
||||
}
|
||||
}
|
||||
7
src/core/Elsa.Abstractions/Services/ICloner.cs
Normal file
7
src/core/Elsa.Abstractions/Services/ICloner.cs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
namespace Elsa.Services
|
||||
{
|
||||
public interface ICloner
|
||||
{
|
||||
T Clone<T>(T source);
|
||||
}
|
||||
}
|
||||
|
|
@ -8,13 +8,13 @@ namespace Elsa.Services
|
|||
{
|
||||
WorkflowDefinition New();
|
||||
|
||||
Task<WorkflowDefinition?> PublishAsync(string id, CancellationToken cancellationToken = default);
|
||||
Task<WorkflowDefinition?> PublishAsync(string workflowDefinitionId, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<WorkflowDefinition> PublishAsync(
|
||||
WorkflowDefinition workflowDefinition,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<WorkflowDefinition?> GetDraftAsync(string id, CancellationToken cancellationToken= default);
|
||||
Task<WorkflowDefinition?> GetDraftAsync(string workflowDefinitionId, CancellationToken cancellationToken= default);
|
||||
|
||||
Task<WorkflowDefinition> SaveDraftAsync(
|
||||
WorkflowDefinition workflowDefinition,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.JsonNet;
|
||||
using YesSql;
|
||||
|
|
@ -8,7 +9,25 @@ namespace Elsa.Data.Services
|
|||
{
|
||||
public class CustomJsonContentSerializer : IContentSerializer
|
||||
{
|
||||
private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
|
||||
private static readonly JsonSerializerSettings JsonSettings;
|
||||
|
||||
static CustomJsonContentSerializer()
|
||||
{
|
||||
JsonSettings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.Auto
|
||||
}.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
|
||||
|
||||
JsonSettings.ContractResolver = new DefaultContractResolver
|
||||
{
|
||||
NamingStrategy = new DefaultNamingStrategy
|
||||
{
|
||||
ProcessDictionaryKeys = true,
|
||||
ProcessExtensionDataNames = true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public object? Deserialize(string content, Type type) => JsonConvert.DeserializeObject(content, type, JsonSettings);
|
||||
public dynamic? DeserializeDynamic(string content) => JsonConvert.DeserializeObject<dynamic>(content, JsonSettings);
|
||||
public string Serialize(object item) => JsonConvert.SerializeObject(item, JsonSettings);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using Elsa.Caching;
|
||||
using Elsa.DistributedLock;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Serialization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
|
|
@ -27,9 +28,15 @@ namespace Elsa
|
|||
ServiceBusConfigurer = ConfigureInMemoryServiceBus;
|
||||
JsonSerializerConfigurer = (sp, serializer) => {};
|
||||
|
||||
AddAutoMapper = () =>
|
||||
{
|
||||
services.AddAutoMapper(ServiceLifetime.Singleton);
|
||||
services.AddSingleton(sp => sp.CreateAutoMapperConfiguration());
|
||||
};
|
||||
|
||||
CreateJsonSerializer = sp =>
|
||||
{
|
||||
var serializer = ContentSerializer.CreateDefaultJsonSerializer();
|
||||
var serializer = DefaultContentSerializer.CreateDefaultJsonSerializer();
|
||||
JsonSerializerConfigurer(sp, serializer);
|
||||
return serializer;
|
||||
};
|
||||
|
|
@ -42,6 +49,7 @@ namespace Elsa
|
|||
internal Func<RebusConfigurer, IServiceProvider, RebusConfigurer> ServiceBusConfigurer { get; private set; }
|
||||
internal Func<IServiceProvider, JsonSerializer> CreateJsonSerializer { get; private set; }
|
||||
internal Action<IServiceProvider, JsonSerializer> JsonSerializerConfigurer { get; private set; }
|
||||
internal Action AddAutoMapper { get; private set; }
|
||||
|
||||
public ElsaOptions UseDistributedLockProvider(Func<IServiceProvider, IDistributedLockProvider> factory)
|
||||
{
|
||||
|
|
@ -62,6 +70,12 @@ namespace Elsa
|
|||
ConfigurePersistence = configure;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElsaOptions UseAutoMapper(Action addAutoMapper)
|
||||
{
|
||||
AddAutoMapper = addAutoMapper;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ElsaOptions ConfigureServiceBus(Func<RebusConfigurer, IServiceProvider, RebusConfigurer> configure)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,20 +9,17 @@ namespace Elsa.Extensions
|
|||
{
|
||||
public static IServiceCollection AddAutoMapper(this IServiceCollection services, ServiceLifetime lifetime)
|
||||
{
|
||||
services.TryAddSingleton(CreateConfigurationProvider);
|
||||
services.TryAdd(new ServiceDescriptor(typeof(IMapper), sp => sp.GetRequiredService<IConfigurationProvider>().CreateMapper(sp.GetService), lifetime));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAutoMapperProfile<TProfile>(this IServiceCollection services, ServiceLifetime lifetime) where TProfile : Profile
|
||||
public static IServiceCollection AddAutoMapperProfile<TProfile>(this IServiceCollection services) where TProfile : Profile
|
||||
{
|
||||
services.AddAutoMapper(lifetime);
|
||||
services.TryAddProvider<Profile, TProfile>(lifetime);
|
||||
services.TryAddProvider<Profile, TProfile>(ServiceLifetime.Transient);
|
||||
return services;
|
||||
}
|
||||
|
||||
private static IConfigurationProvider CreateConfigurationProvider(IServiceProvider serviceProvider)
|
||||
public static IConfigurationProvider CreateAutoMapperConfiguration(this IServiceProvider serviceProvider)
|
||||
{
|
||||
var profiles = serviceProvider.GetServices<Profile>();
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ using Elsa.Expressions;
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Handlers;
|
||||
using Elsa.Indexes;
|
||||
using Elsa.Mapping;
|
||||
using Elsa.Messages;
|
||||
using Elsa.Metadata;
|
||||
using Elsa.Metadata.Handlers;
|
||||
|
|
@ -51,6 +52,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
options.AddWorkflowsCore();
|
||||
options.AddMediatR();
|
||||
options.AddServiceBus();
|
||||
options.AddAutoMapper();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
|
@ -85,8 +87,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddTransient<Func<IEnumerable<IActivity>>>(sp => sp.GetServices<IActivity>)
|
||||
.AddSingleton<IIdGenerator, IdGenerator>()
|
||||
.AddSingleton(sp => sp.GetRequiredService<ElsaOptions>().CreateJsonSerializer(sp))
|
||||
.AddSingleton<IContentSerializer, ContentSerializer>()
|
||||
.AddSingleton<IActivitySerializer, ActivitySerializer>()
|
||||
.AddSingleton<IContentSerializer, DefaultContentSerializer>()
|
||||
.AddSingleton<TypeConverter>()
|
||||
.TryAddProvider<IExpressionHandler, LiteralHandler>(ServiceLifetime.Singleton)
|
||||
.TryAddProvider<IExpressionHandler, VariableHandler>(ServiceLifetime.Singleton)
|
||||
|
|
@ -100,6 +101,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddScoped<IWorkflowSelector, WorkflowSelector>()
|
||||
.AddScoped<IWorkflowDefinitionManager, WorkflowDefinitionManager>()
|
||||
.AddScoped<IWorkflowInstanceManager, WorkflowInstanceManager>()
|
||||
.AddScoped<IWorkflowPublisher, WorkflowPublisher>()
|
||||
.AddIndexProvider<WorkflowDefinitionIndexProvider>()
|
||||
.AddIndexProvider<WorkflowInstanceIndexProvider>()
|
||||
.AddStartupRunner()
|
||||
|
|
@ -107,6 +109,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
.AddWorkflowProvider<CodeWorkflowProvider>()
|
||||
.AddTransient<IWorkflowBuilder, WorkflowBuilder>()
|
||||
.AddTransient<Func<IWorkflowBuilder>>(sp => sp.GetRequiredService<IWorkflowBuilder>)
|
||||
.AddAutoMapperProfile<NodaTimeProfile>()
|
||||
.AddAutoMapperProfile<CloningProfile>()
|
||||
.AddSingleton<ICloner, AutoMapperCloner>()
|
||||
.AddNotificationHandlers(typeof(ElsaServiceCollectionExtensions))
|
||||
.AddStartupTask<StartServiceBusTask>()
|
||||
.AddConsumer<RunWorkflow, RunWorkflowConsumer>()
|
||||
|
|
|
|||
16
src/core/Elsa.Core/Mapping/CloningProfile.cs
Normal file
16
src/core/Elsa.Core/Mapping/CloningProfile.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using AutoMapper;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// An AutoMapper profile that configures certain domain models to be mappable from and to itself, effectively creating deep clones.
|
||||
/// </summary>
|
||||
public class CloningProfile : Profile
|
||||
{
|
||||
public CloningProfile()
|
||||
{
|
||||
CreateMap<WorkflowDefinition, WorkflowDefinition>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,26 +18,11 @@ namespace Elsa.Mapping
|
|||
CreateMap<DateTime?, Instant?>().ConvertUsing(this);
|
||||
}
|
||||
|
||||
public DateTime Convert(Instant source, DateTime target, ResolutionContext context)
|
||||
{
|
||||
return source.ToDateTimeUtc();
|
||||
}
|
||||
public DateTime Convert(Instant source, DateTime target, ResolutionContext context) => source.ToDateTimeUtc();
|
||||
public DateTime? Convert(Instant? source, DateTime? target, ResolutionContext context) => source?.ToDateTimeUtc();
|
||||
public Instant Convert(DateTime source, Instant target, ResolutionContext context) => Convert(source);
|
||||
public Instant? Convert(DateTime? source, Instant? target, ResolutionContext context) => source != null ? Convert(source.Value) : default(Instant?);
|
||||
|
||||
public DateTime? Convert(Instant? source, DateTime? target, ResolutionContext context)
|
||||
{
|
||||
return source?.ToDateTimeUtc();
|
||||
}
|
||||
|
||||
public Instant Convert(DateTime source, Instant target, ResolutionContext context)
|
||||
{
|
||||
return Convert(source);
|
||||
}
|
||||
|
||||
public Instant? Convert(DateTime? source, Instant? target, ResolutionContext context)
|
||||
{
|
||||
return source != null ? Convert(source.Value) : default(Instant?);
|
||||
}
|
||||
|
||||
public Instant Convert(DateTime source)
|
||||
{
|
||||
var utcDateTime = source.Kind == DateTimeKind.Unspecified
|
||||
|
|
|
|||
|
|
@ -21,12 +21,10 @@ namespace Elsa.Queries
|
|||
VersionOptions = versionOptions;
|
||||
}
|
||||
|
||||
public Expression<Func<IQuery<WorkflowDefinition>, IQuery<WorkflowDefinition>>> Query()
|
||||
{
|
||||
return query => query
|
||||
public Expression<Func<IQuery<WorkflowDefinition>, IQuery<WorkflowDefinition>>> Query() =>
|
||||
query => query
|
||||
.With<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionId == WorkflowDefinitionId)
|
||||
.WithVersion(VersionOptions);
|
||||
}
|
||||
}
|
||||
|
||||
public static class WorkflowDefinitionByIdAndVersionQueryWorkflowDefinitionManagerExtensions
|
||||
|
|
@ -34,18 +32,15 @@ namespace Elsa.Queries
|
|||
public static IQuery<WorkflowDefinition> QueryByIdAndVersion(
|
||||
this IWorkflowDefinitionManager manager,
|
||||
string workflowDefinitionId,
|
||||
VersionOptions versionOptions)
|
||||
{
|
||||
return manager.ExecuteQuery(
|
||||
new WorkflowDefinitionByIdAndVersionQuery(workflowDefinitionId, versionOptions));
|
||||
}
|
||||
VersionOptions versionOptions) =>
|
||||
manager.Query<WorkflowDefinitionIndex>(x => x.WorkflowDefinitionId == workflowDefinitionId).WithVersion(versionOptions);
|
||||
//manager.ExecuteQuery(new WorkflowDefinitionByIdAndVersionQuery(workflowDefinitionId, versionOptions));
|
||||
|
||||
public static async Task<WorkflowDefinition?> GetAsync(
|
||||
this IWorkflowDefinitionManager manager,
|
||||
string workflowDefinitionId,
|
||||
VersionOptions versionOptions,
|
||||
CancellationToken cancellationToken = default) =>
|
||||
await manager.QueryByIdAndVersion(workflowDefinitionId, versionOptions)
|
||||
.FirstOrDefaultAsync();
|
||||
await manager.QueryByIdAndVersion(workflowDefinitionId, versionOptions).FirstOrDefaultAsync();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.Services;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Serialization
|
||||
{
|
||||
public class ActivitySerializer : IActivitySerializer
|
||||
{
|
||||
private readonly IContentSerializer _ijSerializer;
|
||||
public ActivitySerializer(IContentSerializer ijSerializer) => _ijSerializer = ijSerializer;
|
||||
public JObject Serialize<T>(T activity) where T : IActivity => _ijSerializer.Serialize(activity);
|
||||
public T Deserialize<T>(JObject data) where T : IActivity => _ijSerializer.Deserialize<T>(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
using Elsa.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.JsonNet;
|
||||
|
||||
namespace Elsa.Serialization
|
||||
{
|
||||
public class ContentSerializer : IContentSerializer
|
||||
{
|
||||
public ContentSerializer(JsonSerializer serializer)
|
||||
{
|
||||
Serializer = serializer;
|
||||
}
|
||||
|
||||
private JsonSerializer Serializer { get; }
|
||||
public JObject Serialize<T>(T value) => JObject.FromObject(value!, Serializer);
|
||||
public T Deserialize<T>(JToken token) => token.ToObject<T>(Serializer)!;
|
||||
|
||||
public T Deserialize<T>(string json)
|
||||
{
|
||||
var token = JObject.Parse(json);
|
||||
return Deserialize<T>(token);
|
||||
}
|
||||
|
||||
public static JsonSerializer CreateDefaultJsonSerializer()
|
||||
{
|
||||
var jsonSerializer = new JsonSerializer();
|
||||
jsonSerializer.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
|
||||
jsonSerializer.NullValueHandling = NullValueHandling.Ignore;
|
||||
jsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
|
||||
jsonSerializer.PreserveReferencesHandling = PreserveReferencesHandling.All;
|
||||
jsonSerializer.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;
|
||||
jsonSerializer.TypeNameHandling = TypeNameHandling.None;
|
||||
jsonSerializer.ContractResolver = new CamelCasePropertyNamesContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
ProcessDictionaryKeys = false
|
||||
}
|
||||
};
|
||||
jsonSerializer.Converters.Add(new TypeConverter());
|
||||
return jsonSerializer;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/core/Elsa.Core/Serialization/DefaultContentSerializer.cs
Normal file
57
src/core/Elsa.Core/Serialization/DefaultContentSerializer.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using Elsa.Converters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.JsonNet;
|
||||
|
||||
namespace Elsa.Serialization
|
||||
{
|
||||
public class DefaultContentSerializer : IContentSerializer
|
||||
{
|
||||
public DefaultContentSerializer(JsonSerializer serializer)
|
||||
{
|
||||
Serializer = serializer;
|
||||
}
|
||||
|
||||
private JsonSerializer Serializer { get; }
|
||||
public string Serialize<T>(T value) => JObject.FromObject(value!, Serializer).ToString();
|
||||
public T Deserialize<T>(JToken token) => token.ToObject<T>(Serializer)!;
|
||||
|
||||
public T Deserialize<T>(string json)
|
||||
{
|
||||
var token = JObject.Parse(json);
|
||||
return Deserialize<T>(token);
|
||||
}
|
||||
|
||||
public object GetSettings() => CreateDefaultJsonSerializationSettings();
|
||||
|
||||
public static void ConfigureDefaultJsonSerializationSettings(JsonSerializerSettings settings)
|
||||
{
|
||||
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
|
||||
settings.NullValueHandling = NullValueHandling.Ignore;
|
||||
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
|
||||
settings.PreserveReferencesHandling = PreserveReferencesHandling.All;
|
||||
settings.TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple;
|
||||
settings.TypeNameHandling = TypeNameHandling.None;
|
||||
settings.ContractResolver = new CamelCasePropertyNamesContractResolver
|
||||
{
|
||||
NamingStrategy = new CamelCaseNamingStrategy
|
||||
{
|
||||
ProcessDictionaryKeys = true,
|
||||
ProcessExtensionDataNames = true
|
||||
}
|
||||
};
|
||||
settings.Converters.Add(new TypeConverter());
|
||||
}
|
||||
|
||||
public static JsonSerializerSettings CreateDefaultJsonSerializationSettings()
|
||||
{
|
||||
var settings = new JsonSerializerSettings();
|
||||
ConfigureDefaultJsonSerializationSettings(settings);
|
||||
return settings;
|
||||
}
|
||||
|
||||
public static JsonSerializer CreateDefaultJsonSerializer() => JsonSerializer.Create(CreateDefaultJsonSerializationSettings());
|
||||
}
|
||||
}
|
||||
15
src/core/Elsa.Core/Services/AutoMapperCloner.cs
Normal file
15
src/core/Elsa.Core/Services/AutoMapperCloner.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using AutoMapper;
|
||||
|
||||
namespace Elsa.Services
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation that relies on AutoMapper to clone objects. This requires the types that need to be supported to be registered with AutoMapper.
|
||||
/// We might eventually consider doing a different implementation that does not require explicitly registering which types support cloning.
|
||||
/// </summary>
|
||||
public class AutoMapperCloner : ICloner
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
public AutoMapperCloner(IMapper mapper) => _mapper = mapper;
|
||||
public T Clone<T>(T source) => _mapper.Map<T>(source);
|
||||
}
|
||||
}
|
||||
|
|
@ -34,13 +34,7 @@ namespace Elsa.Services
|
|||
public async ValueTask<IEnumerable<WorkflowDefinition>> ListAsync(CancellationToken cancellationToken = default) => await Query().ListAsync();
|
||||
public IQuery<WorkflowDefinition> Query() => _session.Query<WorkflowDefinition>(CollectionNames.WorkflowDefinitions);
|
||||
public IQuery<WorkflowDefinition, TIndex> Query<TIndex>() where TIndex : class, IIndex => _session.Query<WorkflowDefinition, TIndex>(CollectionNames.WorkflowDefinitions);
|
||||
|
||||
public IQuery<WorkflowDefinition, TIndex> Query<TIndex>(Expression<Func<TIndex, bool>> predicate)
|
||||
where TIndex : class, IIndex => _session.Query<WorkflowDefinition, TIndex>(
|
||||
predicate,
|
||||
CollectionNames.WorkflowDefinitions);
|
||||
|
||||
public IQuery<WorkflowDefinition> ExecuteQuery(ICompiledQuery<WorkflowDefinition> query) =>
|
||||
_session.ExecuteQuery(query, CollectionNames.WorkflowDefinitions);
|
||||
public IQuery<WorkflowDefinition, TIndex> Query<TIndex>(Expression<Func<TIndex, bool>> predicate) where TIndex : class, IIndex => _session.Query<WorkflowDefinition, TIndex>(predicate, CollectionNames.WorkflowDefinitions);
|
||||
public IQuery<WorkflowDefinition> ExecuteQuery(ICompiledQuery<WorkflowDefinition> query) => _session.ExecuteQuery(query, CollectionNames.WorkflowDefinitions);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,11 +9,13 @@ namespace Elsa.Services
|
|||
{
|
||||
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
|
||||
private readonly IIdGenerator _idGenerator;
|
||||
private readonly ICloner _cloner;
|
||||
|
||||
public WorkflowPublisher(IWorkflowDefinitionManager workflowDefinitionManager, IIdGenerator idGenerator)
|
||||
public WorkflowPublisher(IWorkflowDefinitionManager workflowDefinitionManager, IIdGenerator idGenerator, ICloner cloner)
|
||||
{
|
||||
_workflowDefinitionManager = workflowDefinitionManager;
|
||||
_idGenerator = idGenerator;
|
||||
_cloner = cloner;
|
||||
}
|
||||
|
||||
public WorkflowDefinition New()
|
||||
|
|
@ -34,11 +36,11 @@ namespace Elsa.Services
|
|||
}
|
||||
|
||||
public async Task<WorkflowDefinition?> PublishAsync(
|
||||
string id,
|
||||
string workflowDefinitionId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var definition = await _workflowDefinitionManager.GetAsync(
|
||||
id,
|
||||
workflowDefinitionId,
|
||||
VersionOptions.Latest,
|
||||
cancellationToken);
|
||||
|
||||
|
|
@ -48,16 +50,14 @@ namespace Elsa.Services
|
|||
return await PublishAsync(definition, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<WorkflowDefinition> PublishAsync(
|
||||
WorkflowDefinition workflowDefinition,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
public async Task<WorkflowDefinition> PublishAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken)
|
||||
{
|
||||
var publishedDefinition = await _workflowDefinitionManager.GetAsync(
|
||||
workflowDefinition.WorkflowDefinitionVersionId,
|
||||
workflowDefinition.WorkflowDefinitionId,
|
||||
VersionOptions.Published,
|
||||
cancellationToken);
|
||||
|
||||
if (publishedDefinition != null)
|
||||
if (publishedDefinition != null)
|
||||
{
|
||||
publishedDefinition.IsPublished = false;
|
||||
publishedDefinition.IsLatest = false;
|
||||
|
|
@ -66,7 +66,6 @@ namespace Elsa.Services
|
|||
|
||||
if (workflowDefinition.IsPublished)
|
||||
{
|
||||
workflowDefinition.WorkflowDefinitionId = _idGenerator.Generate();
|
||||
workflowDefinition.Version++;
|
||||
}
|
||||
else
|
||||
|
|
@ -82,12 +81,10 @@ namespace Elsa.Services
|
|||
return workflowDefinition;
|
||||
}
|
||||
|
||||
public async Task<WorkflowDefinition?> GetDraftAsync(
|
||||
string id,
|
||||
CancellationToken cancellationToken)
|
||||
public async Task<WorkflowDefinition?> GetDraftAsync(string workflowDefinitionId, CancellationToken cancellationToken)
|
||||
{
|
||||
var definition = await _workflowDefinitionManager.GetAsync(
|
||||
id,
|
||||
workflowDefinitionId,
|
||||
VersionOptions.Latest,
|
||||
cancellationToken);
|
||||
|
||||
|
|
@ -97,8 +94,9 @@ namespace Elsa.Services
|
|||
if (!definition.IsPublished)
|
||||
return definition;
|
||||
|
||||
var draft = definition;
|
||||
draft.WorkflowDefinitionId = _idGenerator.Generate();
|
||||
var draft = _cloner.Clone(definition);
|
||||
draft.Id = 0;
|
||||
draft.WorkflowDefinitionVersionId = _idGenerator.Generate();
|
||||
draft.IsPublished = false;
|
||||
draft.IsLatest = true;
|
||||
draft.Version++;
|
||||
|
|
@ -106,22 +104,18 @@ namespace Elsa.Services
|
|||
return draft;
|
||||
}
|
||||
|
||||
public async Task<WorkflowDefinition> SaveDraftAsync(
|
||||
WorkflowDefinition workflowDefinition,
|
||||
CancellationToken cancellationToken)
|
||||
public async Task<WorkflowDefinition> SaveDraftAsync(WorkflowDefinition workflowDefinition, CancellationToken cancellationToken)
|
||||
{
|
||||
var draft = workflowDefinition;
|
||||
|
||||
var latestVersion = await _workflowDefinitionManager.GetAsync(
|
||||
workflowDefinition.WorkflowDefinitionVersionId,
|
||||
workflowDefinition.WorkflowDefinitionId,
|
||||
VersionOptions.Latest,
|
||||
cancellationToken);
|
||||
|
||||
if (latestVersion != null && latestVersion.IsPublished && latestVersion.IsLatest)
|
||||
{
|
||||
latestVersion.IsLatest = false;
|
||||
draft.WorkflowDefinitionId = _idGenerator.Generate();
|
||||
draft.Version++;
|
||||
|
||||
await _workflowDefinitionManager.SaveAsync(latestVersion, cancellationToken);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,10 @@
|
|||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Elsa.Server.Core\Elsa.Server.Core.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.9" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="4.1.1" />
|
||||
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="5.6.3" />
|
||||
|
|
@ -26,4 +23,8 @@
|
|||
<DependentUpon>Post.cs</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Queries;
|
||||
using Elsa.Serialization;
|
||||
using Elsa.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
|
@ -10,16 +11,22 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
|
|||
[ApiController]
|
||||
[ApiVersion("1")]
|
||||
[Route("v{version:apiVersion}/workflow-definitions/{id}")]
|
||||
public class Get : ControllerBase
|
||||
public class Get : Controller
|
||||
{
|
||||
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
|
||||
public Get(IWorkflowDefinitionManager workflowDefinitionManager) => _workflowDefinitionManager = workflowDefinitionManager;
|
||||
private readonly IContentSerializer _serializer;
|
||||
|
||||
public Get(IWorkflowDefinitionManager workflowDefinitionManager, IContentSerializer serializer)
|
||||
{
|
||||
_serializer = serializer;
|
||||
_workflowDefinitionManager = workflowDefinitionManager;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Handle([FromRoute(Name = "id")] string workflowDefinitionId, CancellationToken cancellationToken)
|
||||
{
|
||||
var workflowDefinition = await _workflowDefinitionManager.GetAsync(workflowDefinitionId, VersionOptions.Latest, cancellationToken);
|
||||
return workflowDefinition == null ? (IActionResult)NotFound() : Ok(workflowDefinition);
|
||||
return workflowDefinition == null ? (IActionResult)NotFound() : Json(workflowDefinition, _serializer.GetSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ using Elsa.Models;
|
|||
|
||||
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
|
||||
{
|
||||
public class CreateWorkflowDefinitionRequest
|
||||
public class SaveWorkflowDefinitionRequest
|
||||
{
|
||||
public string WorkflowDefinitionId { get; set; } = default!;
|
||||
public string? Name { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Models;
|
||||
using Elsa.Services;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using YesSql;
|
||||
|
||||
namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
|
||||
{
|
||||
|
|
@ -12,34 +12,45 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions
|
|||
public class Post : ControllerBase
|
||||
{
|
||||
private readonly IWorkflowDefinitionManager _workflowDefinitionManager;
|
||||
private readonly IWorkflowPublisher _workflowPublisher;
|
||||
private readonly ISession _session;
|
||||
|
||||
public Post(IWorkflowDefinitionManager workflowDefinitionManager)
|
||||
public Post(IWorkflowDefinitionManager workflowDefinitionManager, IWorkflowPublisher workflowPublisher, ISession session)
|
||||
{
|
||||
_workflowDefinitionManager = workflowDefinitionManager;
|
||||
_workflowPublisher = workflowPublisher;
|
||||
_session = session;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Handle(CreateWorkflowDefinitionRequest request, ApiVersion apiVersion, CancellationToken cancellationToken)
|
||||
public async Task<IActionResult> Handle(SaveWorkflowDefinitionRequest request, ApiVersion apiVersion, CancellationToken cancellationToken)
|
||||
{
|
||||
var workflowDefinition = new WorkflowDefinition
|
||||
{
|
||||
WorkflowDefinitionId = request.WorkflowDefinitionId.Trim(),
|
||||
Activities = request.Activities,
|
||||
Connections = request.Connections,
|
||||
Description = request.Description?.Trim(),
|
||||
Name = request.Name?.Trim(),
|
||||
Variables = request.Variables,
|
||||
IsEnabled = request.Enabled,
|
||||
IsLatest = true,
|
||||
IsPublished = request.Publish,
|
||||
Version = 1,
|
||||
IsSingleton = request.IsSingleton,
|
||||
PersistenceBehavior = request.PersistenceBehavior,
|
||||
DeleteCompletedInstances = request.DeleteCompletedInstances
|
||||
};
|
||||
var workflowDefinition = await _workflowPublisher.GetDraftAsync(request.WorkflowDefinitionId, cancellationToken);
|
||||
|
||||
await _workflowDefinitionManager.SaveAsync(workflowDefinition, cancellationToken);
|
||||
return CreatedAtAction("Handle", "Get", new { version = apiVersion.ToString() }, workflowDefinition);
|
||||
if (workflowDefinition == null)
|
||||
{
|
||||
workflowDefinition = _workflowPublisher.New();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(request.WorkflowDefinitionId))
|
||||
workflowDefinition.WorkflowDefinitionId = request.WorkflowDefinitionId.Trim();
|
||||
}
|
||||
|
||||
workflowDefinition.Activities = request.Activities;
|
||||
workflowDefinition.Connections = request.Connections;
|
||||
workflowDefinition.Description = request.Description?.Trim();
|
||||
workflowDefinition.Name = request.Name?.Trim();
|
||||
workflowDefinition.Variables = request.Variables;
|
||||
workflowDefinition.IsEnabled = request.Enabled;
|
||||
workflowDefinition.IsSingleton = request.IsSingleton;
|
||||
workflowDefinition.PersistenceBehavior = request.PersistenceBehavior;
|
||||
workflowDefinition.DeleteCompletedInstances = request.DeleteCompletedInstances;
|
||||
|
||||
if (request.Publish)
|
||||
await _workflowPublisher.PublishAsync(workflowDefinition, cancellationToken);
|
||||
else
|
||||
await _workflowPublisher.SaveDraftAsync(workflowDefinition, cancellationToken);
|
||||
|
||||
return CreatedAtAction("Handle", "Get", new { id = workflowDefinition.WorkflowDefinitionId, version = apiVersion.ToString() }, workflowDefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
using System.Text.Json;
|
||||
using System;
|
||||
using Elsa.Serialization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NodaTime;
|
||||
using NodaTime.Serialization.SystemTextJson;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Elsa.Server.Api.Extensions
|
||||
{
|
||||
public static class JsonMvcBuilderExtensions
|
||||
{
|
||||
public static IMvcBuilder AddJsonSerialization(this IMvcBuilder builder) =>
|
||||
builder.AddJsonOptions(
|
||||
public static IMvcBuilder AddJsonSerialization(this IMvcBuilder builder, Action<JsonSerializerSettings>? configure = default) =>
|
||||
builder.AddNewtonsoftJson(
|
||||
options =>
|
||||
{
|
||||
options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
options.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
|
||||
configure ??= DefaultContentSerializer.ConfigureDefaultJsonSerializationSettings;
|
||||
//configure(options.SerializerSettings);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||
{
|
||||
public static IServiceCollection AddElsaApiEndpoints(this IServiceCollection services)
|
||||
{
|
||||
services.AddControllers().SetCompatibilityVersion(CompatibilityVersion.Latest).AddJsonSerialization();
|
||||
services.AddControllers().AddJsonSerialization();
|
||||
services.AddRouting(options => options.LowercaseUrls = true);
|
||||
|
||||
services.AddApiVersioning(
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageVersion>1.0.0</PackageVersion>
|
||||
<Authors>Elsa Contributors</Authors>
|
||||
<Description>
|
||||
Elsa is a set of workflow libraries and tools that enable lean and mean workflowing capabilities in any .NET Core application.
|
||||
This package provides services to manage workflows, such as serialization and versioning.
|
||||
</Description>
|
||||
<Copyright>2019</Copyright>
|
||||
<PackageProjectUrl>https://github.com/elsa-workflows/elsa-core</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/elsa-workflows/elsa-core</RepositoryUrl>
|
||||
<RepositoryType>GitHub</RepositoryType>
|
||||
<PackageTags>elsa, workflows</PackageTags>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath />
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System;
|
||||
using Elsa.Server.Core.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddElsaServer(
|
||||
this IServiceCollection services,
|
||||
Action<OptionsBuilder<ElsaServerOptions>> options = default)
|
||||
{
|
||||
var optionsBuilder = services.AddOptions<ElsaServerOptions>();
|
||||
options?.Invoke(optionsBuilder);
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
namespace Elsa.Server.Core.Options
|
||||
{
|
||||
public class ElsaServerOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
|
|
@ -1,38 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageVersion>1.0.0</PackageVersion>
|
||||
<Authors>Elsa Contributors</Authors>
|
||||
<Description>
|
||||
Elsa is a set of workflow libraries and tools that enable lean and mean workflowing capabilities in any .NET Core application.
|
||||
This package provides a GraphQL endpoint to interface with the workflow host.
|
||||
</Description>
|
||||
<Copyright>2019</Copyright>
|
||||
<PackageProjectUrl>https://github.com/elsa-workflows/elsa-core</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/elsa-workflows/elsa-core</RepositoryUrl>
|
||||
<RepositoryType>GitHub</RepositoryType>
|
||||
<PackageTags>elsa, workflows</PackageTags>
|
||||
<PackageIcon>icon.png</PackageIcon>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa\Elsa.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HotChocolate.AspNetCore" Version="10.5.3" />
|
||||
<PackageReference Include="HotChocolate.AspNetCore.Playground" Version="10.5.3" />
|
||||
<PackageReference Include="HotChocolate.AspNetCore.Voyager" Version="10.5.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath />
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Extensions
|
||||
{
|
||||
public static class ParserComposer
|
||||
{
|
||||
public static object FirstNonThrowing<T>(IEnumerable<Func<string, T>> parsers, string value)
|
||||
{
|
||||
if (!parsers.Any())
|
||||
return null;
|
||||
|
||||
foreach (var nextParser in parsers)
|
||||
{
|
||||
try
|
||||
{
|
||||
return nextParser(value);
|
||||
}
|
||||
catch (Exception) { continue; }
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
using Elsa.Extensions;
|
||||
using Elsa.Metadata;
|
||||
using Elsa.Server.GraphQL.Mapping;
|
||||
using Elsa.Server.GraphQL.Types;
|
||||
using Elsa.Services;
|
||||
using HotChocolate;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddElsaGraphQL(this IServiceCollection services)
|
||||
{
|
||||
return services
|
||||
.AddScoped<IWorkflowPublisher, WorkflowPublisher>()
|
||||
.AddSingleton<VersionOptionsConverter>()
|
||||
.AddSingleton<IActivityDescriber, ActivityDescriber>()
|
||||
.AddAutoMapperProfile<MappingProfile>(ServiceLifetime.Singleton)
|
||||
.AddGraphQL(sp => SchemaBuilder.New()
|
||||
.AddServices(sp)
|
||||
.AddQueryType<QueryType>()
|
||||
.AddMutationType<MutationType>()
|
||||
.AddType<ActivityDescriptorType>()
|
||||
.AddType<ActivityPropertyDescriptorType>()
|
||||
.AddType<WorkflowInputType>()
|
||||
.AddType<ActivityDefinitionType>()
|
||||
.AddType<ActivityDefinitionInputType>()
|
||||
.AddType<ConnectionDefinitionType>()
|
||||
.AddType<WorkflowDefinitionVersionType>()
|
||||
.AddType<VersionOptionsInputType>()
|
||||
.AddType<InstantType>()
|
||||
.Create());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
using AutoMapper;
|
||||
using Elsa.Models;
|
||||
using Elsa.Server.GraphQL.Models;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Mapping
|
||||
{
|
||||
public class MappingProfile : Profile
|
||||
{
|
||||
public MappingProfile()
|
||||
{
|
||||
CreateMap<VersionOptionsInput, VersionOptions>().ConvertUsing<VersionOptionsConverter>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
using AutoMapper;
|
||||
using Elsa.Models;
|
||||
using Elsa.Server.GraphQL.Models;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Mapping
|
||||
{
|
||||
public class VersionOptionsConverter : ITypeConverter<VersionOptionsInput, VersionOptions>
|
||||
{
|
||||
public VersionOptions Convert(VersionOptionsInput source, VersionOptions destination, ResolutionContext context)
|
||||
{
|
||||
if (source.AllVersions == true)
|
||||
return VersionOptions.All;
|
||||
if (source.Draft == true)
|
||||
return VersionOptions.Draft;
|
||||
if (source.Latest == true)
|
||||
return VersionOptions.Latest;
|
||||
if (source.Published == true)
|
||||
return VersionOptions.Published;
|
||||
if (source.LatestOrPublished == true)
|
||||
return VersionOptions.LatestOrPublished;
|
||||
|
||||
return VersionOptions.SpecificVersion(source?.Version ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
namespace Elsa.Server.GraphQL.Models
|
||||
{
|
||||
public class VersionOptionsInput
|
||||
{
|
||||
public bool? Latest { get; set; }
|
||||
public bool? LatestOrPublished { get; set; }
|
||||
public bool? Published { get; set; }
|
||||
public bool? Draft { get; set; }
|
||||
public bool? AllVersions { get; set; }
|
||||
public int? Version { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using Elsa.Models;
|
||||
using Elsa.Server.GraphQL.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Models
|
||||
{
|
||||
public class WorkflowInput
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public bool? IsSingleton { get; set; }
|
||||
public bool? IsEnabled { get; set; }
|
||||
public bool? DeleteCompletedInstances { get; set; }
|
||||
public string? Variables { get; set; }
|
||||
public WorkflowPersistenceBehavior? PersistenceBehavior { get; set; }
|
||||
public ICollection<ActivityDefinitionInput>? Activities { get; set; }
|
||||
public ICollection<ConnectionDefinition>? Connections { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
namespace Elsa.Server.GraphQL.Models
|
||||
{
|
||||
public enum WorkflowSaveAction
|
||||
{
|
||||
Draft,
|
||||
Publish
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Elsa.Models;
|
||||
using Elsa.Queries;
|
||||
using Elsa.Serialization;
|
||||
using Elsa.Server.GraphQL.Models;
|
||||
using Elsa.Server.GraphQL.Types;
|
||||
using Elsa.Services;
|
||||
using HotChocolate;
|
||||
using Open.Linq.AsyncExtensions;
|
||||
using IIdGenerator = Elsa.Services.IIdGenerator;
|
||||
|
||||
namespace Elsa.Server.GraphQL
|
||||
{
|
||||
public class Mutation
|
||||
{
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public Mutation(IMapper mapper)
|
||||
{
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<WorkflowDefinition> SaveWorkflowDefinition(
|
||||
string? id,
|
||||
WorkflowSaveAction saveAction,
|
||||
WorkflowInput workflowInput,
|
||||
[Service] IWorkflowDefinitionManager manager,
|
||||
[Service] IIdGenerator idGenerator,
|
||||
[Service] IContentSerializer serializer,
|
||||
[Service] IWorkflowPublisher publisher,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var workflowDefinition = id != null
|
||||
? await manager.GetAsync(id, VersionOptions.Latest, cancellationToken)
|
||||
: default;
|
||||
|
||||
if (workflowDefinition == null)
|
||||
{
|
||||
workflowDefinition = new WorkflowDefinition
|
||||
{
|
||||
WorkflowDefinitionId = idGenerator.Generate(),
|
||||
WorkflowDefinitionVersionId = idGenerator.Generate(),
|
||||
Version = 1,
|
||||
IsLatest = true
|
||||
};
|
||||
}
|
||||
|
||||
if (workflowInput.Activities != null)
|
||||
workflowDefinition.Activities = workflowInput.Activities.Select(ToActivityDefinition).ToList();
|
||||
|
||||
if (workflowInput.Connections != null)
|
||||
workflowDefinition.Connections = workflowInput.Connections;
|
||||
|
||||
if (workflowInput.Description != null)
|
||||
workflowDefinition.Description = workflowInput.Description.Trim();
|
||||
|
||||
if (workflowInput.Name != null)
|
||||
workflowDefinition.Name = workflowInput.Name.Trim();
|
||||
|
||||
if (workflowInput.IsEnabled != null)
|
||||
workflowDefinition.IsEnabled = workflowInput.IsEnabled.Value;
|
||||
|
||||
if (workflowInput.IsSingleton != null)
|
||||
workflowDefinition.IsSingleton = workflowInput.IsSingleton.Value;
|
||||
|
||||
if (workflowInput.DeleteCompletedInstances != null)
|
||||
workflowDefinition.DeleteCompletedInstances = workflowInput.DeleteCompletedInstances.Value;
|
||||
|
||||
if (workflowInput.Variables != null)
|
||||
workflowDefinition.Variables = serializer.Deserialize<Variables>(workflowInput.Variables);
|
||||
|
||||
if (workflowInput.PersistenceBehavior != null)
|
||||
workflowDefinition.PersistenceBehavior = workflowInput.PersistenceBehavior.Value;
|
||||
|
||||
if (saveAction == WorkflowSaveAction.Publish)
|
||||
workflowDefinition = await publisher.PublishAsync(workflowDefinition, cancellationToken);
|
||||
else
|
||||
workflowDefinition = await publisher.SaveDraftAsync(workflowDefinition, cancellationToken);
|
||||
|
||||
return workflowDefinition;
|
||||
}
|
||||
|
||||
public async Task<int> DeleteWorkflowDefinition(
|
||||
string id,
|
||||
[Service] IWorkflowDefinitionManager manager,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var workflowDefinitions = await manager.QueryByIdAndVersion(id, VersionOptions.All)
|
||||
.ListAsync()
|
||||
.ToList();
|
||||
|
||||
foreach (var workflowDefinition in workflowDefinitions)
|
||||
await manager.DeleteAsync(workflowDefinition, cancellationToken);
|
||||
|
||||
return workflowDefinitions.Count;
|
||||
}
|
||||
|
||||
private ActivityDefinition ToActivityDefinition(ActivityDefinitionInput source) =>
|
||||
_mapper.Map<ActivityDefinition>(source);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Elsa.Metadata;
|
||||
using Elsa.Models;
|
||||
using Elsa.Queries;
|
||||
using Elsa.Server.GraphQL.Models;
|
||||
using Elsa.Services;
|
||||
using HotChocolate;
|
||||
|
||||
namespace Elsa.Server.GraphQL
|
||||
{
|
||||
public class Query
|
||||
{
|
||||
public IEnumerable<ActivityDescriptor> GetActivityDescriptors(
|
||||
[Service] IActivityActivator activityActivator,
|
||||
[Service] IActivityDescriber describer) =>
|
||||
activityActivator.GetActivityTypes().Select(describer.Describe).ToList();
|
||||
|
||||
public ActivityDescriptor? GetActivityDescriptor(
|
||||
[Service] IActivityActivator activityActivator,
|
||||
[Service] IActivityDescriber describer,
|
||||
string typeName)
|
||||
{
|
||||
var type = activityActivator.GetActivityType(typeName);
|
||||
|
||||
return type == null ? default : describer.Describe(type);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WorkflowDefinition>> GetWorkflowDefinitions(
|
||||
VersionOptionsInput? version,
|
||||
[Service] IWorkflowDefinitionManager manager,
|
||||
[Service] IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var mappedVersion = mapper.Map<VersionOptions?>(version);
|
||||
return await manager.ListAsync(mappedVersion ?? VersionOptions.Latest, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<WorkflowDefinition?> GetWorkflowDefinition(
|
||||
string? workflowDefinitionVersionId,
|
||||
string? workflowDefinitionId,
|
||||
VersionOptionsInput? version,
|
||||
[Service] IWorkflowDefinitionManager manager,
|
||||
[Service] IMapper mapper,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (workflowDefinitionVersionId != null)
|
||||
return await manager.GetByVersionIdAsync(workflowDefinitionVersionId, cancellationToken);
|
||||
|
||||
var mappedVersion = mapper.Map<VersionOptions?>(version);
|
||||
|
||||
return await manager.GetAsync(
|
||||
workflowDefinitionId!,
|
||||
mappedVersion ?? VersionOptions.Latest,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<WorkflowInstance>> GetWorkflowInstances(
|
||||
string definitionId,
|
||||
WorkflowStatus? status,
|
||||
[Service] IWorkflowInstanceManager manager,
|
||||
CancellationToken cancellationToken) =>
|
||||
status == null
|
||||
? await manager.ListByDefinitionAsync(definitionId, cancellationToken)
|
||||
: await manager.ListByDefinitionAndStatusAsync(definitionId, status.Value, cancellationToken);
|
||||
|
||||
public async Task<WorkflowInstance?> GetWorkflowInstance(
|
||||
string id,
|
||||
[Service] IWorkflowInstanceManager manager,
|
||||
CancellationToken cancellationToken) =>
|
||||
await manager.GetByWorkflowInstanceIdAsync(id, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class ActivityDefinitionInput
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? DisplayName { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public int? Left { get; set; }
|
||||
public int? Top { get; set; }
|
||||
public string? State { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class ActivityDefinitionInputType : InputObjectType<ActivityDefinitionInput>
|
||||
{
|
||||
protected override void Configure(IInputObjectTypeDescriptor<ActivityDefinitionInput> descriptor)
|
||||
{
|
||||
descriptor.Field(x => x.State).Type<StringType>();
|
||||
//descriptor.Field(x => x.State).Type<MyAnyType>();
|
||||
//descriptor.Field(x => x.State).Type<AnyType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
using Elsa.Models;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class ActivityDefinitionType : ObjectType<ActivityDefinition>
|
||||
{
|
||||
protected override void Configure(IObjectTypeDescriptor<ActivityDefinition> descriptor)
|
||||
{
|
||||
//descriptor.Field(x => x.State).Type<VariablesType>();
|
||||
//descriptor.Field(x => x.State).Type<MyAnyType>();
|
||||
//descriptor.Field(x => x.State).Type<AnyType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.Metadata;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class ActivityDescriptorType : ObjectType<ActivityDescriptor>
|
||||
{
|
||||
protected override void Configure(IObjectTypeDescriptor<ActivityDescriptor> descriptor)
|
||||
{
|
||||
descriptor.Field(x => x.Type).Type<NonNullType<StringType>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.Metadata;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class ActivityPropertyDescriptorType : ObjectType<ActivityPropertyDescriptor>
|
||||
{
|
||||
protected override void Configure(IObjectTypeDescriptor<ActivityPropertyDescriptor> descriptor)
|
||||
{
|
||||
descriptor.Field(x => x.Options).Type<JObjectType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using Elsa.Models;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class ConnectionDefinitionType : ObjectType<ConnectionDefinition>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using Elsa.Server.GraphQL.Extensions;
|
||||
using HotChocolate.Language;
|
||||
using HotChocolate.Types;
|
||||
using NodaTime;
|
||||
using NodaTime.Text;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class InstantType : ScalarType
|
||||
{
|
||||
public InstantType() : base("Instant")
|
||||
{
|
||||
Description = "Represents an instant on the global timeline.";
|
||||
}
|
||||
|
||||
public override Type ClrType => typeof(Instant);
|
||||
|
||||
public override bool IsInstanceOfType(IValueNode literal)
|
||||
{
|
||||
if (literal == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(literal));
|
||||
}
|
||||
|
||||
if (literal is NullValueNode)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return literal is StringValueNode stringLiteral && TryParseLiteral(stringLiteral, out _);
|
||||
}
|
||||
|
||||
private bool TryParseLiteral(StringValueNode literal, out object obj) =>
|
||||
TryDeserializeFromString(literal.Value, out obj);
|
||||
|
||||
protected bool TryDeserializeFromString(
|
||||
string serialized,
|
||||
out object obj)
|
||||
{
|
||||
obj = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override object ParseLiteral(IValueNode literal)
|
||||
{
|
||||
if (literal is StringValueNode stringValue)
|
||||
{
|
||||
return FromString(stringValue.Value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IValueNode ParseValue(object value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override object Serialize(object value)
|
||||
{
|
||||
if (value is string)
|
||||
return value;
|
||||
if (value is DateTime dateTime)
|
||||
return dateTime.ToString("o", CultureInfo.InvariantCulture);
|
||||
if (value is Instant instant)
|
||||
return InstantPattern.ExtendedIso
|
||||
.WithCulture(CultureInfo.InvariantCulture)
|
||||
.Format(instant);
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool TryDeserialize(object serialized, out object value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private static object FromString(string stringValue)
|
||||
{
|
||||
return ParserComposer.FirstNonThrowing(new Func<string, Instant>[]
|
||||
{
|
||||
str => OffsetDateTimePattern.ExtendedIso
|
||||
.WithCulture(CultureInfo.InvariantCulture)
|
||||
.Parse(str).GetValueOrThrow().ToInstant(),
|
||||
str => OffsetDateTimePattern
|
||||
.CreateWithInvariantCulture("yyyy'-'MM'-'dd'T'HH':'mm':'sso<+HHmm>")
|
||||
.Parse(str).GetValueOrThrow().ToInstant(),
|
||||
str => InstantPattern.ExtendedIso
|
||||
.WithCulture(CultureInfo.InvariantCulture)
|
||||
.Parse(str).GetValueOrThrow(),
|
||||
}, stringValue);
|
||||
}
|
||||
|
||||
private static object FromDateTimeUtc(DateTime dateTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Instant.FromDateTimeUtc(dateTime);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using HotChocolate.Language;
|
||||
using HotChocolate.Types;
|
||||
using Humanizer;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class JObjectType : ScalarType
|
||||
{
|
||||
public JObjectType() : base("JObjectType")
|
||||
{
|
||||
}
|
||||
|
||||
public override Type ClrType => typeof(JObject);
|
||||
|
||||
public override bool IsInstanceOfType(IValueNode literal)
|
||||
{
|
||||
return literal == null || literal is ObjectValueNode || literal is NullValueNode;
|
||||
}
|
||||
|
||||
public override object ParseLiteral(IValueNode literal)
|
||||
{
|
||||
return new JObject();
|
||||
}
|
||||
|
||||
public override IValueNode ParseValue(object value)
|
||||
{
|
||||
if (value is null)
|
||||
return NullValueNode.Default;
|
||||
|
||||
return new ObjectValueNode();
|
||||
}
|
||||
|
||||
public override object Serialize(object value)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
var jObject = (JObject)value;
|
||||
var dictionary = new Dictionary<string, object>();
|
||||
|
||||
foreach (var variable in jObject)
|
||||
dictionary[variable.Key.Camelize()] = variable.Value;
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
public override bool TryDeserialize(object serialized, out object value)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class MutationType : ObjectType<Mutation>
|
||||
{
|
||||
protected override void Configure(IObjectTypeDescriptor<Mutation> descriptor)
|
||||
{
|
||||
descriptor
|
||||
.Field(x => x.SaveWorkflowDefinition(default, default, default, default, default, default, default, default))
|
||||
.Argument("id", x => x.Type<IdType>());
|
||||
|
||||
descriptor
|
||||
.Field(x => x.DeleteWorkflowDefinition(default, default, default))
|
||||
.Argument("id", x => x.Type<IdType>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class QueryType : ObjectType<Query>
|
||||
{
|
||||
protected override void Configure(IObjectTypeDescriptor<Query> descriptor)
|
||||
{
|
||||
descriptor
|
||||
.Field(x => x.GetActivityDescriptor(default, default, default))
|
||||
.Argument("typeName", x => x.Type<IdType>());
|
||||
|
||||
descriptor
|
||||
.Field(x => x.GetWorkflowDefinitions(default, default, default, default))
|
||||
.Argument("version", x => x.Type<VersionOptionsInputType>());
|
||||
|
||||
descriptor
|
||||
.Field(x => x.GetWorkflowDefinition(default, default, default, default, default, default))
|
||||
.Argument("id", x => x.Type<IdType>())
|
||||
.Argument("definitionId", x => x.Type<IdType>())
|
||||
.Argument("version", x => x.Type<VersionOptionsInputType>());
|
||||
|
||||
descriptor
|
||||
.Field(x => x.GetWorkflowInstances(default, default, default, default))
|
||||
.Argument("definitionId", x => x.Type<IdType>());
|
||||
|
||||
descriptor
|
||||
.Field(x => x.GetWorkflowInstance(default, default, default))
|
||||
.Argument("id", x => x.Type<IdType>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.Server.GraphQL.Models;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class VersionOptionsInputType : InputObjectType<VersionOptionsInput>
|
||||
{
|
||||
protected override void Configure(IInputObjectTypeDescriptor<VersionOptionsInput> descriptor)
|
||||
{
|
||||
descriptor.Field(x => x.Version).Type<IntType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.Models;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class WorkflowDefinitionVersionType : ObjectType<WorkflowDefinition>
|
||||
{
|
||||
protected override void Configure(IObjectTypeDescriptor<WorkflowDefinition> descriptor)
|
||||
{
|
||||
//descriptor.Field(x => x.Variables).Type<VariablesType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.Server.GraphQL.Models;
|
||||
using HotChocolate.Types;
|
||||
|
||||
namespace Elsa.Server.GraphQL.Types
|
||||
{
|
||||
public class WorkflowInputType : InputObjectType<WorkflowInput>
|
||||
{
|
||||
protected override void Configure(IInputObjectTypeDescriptor<WorkflowInput> descriptor)
|
||||
{
|
||||
descriptor.Field(x => x.Variables).Type<StringType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
|
|
@ -26,17 +26,18 @@ namespace Elsa.Server.Host
|
|||
var connectionString = Configuration.GetConnectionString("Sqlite");
|
||||
|
||||
services
|
||||
.AddElsa(elsa => elsa
|
||||
.UsePersistence(config => config.UseSqLite(connectionString)));
|
||||
.AddElsa(
|
||||
elsa => elsa
|
||||
.UsePersistence(config => config.UseSqLite(connectionString)));
|
||||
|
||||
services
|
||||
.AddElsaServer()
|
||||
.AddElsaApiEndpoints()
|
||||
|
||||
.AddCors(options => options.AddDefaultPolicy(cors => cors
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()))
|
||||
.AddCors(
|
||||
options => options.AddDefaultPolicy(
|
||||
cors => cors
|
||||
.AllowAnyOrigin()
|
||||
.AllowAnyMethod()
|
||||
.AllowAnyHeader()))
|
||||
|
||||
.AddConsoleActivities()
|
||||
.AddHttpActivities(options => options.Bind(elsaSection.GetSection("Http")))
|
||||
|
|
@ -54,7 +55,9 @@ namespace Elsa.Server.Host
|
|||
|
||||
app
|
||||
.UseCors()
|
||||
.UseHttpActivities();
|
||||
.UseHttpActivities()
|
||||
.UseRouting()
|
||||
.UseEndpoints(configure => configure.MapControllers());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ namespace Elsa.ComponentTests.Endpoints.WorkflowDefinitions
|
|||
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
|
||||
}
|
||||
|
||||
private CreateWorkflowDefinitionRequest CreateWorkflowDefinitionRequest()
|
||||
private SaveWorkflowDefinitionRequest CreateWorkflowDefinitionRequest()
|
||||
{
|
||||
var writeLine = new ActivityDefinition
|
||||
{
|
||||
|
|
@ -55,7 +55,7 @@ namespace Elsa.ComponentTests.Endpoints.WorkflowDefinitions
|
|||
var activities = new[] { writeLine, readLine };
|
||||
var connections = new[] { new ConnectionDefinition(writeLine.Id, readLine.Id, OutcomeNames.Done) };
|
||||
|
||||
return _fixture.Build<CreateWorkflowDefinitionRequest>()
|
||||
return _fixture.Build<SaveWorkflowDefinitionRequest>()
|
||||
.With(x => x.Activities, activities)
|
||||
.With(x => x.Connections, connections)
|
||||
.Create();
|
||||
|
|
|
|||
Loading…
Reference in a new issue