Skip to content

Commit 65819f9

Browse files
committed
Add Approve and Reject commands to the Workflow execution approval
#103
1 parent 2457f35 commit 65819f9

12 files changed

Lines changed: 394 additions & 1 deletion
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.CommandLine;
2+
3+
namespace FlowCtl.Commands.Workflows.Executions.Approvals.Approve;
4+
5+
internal class WorkflowExecutionApprovePendingTaskCommand
6+
: BaseCommand<WorkflowExecutionApprovePendingTaskCommandOptions, WorkflowExecutionApprovePendingTaskCommandOptionsHandler>
7+
{
8+
public WorkflowExecutionApprovePendingTaskCommand() : base("approve", Resources.Commands_Workflow_Execution_ApprovePendingTaskDescription)
9+
{
10+
var workflowIdOption = new Option<string>(new[] { "-w", "--workflow-id" },
11+
description: Resources.Commands_Workflows_IdentityOption) { IsRequired = true };
12+
13+
var executionIdOption = new Option<string>(new[] { "-e", "--execution-id" },
14+
description: Resources.Commands_Workflows_Execution_IdentityOption) { IsRequired = true };
15+
16+
var approvalIdOption = new Option<string>(new[] { "-p", "--approval-id" },
17+
description: Resources.Commands_Workflows_Execution_ApprovalIdentityOption) { IsRequired = true };
18+
19+
var addressOption = new Option<string?>(new[] { "-a", "--address" },
20+
description: Resources.Commands_FlowSynxAddress);
21+
22+
AddOption(workflowIdOption);
23+
AddOption(executionIdOption);
24+
AddOption(approvalIdOption);
25+
AddOption(addressOption);
26+
}
27+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using FlowCtl.Core.Services.Logger;
2+
3+
namespace FlowCtl.Commands.Workflows.Executions.Approvals.Approve;
4+
5+
internal class WorkflowExecutionApprovePendingTaskCommandOptions : ICommandOptions
6+
{
7+
public required string WorkflowId { get; set; }
8+
public required string ExecutionId { get; set; }
9+
public required string ApprovalId { get; set; }
10+
public string? Address { get; set; } = string.Empty;
11+
public OutputType Output { get; set; } = OutputType.Json;
12+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using FlowCtl.Core.Services.Authentication;
2+
using FlowCtl.Core.Services.Logger;
3+
using FlowCtl.Extensions;
4+
using FlowSynx.Client;
5+
using FlowSynx.Client.Messages.Requests.Workflows;
6+
7+
namespace FlowCtl.Commands.Workflows.Executions.Approvals.Approve;
8+
9+
internal class WorkflowExecutionApprovePendingTaskCommandOptionsHandler : ICommandOptionsHandler<WorkflowExecutionApprovePendingTaskCommandOptions>
10+
{
11+
private readonly IFlowCtlLogger _flowCtlLogger;
12+
private readonly IFlowSynxClient _flowSynxClient;
13+
private readonly IAuthenticationManager _authenticationManager;
14+
15+
public WorkflowExecutionApprovePendingTaskCommandOptionsHandler(IFlowCtlLogger flowCtlLogger,
16+
IFlowSynxClient flowSynxClient, IAuthenticationManager authenticationManager)
17+
{
18+
ArgumentNullException.ThrowIfNull(flowCtlLogger);
19+
ArgumentNullException.ThrowIfNull(flowSynxClient);
20+
ArgumentNullException.ThrowIfNull(flowCtlLogger);
21+
_flowCtlLogger = flowCtlLogger;
22+
_flowSynxClient = flowSynxClient;
23+
_authenticationManager = authenticationManager;
24+
}
25+
26+
public async Task<int> HandleAsync(WorkflowExecutionApprovePendingTaskCommandOptions options, CancellationToken cancellationToken)
27+
{
28+
await Execute(options, cancellationToken);
29+
return 0;
30+
}
31+
32+
private async Task Execute(WorkflowExecutionApprovePendingTaskCommandOptions options, CancellationToken cancellationToken)
33+
{
34+
try
35+
{
36+
_authenticationManager.AuthenticateClient(_flowSynxClient);
37+
38+
if (!string.IsNullOrEmpty(options.Address))
39+
{
40+
var connection = new FlowSynxClientConnection(options.Address);
41+
_flowSynxClient.SetConnection(connection);
42+
}
43+
44+
if (!Guid.TryParse(options.WorkflowId, out Guid workflowId))
45+
throw new FormatException("Invalid workflow id format. Expected a valid GUID.");
46+
47+
if (!Guid.TryParse(options.ExecutionId, out Guid executionId))
48+
throw new FormatException("Invalid execution id format. Expected a valid GUID.");
49+
50+
if (!Guid.TryParse(options.ApprovalId, out Guid approvalId))
51+
throw new FormatException("Invalid approval id format. Expected a valid GUID.");
52+
53+
var request = new ApproveWorkflowRequest
54+
{
55+
WorkflowId = workflowId,
56+
WorkflowExecutionId = executionId,
57+
WorkflowExecutionApprovalId = approvalId
58+
};
59+
var result = await _flowSynxClient.Workflows.ApproveExecutionsAsync(request, cancellationToken);
60+
61+
if (result.StatusCode != 200)
62+
throw new Exception(Resources.Commands_Error_DuringProcessingRequest);
63+
64+
var payload = result.Payload;
65+
if (payload is { Succeeded: false })
66+
_flowCtlLogger.WriteError(payload.Messages);
67+
else
68+
_flowCtlLogger.Write(payload.Data, options.Output);
69+
}
70+
catch (Exception ex)
71+
{
72+
_flowCtlLogger.WriteError(ex.Message);
73+
}
74+
}
75+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.CommandLine;
2+
3+
namespace FlowCtl.Commands.Workflows.Executions.Approvals.Reject;
4+
5+
internal class WorkflowExecutionRejectPendingTaskCommand
6+
: BaseCommand<WorkflowExecutionRejectPendingTaskCommandOptions, WorkflowExecutionRejectPendingTaskCommandOptionsHandler>
7+
{
8+
public WorkflowExecutionRejectPendingTaskCommand() : base("reject", Resources.Commands_Workflow_Execution_RejectPendingTaskDescription)
9+
{
10+
var workflowIdOption = new Option<string>(new[] { "-w", "--workflow-id" },
11+
description: Resources.Commands_Workflows_IdentityOption) { IsRequired = true };
12+
13+
var executionIdOption = new Option<string>(new[] { "-e", "--execution-id" },
14+
description: Resources.Commands_Workflows_Execution_IdentityOption) { IsRequired = true };
15+
16+
var approvalIdOption = new Option<string>(new[] { "-p", "--approval-id" },
17+
description: Resources.Commands_Workflows_Execution_ApprovalIdentityOption) { IsRequired = true };
18+
19+
var addressOption = new Option<string?>(new[] { "-a", "--address" },
20+
description: Resources.Commands_FlowSynxAddress);
21+
22+
AddOption(workflowIdOption);
23+
AddOption(executionIdOption);
24+
AddOption(approvalIdOption);
25+
AddOption(addressOption);
26+
}
27+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using FlowCtl.Core.Services.Logger;
2+
3+
namespace FlowCtl.Commands.Workflows.Executions.Approvals.Reject;
4+
5+
internal class WorkflowExecutionRejectPendingTaskCommandOptions : ICommandOptions
6+
{
7+
public required string WorkflowId { get; set; }
8+
public required string ExecutionId { get; set; }
9+
public required string ApprovalId { get; set; }
10+
public string? Address { get; set; } = string.Empty;
11+
public OutputType Output { get; set; } = OutputType.Json;
12+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
using FlowCtl.Core.Services.Authentication;
2+
using FlowCtl.Core.Services.Logger;
3+
using FlowCtl.Extensions;
4+
using FlowSynx.Client;
5+
using FlowSynx.Client.Messages.Requests.Workflows;
6+
7+
namespace FlowCtl.Commands.Workflows.Executions.Approvals.Reject;
8+
9+
internal class WorkflowExecutionRejectPendingTaskCommandOptionsHandler : ICommandOptionsHandler<WorkflowExecutionRejectPendingTaskCommandOptions>
10+
{
11+
private readonly IFlowCtlLogger _flowCtlLogger;
12+
private readonly IFlowSynxClient _flowSynxClient;
13+
private readonly IAuthenticationManager _authenticationManager;
14+
15+
public WorkflowExecutionRejectPendingTaskCommandOptionsHandler(IFlowCtlLogger flowCtlLogger,
16+
IFlowSynxClient flowSynxClient, IAuthenticationManager authenticationManager)
17+
{
18+
ArgumentNullException.ThrowIfNull(flowCtlLogger);
19+
ArgumentNullException.ThrowIfNull(flowSynxClient);
20+
ArgumentNullException.ThrowIfNull(flowCtlLogger);
21+
_flowCtlLogger = flowCtlLogger;
22+
_flowSynxClient = flowSynxClient;
23+
_authenticationManager = authenticationManager;
24+
}
25+
26+
public async Task<int> HandleAsync(WorkflowExecutionRejectPendingTaskCommandOptions options, CancellationToken cancellationToken)
27+
{
28+
await Execute(options, cancellationToken);
29+
return 0;
30+
}
31+
32+
private async Task Execute(WorkflowExecutionRejectPendingTaskCommandOptions options, CancellationToken cancellationToken)
33+
{
34+
try
35+
{
36+
_authenticationManager.AuthenticateClient(_flowSynxClient);
37+
38+
if (!string.IsNullOrEmpty(options.Address))
39+
{
40+
var connection = new FlowSynxClientConnection(options.Address);
41+
_flowSynxClient.SetConnection(connection);
42+
}
43+
44+
if (!Guid.TryParse(options.WorkflowId, out Guid workflowId))
45+
throw new FormatException("Invalid workflow id format. Expected a valid GUID.");
46+
47+
if (!Guid.TryParse(options.ExecutionId, out Guid executionId))
48+
throw new FormatException("Invalid execution id format. Expected a valid GUID.");
49+
50+
if (!Guid.TryParse(options.ApprovalId, out Guid approvalId))
51+
throw new FormatException("Invalid approval id format. Expected a valid GUID.");
52+
53+
var request = new RejectWorkflowRequest
54+
{
55+
WorkflowId = workflowId,
56+
WorkflowExecutionId = executionId,
57+
WorkflowExecutionApprovalId = approvalId
58+
};
59+
var result = await _flowSynxClient.Workflows.RejectExecutionsAsync(request, cancellationToken);
60+
61+
if (result.StatusCode != 200)
62+
throw new Exception(Resources.Commands_Error_DuringProcessingRequest);
63+
64+
var payload = result.Payload;
65+
if (payload is { Succeeded: false })
66+
_flowCtlLogger.WriteError(payload.Messages);
67+
else
68+
_flowCtlLogger.Write(payload.Data, options.Output);
69+
}
70+
catch (Exception ex)
71+
{
72+
_flowCtlLogger.WriteError(ex.Message);
73+
}
74+
}
75+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using FlowCtl.Core.Services.Logger;
2+
3+
namespace FlowCtl.Commands.Workflows.Executions.Approvals;
4+
5+
internal class WorkflowExecutionPendingApprovalsCommandOptions : ICommandOptions
6+
{
7+
public required string WorkflowId { get; set; }
8+
public required string ExecutionId { get; set; }
9+
public string? Address { get; set; } = string.Empty;
10+
public OutputType Output { get; set; } = OutputType.Json;
11+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using FlowCtl.Core.Services.Authentication;
2+
using FlowCtl.Core.Services.Logger;
3+
using FlowCtl.Extensions;
4+
using FlowSynx.Client;
5+
using FlowSynx.Client.Messages.Requests.Workflows;
6+
7+
namespace FlowCtl.Commands.Workflows.Executions.Approvals;
8+
9+
internal class WorkflowExecutionPendingApprovalsCommandOptionsHandler : ICommandOptionsHandler<WorkflowExecutionPendingApprovalsCommandOptions>
10+
{
11+
private readonly IFlowCtlLogger _flowCtlLogger;
12+
private readonly IFlowSynxClient _flowSynxClient;
13+
private readonly IAuthenticationManager _authenticationManager;
14+
15+
public WorkflowExecutionPendingApprovalsCommandOptionsHandler(IFlowCtlLogger flowCtlLogger,
16+
IFlowSynxClient flowSynxClient, IAuthenticationManager authenticationManager)
17+
{
18+
ArgumentNullException.ThrowIfNull(flowCtlLogger);
19+
ArgumentNullException.ThrowIfNull(flowSynxClient);
20+
ArgumentNullException.ThrowIfNull(flowCtlLogger);
21+
_flowCtlLogger = flowCtlLogger;
22+
_flowSynxClient = flowSynxClient;
23+
_authenticationManager = authenticationManager;
24+
}
25+
26+
public async Task<int> HandleAsync(WorkflowExecutionPendingApprovalsCommandOptions options, CancellationToken cancellationToken)
27+
{
28+
await Execute(options, cancellationToken);
29+
return 0;
30+
}
31+
32+
private async Task Execute(WorkflowExecutionPendingApprovalsCommandOptions options, CancellationToken cancellationToken)
33+
{
34+
try
35+
{
36+
_authenticationManager.AuthenticateClient(_flowSynxClient);
37+
38+
if (!string.IsNullOrEmpty(options.Address))
39+
{
40+
var connection = new FlowSynxClientConnection(options.Address);
41+
_flowSynxClient.SetConnection(connection);
42+
}
43+
44+
if (!Guid.TryParse(options.WorkflowId, out Guid workflowId))
45+
throw new FormatException("Invalid workflow id format. Expected a valid GUID.");
46+
47+
if (!Guid.TryParse(options.ExecutionId, out Guid executionId))
48+
throw new FormatException("Invalid execution id format. Expected a valid GUID.");
49+
50+
var request = new WorkflowExecutionPendingApprovalsRequest {
51+
WorkflowId = workflowId,
52+
WorkflowExecutionId = executionId
53+
};
54+
var result = await _flowSynxClient.Workflows.ExecutionPendingApprovalsAsync(request, cancellationToken);
55+
56+
if (result.StatusCode != 200)
57+
throw new Exception(Resources.Commands_Error_DuringProcessingRequest);
58+
59+
var payload = result.Payload;
60+
if (payload is { Succeeded: false })
61+
_flowCtlLogger.WriteError(payload.Messages);
62+
else
63+
_flowCtlLogger.Write(payload.Data, options.Output);
64+
}
65+
catch (Exception ex)
66+
{
67+
_flowCtlLogger.WriteError(ex.Message);
68+
}
69+
}
70+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using FlowCtl.Commands.Workflows.Executions.Approvals.Approve;
2+
using FlowCtl.Commands.Workflows.Executions.Approvals.Reject;
3+
using FlowCtl.Core.Services.Logger;
4+
using System.CommandLine;
5+
6+
namespace FlowCtl.Commands.Workflows.Executions.Approvals;
7+
8+
internal class WorkflowExecutionPendingApprovalsCommand
9+
: BaseCommand<WorkflowExecutionPendingApprovalsCommandOptions, WorkflowExecutionPendingApprovalsCommandOptionsHandler>
10+
{
11+
public WorkflowExecutionPendingApprovalsCommand() : base("approvals", Resources.Commands_Workflow_Execution_ApprovalsDescription)
12+
{
13+
var workflowIdOption = new Option<string>(new[] { "-w", "--workflow-id" },
14+
description: Resources.Commands_Workflows_IdentityOption) { IsRequired = true };
15+
16+
var executionIdOption = new Option<string>(new[] { "-e", "--execution-id" },
17+
description: Resources.Commands_Workflows_Execution_IdentityOption) { IsRequired = true };
18+
19+
var addressOption = new Option<string?>(new[] { "-a", "--address" },
20+
description: Resources.Commands_FlowSynxAddress);
21+
22+
var outputFormatOption = new Option<OutputType>(new[] { "-o", "--output" },
23+
getDefaultValue: () => OutputType.Json,
24+
description: Resources.Commands_Output_Format);
25+
26+
AddOption(workflowIdOption);
27+
AddOption(executionIdOption);
28+
AddOption(addressOption);
29+
AddOption(outputFormatOption);
30+
31+
AddCommand(new WorkflowExecutionApprovePendingTaskCommand());
32+
AddCommand(new WorkflowExecutionRejectPendingTaskCommand());
33+
}
34+
}

src/FlowCtl/Commands/Workflows/Executions/WorkflowExecutionsCommand.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using FlowCtl.Commands.Workflows.Executions.Cancel;
1+
using FlowCtl.Commands.Workflows.Executions.Approvals;
2+
using FlowCtl.Commands.Workflows.Executions.Cancel;
23
using FlowCtl.Commands.Workflows.Executions.Details;
34
using FlowCtl.Commands.Workflows.Executions.Execute;
45
using FlowCtl.Commands.Workflows.Executions.Logs;
@@ -25,6 +26,7 @@ public WorkflowExecutionsCommand() : base("executions", Resources.Commands_Workf
2526
AddOption(addressOption);
2627
AddOption(outputFormatOption);
2728

29+
AddCommand(new WorkflowExecutionPendingApprovalsCommand());
2830
AddCommand(new WorkflowExecutionCancelCommand());
2931
AddCommand(new WorkflowExecutionDetailsCommand());
3032
AddCommand(new ExecuteWorkflowCommand());

0 commit comments

Comments
 (0)