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 libraryEnerginet-DataHubEnerginet-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
- 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;