diff --git a/docs/ProcessManager.Client/ReleaseNotes/ReleaseNotes.md b/docs/ProcessManager.Client/ReleaseNotes/ReleaseNotes.md index 8e01c1f293..f7037b42e0 100644 --- a/docs/ProcessManager.Client/ReleaseNotes/ReleaseNotes.md +++ b/docs/ProcessManager.Client/ReleaseNotes/ReleaseNotes.md @@ -1,5 +1,9 @@ # ProcessManager.Client Release Notes +## Version 0.11.0 + +- Extend framework to require 'OperatingIdentity' when initiating commands (start, schedule, cancel). + ## Version 0.10.0 - Added 'RequestCalculatedDataClientV1' diff --git a/source/BuildingBlocks.Infrastructure/BuildingBlocks.Infrastructure.csproj b/source/BuildingBlocks.Infrastructure/BuildingBlocks.Infrastructure.csproj index 2d5d91fa48..002880a490 100644 --- a/source/BuildingBlocks.Infrastructure/BuildingBlocks.Infrastructure.csproj +++ b/source/BuildingBlocks.Infrastructure/BuildingBlocks.Infrastructure.csproj @@ -5,7 +5,7 @@ - + diff --git a/source/ProcessManager.Client.Tests/Fixtures/ScenarioOrchestrationsAppFixture.cs b/source/ProcessManager.Client.Tests/Fixtures/ScenarioOrchestrationsAppFixture.cs index 9be0ec57e4..26dd8050c0 100644 --- a/source/ProcessManager.Client.Tests/Fixtures/ScenarioOrchestrationsAppFixture.cs +++ b/source/ProcessManager.Client.Tests/Fixtures/ScenarioOrchestrationsAppFixture.cs @@ -31,7 +31,8 @@ public ScenarioOrchestrationsAppFixture() : base( ScenarioAppFixturesConfiguration.Instance.DatabaseManager, ScenarioAppFixturesConfiguration.Instance.TaskHubName, - ScenarioAppFixturesConfiguration.Instance.OrchestrationsAppPort) + ScenarioAppFixturesConfiguration.Instance.OrchestrationsAppPort, + disposeDatabase: true) // Quickfix: Only dispose database in one of the scenario fixtures { } } diff --git a/source/ProcessManager.Client.Tests/Fixtures/ScenarioProcessManagerAppFixture.cs b/source/ProcessManager.Client.Tests/Fixtures/ScenarioProcessManagerAppFixture.cs index 33d5dd7aab..8ee7de101c 100644 --- a/source/ProcessManager.Client.Tests/Fixtures/ScenarioProcessManagerAppFixture.cs +++ b/source/ProcessManager.Client.Tests/Fixtures/ScenarioProcessManagerAppFixture.cs @@ -31,7 +31,8 @@ public ScenarioProcessManagerAppFixture() : base( ScenarioAppFixturesConfiguration.Instance.DatabaseManager, ScenarioAppFixturesConfiguration.Instance.TaskHubName, - ScenarioAppFixturesConfiguration.Instance.ProcessManagerAppPort) + ScenarioAppFixturesConfiguration.Instance.ProcessManagerAppPort, + disposeDatabase: false) // Quickfix: Only dispose database in one of the scenario fixtures { } } diff --git a/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingApiScenario.cs b/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingApiScenario.cs index 6e02902ea5..446b797605 100644 --- a/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingApiScenario.cs +++ b/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingApiScenario.cs @@ -69,6 +69,9 @@ public async Task CalculationBrs023_WhenScheduledUsingClient_CanMonitorLifecycle { // TODO: Move to API test project dynamic scheduleRequestDto = new ExpandoObject(); + scheduleRequestDto.OperatingIdentity = new ExpandoObject(); + scheduleRequestDto.OperatingIdentity.UserId = Guid.NewGuid(); + scheduleRequestDto.OperatingIdentity.ActorId = Guid.NewGuid(); scheduleRequestDto.RunAt = "2024-11-01T06:19:10.0209567+01:00"; scheduleRequestDto.InputParameter = new ExpandoObject(); scheduleRequestDto.InputParameter.CalculationType = 0; @@ -76,7 +79,6 @@ public async Task CalculationBrs023_WhenScheduledUsingClient_CanMonitorLifecycle scheduleRequestDto.InputParameter.PeriodStartDate = "2024-10-29T15:19:10.0151351+01:00"; scheduleRequestDto.InputParameter.PeriodEndDate = "2024-10-29T16:19:10.0193962+01:00"; scheduleRequestDto.InputParameter.IsInternalCalculation = true; - scheduleRequestDto.InputParameter.UserId = Guid.NewGuid(); using var scheduleRequest = new HttpRequestMessage( HttpMethod.Post, diff --git a/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingClientsScenario.cs b/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingClientsScenario.cs index a32109bf83..2fc7f2fac0 100644 --- a/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingClientsScenario.cs +++ b/source/ProcessManager.Client.Tests/Integration/MonitorCalculationUsingClientsScenario.cs @@ -92,15 +92,17 @@ public async Task CalculationBrs023_WhenScheduledUsingClient_CanMonitorLifecycle // Step 1: Schedule new calculation orchestration instance var orchestrationInstanceId = await calculationClient .ScheduleNewCalculationAsync( - new ClientTypes.Energinet.DataHub.ProcessManager.Api.Model.ScheduleOrchestrationInstanceDto( - RunAt: DateTimeOffset.Parse("2024-11-01T06:19:10.0209567+01:00"), - InputParameter: new NotifyAggregatedMeasureDataInputV1( + new ClientTypes.Energinet.DataHub.ProcessManager.Api.Model.ScheduleOrchestrationInstanceCommand( + operatingIdentity: new ClientTypes.Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance.UserIdentityDto( + UserId: Guid.NewGuid(), + ActorId: Guid.NewGuid()), + runAt: DateTimeOffset.Parse("2024-11-01T06:19:10.0209567+01:00"), + inputParameter: new NotifyAggregatedMeasureDataInputV1( CalculationTypes.BalanceFixing, GridAreaCodes: new[] { "543" }, PeriodStartDate: DateTimeOffset.Parse("2024-10-29T15:19:10.0151351+01:00"), PeriodEndDate: DateTimeOffset.Parse("2024-10-29T16:19:10.0193962+01:00"), - IsInternalCalculation: true, - UserId: Guid.NewGuid())), + IsInternalCalculation: true)), CancellationToken.None); // Step 2: Trigger the scheduler to queue the calculation orchestration instance diff --git a/source/ProcessManager.Client/IProcessManagerClient.cs b/source/ProcessManager.Client/IProcessManagerClient.cs index ec26fcb6ba..4a66c8343b 100644 --- a/source/ProcessManager.Client/IProcessManagerClient.cs +++ b/source/ProcessManager.Client/IProcessManagerClient.cs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Energinet.DataHub.ProcessManager.Api.Model; using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; namespace Energinet.DataHub.ProcessManager.Client; @@ -25,7 +26,7 @@ public interface IProcessManagerClient /// Cancel a scheduled orchestration instance. /// public Task CancelScheduledOrchestrationInstanceAsync( - Guid id, + CancelScheduledOrchestrationInstanceCommand command, CancellationToken cancellationToken); /// diff --git a/source/ProcessManager.Client/ProcessManager.Client.csproj b/source/ProcessManager.Client/ProcessManager.Client.csproj index 8cc2d9ddaf..f0127a572a 100644 --- a/source/ProcessManager.Client/ProcessManager.Client.csproj +++ b/source/ProcessManager.Client/ProcessManager.Client.csproj @@ -7,7 +7,7 @@ Energinet.DataHub.ProcessManager.Client - 0.10.0$(VersionSuffix) + 0.11.0$(VersionSuffix) DH3 Process Manager Client library Energinet-DataHub Energinet-DataHub @@ -52,14 +52,23 @@ + + + + + + + - - + + + + diff --git a/source/ProcessManager.Client/ProcessManagerClient.cs b/source/ProcessManager.Client/ProcessManagerClient.cs index ba1b285b7d..a588c99326 100644 --- a/source/ProcessManager.Client/ProcessManagerClient.cs +++ b/source/ProcessManager.Client/ProcessManagerClient.cs @@ -15,6 +15,8 @@ using System.Globalization; using System.Net.Http.Json; using System.Text; +using System.Text.Json; +using Energinet.DataHub.ProcessManager.Api.Model; using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; using Energinet.DataHub.ProcessManager.Client.Extensions.DependencyInjection; @@ -32,12 +34,17 @@ public ProcessManagerClient(IHttpClientFactory httpClientFactory) /// public async Task CancelScheduledOrchestrationInstanceAsync( - Guid id, + CancelScheduledOrchestrationInstanceCommand command, CancellationToken cancellationToken) { using var request = new HttpRequestMessage( - HttpMethod.Delete, - $"/api/processmanager/orchestrationinstance/{id}"); + HttpMethod.Post, + "/api/processmanager/orchestrationinstance/cancel"); + var json = JsonSerializer.Serialize(command); + request.Content = new StringContent( + json, + Encoding.UTF8, + "application/json"); using var actualResponse = await _httpClient .SendAsync(request, cancellationToken) diff --git a/source/ProcessManager.Client/Processes/BRS_023_027/V1/INotifyAggregatedMeasureDataClientV1.cs b/source/ProcessManager.Client/Processes/BRS_023_027/V1/INotifyAggregatedMeasureDataClientV1.cs index 70f18c8ed7..47ed70d085 100644 --- a/source/ProcessManager.Client/Processes/BRS_023_027/V1/INotifyAggregatedMeasureDataClientV1.cs +++ b/source/ProcessManager.Client/Processes/BRS_023_027/V1/INotifyAggregatedMeasureDataClientV1.cs @@ -27,7 +27,7 @@ public interface INotifyAggregatedMeasureDataClientV1 /// Schedule a BRS-023 or BRS-027 calculation and return its id. /// public Task ScheduleNewCalculationAsync( - ScheduleOrchestrationInstanceDto requestDto, + ScheduleOrchestrationInstanceCommand command, CancellationToken cancellationToken); /// diff --git a/source/ProcessManager.Client/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataClientV1.cs b/source/ProcessManager.Client/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataClientV1.cs index f37092a663..07d9ebb818 100644 --- a/source/ProcessManager.Client/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataClientV1.cs +++ b/source/ProcessManager.Client/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataClientV1.cs @@ -37,7 +37,7 @@ public NotifyAggregatedMeasureDataClientV1(IHttpClientFactory httpClientFactory) /// public async Task ScheduleNewCalculationAsync( - ScheduleOrchestrationInstanceDto requestDto, + ScheduleOrchestrationInstanceCommand command, CancellationToken cancellationToken) { // TODO: @@ -46,8 +46,9 @@ public async Task ScheduleNewCalculationAsync( using var request = new HttpRequestMessage( HttpMethod.Post, "/api/processmanager/orchestrationinstance/brs_023_027/1"); + var json = JsonSerializer.Serialize(command); request.Content = new StringContent( - JsonSerializer.Serialize(requestDto), + json, Encoding.UTF8, "application/json"); diff --git a/source/ProcessManager.Client/Processes/BRS_026_028/V1/IRequestCalculatedDataClientV1.cs b/source/ProcessManager.Client/Processes/BRS_026_028/V1/IRequestCalculatedDataClientV1.cs index 2f3b484128..ae84c8f748 100644 --- a/source/ProcessManager.Client/Processes/BRS_026_028/V1/IRequestCalculatedDataClientV1.cs +++ b/source/ProcessManager.Client/Processes/BRS_026_028/V1/IRequestCalculatedDataClientV1.cs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Energinet.DataHub.ProcessManager.Api.Model; using Energinet.DataHub.ProcessManager.Client.Processes.BRS_026_028.V1.Model; using Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_026.V1.Models; @@ -25,10 +26,14 @@ public interface IRequestCalculatedDataClientV1 /// /// Start a request for energy results /// - public Task RequestCalculatedEnergyTimeSeriesAsync(RequestCalculatedDataInputV1 input, CancellationToken cancellationToken); + public Task RequestCalculatedEnergyTimeSeriesAsync( + MessageCommand command, + CancellationToken cancellationToken); /// /// Start a request for wholesale results /// - public Task RequestCalculatedWholesaleServicesAsync(RequestCalculatedDataInputV1 input, CancellationToken cancellationToken); + public Task RequestCalculatedWholesaleServicesAsync( + MessageCommand command, + CancellationToken cancellationToken); } diff --git a/source/ProcessManager.Client/Processes/BRS_026_028/V1/Model/RequestCalculatedDataInputV1.cs b/source/ProcessManager.Client/Processes/BRS_026_028/V1/Model/RequestCalculatedWholesaleServicesInputV1.cs similarity index 83% rename from source/ProcessManager.Client/Processes/BRS_026_028/V1/Model/RequestCalculatedDataInputV1.cs rename to source/ProcessManager.Client/Processes/BRS_026_028/V1/Model/RequestCalculatedWholesaleServicesInputV1.cs index e18bffa3f7..e3f22976ff 100644 --- a/source/ProcessManager.Client/Processes/BRS_026_028/V1/Model/RequestCalculatedDataInputV1.cs +++ b/source/ProcessManager.Client/Processes/BRS_026_028/V1/Model/RequestCalculatedWholesaleServicesInputV1.cs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Energinet.DataHub.ProcessManager.Api.Model; + namespace Energinet.DataHub.ProcessManager.Client.Processes.BRS_026_028.V1.Model; -public record RequestCalculatedDataInputV1( - string MessageId, - TInput Input) - where TInput : class; +public record RequestCalculatedWholesaleServicesInputV1() + : IInputParameterDto; diff --git a/source/ProcessManager.Client/Processes/BRS_026_028/V1/RequestCalculatedDataClientV1.cs b/source/ProcessManager.Client/Processes/BRS_026_028/V1/RequestCalculatedDataClientV1.cs index 1168476f96..31cde9b3ba 100644 --- a/source/ProcessManager.Client/Processes/BRS_026_028/V1/RequestCalculatedDataClientV1.cs +++ b/source/ProcessManager.Client/Processes/BRS_026_028/V1/RequestCalculatedDataClientV1.cs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -using System.Dynamic; using System.Text.Json; using Azure.Messaging.ServiceBus; +using Energinet.DataHub.ProcessManager.Api.Model; using Energinet.DataHub.ProcessManager.Client.Extensions.Options; using Energinet.DataHub.ProcessManager.Client.Processes.BRS_026_028.V1.Model; using Energinet.DataHub.ProcessManager.Orchestrations.Contracts; @@ -30,12 +30,12 @@ public class RequestCalculatedDataClientV1( { private readonly ServiceBusSender _serviceBusSender = serviceBusFactory.CreateClient(nameof(ProcessManagerServiceBusClientsOptions.TopicName)); - public async Task RequestCalculatedEnergyTimeSeriesAsync(RequestCalculatedDataInputV1 input, CancellationToken cancellationToken) + public async Task RequestCalculatedEnergyTimeSeriesAsync(MessageCommand command, CancellationToken cancellationToken) { var serviceBusMessage = CreateServiceBusMessage( "BRS_026", 1, - input); + command); await SendServiceBusMessage( serviceBusMessage, @@ -43,34 +43,34 @@ await SendServiceBusMessage( .ConfigureAwait(false); } - public async Task RequestCalculatedWholesaleServicesAsync(RequestCalculatedDataInputV1 input, CancellationToken cancellationToken) + public async Task RequestCalculatedWholesaleServicesAsync(MessageCommand command, CancellationToken cancellationToken) { var serviceBusMessage = CreateServiceBusMessage( "BRS_028", 1, - input); + command); await SendServiceBusMessage(serviceBusMessage, cancellationToken) .ConfigureAwait(false); } - private ServiceBusMessage CreateServiceBusMessage( + private ServiceBusMessage CreateServiceBusMessage( string orchestrationName, int orchestrationVersion, - RequestCalculatedDataInputV1 input) - where TInput : class + MessageCommand command) + where TInputParameterDto : IInputParameterDto { var message = new StartOrchestrationDto { OrchestrationName = orchestrationName, OrchestrationVersion = orchestrationVersion, - JsonInput = JsonSerializer.Serialize(input.Input), + JsonInput = JsonSerializer.Serialize(command.InputParameter), }; ServiceBusMessage serviceBusMessage = new(JsonFormatter.Default.Format(message)) { Subject = orchestrationName, - MessageId = input.MessageId, + MessageId = command.MessageId, ContentType = "application/json", }; diff --git a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs index d9be3af314..82f22ff7a1 100644 --- a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs +++ b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Database/ProcessManagerContextTests.cs @@ -78,6 +78,37 @@ public async Task Given_OrchestrationInstanceWithStepsAddedToDbContext_WhenRetri .BeEquivalentTo(existingOrchestrationInstance); } + [Fact] + public async Task Given_UserCanceledOrchestrationInstanceAddedToDbContext_WhenRetrievingFromDatabase_HasCorrectValues() + { + // Arrange + var userIdentity = new UserIdentity(new UserId(Guid.NewGuid()), new ActorId(Guid.NewGuid())); + + var existingOrchestrationDescription = CreateOrchestrationDescription(); + var existingOrchestrationInstance = CreateOrchestrationInstance( + existingOrchestrationDescription, + identity: userIdentity, + runAt: SystemClock.Instance.GetCurrentInstant()); + existingOrchestrationInstance.Lifecycle.TransitionToUserCanceled(SystemClock.Instance, userIdentity); + + await using (var writeDbContext = _fixture.DatabaseManager.CreateDbContext()) + { + writeDbContext.OrchestrationDescriptions.Add(existingOrchestrationDescription); + writeDbContext.OrchestrationInstances.Add(existingOrchestrationInstance); + await writeDbContext.SaveChangesAsync(); + } + + // Act + await using var readDbContext = _fixture.DatabaseManager.CreateDbContext(); + var orchestrationInstance = await readDbContext.OrchestrationInstances.FindAsync(existingOrchestrationInstance.Id); + + // Assert + orchestrationInstance.Should() + .NotBeNull() + .And + .BeEquivalentTo(existingOrchestrationInstance); + } + private static OrchestrationDescription CreateOrchestrationDescription() { var orchestrationDescription = new OrchestrationDescription( @@ -95,12 +126,19 @@ private static OrchestrationDescription CreateOrchestrationDescription() return orchestrationDescription; } - private static OrchestrationInstance CreateOrchestrationInstance(OrchestrationDescription orchestrationDescription) + private static OrchestrationInstance CreateOrchestrationInstance(OrchestrationDescription orchestrationDescription, OperatingIdentity? identity = default, Instant? runAt = default) { + var operatingIdentity = identity + ?? new UserIdentity( + new UserId(Guid.NewGuid()), + new ActorId(Guid.NewGuid())); + var orchestrationInstance = OrchestrationInstance.CreateFromDescription( - description: orchestrationDescription, + operatingIdentity, + orchestrationDescription, skipStepsBySequence: [3], - clock: SystemClock.Instance); + clock: SystemClock.Instance, + runAt); orchestrationInstance.ParameterValue.SetFromInstance(new TestOrchestrationParameter { diff --git a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs index 5e6c215460..e45db84f5f 100644 --- a/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs +++ b/source/ProcessManager.Core.Tests/Integration/Infrastructure/Orchestration/OrchestrationInstanceRepositoryTests.cs @@ -266,7 +266,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi var isTerminatedAsSucceededV1 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); isTerminatedAsSucceededV1.Lifecycle.TransitionToQueued(SystemClock.Instance); isTerminatedAsSucceededV1.Lifecycle.TransitionToRunning(SystemClock.Instance); - isTerminatedAsSucceededV1.Lifecycle.TransitionToTerminated(SystemClock.Instance, OrchestrationInstanceTerminationStates.Succeeded); + isTerminatedAsSucceededV1.Lifecycle.TransitionToSucceeded(SystemClock.Instance); await _sut.AddAsync(isTerminatedAsSucceededV1); var isPendingV2 = CreateOrchestrationInstance(existingOrchestrationDescriptionV2); @@ -275,7 +275,7 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi var isTerminatedAsFailedV2 = CreateOrchestrationInstance(existingOrchestrationDescriptionV2); isTerminatedAsFailedV2.Lifecycle.TransitionToQueued(SystemClock.Instance); isTerminatedAsFailedV2.Lifecycle.TransitionToRunning(SystemClock.Instance); - isTerminatedAsFailedV2.Lifecycle.TransitionToTerminated(SystemClock.Instance, OrchestrationInstanceTerminationStates.Failed); + isTerminatedAsFailedV2.Lifecycle.TransitionToFailed(SystemClock.Instance); await _sut.AddAsync(isTerminatedAsFailedV2); await _sut.UnitOfWork.CommitAsync(); @@ -353,13 +353,13 @@ public async Task GivenOrchestrationInstancesInDatabase_WhenSearchByNameAndTermi var isTerminated01 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); isTerminated01.Lifecycle.TransitionToQueued(SystemClock.Instance); isTerminated01.Lifecycle.TransitionToRunning(SystemClock.Instance); - isTerminated01.Lifecycle.TransitionToTerminated(terminatedAtClockMock01.Object, OrchestrationInstanceTerminationStates.Succeeded); + isTerminated01.Lifecycle.TransitionToSucceeded(terminatedAtClockMock01.Object); await _sut.AddAsync(isTerminated01); var isTerminated02 = CreateOrchestrationInstance(existingOrchestrationDescriptionV1); isTerminated02.Lifecycle.TransitionToQueued(SystemClock.Instance); isTerminated02.Lifecycle.TransitionToRunning(SystemClock.Instance); - isTerminated02.Lifecycle.TransitionToTerminated(SystemClock.Instance, OrchestrationInstanceTerminationStates.Succeeded); + isTerminated02.Lifecycle.TransitionToFailed(SystemClock.Instance); await _sut.AddAsync(isTerminated02); await _sut.UnitOfWork.CommitAsync(); @@ -395,8 +395,13 @@ private static OrchestrationInstance CreateOrchestrationInstance( OrchestrationDescription orchestrationDescription, Instant? runAt = default) { + var userIdentity = new UserIdentity( + new UserId(Guid.NewGuid()), + new ActorId(Guid.NewGuid())); + var orchestrationInstance = OrchestrationInstance.CreateFromDescription( - description: orchestrationDescription, + userIdentity, + orchestrationDescription, skipStepsBySequence: [], clock: SystemClock.Instance, runAt: runAt); diff --git a/source/ProcessManager.Core.Tests/Unit/Domain/OrchestrationParameterDefinitionTests.cs b/source/ProcessManager.Core.Tests/Unit/Domain/OrchestrationParameterDefinitionTests.cs index fb51f46951..191fd5ae33 100644 --- a/source/ProcessManager.Core.Tests/Unit/Domain/OrchestrationParameterDefinitionTests.cs +++ b/source/ProcessManager.Core.Tests/Unit/Domain/OrchestrationParameterDefinitionTests.cs @@ -71,21 +71,21 @@ public async Task GivenSetFromType_WhenValidatingInstanceOfAnotherType_ThenIsNot /// Example orchestration parameter for testing purposes. /// DOES NOT work if the parameter use the 'NodaTime.Instant' type. /// - public sealed record OrchestrationParameterExample01( + public record OrchestrationParameterExample01( DateTimeOffset RunAt, bool IsInternal); /// /// Example orchestration parameter for testing purposes. /// - public sealed record OrchestrationParameterExample02( + public record OrchestrationParameterExample02( DateTimeOffset RunAt, bool IsInternal); /// /// Example orchestration parameter for testing purposes. /// - public sealed record OrchestrationParameterExample03( + public record OrchestrationParameterExample03( int Version, bool IsInternal); } diff --git a/source/ProcessManager.Core/Application/Orchestration/ICancelScheduledOrchestrationInstanceCommand.cs b/source/ProcessManager.Core/Application/Orchestration/ICancelScheduledOrchestrationInstanceCommand.cs index 43a958e9eb..87b3892d01 100644 --- a/source/ProcessManager.Core/Application/Orchestration/ICancelScheduledOrchestrationInstanceCommand.cs +++ b/source/ProcessManager.Core/Application/Orchestration/ICancelScheduledOrchestrationInstanceCommand.cs @@ -21,5 +21,5 @@ public interface ICancelScheduledOrchestrationInstanceCommand /// /// Cancel a scheduled orchestration instance. /// - Task CancelScheduledOrchestrationInstanceAsync(OrchestrationInstanceId id); + Task CancelScheduledOrchestrationInstanceAsync(UserIdentity userIdentity, OrchestrationInstanceId id); } diff --git a/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs b/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs index e3d842ea86..60b8a692f2 100644 --- a/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs +++ b/source/ProcessManager.Core/Application/Orchestration/IStartOrchestrationInstanceCommands.cs @@ -23,6 +23,7 @@ public interface IStartOrchestrationInstanceCommands /// Start a new instance of an orchestration. /// Task StartNewOrchestrationInstanceAsync( + OperatingIdentity identity, string name, int version, TParameter inputParameter, @@ -33,6 +34,7 @@ Task StartNewOrchestrationInstanceAsync( /// Schedule a new instance of an orchestration. /// Task ScheduleNewOrchestrationInstanceAsync( + UserIdentity identity, string name, int version, TParameter inputParameter, diff --git a/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs b/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs index ea974f2a52..2396dbb605 100644 --- a/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs +++ b/source/ProcessManager.Core/Application/Orchestration/OrchestrationInstanceManager.cs @@ -39,22 +39,35 @@ internal class OrchestrationInstanceManager( /// public async Task StartNewOrchestrationInstanceAsync( + OperatingIdentity identity, string name, int version, TParameter inputParameter, IReadOnlyCollection skipStepsBySequence) where TParameter : class { - var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync(name, version, inputParameter, skipStepsBySequence).ConfigureAwait(false); + var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync( + name, + version, + inputParameter, + skipStepsBySequence).ConfigureAwait(false); + + var orchestrationInstance = await CreateOrchestrationInstanceAsync( + identity, + orchestrationDescription, + inputParameter, + skipStepsBySequence).ConfigureAwait(false); - var orchestrationInstance = await CreateOrchestrationInstanceAsync(inputParameter, orchestrationDescription, skipStepsBySequence).ConfigureAwait(false); - await RequestStartOfOrchestrationInstanceAsync(orchestrationDescription, orchestrationInstance).ConfigureAwait(false); + await RequestStartOfOrchestrationInstanceAsync( + orchestrationDescription, + orchestrationInstance).ConfigureAwait(false); return orchestrationInstance.Id; } /// public async Task ScheduleNewOrchestrationInstanceAsync( + UserIdentity userIdentity, string name, int version, TParameter inputParameter, @@ -62,11 +75,21 @@ public async Task ScheduleNewOrchestrationInstanceAsync IReadOnlyCollection skipStepsBySequence) where TParameter : class { - var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync(name, version, inputParameter, skipStepsBySequence).ConfigureAwait(false); + var orchestrationDescription = await GuardMatchingOrchestrationDescriptionAsync( + name, + version, + inputParameter, + skipStepsBySequence).ConfigureAwait(false); + if (orchestrationDescription.CanBeScheduled == false) throw new InvalidOperationException("Orchestration description cannot be scheduled."); - var orchestrationInstance = await CreateOrchestrationInstanceAsync(inputParameter, orchestrationDescription, skipStepsBySequence, runAt).ConfigureAwait(false); + var orchestrationInstance = await CreateOrchestrationInstanceAsync( + userIdentity, + orchestrationDescription, + inputParameter, + skipStepsBySequence, + runAt).ConfigureAwait(false); return orchestrationInstance.Id; } @@ -86,14 +109,14 @@ public async Task StartScheduledOrchestrationInstanceAsync(OrchestrationInstance } /// - public async Task CancelScheduledOrchestrationInstanceAsync(OrchestrationInstanceId id) + public async Task CancelScheduledOrchestrationInstanceAsync(UserIdentity userIdentity, OrchestrationInstanceId id) { var orchestrationInstance = await _repository.GetAsync(id).ConfigureAwait(false); if (!orchestrationInstance.Lifecycle.IsPendingForScheduledStart()) throw new InvalidOperationException("Orchestration instance cannot be canceled."); // Transition lifecycle - orchestrationInstance.Lifecycle.TransitionToTerminated(_clock, OrchestrationInstanceTerminationStates.UserCanceled); + orchestrationInstance.Lifecycle.TransitionToUserCanceled(_clock, userIdentity); await _repository.UnitOfWork.CommitAsync().ConfigureAwait(false); } @@ -129,13 +152,15 @@ private async Task GuardMatchingOrchestrationDescripti } private async Task CreateOrchestrationInstanceAsync( - TParameter inputParameter, + OperatingIdentity identity, OrchestrationDescription orchestrationDescription, + TParameter inputParameter, IReadOnlyCollection skipStepsBySequence, Instant? runAt = default) where TParameter : class { var orchestrationInstance = OrchestrationInstance.CreateFromDescription( + identity, orchestrationDescription, skipStepsBySequence, _clock, diff --git a/source/ProcessManager.Core/Domain/OrchestrationDescription/ParameterDefinition.cs b/source/ProcessManager.Core/Domain/OrchestrationDescription/ParameterDefinition.cs index 1d475851bc..b61440d8a8 100644 --- a/source/ProcessManager.Core/Domain/OrchestrationDescription/ParameterDefinition.cs +++ b/source/ProcessManager.Core/Domain/OrchestrationDescription/ParameterDefinition.cs @@ -22,8 +22,6 @@ namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationDescripti /// public class ParameterDefinition { - internal const string SerializedParameterDefinitionPropertyName = nameof(SerializedParameterDefinition); - internal ParameterDefinition() { SerializedParameterDefinition = string.Empty; @@ -31,12 +29,8 @@ internal ParameterDefinition() /// /// The JSON schema defining the parameter type. - /// - /// Parameter name "SerializedParameterDefinition" needs to be in sync with the Entity Framework configuration - /// (since it is private). - /// /// - private string SerializedParameterDefinition { get; set; } + internal string SerializedParameterDefinition { get; private set; } /// /// Set the parameter definition by specifying its type. diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/ActorId.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/ActorId.cs new file mode 100644 index 0000000000..cbf3c16fd1 --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/ActorId.cs @@ -0,0 +1,17 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; + +public record ActorId(Guid Value); diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/ActorIdentity.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/ActorIdentity.cs new file mode 100644 index 0000000000..45b48af35b --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/ActorIdentity.cs @@ -0,0 +1,21 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; + +/// +/// An actor identity performing a Process Manager operation. +/// +public record ActorIdentity(ActorId ActorId) + : OperatingIdentity; diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/OperatingIdentity.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/OperatingIdentity.cs new file mode 100644 index 0000000000..f1ed7fc3a8 --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/OperatingIdentity.cs @@ -0,0 +1,20 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; + +/// +/// An identity performing an Process Manager operation. +/// +public abstract record OperatingIdentity; diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/OperatingIdentityComplexType.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/OperatingIdentityComplexType.cs new file mode 100644 index 0000000000..7ef6138c0d --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/OperatingIdentityComplexType.cs @@ -0,0 +1,79 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.ComponentModel.DataAnnotations.Schema; + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; + +public record OperatingIdentityComplexType +{ + internal OperatingIdentityComplexType(OperatingIdentity value) + { + Value = value; + } + + /// + /// Used by Entity Framework + /// +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + // ReSharper disable once UnusedMember.Local -- Used by Entity Framework + private OperatingIdentityComplexType() + { + } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + + public OperatingIdentity Value + { + get + { + switch (IdentityType) + { + case nameof(ActorIdentity): + return new ActorIdentity(new ActorId(ActorId!.Value)); + + case nameof(UserIdentity): + return new UserIdentity(new UserId(UserId!.Value), new ActorId(ActorId!.Value)); + + default: + throw new InvalidOperationException($"Unknown operating identity type '{IdentityType}'."); + } + } + + private set + { + switch (value) + { + case ActorIdentity actor: + IdentityType = nameof(ActorIdentity); + ActorId = actor.ActorId.Value; + break; + + case UserIdentity user: + IdentityType = nameof(UserIdentity); + ActorId = user.ActorId.Value; + UserId = user.UserId.Value; + break; + + default: + throw new InvalidOperationException($"Invalid type '{value.GetType()}'."); + } + } + } + + internal string? IdentityType { get; private set; } + + internal Guid? ActorId { get; private set; } + + internal Guid? UserId { get; private set; } +} diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstance.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstance.cs index 07bfe5384c..60a0138458 100644 --- a/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstance.cs +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstance.cs @@ -28,11 +28,12 @@ public class OrchestrationInstance private OrchestrationInstance( OrchestrationDescriptionId orchestrationDescriptionId, + OperatingIdentity identity, IClock clock, Instant? runAt = default) { Id = new OrchestrationInstanceId(Guid.NewGuid()); - Lifecycle = new OrchestrationInstanceLifecycleState(clock, runAt); + Lifecycle = new OrchestrationInstanceLifecycleState(identity, clock, runAt); ParameterValue = new(); CustomState = new OrchestrationInstanceCustomState(string.Empty); @@ -86,6 +87,7 @@ private OrchestrationInstance() /// orchestration instance. /// internal static OrchestrationInstance CreateFromDescription( + OperatingIdentity identity, OrchestrationDescription.OrchestrationDescription description, IReadOnlyCollection skipStepsBySequence, IClock clock, @@ -106,6 +108,7 @@ internal static OrchestrationInstance CreateFromDescription( var orchestrationInstance = new OrchestrationInstance( description.Id, + identity, clock, runAt); diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstanceLifecycleState.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstanceLifecycleState.cs index e51af9aebf..dc6dea9989 100644 --- a/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstanceLifecycleState.cs +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/OrchestrationInstanceLifecycleState.cs @@ -18,8 +18,9 @@ namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; public class OrchestrationInstanceLifecycleState { - internal OrchestrationInstanceLifecycleState(IClock clock, Instant? runAt) + internal OrchestrationInstanceLifecycleState(OperatingIdentity createdBy, IClock clock, Instant? runAt) { + CreatedBy = new OperatingIdentityComplexType(createdBy); CreatedAt = clock.GetCurrentInstant(); ScheduledToRunAt = runAt; @@ -40,6 +41,11 @@ private OrchestrationInstanceLifecycleState() public OrchestrationInstanceTerminationStates? TerminationState { get; private set; } + /// + /// The identity that caused this orchestration instance to be created. + /// + public OperatingIdentityComplexType CreatedBy { get; } + /// /// The time when the orchestration instance was created (State => Pending). /// @@ -68,6 +74,17 @@ private OrchestrationInstanceLifecycleState() /// public Instant? TerminatedAt { get; private set; } + /// + /// The identity that caused this orchestration instance to be canceled. + /// + public OperatingIdentityComplexType? CanceledBy { get; private set; } + + internal string? CreatedByIdentityType { get; private set; } + + internal Guid? CreatedByActorId { get; private set; } + + internal Guid? CreatedByUserId { get; private set; } + public bool IsPendingForScheduledStart() { return @@ -93,7 +110,22 @@ public void TransitionToRunning(IClock clock) StartedAt = clock.GetCurrentInstant(); } - public void TransitionToTerminated(IClock clock, OrchestrationInstanceTerminationStates terminationState) + public void TransitionToSucceeded(IClock clock) + { + TransitionToTerminated(clock, OrchestrationInstanceTerminationStates.Succeeded); + } + + public void TransitionToFailed(IClock clock) + { + TransitionToTerminated(clock, OrchestrationInstanceTerminationStates.Failed); + } + + public void TransitionToUserCanceled(IClock clock, UserIdentity userIdentity) + { + TransitionToTerminated(clock, OrchestrationInstanceTerminationStates.UserCanceled, userIdentity); + } + + private void TransitionToTerminated(IClock clock, OrchestrationInstanceTerminationStates terminationState, UserIdentity? userIdentity = default) { switch (terminationState) { @@ -102,10 +134,15 @@ public void TransitionToTerminated(IClock clock, OrchestrationInstanceTerminatio if (State is not OrchestrationInstanceLifecycleStates.Running) throw new InvalidOperationException($"Cannot change termination state to '{terminationState}' when '{State}'."); break; + case OrchestrationInstanceTerminationStates.UserCanceled: if (!IsPendingForScheduledStart()) throw new InvalidOperationException("User cannot cancel orchestration instance."); + if (userIdentity == null) + throw new InvalidOperationException("User identity must be specified."); + CanceledBy = new OperatingIdentityComplexType(userIdentity); break; + default: throw new InvalidOperationException($"Unsupported termination state '{terminationState}'."); } diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/UserId.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/UserId.cs new file mode 100644 index 0000000000..2e681557b0 --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/UserId.cs @@ -0,0 +1,17 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; + +public record UserId(Guid Value); diff --git a/source/ProcessManager.Core/Domain/OrchestrationInstance/UserIdentity.cs b/source/ProcessManager.Core/Domain/OrchestrationInstance/UserIdentity.cs new file mode 100644 index 0000000000..ce8a8c6ae3 --- /dev/null +++ b/source/ProcessManager.Core/Domain/OrchestrationInstance/UserIdentity.cs @@ -0,0 +1,21 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; + +/// +/// A user identity performing a Process Manager operation. +/// +public record UserIdentity(UserId UserId, ActorId ActorId) + : OperatingIdentity; diff --git a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs index 1c47413acf..685e2b9915 100644 --- a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs +++ b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationDescriptionEntityConfiguration.cs @@ -38,10 +38,10 @@ public void Configure(EntityTypeBuilder builder) builder.OwnsOne( o => o.ParameterDefinition, - pd => + b => { - pd.Property(ParameterDefinition.SerializedParameterDefinitionPropertyName) - .HasColumnName(ParameterDefinition.SerializedParameterDefinitionPropertyName); + b.Property(pd => pd.SerializedParameterDefinition) + .HasColumnName(nameof(OrchestrationDescription.ParameterDefinition.SerializedParameterDefinition)); }); builder.Property(o => o.HostName); diff --git a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs index f50b1562d0..0848e650ba 100644 --- a/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs +++ b/source/ProcessManager.Core/Infrastructure/Database/OrchestrationInstanceEntityConfiguration.cs @@ -36,21 +36,43 @@ public void Configure(EntityTypeBuilder builder) o => o.Lifecycle, b => { - b.Property(pv => pv.State); - b.Property(pv => pv.TerminationState); - - b.Property(pv => pv.CreatedAt); - b.Property(pv => pv.ScheduledToRunAt); - b.Property(pv => pv.QueuedAt); - b.Property(pv => pv.StartedAt); - b.Property(pv => pv.TerminatedAt); + b.Property(l => l.State); + b.Property(l => l.TerminationState); + + b.OwnsOne( + l => l.CreatedBy, + lb => + { + lb.Ignore(ct => ct.Value); + + lb.Property(ct => ct.IdentityType); + lb.Property(ct => ct.ActorId); + lb.Property(ct => ct.UserId); + }); + + b.Property(l => l.CreatedAt); + b.Property(l => l.ScheduledToRunAt); + b.Property(l => l.QueuedAt); + b.Property(l => l.StartedAt); + b.Property(l => l.TerminatedAt); + + b.OwnsOne( + l => l.CanceledBy, + lb => + { + lb.Ignore(ct => ct.Value); + + lb.Property(ct => ct.IdentityType); + lb.Property(ct => ct.ActorId); + lb.Property(ct => ct.UserId); + }); }); builder.OwnsOne( o => o.ParameterValue, b => { - b.Property(pv => pv.SerializedParameterValue) + b.Property(l => l.SerializedParameterValue) .HasColumnName(nameof(OrchestrationInstance.ParameterValue.SerializedParameterValue)); }); @@ -71,13 +93,13 @@ public void Configure(EntityTypeBuilder builder) o => o.Lifecycle, b => { - b.Property(pv => pv.State); - b.Property(pv => pv.TerminationState); + b.Property(l => l.State); + b.Property(l => l.TerminationState); - b.Property(pv => pv.StartedAt); - b.Property(pv => pv.TerminatedAt); + b.Property(l => l.StartedAt); + b.Property(l => l.TerminatedAt); - b.Property(pv => pv.CanBeSkipped); + b.Property(l => l.CanBeSkipped); }); b.Property(s => s.Description); diff --git a/source/ProcessManager.DatabaseMigration/ProcessManager.DatabaseMigration.csproj b/source/ProcessManager.DatabaseMigration/ProcessManager.DatabaseMigration.csproj index 2f50d7de9e..a7642fb63f 100644 --- a/source/ProcessManager.DatabaseMigration/ProcessManager.DatabaseMigration.csproj +++ b/source/ProcessManager.DatabaseMigration/ProcessManager.DatabaseMigration.csproj @@ -8,6 +8,8 @@ + + @@ -20,6 +22,8 @@ + + diff --git a/source/ProcessManager.DatabaseMigration/Scripts/202411192300 Add operating identity columns.sql b/source/ProcessManager.DatabaseMigration/Scripts/202411192300 Add operating identity columns.sql new file mode 100644 index 0000000000..e0713b8cff --- /dev/null +++ b/source/ProcessManager.DatabaseMigration/Scripts/202411192300 Add operating identity columns.sql @@ -0,0 +1,8 @@ +ALTER TABLE [pm].[OrchestrationInstance] + ADD [Lifecycle_CreatedBy_IdentityType] NVARCHAR(255) NULL, + [Lifecycle_CreatedBy_ActorId] UNIQUEIDENTIFIER NULL, + [Lifecycle_CreatedBy_UserId] UNIQUEIDENTIFIER NULL, + [Lifecycle_CanceledBy_IdentityType] NVARCHAR(255) NULL, + [Lifecycle_CanceledBy_ActorId] UNIQUEIDENTIFIER NULL, + [Lifecycle_CanceledBy_UserId] UNIQUEIDENTIFIER NULL +GO diff --git a/source/ProcessManager.DatabaseMigration/Scripts/202411211300 Update Lifecycle_CreatedBy_IdentityType.sql b/source/ProcessManager.DatabaseMigration/Scripts/202411211300 Update Lifecycle_CreatedBy_IdentityType.sql new file mode 100644 index 0000000000..0a868dea2d --- /dev/null +++ b/source/ProcessManager.DatabaseMigration/Scripts/202411211300 Update Lifecycle_CreatedBy_IdentityType.sql @@ -0,0 +1,8 @@ +UPDATE [pm].[OrchestrationInstance] + SET [Lifecycle_CreatedBy_IdentityType] = 'NULL-VALUE-SET-BY-SCRIPT' -- <-- Use a value that makes it easy to determine the value is set by this script in the future + WHERE [Lifecycle_CreatedBy_IdentityType] IS NULL +GO + +ALTER TABLE [pm].[OrchestrationInstance] + ALTER COLUMN [Lifecycle_CreatedBy_IdentityType] NVARCHAR(255) NOT NULL +GO \ No newline at end of file diff --git a/source/ProcessManager.Orchestrations.Tests/Fixtures/OrchestrationsAppFixtureBase.cs b/source/ProcessManager.Orchestrations.Tests/Fixtures/OrchestrationsAppFixtureBase.cs index 6f783da360..4a38d7ed3b 100644 --- a/source/ProcessManager.Orchestrations.Tests/Fixtures/OrchestrationsAppFixtureBase.cs +++ b/source/ProcessManager.Orchestrations.Tests/Fixtures/OrchestrationsAppFixtureBase.cs @@ -30,10 +30,13 @@ namespace Energinet.DataHub.ProcessManager.Orchestrations.Tests.Fixtures; /// public abstract class OrchestrationsAppFixtureBase : IAsyncLifetime { + private readonly bool _disposeDatabase; + public OrchestrationsAppFixtureBase( ProcessManagerDatabaseManager databaseManager, string taskHubName, - int port) + int port, + bool disposeDatabase = true) { DatabaseManager = databaseManager ?? throw new ArgumentNullException(nameof(databaseManager)); @@ -41,7 +44,7 @@ public OrchestrationsAppFixtureBase( ? throw new ArgumentException("Cannot be null or whitespace.", nameof(taskHubName)) : taskHubName; Port = port; - + _disposeDatabase = disposeDatabase; TestLogger = new TestDiagnosticsLogger(); IntegrationTestConfiguration = new IntegrationTestConfiguration(); @@ -94,7 +97,9 @@ public async Task DisposeAsync() { AppHostManager.Dispose(); AzuriteManager.Dispose(); - await DatabaseManager.DeleteDatabaseAsync(); + + if (_disposeDatabase) + await DatabaseManager.DeleteDatabaseAsync(); } /// diff --git a/source/ProcessManager.Orchestrations/ProcessManager.Orchestrations.csproj b/source/ProcessManager.Orchestrations/ProcessManager.Orchestrations.csproj index f097d9b8b8..b82cd52dc3 100644 --- a/source/ProcessManager.Orchestrations/ProcessManager.Orchestrations.csproj +++ b/source/ProcessManager.Orchestrations/ProcessManager.Orchestrations.csproj @@ -34,12 +34,19 @@ - + - + + + + + + + + diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Activities/Brs023OrchestrationTerminateActivityV1.cs b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Activities/Brs023OrchestrationTerminateActivityV1.cs index 43560cd96f..a0ee4d0e16 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Activities/Brs023OrchestrationTerminateActivityV1.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/Activities/Brs023OrchestrationTerminateActivityV1.cs @@ -38,7 +38,7 @@ public async Task Run( .GetAsync(new OrchestrationInstanceId(orchestrationInstanceId)) .ConfigureAwait(false); - orchestrationInstance.Lifecycle.TransitionToTerminated(Clock, OrchestrationInstanceTerminationStates.Succeeded); + orchestrationInstance.Lifecycle.TransitionToSucceeded(Clock); await ProgressRepository.UnitOfWork.CommitAsync().ConfigureAwait(false); // TODO: For demo purposes; remove when done diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs index a97a18161e..e12daee5a6 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataHandler.cs @@ -26,23 +26,26 @@ internal class NotifyAggregatedMeasureDataHandler( private readonly IStartOrchestrationInstanceCommands _manager = manager; public async Task ScheduleNewCalculationAsync( - ScheduleOrchestrationInstanceDto dto) + ScheduleOrchestrationInstanceCommand command) { // TODO: // Server-side validation => Validate "period" is midnight values when given "timezone" etc. // See class Calculation and method IsValid in Wholesale. // Here we show how its possible, based on input, to decide certain steps should be skipped by the orchestration. - IReadOnlyCollection skipStepsBySequence = dto.InputParameter.IsInternalCalculation + IReadOnlyCollection skipStepsBySequence = command.InputParameter.IsInternalCalculation ? [NotifyAggregatedMeasureDataOrchestrationV1.EnqueueMessagesStepSequence] : []; var orchestrationInstanceId = await _manager .ScheduleNewOrchestrationInstanceAsync( + identity: new UserIdentity( + new UserId(command.OperatingIdentity.UserId), + new ActorId(command.OperatingIdentity.ActorId)), name: "BRS_023_027", version: 1, - inputParameter: dto.InputParameter, - runAt: dto.RunAt.ToInstant(), + inputParameter: command.InputParameter, + runAt: command.RunAt.ToInstant(), skipStepsBySequence: skipStepsBySequence) .ConfigureAwait(false); diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataOrchestrationV1.cs b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataOrchestrationV1.cs index 149d411e2e..a12b283732 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataOrchestrationV1.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataOrchestrationV1.cs @@ -30,6 +30,11 @@ internal class NotifyAggregatedMeasureDataOrchestrationV1 public async Task Run( [OrchestrationTrigger] TaskOrchestrationContext context) { + // TODO: For demo purposes; decide if we want to continue injecting parameters + // OR we want to have a pattern where developers load any info they need from the databae, using the first activity. + // Currently we inject parameters when an orchestration is started. + // But 'context.InstanceId' contains the 'OrchestrationInstance.Id' so it is possible to load all + // information about an 'OrchestrationInstance' in activities and use any information (e.g. UserIdentity). var input = context.GetOrchestrationParameterValue(); if (input == null) return "Error: No input specified."; diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataTriggerV1.cs b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataTriggerV1.cs index 13f19c5d98..92b0f01d1c 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataTriggerV1.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_023_027/V1/NotifyAggregatedMeasureDataTriggerV1.cs @@ -37,10 +37,10 @@ public async Task Run( Route = "processmanager/orchestrationinstance/brs_023_027/1")] HttpRequest httpRequest, [FromBody] - ScheduleOrchestrationInstanceDto dto, + ScheduleOrchestrationInstanceCommand command, FunctionContext executionContext) { - var orchestrationInstanceId = await _handler.ScheduleNewCalculationAsync(dto).ConfigureAwait(false); + var orchestrationInstanceId = await _handler.ScheduleNewCalculationAsync(command).ConfigureAwait(false); return new OkObjectResult(orchestrationInstanceId.Value); } } diff --git a/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs b/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs index 0743cbcfce..eba6f2fafd 100644 --- a/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs +++ b/source/ProcessManager.Orchestrations/Processes/BRS_026/V1/RequestCalculatedEnergyTimeSeriesHandler.cs @@ -13,6 +13,7 @@ // limitations under the License. using Energinet.DataHub.ProcessManagement.Core.Application.Orchestration; +using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; using Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_026.V1.Models; namespace Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_026.V1; @@ -28,6 +29,7 @@ public class RequestCalculatedEnergyTimeSeriesHandler( public async Task StartRequestCalculatedEnergyTimeSeriesAsync(RequestCalculatedEnergyTimeSeriesInputV1 input) { await _commands.StartNewOrchestrationInstanceAsync( + identity: new ActorIdentity(new ActorId(Guid.NewGuid())), // TODO: Any call to commands must include identity information; see 'ScheduleOrchestrationInstanceDto' and 'CancelOrchestrationInstanceDto' "BRS_026", 1, input, diff --git a/source/ProcessManager.Tests/Fixtures/ProcessManagerAppFixtureBase.cs b/source/ProcessManager.Tests/Fixtures/ProcessManagerAppFixtureBase.cs index 5f15985bcb..ba40ab0e4a 100644 --- a/source/ProcessManager.Tests/Fixtures/ProcessManagerAppFixtureBase.cs +++ b/source/ProcessManager.Tests/Fixtures/ProcessManagerAppFixtureBase.cs @@ -30,10 +30,13 @@ namespace Energinet.DataHub.ProcessManager.Tests.Fixtures; /// public abstract class ProcessManagerAppFixtureBase : IAsyncLifetime { + private readonly bool _disposeDatabase; + public ProcessManagerAppFixtureBase( ProcessManagerDatabaseManager databaseManager, string taskHubName, - int port) + int port, + bool disposeDatabase = true) { DatabaseManager = databaseManager ?? throw new ArgumentNullException(nameof(databaseManager)); @@ -41,6 +44,7 @@ public ProcessManagerAppFixtureBase( ? throw new ArgumentException("Cannot be null or whitespace.", nameof(taskHubName)) : taskHubName; Port = port; + _disposeDatabase = disposeDatabase; TestLogger = new TestDiagnosticsLogger(); IntegrationTestConfiguration = new IntegrationTestConfiguration(); @@ -94,7 +98,9 @@ public async Task DisposeAsync() { AppHostManager.Dispose(); AzuriteManager.Dispose(); - await DatabaseManager.DeleteDatabaseAsync(); + + if (_disposeDatabase) + await DatabaseManager.DeleteDatabaseAsync(); } /// diff --git a/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs b/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs index 456e27e17e..f5d3deae3c 100644 --- a/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs +++ b/source/ProcessManager.Tests/Unit/Api/Mappers/OrchestrationInstanceMapperExtensionsTests.cs @@ -17,6 +17,7 @@ using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; using Energinet.DataHub.ProcessManager.Api.Mappers; using Energinet.DataHub.ProcessManager.Api.Model; +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; using FluentAssertions; using NodaTime; @@ -24,6 +25,15 @@ namespace Energinet.DataHub.ProcessManager.Tests.Unit.Api.Mappers; public class OrchestrationInstanceMapperExtensionsTests { + public static IEnumerable GetOperatingIdentity() + { + return new List + { + new object[] { new ActorIdentity(new ActorId(Guid.NewGuid())), typeof(ActorIdentityDto) }, + new object[] { new UserIdentity(new UserId(Guid.NewGuid()), new ActorId(Guid.NewGuid())), typeof(UserIdentityDto) }, + }; + } + /// /// Even the 'ParameterValue' is mapped in a way that allows us to serialize the object /// and deserialize it to a strongly typed orchestration instance with parmeters. @@ -34,16 +44,33 @@ public void MapToDto_WhenOrchestrationInstance_CreateOrchestrationInstanceDtoTha var orchestrationInstance = CreateOrchestrationInstance(); // Act + // => We create and serialize 'OrchestrationInstanceDto' var actualDto = orchestrationInstance.MapToDto(); var dtoAsJson = JsonSerializer.Serialize(actualDto); // Assert + // => But we can deserialize to specific 'OrchestrationInstanceTypedDto' var typedDto = JsonSerializer.Deserialize>(dtoAsJson); typedDto!.ParameterValue.TestString.Should().NotBeNull(); typedDto!.ParameterValue.TestInt.Should().NotBeNull(); } - private static OrchestrationInstance CreateOrchestrationInstance() + [Theory] + [MemberData(nameof(GetOperatingIdentity))] + public void MapToDto_WhenOrchestrationInstanceWithOperatingIdentity_DeserializedToExpectedType(OperatingIdentity operatingIdentity, Type expectedType) + { + var orchestrationInstance = CreateOrchestrationInstance(operatingIdentity); + + // Act + var actualDto = orchestrationInstance.MapToDto(); + var dtoAsJson = JsonSerializer.Serialize(actualDto); + + // Assert + var dto = JsonSerializer.Deserialize(dtoAsJson); + dto!.Lifecycle.CreatedBy.Should().BeOfType(expectedType); + } + + private static OrchestrationInstance CreateOrchestrationInstance(OperatingIdentity? createdBy = default) { var orchestrationDescription = new OrchestrationDescription( name: "name", @@ -57,7 +84,13 @@ private static OrchestrationInstance CreateOrchestrationInstance() orchestrationDescription.AppendStepDescription("Test step 2"); orchestrationDescription.AppendStepDescription("Test step 3"); + var userIdentity = createdBy + ?? new UserIdentity( + new UserId(Guid.NewGuid()), + new ActorId(Guid.NewGuid())); + var orchestrationInstance = OrchestrationInstance.CreateFromDescription( + userIdentity, orchestrationDescription, skipStepsBySequence: [], SystemClock.Instance); @@ -71,7 +104,7 @@ private static OrchestrationInstance CreateOrchestrationInstance() return orchestrationInstance; } - private class TestOrchestrationParameter + private class TestOrchestrationParameter : IInputParameterDto { public string? TestString { get; set; } diff --git a/source/ProcessManager/Api/CancelScheduledOrchestrationInstanceTrigger.cs b/source/ProcessManager/Api/CancelScheduledOrchestrationInstanceTrigger.cs index 6e8f465888..a600337d10 100644 --- a/source/ProcessManager/Api/CancelScheduledOrchestrationInstanceTrigger.cs +++ b/source/ProcessManager/Api/CancelScheduledOrchestrationInstanceTrigger.cs @@ -14,6 +14,7 @@ using Energinet.DataHub.ProcessManagement.Core.Application.Orchestration; using Energinet.DataHub.ProcessManagement.Core.Domain.OrchestrationInstance; +using Energinet.DataHub.ProcessManager.Api.Model; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Azure.Functions.Worker; @@ -35,14 +36,19 @@ internal class CancelScheduledOrchestrationInstanceTrigger( public async Task Run( [HttpTrigger( AuthorizationLevel.Anonymous, - "delete", - Route = "processmanager/orchestrationinstance/{id:guid}")] + "post", + Route = "processmanager/orchestrationinstance/cancel")] HttpRequest httpRequest, - Guid id, + [FromBody] + CancelScheduledOrchestrationInstanceCommand command, FunctionContext executionContext) { await _command - .CancelScheduledOrchestrationInstanceAsync(new OrchestrationInstanceId(id)) + .CancelScheduledOrchestrationInstanceAsync( + new UserIdentity( + new UserId(command.OperatingIdentity.UserId), + new ActorId(command.OperatingIdentity.ActorId)), + new OrchestrationInstanceId(command.Id)) .ConfigureAwait(false); return new OkResult(); diff --git a/source/ProcessManager/Api/Mappers/OrchestrationInstanceMapperExtensions.cs b/source/ProcessManager/Api/Mappers/OrchestrationInstanceMapperExtensions.cs index 83cdb2eee0..8b96a89bb2 100644 --- a/source/ProcessManager/Api/Mappers/OrchestrationInstanceMapperExtensions.cs +++ b/source/ProcessManager/Api/Mappers/OrchestrationInstanceMapperExtensions.cs @@ -31,10 +31,11 @@ public static ApiModel.OrchestrationInstanceDto MapToDto( CustomState: entity.CustomState.Value); } - public static ApiModel.OrchestrationInstanceLifecycleStatesDto MapToDto( + public static ApiModel.OrchestrationInstanceLifecycleStateDto MapToDto( this DomainModel.OrchestrationInstanceLifecycleState entity) { - return new ApiModel.OrchestrationInstanceLifecycleStatesDto( + return new ApiModel.OrchestrationInstanceLifecycleStateDto( + CreatedBy: entity.CreatedBy.Value.MapToDto(), State: Enum .TryParse( entity.State.ToString(), @@ -49,6 +50,7 @@ public static ApiModel.OrchestrationInstanceLifecycleStatesDto MapToDto( out var terminationStateResult) ? terminationStateResult : null, + CanceledBy: entity.CanceledBy?.Value.MapToDto(), CreatedAt: entity.CreatedAt.ToDateTimeOffset(), ScheduledToRunAt: entity.ScheduledToRunAt?.ToDateTimeOffset(), QueuedAt: entity.QueuedAt?.ToDateTimeOffset(), @@ -56,6 +58,25 @@ public static ApiModel.OrchestrationInstanceLifecycleStatesDto MapToDto( TerminatedAt: entity.TerminatedAt?.ToDateTimeOffset()); } + public static ApiModel.IOperatingIdentityDto MapToDto( + this DomainModel.OperatingIdentity entity) + { + switch (entity) + { + case DomainModel.ActorIdentity actor: + return new ApiModel.ActorIdentityDto( + ActorId: actor.ActorId.Value); + + case DomainModel.UserIdentity user: + return new ApiModel.UserIdentityDto( + UserId: user.UserId.Value, + ActorId: user.ActorId.Value); + + default: + throw new InvalidOperationException($"Invalid type '{entity.GetType()}'; cannot be mapped."); + } + } + public static ApiModel.StepInstanceDto MapToDto( this DomainModel.StepInstance entity) { diff --git a/source/ProcessManager/ProcessManager.csproj b/source/ProcessManager/ProcessManager.csproj index 364545f7ff..5891230755 100644 --- a/source/ProcessManager/ProcessManager.csproj +++ b/source/ProcessManager/ProcessManager.csproj @@ -31,13 +31,21 @@ + + + + + + - - + + + + \ No newline at end of file diff --git a/source/Shared/ProcessManager/Api/Model/CancelScheduledOrchestrationInstanceCommand.cs b/source/Shared/ProcessManager/Api/Model/CancelScheduledOrchestrationInstanceCommand.cs new file mode 100644 index 0000000000..f58cb7f755 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/CancelScheduledOrchestrationInstanceCommand.cs @@ -0,0 +1,43 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +namespace Energinet.DataHub.ProcessManager.Api.Model; + +/// +/// Command for canceling a scheduled orchestration instance. +/// Must be JSON serializable. +/// +public record CancelScheduledOrchestrationInstanceCommand + : UserCommand +{ + /// + /// Construct command. + /// + /// Identity of the user executing the command. + /// Id of the scheduled orchestration instance to cancel. + public CancelScheduledOrchestrationInstanceCommand( + UserIdentityDto operatingIdentity, + Guid id) + : base(operatingIdentity) + { + Id = id; + } + + /// + /// Id of the scheduled orchestration instance to cancel. + /// + public Guid Id { get; } +} diff --git a/source/Shared/ProcessManager/Api/Model/ScheduleOrchestrationInstanceDto.cs b/source/Shared/ProcessManager/Api/Model/IInputParameterDto.cs similarity index 80% rename from source/Shared/ProcessManager/Api/Model/ScheduleOrchestrationInstanceDto.cs rename to source/Shared/ProcessManager/Api/Model/IInputParameterDto.cs index 0eb3cc8693..c5e85d28df 100644 --- a/source/Shared/ProcessManager/Api/Model/ScheduleOrchestrationInstanceDto.cs +++ b/source/Shared/ProcessManager/Api/Model/IInputParameterDto.cs @@ -14,7 +14,7 @@ namespace Energinet.DataHub.ProcessManager.Api.Model; -public sealed record ScheduleOrchestrationInstanceDto( - DateTimeOffset RunAt, - TParameter InputParameter) - where TParameter : class; +/// +/// Marker interface for JSON serializable input parameters to an orchestration instance. +/// +public interface IInputParameterDto; diff --git a/source/Shared/ProcessManager/Api/Model/MessageCommand.cs b/source/Shared/ProcessManager/Api/Model/MessageCommand.cs new file mode 100644 index 0000000000..c557139340 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/MessageCommand.cs @@ -0,0 +1,47 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +namespace Energinet.DataHub.ProcessManager.Api.Model; + +/// +/// Command for starting an orchestration instance for a message. +/// Must be JSON serializable. +/// +/// Must be a JSON serializable type. +public record MessageCommand + : StartOrchestrationInstanceCommand + where TInputParameterDto : IInputParameterDto +{ + /// + /// Construct command. + /// + /// Identity executing the command. + /// Contains the Durable Functions orchestration input parameter value. + /// Id of the message that casued this command to be executed. + public MessageCommand( + IOperatingIdentityDto operatingIdentity, + TInputParameterDto inputParameter, + string messageId) + : base(operatingIdentity, inputParameter) + { + MessageId = messageId; + } + + /// + /// Id of the message that casued this command to be executed. + /// + public string MessageId { get; } +} diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/ActorIdentityDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/ActorIdentityDto.cs new file mode 100644 index 0000000000..ca06919a5a --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/ActorIdentityDto.cs @@ -0,0 +1,19 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +public record ActorIdentityDto( + Guid ActorId) + : IOperatingIdentityDto; diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OperatingIdentityDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OperatingIdentityDto.cs new file mode 100644 index 0000000000..c88a8287f8 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OperatingIdentityDto.cs @@ -0,0 +1,28 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System.Text.Json.Serialization; + +namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +/// +/// An identity performing an Process Manager operation. +/// +/// We use https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/polymorphism +/// +[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FallBackToNearestAncestor)] +[JsonDerivedType(typeof(IOperatingIdentityDto), typeDiscriminator: "base")] +[JsonDerivedType(typeof(UserIdentityDto), typeDiscriminator: "user")] +[JsonDerivedType(typeof(ActorIdentityDto), typeDiscriminator: "actor")] +public interface IOperatingIdentityDto; diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceDto.cs index ed482d4e2c..be0463b608 100644 --- a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceDto.cs +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceDto.cs @@ -20,32 +20,14 @@ namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; /// Represents the instance of an orchestration. /// It contains state information about the instance. /// +/// +/// The high-level lifecycle states that all orchestration instances can go through. +/// Contains the Durable Functions orchestration input parameter value. +/// Workflow steps the orchestration instance is going through. +/// Any custom state of the orchestration instance. public record OrchestrationInstanceDto( Guid Id, - OrchestrationInstanceLifecycleStatesDto Lifecycle, + OrchestrationInstanceLifecycleStateDto Lifecycle, ExpandoObject ParameterValue, IReadOnlyCollection Steps, - string CustomState) -{ - public Guid Id { get; } = Id; - - /// - /// The high-level lifecycle states that all orchestration instances can go through. - /// - public OrchestrationInstanceLifecycleStatesDto Lifecycle { get; } = Lifecycle; - - /// - /// Contains the Durable Functions orchestration input parameter value. - /// - public ExpandoObject ParameterValue { get; } = ParameterValue; - - /// - /// Workflow steps the orchestration instance is going through. - /// - public IReadOnlyCollection Steps { get; } = Steps; - - /// - /// Any custom state of the orchestration instance. - /// - public string CustomState { get; } = CustomState; -} + string CustomState); diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceLifecycleStateDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceLifecycleStateDto.cs new file mode 100644 index 0000000000..0b8145612c --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceLifecycleStateDto.cs @@ -0,0 +1,38 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +/// +/// The orchestration instance lifecycle state information. +/// +/// The identity that caused this orchestration instance to be created. +/// +/// +/// The identity that caused this orchestration instance to be canceled. +/// The time when the orchestration instance was created (State => Pending). +/// The time when the orchestration instance should be executed by the Scheduler. +/// The time when the Process Manager has queued the orchestration instance for execution by Durable Functions (State => Queued). +/// The time when the Process Manager was used from Durable Functions to transition the state to Running. +/// The time when the Process Manager was used from Durable Functions to transition the state to Terminated. +public record OrchestrationInstanceLifecycleStateDto( + IOperatingIdentityDto CreatedBy, + OrchestrationInstanceLifecycleStates State, + OrchestrationInstanceTerminationStates? TerminationState, + IOperatingIdentityDto? CanceledBy, + DateTimeOffset CreatedAt, + DateTimeOffset? ScheduledToRunAt, + DateTimeOffset? QueuedAt, + DateTimeOffset? StartedAt, + DateTimeOffset? TerminatedAt); diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceLifecycleStatesDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceLifecycleStatesDto.cs deleted file mode 100644 index 616959c3b5..0000000000 --- a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/OrchestrationInstanceLifecycleStatesDto.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 Energinet DataHub A/S -// -// Licensed under the Apache License, Version 2.0 (the "License2"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; - -public record OrchestrationInstanceLifecycleStatesDto( - OrchestrationInstanceLifecycleStates State, - OrchestrationInstanceTerminationStates? TerminationState, - DateTimeOffset CreatedAt, - DateTimeOffset? ScheduledToRunAt, - DateTimeOffset? QueuedAt, - DateTimeOffset? StartedAt, - DateTimeOffset? TerminatedAt) -{ - public OrchestrationInstanceLifecycleStates State { get; } = State; - - public OrchestrationInstanceTerminationStates? TerminationState { get; } = TerminationState; - - /// - /// The time when the orchestration instance was created (State => Pending). - /// - public DateTimeOffset CreatedAt { get; } = CreatedAt; - - /// - /// The time when the orchestration instance should be executed by the Scheduler. - /// - public DateTimeOffset? ScheduledToRunAt { get; } = ScheduledToRunAt; - - /// - /// The time when the Process Manager has queued the orchestration instance - /// for execution by Durable Functions (State => Queued). - /// - public DateTimeOffset? QueuedAt { get; } = QueuedAt; - - /// - /// The time when the Process Manager was used from Durable Functions to - /// transition the state to Running. - /// - public DateTimeOffset? StartedAt { get; } = StartedAt; - - /// - /// The time when the Process Manager was used from Durable Functions to - /// transition the state to Terminated. - /// - public DateTimeOffset? TerminatedAt { get; } = TerminatedAt; -} diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceDto.cs index f076383fd6..8a0c021be8 100644 --- a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceDto.cs +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceDto.cs @@ -19,30 +19,14 @@ namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; /// It contains state information about the step, and is linked /// to the orchestration instance that it is part of. /// +/// +/// The high-level lifecycle states that all orchestration steps can go through. +/// +/// The steps number in the list of steps. The sequence of the first step in the list is 1. +/// Any custom state of the step. public record StepInstanceDto( Guid Id, StepInstanceLifecycleStateDto Lifecycle, string Description, int Sequence, - string CustomState) -{ - public Guid Id { get; } = Id; - - /// - /// The high-level lifecycle states that all orchestration steps can go through. - /// - public StepInstanceLifecycleStateDto Lifecycle { get; } = Lifecycle; - - public string Description { get; } = Description; - - /// - /// The steps number in the list of steps. - /// The sequence of the first step in the list is 1. - /// - public int Sequence { get; } = Sequence; - - /// - /// Any custom state of the step. - /// - public string CustomState { get; } = CustomState; -} + string CustomState); diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceLifecycleStateDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceLifecycleStateDto.cs index 282a11509d..206c3fac46 100644 --- a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceLifecycleStateDto.cs +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/StepInstanceLifecycleStateDto.cs @@ -14,25 +14,15 @@ namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; +/// +/// The step instance lifecycle state information. +/// +/// +/// +/// The time when the Process Manager was used from Durable Functions to transition the state to Running. +/// The time when the Process Manager was used from Durable Functions to transition the state to Terminated. public record StepInstanceLifecycleStateDto( StepInstanceLifecycleStates State, OrchestrationStepTerminationStates? TerminationState, DateTimeOffset? StartedAt, - DateTimeOffset? TerminatedAt) -{ - public StepInstanceLifecycleStates State { get; } = State; - - public OrchestrationStepTerminationStates? TerminationState { get; } = TerminationState; - - /// - /// The time when the Process Manager was used from Durable Functions to - /// transition the state to Running. - /// - public DateTimeOffset? StartedAt { get; } = StartedAt; - - /// - /// The time when the Process Manager was used from Durable Functions to - /// transition the state to Terminated. - /// - public DateTimeOffset? TerminatedAt { get; } = TerminatedAt; -} + DateTimeOffset? TerminatedAt); diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/UserIdentityDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/UserIdentityDto.cs new file mode 100644 index 0000000000..69f8c6735b --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstance/UserIdentityDto.cs @@ -0,0 +1,20 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +public record UserIdentityDto( + Guid UserId, + Guid ActorId) + : IOperatingIdentityDto; diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceCommand.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceCommand.cs new file mode 100644 index 0000000000..12580286d4 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceCommand.cs @@ -0,0 +1,25 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +namespace Energinet.DataHub.ProcessManager.Api.Model; + +/// +/// A orchestration instance command executed by an identity. +/// Must be JSON serializable. +/// +/// The identity executing the command. +public abstract record OrchestrationInstanceCommand( + IOperatingIdentityDto OperatingIdentity); diff --git a/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceTypedDto.cs b/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceTypedDto.cs index c1274426cd..44d05d24a2 100644 --- a/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceTypedDto.cs +++ b/source/Shared/ProcessManager/Api/Model/OrchestrationInstanceTypedDto.cs @@ -19,35 +19,18 @@ namespace Energinet.DataHub.ProcessManager.Api.Model; /// /// Contains information about an orchestration instance including /// specific input parameter values. +/// Must be JSON serializable. /// -/// Must be a JSON serializable type. -public record OrchestrationInstanceTypedDto( +/// Must be a JSON serializable type. +/// +/// The high-level lifecycle states that all orchestration instances can go through. +/// Contains the Durable Functions orchestration input parameter value. +/// Workflow steps the orchestration instance is going through. +/// Any custom state of the orchestration instance. +public record OrchestrationInstanceTypedDto( Guid Id, - OrchestrationInstanceLifecycleStatesDto Lifecycle, - TParameterDto ParameterValue, + OrchestrationInstanceLifecycleStateDto Lifecycle, + TInputParameterDto ParameterValue, IReadOnlyCollection Steps, string CustomState) - where TParameterDto : class -{ - public Guid Id { get; } = Id; - - /// - /// The high-level lifecycle states that all orchestration instances can go through. - /// - public OrchestrationInstanceLifecycleStatesDto Lifecycle { get; } = Lifecycle; - - /// - /// Contains the Durable Functions orchestration input parameter value. - /// - public TParameterDto ParameterValue { get; } = ParameterValue; - - /// - /// Workflow steps the orchestration instance is going through. - /// - public IReadOnlyCollection Steps { get; } = Steps; - - /// - /// Any custom state of the orchestration instance. - /// - public string CustomState { get; } = CustomState; -} + where TInputParameterDto : IInputParameterDto; diff --git a/source/Shared/ProcessManager/Api/Model/ScheduleOrchestrationInstanceCommand.cs b/source/Shared/ProcessManager/Api/Model/ScheduleOrchestrationInstanceCommand.cs new file mode 100644 index 0000000000..755b7df651 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/ScheduleOrchestrationInstanceCommand.cs @@ -0,0 +1,53 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +namespace Energinet.DataHub.ProcessManager.Api.Model; + +/// +/// Command for scheduling an orchestration instance. +/// Must be JSON serializable. +/// +/// Must be a JSON serializable type. +public record ScheduleOrchestrationInstanceCommand + : UserCommand + where TInputParameterDto : IInputParameterDto +{ + /// + /// Construct command. + /// + /// Identity of the user executing the command. + /// The time when the orchestration instance should be executed by the Scheduler. + /// Contains the Durable Functions orchestration input parameter value. + public ScheduleOrchestrationInstanceCommand( + UserIdentityDto operatingIdentity, + DateTimeOffset runAt, + TInputParameterDto inputParameter) + : base(operatingIdentity) + { + RunAt = runAt; + InputParameter = inputParameter; + } + + /// + /// The time when the orchestration instance should be executed by the Scheduler. + /// + public DateTimeOffset RunAt { get; } + + /// + /// Contains the Durable Functions orchestration input parameter value. + /// + public TInputParameterDto InputParameter { get; } +} diff --git a/source/Shared/ProcessManager/Api/Model/StartOrchestrationInstanceCommand.cs b/source/Shared/ProcessManager/Api/Model/StartOrchestrationInstanceCommand.cs new file mode 100644 index 0000000000..eb61f1a693 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/StartOrchestrationInstanceCommand.cs @@ -0,0 +1,45 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +namespace Energinet.DataHub.ProcessManager.Api.Model; + +/// +/// Command for starting an orchestration instance. +/// Must be JSON serializable. +/// +/// Must be a JSON serializable type. +public record StartOrchestrationInstanceCommand + : OrchestrationInstanceCommand + where TInputParameterDto : IInputParameterDto +{ + /// + /// Construct command. + /// + /// Identity executing the command. + /// Contains the Durable Functions orchestration input parameter value. + public StartOrchestrationInstanceCommand( + IOperatingIdentityDto operatingIdentity, + TInputParameterDto inputParameter) + : base(operatingIdentity) + { + InputParameter = inputParameter; + } + + /// + /// Contains the Durable Functions orchestration input parameter value. + /// + public TInputParameterDto InputParameter { get; } +} diff --git a/source/Shared/ProcessManager/Api/Model/UserCommand.cs b/source/Shared/ProcessManager/Api/Model/UserCommand.cs new file mode 100644 index 0000000000..7ff494e1e5 --- /dev/null +++ b/source/Shared/ProcessManager/Api/Model/UserCommand.cs @@ -0,0 +1,36 @@ +// Copyright 2020 Energinet DataHub A/S +// +// Licensed under the Apache License, Version 2.0 (the "License2"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using Energinet.DataHub.ProcessManager.Api.Model.OrchestrationInstance; + +namespace Energinet.DataHub.ProcessManager.Api.Model; + +/// +/// A command executed by a user. +/// Must be JSON serializable. +/// +public abstract record UserCommand + : OrchestrationInstanceCommand +{ + /// + /// Construct command. + /// + /// Identity of the user executing the command. + protected UserCommand(UserIdentityDto operatingIdentity) + : base(operatingIdentity) + { + } + + public new UserIdentityDto OperatingIdentity => (UserIdentityDto)base.OperatingIdentity; +} diff --git a/source/Shared/ProcessManager/Orchestrations/Processes/BRS_023_027/V1/Model/NotifyAggregatedMeasureDataInputV1.cs b/source/Shared/ProcessManager/Orchestrations/Processes/BRS_023_027/V1/Model/NotifyAggregatedMeasureDataInputV1.cs index c4b03aa400..a74d295c96 100644 --- a/source/Shared/ProcessManager/Orchestrations/Processes/BRS_023_027/V1/Model/NotifyAggregatedMeasureDataInputV1.cs +++ b/source/Shared/ProcessManager/Orchestrations/Processes/BRS_023_027/V1/Model/NotifyAggregatedMeasureDataInputV1.cs @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Energinet.DataHub.ProcessManager.Api.Model; + namespace Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_023_027.V1.Model; /// /// An immutable input to start the orchestration instance for "BRS_023_027" V1. /// -public sealed record NotifyAggregatedMeasureDataInputV1( +public record NotifyAggregatedMeasureDataInputV1( CalculationTypes CalculationType, IReadOnlyCollection GridAreaCodes, DateTimeOffset PeriodStartDate, DateTimeOffset PeriodEndDate, - bool IsInternalCalculation, - Guid UserId); + bool IsInternalCalculation) + : IInputParameterDto; diff --git a/source/Shared/ProcessManager/Orchestrations/Processes/BRS_026/V1/Model/RequestCalculatedEnergyTimeSeriesInputV1.cs b/source/Shared/ProcessManager/Orchestrations/Processes/BRS_026/V1/Model/RequestCalculatedEnergyTimeSeriesInputV1.cs index bc722a42ab..fa122de375 100644 --- a/source/Shared/ProcessManager/Orchestrations/Processes/BRS_026/V1/Model/RequestCalculatedEnergyTimeSeriesInputV1.cs +++ b/source/Shared/ProcessManager/Orchestrations/Processes/BRS_026/V1/Model/RequestCalculatedEnergyTimeSeriesInputV1.cs @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +using Energinet.DataHub.ProcessManager.Api.Model; + namespace Energinet.DataHub.ProcessManager.Orchestrations.Processes.BRS_026.V1.Models; public record RequestCalculatedEnergyTimeSeriesInputV1( - string BusinessReason); + string BusinessReason) + : IInputParameterDto;