Incremental work
This commit is contained in:
parent
58663b4b2f
commit
078f21cf61
18
Elsa.sln
18
Elsa.sln
|
|
@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{7D
|
|||
ProjectSection(SolutionItems) = preProject
|
||||
README.md = README.md
|
||||
docker-compose.yml = docker-compose.yml
|
||||
common.props = common.props
|
||||
configureawait.props = configureawait.props
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{0354F050-3992-4DD4-B0EE-5FBA04AC72B6}"
|
||||
|
|
@ -78,7 +80,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.AllInOne.Web", "src\bu
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.WorkflowServer.Web", "src\bundles\Elsa.WorkflowServer.Web\Elsa.WorkflowServer.Web.csproj", "{3C2752A7-EEBC-4ED4-B1BF-0FCF6E071BC2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.Abstractions", "src\common\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj", "{6D590FA1-898B-429B-AE85-DE16BE691246}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.Common", "src\common\Elsa.Persistence.Common\Elsa.Persistence.Common.csproj", "{6D590FA1-898B-429B-AE85-DE16BE691246}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.EntityFrameworkCore.Common", "src\common\Elsa.Persistence.EntityFrameworkCore.Common\Elsa.Persistence.EntityFrameworkCore.Common.csproj", "{B962750E-C2B1-4F5A-B3C5-6C64CAF1ED2E}"
|
||||
EndProject
|
||||
|
|
@ -100,8 +102,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Features", "src\common
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.MemoryCache", "src\modules\Elsa.MemoryCache\Elsa.MemoryCache.csproj", "{2570418D-1674-4DAE-9A24-9146D522450C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.AspNetCore", "src\modules\Elsa.AspNetCore\Elsa.AspNetCore.csproj", "{2CFF3041-BB6A-45EA-9716-7BA531BA6479}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Expressions", "src\modules\Elsa.Expressions\Elsa.Expressions.csproj", "{80529478-A383-4FEA-B744-C71264969E9A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Mediator", "src\modules\Elsa.Mediator\Elsa.Mediator.csproj", "{40ED82D8-A7BB-4D37-9157-3176EDA3E119}"
|
||||
|
|
@ -132,6 +132,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "worker", "worker", "{389D40
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.Worker1", "src\samples\Elsa.Samples.Worker1\Elsa.Samples.Worker1.csproj", "{197223FB-2472-442C-BD10-2E1F931285BC}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Models.Common", "src\common\Elsa.Models.Common\Elsa.Models.Common.csproj", "{81BDD2FB-810E-4526-8290-80BA2F4FC473}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -290,10 +292,6 @@ Global
|
|||
{2570418D-1674-4DAE-9A24-9146D522450C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2570418D-1674-4DAE-9A24-9146D522450C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2570418D-1674-4DAE-9A24-9146D522450C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2CFF3041-BB6A-45EA-9716-7BA531BA6479}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2CFF3041-BB6A-45EA-9716-7BA531BA6479}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2CFF3041-BB6A-45EA-9716-7BA531BA6479}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2CFF3041-BB6A-45EA-9716-7BA531BA6479}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{80529478-A383-4FEA-B744-C71264969E9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{80529478-A383-4FEA-B744-C71264969E9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{80529478-A383-4FEA-B744-C71264969E9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
@ -342,6 +340,10 @@ Global
|
|||
{517B703A-7653-4036-AAB5-7B4293D39D0F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{197223FB-2472-442C-BD10-2E1F931285BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{197223FB-2472-442C-BD10-2E1F931285BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81BDD2FB-810E-4526-8290-80BA2F4FC473}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81BDD2FB-810E-4526-8290-80BA2F4FC473}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81BDD2FB-810E-4526-8290-80BA2F4FC473}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81BDD2FB-810E-4526-8290-80BA2F4FC473}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{155227F0-A33B-40AA-A4B4-06F813EB921B} = {61017E64-6D00-49CB-9E81-5002DC8F7D5F}
|
||||
|
|
@ -385,7 +387,6 @@ Global
|
|||
{8A050229-DB79-4E0B-9AFF-7565E87F2954} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{C237BA1A-3A7D-4AB2-BE09-2696F3C082A4} = {C6658DE0-2B2F-47F0-BB61-2CA66D435C09}
|
||||
{2570418D-1674-4DAE-9A24-9146D522450C} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{2CFF3041-BB6A-45EA-9716-7BA531BA6479} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{80529478-A383-4FEA-B744-C71264969E9A} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{40ED82D8-A7BB-4D37-9157-3176EDA3E119} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{80FF5821-E831-450D-AA0C-C76D07D878F4} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
|
|
@ -402,5 +403,6 @@ Global
|
|||
{517B703A-7653-4036-AAB5-7B4293D39D0F} = {873BFC3E-63C2-4495-A503-5EC05DCD84E4}
|
||||
{F599E891-598E-402F-A9B9-95D0B1C661F6} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{26087ED2-9249-4FF3-8869-C11C405E441A} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79}
|
||||
{81BDD2FB-810E-4526-8290-80BA2F4FC473} = {C6658DE0-2B2F-47F0-BB61-2CA66D435C09}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
30
common.props
Normal file
30
common.props
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Authors>Elsa Contributors</Authors>
|
||||
<Copyright>2022</Copyright>
|
||||
<PackageProjectUrl>https://github.com/elsa-workflows/elsa-core</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/elsa-workflows/elsa-core</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageIconUrl>https://elsaworkflows.io/nuget-icon.png</PackageIconUrl>
|
||||
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<AnalysisModeDocumentation>Default</AnalysisModeDocumentation>
|
||||
<AnalysisLevelDocumentation>latest</AnalysisLevelDocumentation>
|
||||
|
||||
<!-- https://github.com/dotnet/sourcelink -->
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
9
configureawait.props
Normal file
9
configureawait.props
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<Project>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ConfigureAwait.Fody" Version="3.3.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Fody" Version="6.6.3">
|
||||
<PrivateAssets>All</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Elsa.Workflows.Api.Extensions;
|
||||
using Elsa.AspNetCore.Extensions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Jobs.Extensions;
|
||||
using Elsa.Http;
|
||||
|
|
@ -46,7 +45,6 @@ services
|
|||
.UseLiquid()
|
||||
.UseHttp()
|
||||
.UseCustomActivities()
|
||||
.UseMvc()
|
||||
);
|
||||
|
||||
// Register serialization configurator for configuring what types to allow to be serialized.
|
||||
|
|
|
|||
3
src/bundles/Elsa.AllInOne.Web/README
Normal file
3
src/bundles/Elsa.AllInOne.Web/README
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# All In One
|
||||
|
||||
This project represents an Elsa application that hosts both the workflow server as well as the dashboard.
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Elsa.Api.Common;
|
||||
using Elsa.Api.Common.Options;
|
||||
using Elsa.Api.Common.Services;
|
||||
using Elsa.WorkflowServer.Web.Models;
|
||||
using FastEndpoints.Security;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.WorkflowServer.Web.Implementations;
|
||||
|
||||
public class CustomAccessTokenIssuer : IAccessTokenIssuer
|
||||
{
|
||||
private readonly AccessTokenOptions _options;
|
||||
|
||||
public CustomAccessTokenIssuer(IOptions<AccessTokenOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public ValueTask<string> CreateTokenAsync(IDictionary<string, string> credentials, object? context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var user = context as User;
|
||||
var fullName = user!.FullName;
|
||||
|
||||
var jwtToken = JWTBearer.CreateToken(
|
||||
signingKey: _options.SigningKey,
|
||||
roles: new[] { RoleNames.Admin },
|
||||
permissions: new[] { PermissionNames.Everything },
|
||||
claims: new[] { new Claim(JwtRegisteredClaimNames.Name, fullName) }
|
||||
);
|
||||
|
||||
return new(jwtToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
using Elsa.Api.Common.Models;
|
||||
using Elsa.Api.Common.Services;
|
||||
using Elsa.WorkflowServer.Web.Models;
|
||||
|
||||
namespace Elsa.WorkflowServer.Web.Implementations;
|
||||
|
||||
public class CustomCredentialsValidator : ICredentialsValidator
|
||||
{
|
||||
public ValueTask<ValidateCredentialsResult> ValidateCredentialsAsync(IDictionary<string, string> credentials, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var isValid = credentials.TryGetValue("user", out var user) && user == "admin" && credentials.TryGetValue("password", out var password) && password == "admin";
|
||||
|
||||
return !isValid
|
||||
? new(ValidateCredentialsResult.Invalid())
|
||||
: new(ValidateCredentialsResult.Valid(new User("Superman")));
|
||||
}
|
||||
}
|
||||
|
|
@ -2,10 +2,6 @@ using System.Text.Json;
|
|||
using System.Text.Json.Serialization;
|
||||
using Elsa.ActivityDefinitions.EntityFrameworkCore.Extensions;
|
||||
using Elsa.ActivityDefinitions.EntityFrameworkCore.Sqlite;
|
||||
using Elsa.Api.Common;
|
||||
using Elsa.Api.Common.Features;
|
||||
using Elsa.Api.Common.Options;
|
||||
using Elsa.AspNetCore.Extensions;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Features.Extensions;
|
||||
using Elsa.Http;
|
||||
|
|
@ -32,24 +28,12 @@ using Elsa.Workflows.Persistence.EntityFrameworkCore.Extensions;
|
|||
using Elsa.Workflows.Persistence.EntityFrameworkCore.Sqlite;
|
||||
using Elsa.Workflows.Persistence.Extensions;
|
||||
using Elsa.Workflows.Runtime.Extensions;
|
||||
using Elsa.WorkflowServer.Web.Implementations;
|
||||
using Elsa.WorkflowServer.Web.Jobs;
|
||||
using FastEndpoints;
|
||||
using FastEndpoints.Security;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
var services = builder.Services;
|
||||
var configuration = builder.Configuration;
|
||||
var accessTokenOptions = new AccessTokenOptions();
|
||||
configuration.GetSection("AccessTokens").Bind(accessTokenOptions);
|
||||
|
||||
// Global control over Elsa API endpoints security.
|
||||
ApiSecurityOptions.AllowAnonymous = !builder.Environment.IsProduction();
|
||||
ApiSecurityOptions.ValidateRoles = builder.Environment.IsProduction();
|
||||
|
||||
// Add application-specific services.
|
||||
services.AddSingleton<CustomCredentialsValidator>();
|
||||
services.AddSingleton<CustomAccessTokenIssuer>();
|
||||
|
||||
// Add Elsa services.
|
||||
services
|
||||
|
|
@ -70,12 +54,6 @@ services
|
|||
.AddActivity<RunJavaScript>()
|
||||
.AddActivity<Event>()
|
||||
)
|
||||
.Use<CommonApiFeature>(feature =>
|
||||
{
|
||||
feature.TokenSigningKey = accessTokenOptions.SigningKey;
|
||||
feature.CredentialsValidator = sp => sp.GetRequiredService<CustomCredentialsValidator>();
|
||||
feature.AccessTokenIssuer = sp => sp.GetRequiredService<CustomAccessTokenIssuer>();
|
||||
})
|
||||
.UseJobActivities()
|
||||
.UseScheduling()
|
||||
.UseWorkflowPersistence(p => p.UseEntityFrameworkCore(ef => ef.UseSqlite()))
|
||||
|
|
@ -85,11 +63,9 @@ services
|
|||
.UseLabels(labels => labels.UseEntityFrameworkCore(ef => ef.UseSqlite()))
|
||||
.UseCustomActivities(feature => feature.UseEntityFrameworkCore(ef => ef.UseSqlite()))
|
||||
.UseHttp()
|
||||
.UseMvc()
|
||||
);
|
||||
|
||||
services.AddFastEndpoints();
|
||||
services.AddAuthenticationJWTBearer(accessTokenOptions.SigningKey);
|
||||
services.AddHealthChecks();
|
||||
services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
|
||||
|
||||
|
|
@ -161,9 +137,9 @@ Task SerializeRequestAsync(HttpResponse httpResponse, object dto, string content
|
|||
|
||||
app.UseFastEndpoints(config =>
|
||||
{
|
||||
config.RoutingOptions = routing => routing.Prefix = "elsa/api";
|
||||
config.RequestDeserializer = DeserializeRequestAsync;
|
||||
config.ResponseSerializer = SerializeRequestAsync;
|
||||
config.Endpoints.RoutePrefix = "elsa/api";
|
||||
config.Serializer.RequestDeserializer = DeserializeRequestAsync;
|
||||
config.Serializer.ResponseSerializer = SerializeRequestAsync;
|
||||
});
|
||||
|
||||
// Register Elsa middleware.
|
||||
|
|
|
|||
3
src/bundles/Elsa.WorkflowServer.Web/README
Normal file
3
src/bundles/Elsa.WorkflowServer.Web/README
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# Server
|
||||
|
||||
This project represents an Elsa application that hosts workflows and exposes API endpoints to manage & execute workflows.
|
||||
|
|
@ -6,8 +6,5 @@
|
|||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"AccessTokens": {
|
||||
"SigningKey": "ultra-secure-key"
|
||||
}
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Bundles the most commonly-used packages when building an Elsa workflows application.
|
||||
</Description>
|
||||
<RootNamespace>Elsa</RootNamespace>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<PackageTags>elsa</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using Elsa.Features;
|
||||
using Elsa.Features.Extensions;
|
||||
using Elsa.Features.Services;
|
||||
|
|
@ -6,21 +5,20 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods to <see cref="IServiceCollection"/>.
|
||||
/// </summary>
|
||||
public static class DependencyInjectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new Elsa module and adds the <see cref="ElsaFeature"/> to it.
|
||||
/// </summary>
|
||||
public static IServiceCollection AddElsa(this IServiceCollection services, Action<IModule>? configure = default)
|
||||
{
|
||||
var serviceConfiguration = services.ConfigureElsa();
|
||||
configure?.Invoke(serviceConfiguration);
|
||||
serviceConfiguration.Apply();
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IModule ConfigureElsa(this IServiceCollection services)
|
||||
{
|
||||
var module = services.CreateModule();
|
||||
module.Configure<ElsaFeature>();
|
||||
|
||||
return module;
|
||||
configure?.Invoke(module);
|
||||
module.Apply();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,16 @@
|
|||
using System;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Provides extension methods to the <see cref="IServiceProvider"/>.
|
||||
/// </summary>
|
||||
public static class ServiceProviderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Configure the default activity execution pipeline.
|
||||
/// </summary>
|
||||
public static IServiceProvider ConfigureDefaultActivityExecutionPipeline(this IServiceProvider services, Action<IActivityExecutionBuilder> setup)
|
||||
{
|
||||
var pipeline = services.GetRequiredService<IActivityExecutionPipeline>();
|
||||
|
|
@ -13,6 +18,9 @@ public static class ServiceProviderExtensions
|
|||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the default workflow execution pipeline.
|
||||
/// </summary>
|
||||
public static IServiceProvider ConfigureDefaultWorkflowExecutionPipeline(this IServiceProvider services, Action<IWorkflowExecutionBuilder> setup)
|
||||
{
|
||||
var pipeline = services.GetRequiredService<IWorkflowExecutionPipeline>();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Elsa.Api.Common.Features;
|
||||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Attributes;
|
||||
using Elsa.Features.Services;
|
||||
|
|
@ -10,15 +9,18 @@ using Elsa.Workflows.Runtime.Features;
|
|||
|
||||
namespace Elsa.Features;
|
||||
|
||||
/// <summary>
|
||||
/// Represents Elsa as a feature of the system.
|
||||
/// </summary>
|
||||
[DependsOn(typeof(MediatorFeature))]
|
||||
[DependsOn(typeof(WorkflowsFeature))]
|
||||
[DependsOn(typeof(FlowchartFeature))]
|
||||
[DependsOn(typeof(WorkflowPersistenceFeature))]
|
||||
[DependsOn(typeof(WorkflowRuntimeFeature))]
|
||||
[DependsOn(typeof(WorkflowManagementFeature))]
|
||||
[DependsOn(typeof(CommonApiFeature))]
|
||||
public class ElsaFeature : FeatureBase
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ElsaFeature(IModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
namespace Elsa.Api.Common;
|
||||
|
||||
public static class ApiSecurityOptions
|
||||
{
|
||||
public static bool AllowAnonymous = true;
|
||||
public static bool ValidatePermissions = false;
|
||||
public static bool ValidatePolicies = false;
|
||||
public static bool ValidateRoles = false;
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
namespace Elsa.Api.Common;
|
||||
|
||||
public static class PermissionNames
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow access to all API endpoints.
|
||||
/// </summary>
|
||||
public const string Everything = "Everything";
|
||||
}
|
||||
|
||||
public static class PolicyNames
|
||||
{
|
||||
public const string Admin = "Admin";
|
||||
}
|
||||
|
||||
public static class RoleNames
|
||||
{
|
||||
public const string Admin = "Admin";
|
||||
}
|
||||
|
|
@ -1,20 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Provides common features to modules that expose API endpoints.
|
||||
</Description>
|
||||
<RootNamespace>Elsa</RootNamespace>
|
||||
<PackageTags>elsa, api</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FastEndpoints" Version="4.3.1" />
|
||||
<PackageReference Include="FastEndpoints.Security" Version="4.3.1" />
|
||||
<PackageReference Include="FastEndpoints.Swagger" Version="4.3.1" />
|
||||
<PackageReference Include="FastEndpoints" Version="5.0.0" />
|
||||
<PackageReference Include="FastEndpoints.Security" Version="5.0.0" />
|
||||
<PackageReference Include="FastEndpoints.Swagger" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Elsa.Features\Elsa.Features.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Models.Common\Elsa.Models.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
using Elsa.Api.Common.Implementations;
|
||||
using Elsa.Api.Common.Options;
|
||||
using Elsa.Api.Common.Services;
|
||||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.Api.Common.Features;
|
||||
|
||||
public class CommonApiFeature : FeatureBase
|
||||
{
|
||||
public CommonApiFeature(IModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public string TokenSigningKey { get; set; } = default!;
|
||||
public Func<IServiceProvider, ICredentialsValidator> CredentialsValidator { get; set; } = ActivatorUtilities.GetServiceOrCreateInstance<AllowAnyCredentialsValidator>;
|
||||
public Func<IServiceProvider, IAccessTokenIssuer> AccessTokenIssuer { get; set; } = ActivatorUtilities.GetServiceOrCreateInstance<AdminAccessTokenIssuer>;
|
||||
|
||||
public override void Apply()
|
||||
{
|
||||
Services.Configure<AccessTokenOptions>(options => options.SigningKey = TokenSigningKey);
|
||||
Services.AddSingleton(sp => CredentialsValidator(sp));
|
||||
Services.AddSingleton(sp => AccessTokenIssuer(sp));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
using Elsa.Api.Common.Options;
|
||||
using Elsa.Api.Common.Services;
|
||||
using FastEndpoints.Security;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Api.Common.Implementations;
|
||||
|
||||
/// <summary>
|
||||
/// Creates access tokens that grant full access to all Elsa API endpoints by means of the Admin role and Everything permissions.
|
||||
/// </summary>
|
||||
public class AdminAccessTokenIssuer : IAccessTokenIssuer
|
||||
{
|
||||
private readonly AccessTokenOptions _options;
|
||||
|
||||
public AdminAccessTokenIssuer(IOptions<AccessTokenOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public ValueTask<string> CreateTokenAsync(IDictionary<string, string> credentials, object? context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var jwtToken = JWTBearer.CreateToken(
|
||||
signingKey: _options.SigningKey,
|
||||
roles: new[] { RoleNames.Admin },
|
||||
permissions: new[] { PermissionNames.Everything });
|
||||
|
||||
return new(jwtToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using Elsa.Api.Common.Models;
|
||||
using Elsa.Api.Common.Services;
|
||||
|
||||
namespace Elsa.Api.Common.Implementations;
|
||||
|
||||
public class AllowAnyCredentialsValidator : ICredentialsValidator
|
||||
{
|
||||
public ValueTask<ValidateCredentialsResult> ValidateCredentialsAsync(IDictionary<string, string> credentials, CancellationToken cancellationToken = default) => new(ValidateCredentialsResult.Valid());
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
namespace Elsa.Api.Common.Models;
|
||||
|
||||
public class EndpointConfiguration
|
||||
{
|
||||
public ICollection<string> Policies { get; } = new List<string>();
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
using Elsa.Persistence.Common.Models;
|
||||
|
||||
namespace Elsa.Api.Common.Models;
|
||||
namespace Elsa.Models;
|
||||
|
||||
public class PagedListResponse<T>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Elsa.Api.Common.Models;
|
||||
namespace Elsa.Models;
|
||||
|
||||
public record ValidateCredentialsResult(bool IsValid, object? Context = null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
namespace Elsa.Api.Common.Options;
|
||||
|
||||
public class AccessTokenOptions
|
||||
{
|
||||
public string SigningKey { get; set; } = default!;
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.Api.Common;
|
||||
|
||||
public class ProtectedEndpoint<TRequest, TResponse> : Endpoint<TRequest, TResponse> where TRequest : notnull, new() where TResponse : notnull, new()
|
||||
{
|
||||
protected void ConfigureSecurity(IEnumerable<string> permissions, IEnumerable<string> policies, IEnumerable<string> roles)
|
||||
{
|
||||
if (ApiSecurityOptions.AllowAnonymous)
|
||||
{
|
||||
AllowAnonymous();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ApiSecurityOptions.ValidatePermissions)
|
||||
Permissions(new[] { PermissionNames.Everything }.Concat(permissions).ToArray());
|
||||
|
||||
if (ApiSecurityOptions.ValidatePolicies)
|
||||
Policies(new[] { PolicyNames.Admin }.Concat(policies).ToArray());
|
||||
|
||||
if (ApiSecurityOptions.ValidateRoles)
|
||||
Roles(new[] { RoleNames.Admin }.Concat(roles).ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public class ProtectedEndpoint<TRequest> : Endpoint<TRequest> where TRequest : notnull, new()
|
||||
{
|
||||
protected void ConfigureSecurity(IEnumerable<string> permissions, IEnumerable<string> policies, IEnumerable<string> roles)
|
||||
{
|
||||
if (ApiSecurityOptions.AllowAnonymous)
|
||||
{
|
||||
AllowAnonymous();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ApiSecurityOptions.ValidatePermissions)
|
||||
Permissions(new[] { PermissionNames.Everything }.Concat(permissions).ToArray());
|
||||
|
||||
if (ApiSecurityOptions.ValidatePolicies)
|
||||
Policies(new[] { PolicyNames.Admin }.Concat(policies).ToArray());
|
||||
|
||||
if (ApiSecurityOptions.ValidateRoles)
|
||||
Roles(new[] { RoleNames.Admin }.Concat(roles).ToArray());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
namespace Elsa.Api.Common.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Implement this to issue new security tokens based on the specified credentials.
|
||||
/// </summary>
|
||||
public interface IAccessTokenIssuer
|
||||
{
|
||||
ValueTask<string> CreateTokenAsync(IDictionary<string, string> credentials, object? context, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
using Elsa.Api.Common.Models;
|
||||
|
||||
namespace Elsa.Api.Common.Services;
|
||||
|
||||
public interface ICredentialsValidator
|
||||
{
|
||||
ValueTask<ValidateCredentialsResult> ValidateCredentialsAsync(IDictionary<string, string> credentials, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -3,24 +3,46 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
|
||||
namespace Elsa.Features.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Base type for classes that represent a feature.
|
||||
/// </summary>
|
||||
public abstract class FeatureBase : IFeature
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor.
|
||||
/// </summary>
|
||||
protected FeatureBase(IModule module)
|
||||
{
|
||||
Module = module;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The module this feature is a part of.
|
||||
/// </summary>
|
||||
public IModule Module { get; }
|
||||
|
||||
/// <summary>
|
||||
/// A reference to the <see cref="IServiceCollection"/> to which services can be added.
|
||||
/// </summary>
|
||||
public IServiceCollection Services => Module.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to configure your feature.
|
||||
/// </summary>
|
||||
public virtual void Configure()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this method to register any hosted services provided by your feature.
|
||||
/// </summary>
|
||||
public virtual void ConfigureHostedServices()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override this to register services with <see cref="Services"/>.
|
||||
/// </summary>
|
||||
public virtual void Apply()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Provides utilities to turn your class library into a module that provides features.
|
||||
</Description>
|
||||
<PackageTags>elsa, common</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
A small utility library for formatting objects from and to strings.
|
||||
</Description>
|
||||
<PackageTags>elsa, common</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
15
src/common/Elsa.Models.Common/Elsa.Models.Common.csproj
Normal file
15
src/common/Elsa.Models.Common/Elsa.Models.Common.csproj
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Description>
|
||||
Provides common models used by various modules.
|
||||
</Description>
|
||||
<RootNamespace>Elsa</RootNamespace>
|
||||
<PackageTags>elsa, common</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Elsa.Persistence.Common.Models;
|
||||
namespace Elsa.Models;
|
||||
|
||||
public record Page<T>(ICollection<T> Items, long TotalCount);
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Elsa.Persistence.Common.Models;
|
||||
namespace Elsa.Models;
|
||||
|
||||
public record PageArgs(int? Page, int? PageSize)
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using System.ComponentModel;
|
||||
using Elsa.Persistence.Common.TypeConverters;
|
||||
using Elsa.TypeConverters;
|
||||
|
||||
namespace Elsa.Persistence.Common.Models;
|
||||
namespace Elsa.Models;
|
||||
|
||||
[TypeConverter(typeof(VersionOptionsTypeConverter))]
|
||||
public struct VersionOptions
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Persistence.Common.TypeConverters
|
||||
namespace Elsa.TypeConverters
|
||||
{
|
||||
public class VersionOptionsTypeConverter : TypeConverter
|
||||
{
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>Elsa.Persistence.Common</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LinqKit" Version="1.2.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Description>
|
||||
Provides common features that can be used by persistence modules.
|
||||
</Description>
|
||||
<PackageTags>elsa, common, persistence</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LinqKit" Version="1.2.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Elsa.Models.Common\Elsa.Models.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Persistence.Common.Extensions;
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using System.Linq.Expressions;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Persistence.Common.Extensions;
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Linq.Expressions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.Common.Entities;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using LinqKit;
|
||||
|
||||
namespace Elsa.Persistence.Common.Extensions;
|
||||
|
|
@ -1,9 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Provides common features that can be used by persistence modules using Entity Framework Core.
|
||||
</Description>
|
||||
<PackageTags>elsa</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -23,7 +28,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Persistence.Common\Elsa.Persistence.Common.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Features\Elsa.Features.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Linq.Expressions;
|
||||
using EFCore.BulkExtensions;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Elsa.Persistence.EntityFrameworkCore.Common.Extensions;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System.Linq.Expressions;
|
||||
using EFCore.BulkExtensions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.Common.Entities;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Common.Extensions;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Common.Services;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using System.Linq.Expressions;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.Common.Entities;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
|
||||
namespace Elsa.Persistence.EntityFrameworkCore.Common.Services;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Provides abstractions representing a service bus that can be used by other Elsa modules.
|
||||
Concrete implementations are provided by different packages such as Elsa.MassTransit.
|
||||
</Description>
|
||||
<PackageTags>elsa, common, service bus</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props"/>
|
||||
<Import Project="..\..\..\configureawait.props"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Provides migrations specific to SQLite for the Entity Framework Core implementation.
|
||||
</Description>
|
||||
<PackageTags>elsa, module, efcore, sqlite</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.3">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,18 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props"/>
|
||||
<Import Project="..\..\..\configureawait.props"/>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Provides an Entity Framework Core implementation of the persistence abstractions provided by Elsa.ActivityDefinitions.
|
||||
</Description>
|
||||
<PackageTags>elsa, module, efcore</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.3">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ using System.Linq.Expressions;
|
|||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Models;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.Common.Extensions;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Common.Extensions;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Common.Services;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<Import Project="..\..\..\common.props" />
|
||||
<Import Project="..\..\..\configureawait.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Description>
|
||||
Activity Definitions allow you to manage custom activity definitions that can be created using the workflow designer.
|
||||
Think reusable mini workflows that can be used as composite activities.
|
||||
</Description>
|
||||
<PackageTags>elsa, module</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -17,7 +23,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\Elsa.Api.Common\Elsa.Api.Common.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Mediator\Elsa.Mediator.csproj" />
|
||||
<ProjectReference Include="..\..\common\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\common\Elsa.Persistence.Common\Elsa.Persistence.Common.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Core\Elsa.Workflows.Core.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Management\Elsa.Workflows.Management.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Persistence\Elsa.Workflows.Persistence.csproj" />
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.BulkDelete;
|
||||
|
||||
public static class SecurityConstants
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="BulkDelete"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly string[] Policies = { "DeleteActivityDefinitions" };
|
||||
public static readonly string[] Permissions = { "DeleteActivityDefinitions" };
|
||||
public static readonly string[] Roles = { "DefinitionsDeleter" };
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "BulkDeleteActivityDefinitions";
|
||||
}
|
||||
|
|
@ -1,23 +1,29 @@
|
|||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Api.Common;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.BulkDelete;
|
||||
|
||||
public class BulkDelete : ProtectedEndpoint<Request, Response>
|
||||
/// <summary>
|
||||
/// An endpoint that bulk-deletes activity definitions.
|
||||
/// </summary>
|
||||
public class BulkDelete : Endpoint<Request, Response>
|
||||
{
|
||||
private readonly IActivityDefinitionStore _activityDefinitionStore;
|
||||
|
||||
/// <inheritdoc />
|
||||
public BulkDelete(IActivityDefinitionStore activityDefinitionStore)
|
||||
{
|
||||
_activityDefinitionStore = activityDefinitionStore;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/bulk-actions/delete/activity-definitions/by-definition-id");
|
||||
ConfigureSecurity(SecurityConstants.Permissions, SecurityConstants.Policies, SecurityConstants.Roles);
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<Response> ExecuteAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var deleted = await _activityDefinitionStore.DeleteByDefinitionIdsAsync(request.DefinitionIds, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.BulkDelete;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a bulk-delete activity definitions request.
|
||||
/// </summary>
|
||||
public class Request
|
||||
{
|
||||
/// <summary>
|
||||
/// The activity definition IDs to delete.
|
||||
/// </summary>
|
||||
public ICollection<string> DefinitionIds { get; set; } = default!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a bulk-delete response.
|
||||
/// </summary>
|
||||
public class Response
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of records that were actually deleted.
|
||||
/// </summary>
|
||||
public int Deleted { get; set; }
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.Delete;
|
||||
|
||||
public static class SecurityConstants
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="Delete"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly string[] Policies = { "DeleteActivityDefinitions" };
|
||||
public static readonly string[] Permissions = { "DeleteActivityDefinitions" };
|
||||
public static readonly string[] Roles = { "DefinitionsDeleter" };
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "DeleteActivityDefinition";
|
||||
}
|
||||
|
|
@ -1,23 +1,29 @@
|
|||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Api.Common;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.Delete;
|
||||
|
||||
public class Delete : ProtectedEndpoint<Request>
|
||||
/// <summary>
|
||||
/// An endpoint that deletes a specific activity definition by ID.
|
||||
/// </summary>
|
||||
public class Delete : Endpoint<Request>
|
||||
{
|
||||
private readonly IActivityDefinitionStore _activityDefinitionStore;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Delete(IActivityDefinitionStore activityDefinitionStore)
|
||||
{
|
||||
_activityDefinitionStore = activityDefinitionStore;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/activity-definitions/{definitionId}");
|
||||
ConfigureSecurity(SecurityConstants.Permissions, SecurityConstants.Policies, SecurityConstants.Roles);
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
await _activityDefinitionStore.DeleteByDefinitionIdAsync(request.DefinitionId, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.Get;
|
||||
|
||||
public static class SecurityConstants
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="Get"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly string[] Policies = { "ReadActivityDefinitions" };
|
||||
public static readonly string[] Permissions = { "ReadActivityDefinitions" };
|
||||
public static readonly string[] Roles = { "ActivityDefinitionsReader" };
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "ReadActivityDefinitions";
|
||||
}
|
||||
|
|
@ -1,20 +1,26 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Models;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Api.Common;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
using Elsa.Workflows.Management.Mappers;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.Get;
|
||||
|
||||
public class Get : ProtectedEndpoint<Request, ActivityDefinitionModel>
|
||||
/// <summary>
|
||||
/// An endpoint that returns the specified <see cref="ActivityDefinition"/> by ID.
|
||||
/// </summary>
|
||||
public class Get : Endpoint<Request, ActivityDefinitionModel>
|
||||
{
|
||||
private readonly IActivityDefinitionStore _activityDefinitionStore;
|
||||
private readonly VariableDefinitionMapper _variableDefinitionMapper;
|
||||
private readonly SerializerOptionsProvider _serializerOptionsProvider;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Get(IActivityDefinitionStore activityDefinitionStore, VariableDefinitionMapper variableDefinitionMapper, SerializerOptionsProvider serializerOptionsProvider)
|
||||
{
|
||||
_activityDefinitionStore = activityDefinitionStore;
|
||||
|
|
@ -22,12 +28,14 @@ public class Get : ProtectedEndpoint<Request, ActivityDefinitionModel>
|
|||
_serializerOptionsProvider = serializerOptionsProvider;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/activity-definitions/{definitionId}");
|
||||
ConfigureSecurity(SecurityConstants.Permissions, SecurityConstants.Policies, SecurityConstants.Roles);
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<ActivityDefinitionModel> ExecuteAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var parsedVersionOptions = request.VersionOptions != null ? VersionOptions.FromString(request.VersionOptions) : VersionOptions.Latest;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.List;
|
||||
|
||||
public static class SecurityConstants
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="List"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly string[] Policies = { "ListActivityDefinitions" };
|
||||
public static readonly string[] Permissions = { "ListActivityDefinitions" };
|
||||
public static readonly string[] Roles = { "ActivityDefinitionsViewer" };
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "ListActivityDefinitions";
|
||||
}
|
||||
|
|
@ -1,26 +1,31 @@
|
|||
using Elsa.ActivityDefinitions.Models;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Api.Common;
|
||||
using Elsa.Api.Common.Models;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.List;
|
||||
|
||||
public class List : ProtectedEndpoint<Request, PagedListResponse<ActivityDefinitionSummary>>
|
||||
/// <summary>
|
||||
/// An endpoint that returns a page of <see cref="ActivityDefinitionSummary"/> objects.
|
||||
/// </summary>
|
||||
public class List : Endpoint<Request, PagedListResponse<ActivityDefinitionSummary>>
|
||||
{
|
||||
private readonly IActivityDefinitionStore _store;
|
||||
|
||||
/// <inheritdoc />
|
||||
public List(IActivityDefinitionStore store)
|
||||
{
|
||||
_store = store;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/activity-definitions");
|
||||
ConfigureSecurity(SecurityConstants.Permissions, SecurityConstants.Policies, SecurityConstants.Roles);
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<PagedListResponse<ActivityDefinitionSummary>> ExecuteAsync(Request req, CancellationToken ct)
|
||||
{
|
||||
var parsedVersionOptions = req.VersionOptions != null ? VersionOptions.FromString(req.VersionOptions) : VersionOptions.Published;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.Post;
|
||||
|
||||
public static class SecurityConstants
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="Post"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
public static readonly string[] Policies = { "CreateActivityDefinitions", "UpdateActivityDefinitions" };
|
||||
public static readonly string[] Permissions = { "CreateActivityDefinitions", "UpdateActivityDefinitions" };
|
||||
public static readonly string[] Roles = { "ActivityDefinitionsCreator", "ActivityDefinitionsUpdater" };
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "CreateOrUpdateActivityDefinition";
|
||||
}
|
||||
|
|
@ -1,19 +1,24 @@
|
|||
using System.Text.Json;
|
||||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Api.Common;
|
||||
using Elsa.Workflows.Core.Activities.Flowchart.Activities;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
using Elsa.Workflows.Management.Mappers;
|
||||
using Elsa.Workflows.Management.Models;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Endpoints.ActivityDefinitions.Post;
|
||||
|
||||
public class Post : ProtectedEndpoint<Request, Response>
|
||||
/// <summary>
|
||||
/// An endpoint that creates or updates <see cref="ActivityDefinition"/> objects.
|
||||
/// </summary>
|
||||
public class Post : Endpoint<Request, Response>
|
||||
{
|
||||
private readonly SerializerOptionsProvider _serializerOptionsProvider;
|
||||
private readonly IActivityDefinitionPublisher _activityDefinitionPublisher;
|
||||
private readonly VariableDefinitionMapper _variableDefinitionMapper;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Post(
|
||||
SerializerOptionsProvider serializerOptionsProvider,
|
||||
IActivityDefinitionPublisher activityDefinitionPublisher,
|
||||
|
|
@ -24,12 +29,14 @@ public class Post : ProtectedEndpoint<Request, Response>
|
|||
_variableDefinitionMapper = variableDefinitionMapper;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Configure()
|
||||
{
|
||||
Post("/activity-definitions");
|
||||
ConfigureSecurity(List.SecurityConstants.Permissions, List.SecurityConstants.Policies, List.SecurityConstants.Roles);
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override async Task<Response> ExecuteAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var definitionId = request.DefinitionId;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Extensions;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ using Elsa.ActivityDefinitions.Activities;
|
|||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Extensions;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Workflows.Management.Services;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Text.Json;
|
||||
using Elsa.ActivityDefinitions.Activities;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Activities;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Elsa.ActivityDefinitions.Notifications;
|
|||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Common.Services;
|
||||
using Elsa.Mediator.Services;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
using Elsa.Workflows.Core.Activities.Flowchart.Activities;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Models;
|
||||
using Elsa.ActivityDefinitions.Services;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.Common.Extensions;
|
||||
using Elsa.Persistence.Common.Implementations;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Implementations;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.ActivityDefinitions.Entities;
|
||||
using Elsa.ActivityDefinitions.Models;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.ActivityDefinitions.Services;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
namespace Elsa.AspNetCore.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Apply this to a controller that models an API endpoint, where the controller contains a single action.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ApiEndpointAttribute : Attribute
|
||||
{
|
||||
public string ControllerName { get; }
|
||||
public string ActionName { get; }
|
||||
|
||||
public ApiEndpointAttribute(string controllerName, string actionName)
|
||||
{
|
||||
ControllerName = controllerName;
|
||||
ActionName = actionName;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
using Elsa.AspNetCore.Attributes;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
|
||||
namespace Elsa.AspNetCore.Conventions;
|
||||
|
||||
/// <summary>
|
||||
/// A custom controller model convention that applies a controller & action name based on the values provided via <see cref="ApiEndpointAttribute"/>.
|
||||
/// </summary>
|
||||
public class ApiEndpointAttributeConvention : IControllerModelConvention
|
||||
{
|
||||
public void Apply(ControllerModel controller)
|
||||
{
|
||||
var controllerNameAttribute = controller.Attributes.OfType<ApiEndpointAttribute>().SingleOrDefault();
|
||||
|
||||
if (controllerNameAttribute != null)
|
||||
{
|
||||
controller.ControllerName = controllerNameAttribute.ControllerName;
|
||||
var actionModel = controller.Actions.FirstOrDefault();
|
||||
|
||||
if (actionModel != null)
|
||||
actionModel.ActionName = controllerNameAttribute.ActionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FastEndpoints" Version="4.3.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor" Version="2.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\Elsa.Features\Elsa.Features.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
using Elsa.AspNetCore.Features;
|
||||
using Elsa.Features.Services;
|
||||
|
||||
namespace Elsa.AspNetCore.Extensions;
|
||||
|
||||
public static class DependencyInjectionExtensions
|
||||
{
|
||||
public static IModule UseMvc(this IModule configuration, Action<MvcFeature>? configure = default)
|
||||
{
|
||||
configuration.Configure(configure);
|
||||
return configuration;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
using Elsa.AspNetCore.Parts;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.AspNetCore.Extensions;
|
||||
|
||||
public static class MvcBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Remove all application parts. This allows for manually controlling what controllers to add.
|
||||
/// </summary>
|
||||
public static IMvcBuilder ClearApplicationParts(this IMvcBuilder mvcBuilder) =>
|
||||
mvcBuilder.ConfigureApplicationPartManager(partManager =>
|
||||
partManager.ApplicationParts.Clear());
|
||||
|
||||
/// <summary>
|
||||
/// Add application parts from the assembly containing the specified type.
|
||||
/// </summary>
|
||||
public static IMvcBuilder AddApplicationPartsFrom<T>(this IMvcBuilder mvcBuilder) =>
|
||||
mvcBuilder.ConfigureApplicationPartManager(partManager =>
|
||||
partManager.ApplicationParts.Add(new AssemblyPart(typeof(T).Assembly)));
|
||||
|
||||
/// <summary>
|
||||
/// Add the specified controller types.
|
||||
/// </summary>
|
||||
public static IMvcBuilder AddControllerTypes(this IMvcBuilder mvcBuilder, params Type[] controllerTypes) =>
|
||||
mvcBuilder.ConfigureApplicationPartManager(partManager =>
|
||||
partManager.ApplicationParts.Add(new TypesPart(controllerTypes)));
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
using Elsa.AspNetCore.Conventions;
|
||||
using Elsa.Features.Abstractions;
|
||||
using Elsa.Features.Services;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Elsa.AspNetCore.Features;
|
||||
|
||||
public class MvcFeature : FeatureBase
|
||||
{
|
||||
public MvcFeature(IModule module) : base(module)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Services.AddMvc(mvc => mvc.Conventions.Add(new ApiEndpointAttributeConvention()));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
namespace Elsa.AspNetCore.Models;
|
||||
|
||||
public record ListModel<T>(ICollection<T> Items);
|
||||
|
||||
public static class ListModel
|
||||
{
|
||||
public static ListModel<T> Of<T>(ICollection<T> items) => new(items);
|
||||
public static ListModel<T> Of<T>(IEnumerable<T> items) => new(items.ToList());
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
|
||||
namespace Elsa.AspNetCore.Parts;
|
||||
|
||||
/// <summary>
|
||||
/// A custom <see cref="ApplicationPart"/> that controls what types will be provided to the system.
|
||||
/// Use this to control what controllers should be made available from other libraries.
|
||||
/// </summary>
|
||||
public class TypesPart : ApplicationPart, IApplicationPartTypeProvider
|
||||
{
|
||||
public TypesPart(params Type[] types)
|
||||
{
|
||||
Types = types.Select(t => t.GetTypeInfo());
|
||||
}
|
||||
|
||||
public override string Name => string.Join(", ", Types.Select(t => t.FullName));
|
||||
|
||||
public IEnumerable<TypeInfo> Types { get; }
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using Elsa.Labels.Entities;
|
||||
using Elsa.Labels.Services;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Models;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Common.Extensions;
|
||||
using Elsa.Persistence.EntityFrameworkCore.Common.Services;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,18 +6,15 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Open.Linq.AsyncExtensions" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\common\Elsa.Api.Common\Elsa.Api.Common.csproj" />
|
||||
<ProjectReference Include="..\Elsa.AspNetCore\Elsa.AspNetCore.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Mediator\Elsa.Mediator.csproj" />
|
||||
<ProjectReference Include="..\..\common\Elsa.Persistence.Abstractions\Elsa.Persistence.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\common\Elsa.Persistence.Common\Elsa.Persistence.Common.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Core\Elsa.Workflows.Core.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Management\Elsa.Workflows.Management.csproj" />
|
||||
<ProjectReference Include="..\Elsa.Workflows.Persistence\Elsa.Workflows.Persistence.csproj" />
|
||||
|
|
|
|||
|
|
@ -1,48 +0,0 @@
|
|||
using Elsa.AspNetCore.Attributes;
|
||||
using Elsa.Labels.Entities;
|
||||
using Elsa.Labels.Services;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels;
|
||||
|
||||
[Area(AreaNames.Elsa)]
|
||||
[ApiEndpoint(ControllerNames.Labels, "Create")]
|
||||
[ProducesResponseType(typeof(Label), StatusCodes.Status201Created)]
|
||||
public class Create : Controller
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
private readonly IIdentityGenerator _identityGenerator;
|
||||
private readonly SerializerOptionsProvider _serializerOptionsProvider;
|
||||
|
||||
// ReSharper disable once ClassNeverInstantiated.Local
|
||||
private record LabelModel(string Name, string? Description, string? Color);
|
||||
|
||||
public Create(ILabelStore store, IIdentityGenerator identityGenerator, SerializerOptionsProvider serializerOptionsProvider)
|
||||
{
|
||||
_store = store;
|
||||
_identityGenerator = identityGenerator;
|
||||
_serializerOptionsProvider = serializerOptionsProvider;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> HandleAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
|
||||
var model = (await Request.ReadFromJsonAsync<LabelModel>(serializerOptions, cancellationToken))!;
|
||||
|
||||
var label = new Label
|
||||
{
|
||||
Id = _identityGenerator.GenerateId(),
|
||||
Name = model.Name.Trim(),
|
||||
Description = model.Description?.Trim(),
|
||||
Color = model.Color?.Trim()
|
||||
};
|
||||
|
||||
await _store.SaveAsync(label, cancellationToken);
|
||||
|
||||
return CreatedAtRoute("Elsa.Labels.Get", new { Id = label.Id }, label);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
using Elsa.AspNetCore.Attributes;
|
||||
using Elsa.Labels.Entities;
|
||||
using Elsa.Labels.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels;
|
||||
|
||||
[Area(AreaNames.Elsa)]
|
||||
[ApiEndpoint(ControllerNames.Labels, "Delete")]
|
||||
[ProducesResponseType(typeof(Label), StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public class Delete : Controller
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
|
||||
public Delete(ILabelStore store) => _store = store;
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> HandleAsync(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
var deleted = await _store.DeleteAsync(id, cancellationToken);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
12
src/modules/Elsa.Labels/Endpoints/Labels/Delete/Constants.cs
Normal file
12
src/modules/Elsa.Labels/Endpoints/Labels/Delete/Constants.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
namespace Elsa.Labels.Endpoints.Labels.Delete;
|
||||
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="Delete"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "DeleteLabel";
|
||||
}
|
||||
27
src/modules/Elsa.Labels/Endpoints/Labels/Delete/Endpoint.cs
Normal file
27
src/modules/Elsa.Labels/Endpoints/Labels/Delete/Endpoint.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Elsa.Labels.Services;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.Delete;
|
||||
|
||||
public class Delete : Endpoint<Request>
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
|
||||
public Delete(ILabelStore store) => _store = store;
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Delete("/labels/{id}");
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var deleted = await _store.DeleteAsync(request.Id, cancellationToken);
|
||||
|
||||
if (deleted)
|
||||
await SendNoContentAsync(cancellationToken);
|
||||
else
|
||||
await SendNotFoundAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
namespace Elsa.Labels.Endpoints.Labels.Delete;
|
||||
|
||||
public class Request
|
||||
{
|
||||
public string Id { get; init; } = default!;
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
using Elsa.AspNetCore.Attributes;
|
||||
using Elsa.Labels.Entities;
|
||||
using Elsa.Labels.Services;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels;
|
||||
|
||||
[Area(AreaNames.Elsa)]
|
||||
[ApiEndpoint(ControllerNames.Labels, "Get")]
|
||||
[ProducesResponseType(typeof(Label), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public class Get : Controller
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
private readonly SerializerOptionsProvider _serializerOptionsProvider;
|
||||
|
||||
public Get(ILabelStore store, SerializerOptionsProvider serializerOptionsProvider)
|
||||
{
|
||||
_store = store;
|
||||
_serializerOptionsProvider = serializerOptionsProvider;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> HandleAsync(string id, CancellationToken cancellationToken)
|
||||
{
|
||||
var label = await _store.FindByIdAsync(id, cancellationToken);
|
||||
return label == null ? NotFound() : Json(label, _serializerOptionsProvider.CreateApiOptions());
|
||||
}
|
||||
}
|
||||
12
src/modules/Elsa.Labels/Endpoints/Labels/Get/Constants.cs
Normal file
12
src/modules/Elsa.Labels/Endpoints/Labels/Get/Constants.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
namespace Elsa.Labels.Endpoints.Labels.Get;
|
||||
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="Get"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "GetLabel";
|
||||
}
|
||||
33
src/modules/Elsa.Labels/Endpoints/Labels/Get/Endpoint.cs
Normal file
33
src/modules/Elsa.Labels/Endpoints/Labels/Get/Endpoint.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using Elsa.Labels.Services;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.Get;
|
||||
|
||||
public class Get : Endpoint<Request, Response, LabelMapper>
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
|
||||
public Get(ILabelStore store)
|
||||
{
|
||||
_store = store;
|
||||
}
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/labels/{id}");
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var label = await _store.FindByIdAsync(request.Id, cancellationToken);
|
||||
|
||||
if (label == null)
|
||||
await SendNotFoundAsync(cancellationToken);
|
||||
else
|
||||
{
|
||||
var response = await Map.FromEntityAsync(label);
|
||||
await SendOkAsync(response, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
src/modules/Elsa.Labels/Endpoints/Labels/Get/Mappers.cs
Normal file
16
src/modules/Elsa.Labels/Endpoints/Labels/Get/Mappers.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Elsa.Labels.Entities;
|
||||
using Elsa.Workflows.Core.Services;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.Get;
|
||||
|
||||
public class LabelMapper : Mapper<Request, Response, Label>
|
||||
{
|
||||
public override Task<Response> FromEntityAsync(Label e) => Task.FromResult(new Response
|
||||
{
|
||||
Id = e.Id,
|
||||
Color = e.Color,
|
||||
Description = e.Description,
|
||||
NormalizedName = e.NormalizedName
|
||||
});
|
||||
}
|
||||
14
src/modules/Elsa.Labels/Endpoints/Labels/Get/Models.cs
Normal file
14
src/modules/Elsa.Labels/Endpoints/Labels/Get/Models.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
namespace Elsa.Labels.Endpoints.Labels.Get;
|
||||
|
||||
public class Request
|
||||
{
|
||||
public string Id { get; set; } = default!;
|
||||
}
|
||||
|
||||
public class Response
|
||||
{
|
||||
public string Id { get; set; } = default!;
|
||||
public string NormalizedName { get; set; } = default!;
|
||||
public string? Description { get; set; }
|
||||
public string? Color { get; set; }
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
using Elsa.AspNetCore.Attributes;
|
||||
using Elsa.Labels.Entities;
|
||||
using Elsa.Labels.Services;
|
||||
using Elsa.Persistence.Common.Models;
|
||||
using Elsa.Workflows.Core.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels;
|
||||
|
||||
[Area(AreaNames.Elsa)]
|
||||
[ApiEndpoint(ControllerNames.Labels, "List")]
|
||||
[ProducesResponseType(typeof(Page<Label>), StatusCodes.Status200OK)]
|
||||
public class List : Controller
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
private readonly SerializerOptionsProvider _serializerOptionsProvider;
|
||||
|
||||
public List(ILabelStore store, SerializerOptionsProvider serializerOptionsProvider)
|
||||
{
|
||||
_store = store;
|
||||
_serializerOptionsProvider = serializerOptionsProvider;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> HandleAsync([FromQuery] PageArgs? pageArgs, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var pageOfLabels = await _store.ListAsync(pageArgs, cancellationToken);
|
||||
return Json(pageOfLabels, _serializerOptionsProvider.CreateApiOptions());
|
||||
}
|
||||
}
|
||||
14
src/modules/Elsa.Labels/Endpoints/Labels/List/Constants.cs
Normal file
14
src/modules/Elsa.Labels/Endpoints/Labels/List/Constants.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using Elsa.Labels.Endpoints.Labels.Get;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.List;
|
||||
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="List"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "ListLabels";
|
||||
}
|
||||
26
src/modules/Elsa.Labels/Endpoints/Labels/List/Endpoint.cs
Normal file
26
src/modules/Elsa.Labels/Endpoints/Labels/List/Endpoint.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using Elsa.Labels.Services;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.List;
|
||||
|
||||
public class List : Endpoint<Request, Response, PageMapper>
|
||||
{
|
||||
private readonly ILabelStore _store;
|
||||
|
||||
public List(ILabelStore store)
|
||||
{
|
||||
_store = store;
|
||||
}
|
||||
|
||||
public override void Configure()
|
||||
{
|
||||
Get("/labels");
|
||||
Policies(Constants.PolicyName);
|
||||
}
|
||||
|
||||
public override async Task<Response> ExecuteAsync(Request request, CancellationToken cancellationToken)
|
||||
{
|
||||
var pageOfLabels = await _store.ListAsync(request.ToPageArgs(), cancellationToken);
|
||||
return Map.FromEntity(pageOfLabels);
|
||||
}
|
||||
}
|
||||
14
src/modules/Elsa.Labels/Endpoints/Labels/List/Mappers.cs
Normal file
14
src/modules/Elsa.Labels/Endpoints/Labels/List/Mappers.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using Elsa.Labels.Entities;
|
||||
using Elsa.Models;
|
||||
using FastEndpoints;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.List;
|
||||
|
||||
public class PageMapper : Mapper<Request, Response, Page<Label>>
|
||||
{
|
||||
public override Response FromEntity(Page<Label> e) => new()
|
||||
{
|
||||
Items = e.Items,
|
||||
TotalCount = e.TotalCount
|
||||
};
|
||||
}
|
||||
18
src/modules/Elsa.Labels/Endpoints/Labels/List/Models.cs
Normal file
18
src/modules/Elsa.Labels/Endpoints/Labels/List/Models.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using Elsa.Labels.Entities;
|
||||
using Elsa.Models;
|
||||
|
||||
namespace Elsa.Labels.Endpoints.Labels.List;
|
||||
|
||||
public class Request
|
||||
{
|
||||
public int? Page { get; set; }
|
||||
public int? PageSize { get; set; }
|
||||
|
||||
public PageArgs ToPageArgs() => new(Page, PageSize);
|
||||
}
|
||||
|
||||
public class Response
|
||||
{
|
||||
public ICollection<Label> Items { get; set; } = default!;
|
||||
public long TotalCount { get; set; }
|
||||
}
|
||||
12
src/modules/Elsa.Labels/Endpoints/Labels/Post/Constants.cs
Normal file
12
src/modules/Elsa.Labels/Endpoints/Labels/Post/Constants.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
namespace Elsa.Labels.Endpoints.Labels.Post;
|
||||
|
||||
/// <summary>
|
||||
/// Provides policy names accepted by the <see cref="Post"/> endpoint.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// The policy name accepted by this endpoint.
|
||||
/// </summary>
|
||||
public const string PolicyName = "CreateLabel";
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue