feat(application): add workflow and document request handlers

This commit is contained in:
2026-10-09 23:06:05 +02:00
parent 4f0718a4f5
commit ed06e460c3
3 changed files with 217 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Documents;
using DigitalData.TaskFlow.Domain.Enums;
using FluentValidation;
using MediatR;
namespace DigitalData.TaskFlow.Application.Features.Documents.Queries.GetDocument;
/// <summary>
/// Represents a request to retrieve binary document content by document identifier.
/// </summary>
/// <param name="Id">Document identifier.</param>
public sealed record GetDocumentQuery(string Id) : IRequest<ApiEnvelope<DocumentBinaryResult>>;
/// <summary>
/// Validates <see cref="GetDocumentQuery"/> requests.
/// </summary>
public sealed class GetDocumentQueryValidator : AbstractValidator<GetDocumentQuery>
{
/// <summary>
/// Initializes validation rules for <see cref="GetDocumentQuery"/>.
/// </summary>
public GetDocumentQueryValidator()
{
RuleFor(x => x.Id)
.NotEmpty();
}
}
/// <summary>
/// Handles <see cref="GetDocumentQuery"/> requests.
/// </summary>
public sealed class GetDocumentQueryHandler(IDocumentRepository documentRepository)
: IRequestHandler<GetDocumentQuery, ApiEnvelope<DocumentBinaryResult>>
{
/// <summary>
/// Executes the query and returns binary document data in the standard API envelope.
/// </summary>
/// <param name="request">Query request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Document response envelope.</returns>
public async Task<ApiEnvelope<DocumentBinaryResult>> Handle(GetDocumentQuery request, CancellationToken cancellationToken)
{
var document = await documentRepository.GetAsync(request.Id, cancellationToken);
return new ApiEnvelope<DocumentBinaryResult>
{
Meta =
[
new MetaEntry
{
Code = (int)MetaCode.Ok,
Message = "OK"
}
],
Data = document
};
}
}

View File

@@ -0,0 +1,97 @@
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Closing;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Enums;
using FluentValidation;
using MediatR;
namespace DigitalData.TaskFlow.Application.Features.Workflows.Commands.CloseWorkflow;
/// <summary>
/// Represents a request to close a workflow process using a selected closing method.
/// </summary>
/// <param name="WisagId">WISAG user identifier.</param>
/// <param name="Source">Source system name.</param>
/// <param name="ProcessId">Process identifier.</param>
/// <param name="ClosingMethodId">Selected closing method identifier.</param>
/// <param name="Comment">Optional user comment.</param>
/// <param name="RejectionReasonId">Optional rejection reason identifier.</param>
public sealed record CloseWorkflowCommand(
int WisagId,
string Source,
int ProcessId,
int ClosingMethodId,
string? Comment,
int? RejectionReasonId)
: IRequest<ApiEnvelope<CloseWorkflowResult>>;
/// <summary>
/// Validates <see cref="CloseWorkflowCommand"/> requests.
/// </summary>
public sealed class CloseWorkflowCommandValidator : AbstractValidator<CloseWorkflowCommand>
{
private static readonly string[] AllowedSources = ["Ferdinand", "Contracts"];
/// <summary>
/// Initializes validation rules for <see cref="CloseWorkflowCommand"/>.
/// </summary>
public CloseWorkflowCommandValidator()
{
RuleFor(x => x.WisagId)
.GreaterThan(0);
RuleFor(x => x.ProcessId)
.GreaterThan(0);
RuleFor(x => x.ClosingMethodId)
.GreaterThan(0);
RuleFor(x => x.Source)
.NotEmpty()
.Must(source => AllowedSources.Contains(source))
.WithMessage("Source must be one of the supported source systems.");
}
}
/// <summary>
/// Handles <see cref="CloseWorkflowCommand"/> requests.
/// </summary>
public sealed class CloseWorkflowCommandHandler(IWorkflowRepository workflowRepository)
: IRequestHandler<CloseWorkflowCommand, ApiEnvelope<CloseWorkflowResult>>
{
/// <summary>
/// Executes the closing request and returns the operation result in the standard API envelope.
/// </summary>
/// <param name="request">Command request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Closing result envelope.</returns>
public async Task<ApiEnvelope<CloseWorkflowResult>> Handle(CloseWorkflowCommand request, CancellationToken cancellationToken)
{
var decision = new CloseWorkflowDecision
{
ClosingMethodId = request.ClosingMethodId,
Comment = request.Comment,
RejectionReasonId = request.RejectionReasonId
};
var result = await workflowRepository.CloseAsync(
request.WisagId,
request.Source,
request.ProcessId,
decision,
cancellationToken);
return new ApiEnvelope<CloseWorkflowResult>
{
Meta =
[
new MetaEntry
{
Code = (int)MetaCode.Ok,
Message = "OK"
}
],
Data = result
};
}
}

View File

@@ -0,0 +1,60 @@
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Enums;
using DigitalData.TaskFlow.Domain.Workflows;
using FluentValidation;
using MediatR;
namespace DigitalData.TaskFlow.Application.Features.Workflows.Queries.GetWorkflows;
/// <summary>
/// Represents a request to fetch grouped workflow data for a WISAG user.
/// </summary>
/// <param name="WisagId">WISAG user identifier.</param>
public sealed record GetWorkflowsQuery(int WisagId) : IRequest<ApiEnvelope<WorkflowSourcesResponse>>;
/// <summary>
/// Validates <see cref="GetWorkflowsQuery"/> requests.
/// </summary>
public sealed class GetWorkflowsQueryValidator : AbstractValidator<GetWorkflowsQuery>
{
/// <summary>
/// Initializes validation rules for <see cref="GetWorkflowsQuery"/>.
/// </summary>
public GetWorkflowsQueryValidator()
{
RuleFor(x => x.WisagId)
.GreaterThan(0);
}
}
/// <summary>
/// Handles <see cref="GetWorkflowsQuery"/> requests.
/// </summary>
public sealed class GetWorkflowsQueryHandler(IWorkflowRepository workflowRepository)
: IRequestHandler<GetWorkflowsQuery, ApiEnvelope<WorkflowSourcesResponse>>
{
/// <summary>
/// Executes the query and returns a workflow payload wrapped in the standard API envelope.
/// </summary>
/// <param name="request">Query request.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Workflow response envelope.</returns>
public async Task<ApiEnvelope<WorkflowSourcesResponse>> Handle(GetWorkflowsQuery request, CancellationToken cancellationToken)
{
var data = await workflowRepository.GetAsync(request.WisagId, cancellationToken);
return new ApiEnvelope<WorkflowSourcesResponse>
{
Meta =
[
new MetaEntry
{
Code = (int)MetaCode.Ok,
Message = "OK"
}
],
Data = data
};
}
}