diff --git a/Elsa.sln b/Elsa.sln index b9ba3a7e6..5a4c2d72e 100644 --- a/Elsa.sln +++ b/Elsa.sln @@ -267,8 +267,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "github", "github", "{3BF2C5 ProjectSection(SolutionItems) = preProject .github\workflows\publish-latest-dashboard-and-server-docker.yml = .github\workflows\publish-latest-dashboard-and-server-docker.yml .github\workflows\publish-latest-dashboard-docker.yml = .github\workflows\publish-latest-dashboard-docker.yml - .github\workflows\publish-latest-server-docker.yml = .github\workflows\publish-latest-server-docker.yml .github\workflows\publish-latest-designer-npm.yml = .github\workflows\publish-latest-designer-npm.yml + .github\workflows\publish-latest-server-docker.yml = .github\workflows\publish-latest-server-docker.yml EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Samples.SignalApi", "src\samples\aspnet\Elsa.Samples.SignalApi\Elsa.Samples.SignalApi.csproj", "{3E2423CF-50E6-4D2B-8749-17B1EF540FE4}" @@ -325,6 +325,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Elsa.Activities.Conductor", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "aspnetcore", "aspnetcore", "{39DE1EE2-DF4F-44EB-9F5A-551BEADD6673}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.CustomTenantIdSource", "src\samples\aspnet\Elsa.Samples.CustomTenantIdSource\Elsa.Samples.CustomTenantIdSource.csproj", "{6E191628-927B-42FB-8805-D2977D8FC4E3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -751,6 +753,10 @@ Global {4D4022DD-244B-47EE-95FA-7071EC687B24}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D4022DD-244B-47EE-95FA-7071EC687B24}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D4022DD-244B-47EE-95FA-7071EC687B24}.Release|Any CPU.Build.0 = Release|Any CPU + {6E191628-927B-42FB-8805-D2977D8FC4E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E191628-927B-42FB-8805-D2977D8FC4E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E191628-927B-42FB-8805-D2977D8FC4E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E191628-927B-42FB-8805-D2977D8FC4E3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -893,6 +899,7 @@ Global {84751112-C2B7-41D4-98F5-D87D7C2E1DAE} = {22E75696-6FE9-436A-9097-EE21C603F818} {4D4022DD-244B-47EE-95FA-7071EC687B24} = {B43B546E-23F3-46E8-ACB7-D04F05CDA180} {39DE1EE2-DF4F-44EB-9F5A-551BEADD6673} = {4673732F-2853-47BD-91B8-C95C229D2C89} + {6E191628-927B-42FB-8805-D2977D8FC4E3} = {22E75696-6FE9-436A-9097-EE21C603F818} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158} diff --git a/src/core/Elsa.Abstractions/Services/ITenantAccessor.cs b/src/core/Elsa.Abstractions/Services/ITenantAccessor.cs new file mode 100644 index 000000000..c11a6b114 --- /dev/null +++ b/src/core/Elsa.Abstractions/Services/ITenantAccessor.cs @@ -0,0 +1,10 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Services +{ + public interface ITenantAccessor + { + Task GetTenantIdAsync(CancellationToken cancellationToken = default); + } +} diff --git a/src/core/Elsa.Core/Activities/Signaling/Services/Signaler.cs b/src/core/Elsa.Core/Activities/Signaling/Services/Signaler.cs index 67e828c00..899a5506d 100644 --- a/src/core/Elsa.Core/Activities/Signaling/Services/Signaler.cs +++ b/src/core/Elsa.Core/Activities/Signaling/Services/Signaler.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -33,7 +33,7 @@ namespace Elsa.Activities.Signaling.Services public async Task> TriggerSignalAsync(string signal, object? input = default, string? workflowInstanceId = default, string? correlationId = default, CancellationToken cancellationToken = default) { var normalizedSignal = signal.ToLowerInvariant(); - + return await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(new CollectWorkflowsContext( nameof(SignalReceived), new SignalReceivedBookmark { Signal = normalizedSignal, WorkflowInstanceId = workflowInstanceId }, @@ -54,16 +54,16 @@ namespace Elsa.Activities.Signaling.Services } public async Task> DispatchSignalAsync(string signal, object? input = default, string? workflowInstanceId = default, string? correlationId = default, CancellationToken cancellationToken = default) => - await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(new CollectWorkflowsContext( - nameof(SignalReceived), - new SignalReceivedBookmark { Signal = signal, WorkflowInstanceId = workflowInstanceId }, - new SignalReceivedBookmark { Signal = signal }, - correlationId, - workflowInstanceId, - default, - TenantId - ), - new Signal(signal, input), - cancellationToken); + await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(new CollectWorkflowsContext( + nameof(SignalReceived), + new SignalReceivedBookmark { Signal = signal, WorkflowInstanceId = workflowInstanceId }, + new SignalReceivedBookmark { Signal = signal }, + correlationId, + workflowInstanceId, + default, + TenantId + ), + new Signal(signal, input), + cancellationToken); } } \ No newline at end of file diff --git a/src/core/Elsa.Core/ElsaOptionsBuilder.cs b/src/core/Elsa.Core/ElsaOptionsBuilder.cs index 68ac903fb..3712b6176 100644 --- a/src/core/Elsa.Core/ElsaOptionsBuilder.cs +++ b/src/core/Elsa.Core/ElsaOptionsBuilder.cs @@ -235,5 +235,11 @@ namespace Elsa ElsaOptions.ConfigureServiceBusEndpoint = setup; return this; } + + public ElsaOptionsBuilder AddCustomTenantAccessor() where T : class, ITenantAccessor + { + Services.AddScoped(); + return this; + } } } \ No newline at end of file diff --git a/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs b/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs index 220a1c35e..7420a52cd 100644 --- a/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs +++ b/src/core/Elsa.Core/Extensions/ElsaServiceCollectionExtensions.cs @@ -87,6 +87,9 @@ namespace Microsoft.Extensions.DependencyInjection services.Decorate(); services.Decorate(); + //TenantId default source + services.TryAddScoped(); + return services; } diff --git a/src/core/Elsa.Core/Services/DefaultTenantAccessor.cs b/src/core/Elsa.Core/Services/DefaultTenantAccessor.cs new file mode 100644 index 000000000..5618c61dc --- /dev/null +++ b/src/core/Elsa.Core/Services/DefaultTenantAccessor.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Services +{ + public class DefaultTenantAccessor : ITenantAccessor + { + public Task GetTenantIdAsync(CancellationToken cancellationToken = default) + { + string? tenantId = default; + return Task.FromResult(tenantId); + } + } +} diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/CustomTenantAccessor.cs b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/CustomTenantAccessor.cs new file mode 100644 index 000000000..0efee968a --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/CustomTenantAccessor.cs @@ -0,0 +1,34 @@ +using Elsa.Services; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; + +namespace Elsa.Samples.CustomTenantIdSource +{ + public class CustomTenantAccessor : ITenantAccessor + { + private readonly IHttpContextAccessor _accessor; + + public CustomTenantAccessor(IHttpContextAccessor accessor) + { + _accessor = accessor; + } + public Task GetTenantIdAsync(CancellationToken cancellationToken = default) + { + //You can customize the data + var httpContext = _accessor.HttpContext; + + var tenantId = httpContext.Request.Headers["x-tenant"].ToString(); + + // Or you can get tenantid from claim + //var tenantId = httpContext.User.FindFirstValue("x-tenant"); + + return Task.FromResult(tenantId); + + } + } +} diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Elsa.Samples.CustomTenantIdSource.csproj b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Elsa.Samples.CustomTenantIdSource.csproj new file mode 100644 index 000000000..f43ea5ae1 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Elsa.Samples.CustomTenantIdSource.csproj @@ -0,0 +1,15 @@ + + + + net5.0 + + + + + + + + + + + diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Program.cs b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Program.cs new file mode 100644 index 000000000..850625eb6 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Program.cs @@ -0,0 +1,26 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Elsa.Samples.CustomTenantIdSource +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) => + Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } +} diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Properties/launchSettings.json b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Properties/launchSettings.json new file mode 100644 index 000000000..93914f25e --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:2114", + "sslPort": 44301 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Elsa.Samples.CustomTenantIdSource": { + "commandName": "Project", + "dotnetRunMessages": "true", + "launchBrowser": true, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Startup.cs b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Startup.cs new file mode 100644 index 000000000..dea488862 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/Startup.cs @@ -0,0 +1,65 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Elsa.Persistence.EntityFramework.Core.Extensions; +using Elsa.Persistence.EntityFramework.Sqlite; + +namespace Elsa.Samples.CustomTenantIdSource +{ + public class Startup + { + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + services.AddControllers(); + + services.AddHttpContextAccessor(); + + services + .AddElsa(options => options + .UseEntityFrameworkPersistence(ef => ef.UseSqlite()) + .AddConsoleActivities() + .AddActivitiesFrom() + .AddCustomTenantAccessor() + ); + + services + .AddElsaSwagger() + .AddElsaApiEndpoints(); + + // Allow arbitrary client browser apps to access the API. + // In a production environment, make sure to allow only origins you trust. + services.AddCors(cors => cors.AddDefaultPolicy(policy => policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().WithExposedHeaders("Content-Disposition"))); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Elsa")); + } + app.UseCors(); + app.UseRouting(); + + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + + endpoints.MapGet("/", async context => + { + await context.Response.WriteAsync("Hello World!"); + }); + }); + } + } +} diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/appsettings.Development.json b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/appsettings.Development.json new file mode 100644 index 000000000..8983e0fc1 --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/appsettings.json b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/appsettings.json new file mode 100644 index 000000000..d9d9a9bff --- /dev/null +++ b/src/samples/aspnet/Elsa.Samples.CustomTenantIdSource/appsettings.json @@ -0,0 +1,10 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "AllowedHosts": "*" +} diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Import.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Import.cs index 24ebacfb6..2b139605f 100644 --- a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Import.cs +++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Import.cs @@ -1,11 +1,11 @@ -using System.Threading; -using System.Threading.Tasks; using Elsa.Models; using Elsa.Serialization; using Elsa.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; +using System.Threading; +using System.Threading.Tasks; namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions { @@ -17,11 +17,12 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions { private readonly IWorkflowPublisher _workflowPublisher; private readonly IContentSerializer _contentSerializer; - - public Import(IWorkflowPublisher workflowPublisher, IContentSerializer contentSerializer) + private readonly ITenantAccessor _tenantAccessor; + public Import(IWorkflowPublisher workflowPublisher, IContentSerializer contentSerializer, ITenantAccessor tenantAccessor) { _workflowPublisher = workflowPublisher; _contentSerializer = contentSerializer; + _tenantAccessor = tenantAccessor; } [HttpPost] @@ -32,15 +33,15 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions OperationId = "WorkflowDefinitions.Import", Tags = new[] { "WorkflowDefinitions" }) ] - public async Task Handle(string workflowDefinitionId, [FromForm]IFormFile? file, CancellationToken cancellationToken) + public async Task Handle(string workflowDefinitionId, [FromForm] IFormFile? file, CancellationToken cancellationToken) { if (file == null) return BadRequest(); - + var json = await file.OpenReadStream().ReadStringToEndAsync(cancellationToken); var workflowDefinition = await _workflowPublisher.GetDraftAsync(workflowDefinitionId, cancellationToken) ?? _workflowPublisher.New(); var postedModel = _contentSerializer.Deserialize(json); - + workflowDefinition.Activities = postedModel.Activities; workflowDefinition.Connections = postedModel.Connections; workflowDefinition.Description = postedModel.Description; @@ -53,6 +54,8 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions workflowDefinition.IsSingleton = postedModel.IsSingleton; workflowDefinition.DeleteCompletedInstances = postedModel.DeleteCompletedInstances; + workflowDefinition.TenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken); + await _workflowPublisher.SaveDraftAsync(workflowDefinition, cancellationToken); return Ok(workflowDefinition); } diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs index 808ef9239..a3a62e30e 100644 --- a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs +++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/List.cs @@ -9,6 +9,7 @@ using Elsa.Persistence.Specifications.WorkflowDefinitions; using Elsa.Serialization; using Elsa.Server.Api.Models; using Elsa.Server.Api.Swagger.Examples; +using Elsa.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; @@ -25,12 +26,14 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions private readonly IWorkflowDefinitionStore _workflowDefinitionStore; private readonly IContentSerializer _serializer; private readonly IMapper _mapper; + private readonly ITenantAccessor _tenantAccessor; - public List(IWorkflowDefinitionStore workflowDefinitionStore, IContentSerializer serializer, IMapper mapper) + public List(IWorkflowDefinitionStore workflowDefinitionStore, IContentSerializer serializer, IMapper mapper, ITenantAccessor tenantAccessor) { _workflowDefinitionStore = workflowDefinitionStore; _serializer = serializer; _mapper = mapper; + _tenantAccessor = tenantAccessor; } [HttpGet] @@ -44,8 +47,9 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions ] public async Task>> Handle(int? page = default, int? pageSize = default, VersionOptions? version = default, CancellationToken cancellationToken = default) { + var tenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken); version ??= VersionOptions.Latest; - var specification = new VersionOptionsSpecification(version.Value); + var specification = new VersionOptionsSpecification(version.Value).And(new TenantSpecification(tenantId)); var totalCount = await _workflowDefinitionStore.CountAsync(specification, cancellationToken); var paging = page == null || pageSize == null ? default : Paging.Page(page.Value, pageSize.Value); var items = await _workflowDefinitionStore.FindManyAsync(specification, paging: paging, cancellationToken: cancellationToken); diff --git a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Save.cs b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Save.cs index 545da1960..f73c81746 100644 --- a/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Save.cs +++ b/src/server/Elsa.Server.Api/Endpoints/WorkflowDefinitions/Save.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -19,10 +19,11 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions public partial class Save : ControllerBase { private readonly IWorkflowPublisher _workflowPublisher; - - public Save(IWorkflowPublisher workflowPublisher) + private readonly ITenantAccessor _tenantAccessor; + public Save(IWorkflowPublisher workflowPublisher, ITenantAccessor tenantAccessor) { _workflowPublisher = workflowPublisher; + _tenantAccessor = tenantAccessor; } [HttpPost] @@ -35,7 +36,7 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions OperationId = "WorkflowDefinitions.Post", Tags = new[] { "WorkflowDefinitions" }) ] - public async Task> Handle([FromBody]SaveWorkflowDefinitionRequest request, [FromRoute]ApiVersion apiVersion, CancellationToken cancellationToken) + public async Task> Handle([FromBody] SaveWorkflowDefinitionRequest request, [FromRoute] ApiVersion apiVersion, CancellationToken cancellationToken) { var workflowDefinitionId = request.WorkflowDefinitionId; var workflowDefinition = !string.IsNullOrWhiteSpace(workflowDefinitionId) ? await _workflowPublisher.GetDraftAsync(workflowDefinitionId, cancellationToken) : default; @@ -61,6 +62,8 @@ namespace Elsa.Server.Api.Endpoints.WorkflowDefinitions workflowDefinition.Tag = request.Tag?.Trim(); workflowDefinition.Channel = request.Channel?.Trim(); + workflowDefinition.TenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken); + if (request.Publish) workflowDefinition = await _workflowPublisher.PublishAsync(workflowDefinition, cancellationToken); else diff --git a/src/server/Elsa.Server.Api/Endpoints/Workflows/Dispatch.cs b/src/server/Elsa.Server.Api/Endpoints/Workflows/Dispatch.cs index f3ff1a76c..15b6481be 100644 --- a/src/server/Elsa.Server.Api/Endpoints/Workflows/Dispatch.cs +++ b/src/server/Elsa.Server.Api/Endpoints/Workflows/Dispatch.cs @@ -1,10 +1,10 @@ -using System.Threading; -using System.Threading.Tasks; using Elsa.Server.Api.ActionFilters; using Elsa.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; +using System.Threading; +using System.Threading.Tasks; namespace Elsa.Server.Api.Endpoints.Workflows { @@ -15,10 +15,12 @@ namespace Elsa.Server.Api.Endpoints.Workflows public class Dispatch : Controller { private readonly IWorkflowLaunchpad _workflowLaunchpad; + private readonly ITenantAccessor _tenantAccessor; - public Dispatch(IWorkflowLaunchpad workflowLaunchpad) + public Dispatch(IWorkflowLaunchpad workflowLaunchpad, ITenantAccessor tenantAccessor) { _workflowLaunchpad = workflowLaunchpad; + _tenantAccessor = tenantAccessor; } [HttpPost] @@ -33,11 +35,12 @@ namespace Elsa.Server.Api.Endpoints.Workflows ] public async Task Handle(string workflowDefinitionId, DispatchWorkflowDefinitionRequestModel request, CancellationToken cancellationToken = default) { - var startableWorkflow = await _workflowLaunchpad.CollectStartableWorkflowAsync(workflowDefinitionId, request.ActivityId, request.CorrelationId, request.ContextId, default, cancellationToken); + var tenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken); + var startableWorkflow = await _workflowLaunchpad.CollectStartableWorkflowAsync(workflowDefinitionId, request.ActivityId, request.CorrelationId, request.ContextId, tenantId, cancellationToken); if (startableWorkflow == null) return NotFound(); - + var result = await _workflowLaunchpad.DispatchStartableWorkflowAsync(startableWorkflow, request.Input, cancellationToken); return Ok(new DispatchWorkflowDefinitionResponseModel(result.WorkflowInstanceId, result.ActivityId)); } diff --git a/src/server/Elsa.Server.Api/Endpoints/Workflows/Execute.cs b/src/server/Elsa.Server.Api/Endpoints/Workflows/Execute.cs index a45c945cf..fe3188ed3 100644 --- a/src/server/Elsa.Server.Api/Endpoints/Workflows/Execute.cs +++ b/src/server/Elsa.Server.Api/Endpoints/Workflows/Execute.cs @@ -1,10 +1,10 @@ -using System.Threading; -using System.Threading.Tasks; using Elsa.Server.Api.ActionFilters; using Elsa.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Swashbuckle.AspNetCore.Annotations; +using System.Threading; +using System.Threading.Tasks; namespace Elsa.Server.Api.Endpoints.Workflows { @@ -15,10 +15,12 @@ namespace Elsa.Server.Api.Endpoints.Workflows public class Execute : Controller { private readonly IWorkflowLaunchpad _workflowLaunchpad; + private readonly ITenantAccessor _tenantAccessor; - public Execute(IWorkflowLaunchpad workflowLaunchpad) + public Execute(IWorkflowLaunchpad workflowLaunchpad, ITenantAccessor tenantAccessor) { _workflowLaunchpad = workflowLaunchpad; + _tenantAccessor = tenantAccessor; } [HttpPost] @@ -33,7 +35,8 @@ namespace Elsa.Server.Api.Endpoints.Workflows ] public async Task Handle(string workflowDefinitionId, ExecuteWorkflowDefinitionRequestModel request, CancellationToken cancellationToken = default) { - var startableWorkflow = await _workflowLaunchpad.CollectStartableWorkflowAsync(workflowDefinitionId, request.ActivityId, request.CorrelationId, request.ContextId, default, cancellationToken); + var tenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken); + var startableWorkflow = await _workflowLaunchpad.CollectStartableWorkflowAsync(workflowDefinitionId, request.ActivityId, request.CorrelationId, request.ContextId, tenantId, cancellationToken); if (startableWorkflow == null) return NotFound(); diff --git a/src/server/Elsa.Server.Api/Endpoints/Workflows/Trigger.cs b/src/server/Elsa.Server.Api/Endpoints/Workflows/Trigger.cs index 4fd8476a6..c83e26b98 100644 --- a/src/server/Elsa.Server.Api/Endpoints/Workflows/Trigger.cs +++ b/src/server/Elsa.Server.Api/Endpoints/Workflows/Trigger.cs @@ -18,7 +18,12 @@ namespace Elsa.Server.Api.Endpoints.Workflows public class Trigger : Controller { private readonly IWorkflowLaunchpad _workflowLaunchpad; - public Trigger(IWorkflowLaunchpad workflowLaunchpad) => _workflowLaunchpad = workflowLaunchpad; + private readonly ITenantAccessor _tenantAccessor; + public Trigger(IWorkflowLaunchpad workflowLaunchpad,ITenantAccessor tenantAccessor) + { + _workflowLaunchpad = workflowLaunchpad; + _tenantAccessor = tenantAccessor; + } [HttpPost] [ElsaJsonFormatter] @@ -32,7 +37,8 @@ namespace Elsa.Server.Api.Endpoints.Workflows ] public async Task Handle(TriggerWorkflowsRequestModel request, CancellationToken cancellationToken = default) { - var context = new CollectWorkflowsContext(request.ActivityType, request.Bookmark, request.Trigger, request.CorrelationId, request.WorkflowInstanceId, request.ContextId); + var tenantId = await _tenantAccessor.GetTenantIdAsync(cancellationToken); + var context = new CollectWorkflowsContext(request.ActivityType, request.Bookmark, request.Trigger, request.CorrelationId, request.WorkflowInstanceId, request.ContextId, tenantId); ICollection triggeredWorkflows; if (request.Dispatch)