diff --git a/src/core/DigitalData.TaskFlow.Application/Common/Exceptions/ForbiddenApiException.cs b/src/core/DigitalData.TaskFlow.Application/Common/Exceptions/ForbiddenApiException.cs
new file mode 100644
index 0000000..09ae1bd
--- /dev/null
+++ b/src/core/DigitalData.TaskFlow.Application/Common/Exceptions/ForbiddenApiException.cs
@@ -0,0 +1,18 @@
+using DigitalData.TaskFlow.Domain.Enums;
+
+namespace DigitalData.TaskFlow.Application.Common.Exceptions;
+
+///
+/// Represents a 403 API exception.
+///
+public sealed class ForbiddenApiException : ApiException
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Response message.
+ public ForbiddenApiException(string message)
+ : base(403, MetaCode.NoAccess, message)
+ {
+ }
+}
diff --git a/src/core/DigitalData.TaskFlow.Application/Common/Exceptions/InvalidRequestApiException.cs b/src/core/DigitalData.TaskFlow.Application/Common/Exceptions/InvalidRequestApiException.cs
new file mode 100644
index 0000000..d93772c
--- /dev/null
+++ b/src/core/DigitalData.TaskFlow.Application/Common/Exceptions/InvalidRequestApiException.cs
@@ -0,0 +1,18 @@
+using DigitalData.TaskFlow.Domain.Enums;
+
+namespace DigitalData.TaskFlow.Application.Common.Exceptions;
+
+///
+/// Represents a 400 API exception.
+///
+public sealed class InvalidRequestApiException : ApiException
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Response message.
+ public InvalidRequestApiException(string message)
+ : base(400, MetaCode.InvalidRequest, message)
+ {
+ }
+}
diff --git a/src/core/DigitalData.TaskFlow.Application/Common/Interfaces/IDocumentRepository.cs b/src/core/DigitalData.TaskFlow.Application/Common/Interfaces/IDocumentRepository.cs
index 058c4fd..c42220e 100644
--- a/src/core/DigitalData.TaskFlow.Application/Common/Interfaces/IDocumentRepository.cs
+++ b/src/core/DigitalData.TaskFlow.Application/Common/Interfaces/IDocumentRepository.cs
@@ -12,6 +12,6 @@ public interface IDocumentRepository : IRepository
///
/// Document identifier.
/// Cancellation token.
- /// Binary document payload.
- Task GetAsync(string id, CancellationToken cancellationToken);
+ /// Binary document payload when found; otherwise .
+ Task GetAsync(string id, CancellationToken cancellationToken);
}
diff --git a/src/core/DigitalData.TaskFlow.Application/Features/Documents/Queries/GetDocument/GetDocumentQuery.cs b/src/core/DigitalData.TaskFlow.Application/Features/Documents/Queries/GetDocument/GetDocumentQuery.cs
index 206b481..b48c961 100644
--- a/src/core/DigitalData.TaskFlow.Application/Features/Documents/Queries/GetDocument/GetDocumentQuery.cs
+++ b/src/core/DigitalData.TaskFlow.Application/Features/Documents/Queries/GetDocument/GetDocumentQuery.cs
@@ -1,4 +1,5 @@
using DigitalData.TaskFlow.Application.Common.Factories;
+using DigitalData.TaskFlow.Application.Common.Exceptions;
using DigitalData.TaskFlow.Application.Common.Interfaces;
using DigitalData.TaskFlow.Domain.Common;
using DigitalData.TaskFlow.Domain.Documents;
@@ -45,6 +46,11 @@ public sealed class GetDocumentQueryHandler(IDocumentRepository documentReposito
{
var document = await documentRepository.GetAsync(request.Id, cancellationToken);
+ if (document is null)
+ {
+ throw new NotFoundApiException("Dokument nicht gefunden");
+ }
+
return ApiEnvelopeFactory.Create(document);
}
}
diff --git a/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Commands/CloseWorkflow/CloseWorkflowCommand.cs b/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Commands/CloseWorkflow/CloseWorkflowCommand.cs
index 332c77b..94ebd3c 100644
--- a/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Commands/CloseWorkflow/CloseWorkflowCommand.cs
+++ b/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Commands/CloseWorkflow/CloseWorkflowCommand.cs
@@ -34,6 +34,8 @@ public sealed record CloseWorkflowCommand(
public sealed class CloseWorkflowCommandValidator : AbstractValidator
{
private static readonly string[] AllowedSources = ["Ferdinand", "Contracts"];
+ private const int ApproveMethodId = 2;
+ private const int RejectMethodId = 3;
///
/// Initializes validation rules for .
@@ -53,6 +55,20 @@ public sealed class CloseWorkflowCommandValidator : AbstractValidator AllowedSources.Contains(source))
.WithMessage("Source must be one of the supported source systems.");
+
+ RuleFor(x => x.ClosingMethodId)
+ .Must(methodId => methodId is ApproveMethodId or RejectMethodId)
+ .WithMessage("Unbekannte closing_method_id");
+
+ RuleFor(x => x.Comment)
+ .NotEmpty()
+ .When(x => x.ClosingMethodId == RejectMethodId)
+ .WithMessage("Kommentar ist fur diese closing_method Pflicht");
+
+ RuleFor(x => x.RejectionReasonId)
+ .NotNull()
+ .When(x => x.ClosingMethodId == RejectMethodId)
+ .WithMessage("rejection_reason_id ist fur diese closing_method Pflicht");
}
}
@@ -79,6 +95,16 @@ public sealed class CloseWorkflowCommandHandler(IWorkflowRepository workflowRepo
decision,
cancellationToken);
+ if (result.Outcome == CloseWorkflowOutcome.NoAccess)
+ {
+ throw new ForbiddenApiException("Kein Zugriff");
+ }
+
+ if (result.Outcome == CloseWorkflowOutcome.NotImplemented)
+ {
+ throw new InvalidOperationException("Closing integration is not finalized yet.");
+ }
+
if (result.ProcessId <= 0)
{
throw new NotFoundApiException("Vorgang nicht gefunden");
diff --git a/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Queries/GetWorkflows/GetWorkflowsQuery.cs b/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Queries/GetWorkflows/GetWorkflowsQuery.cs
index 78a3e16..aa4449e 100644
--- a/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Queries/GetWorkflows/GetWorkflowsQuery.cs
+++ b/src/core/DigitalData.TaskFlow.Application/Features/Workflows/Queries/GetWorkflows/GetWorkflowsQuery.cs
@@ -45,6 +45,11 @@ public sealed class GetWorkflowsQueryHandler(IWorkflowRepository workflowReposit
{
var data = await workflowRepository.GetAsync(request.WisagId, cancellationToken);
+ if (data.Sources.Count == 0)
+ {
+ return ApiEnvelopeFactory.Create(data, MetaCode.NoAccess);
+ }
+
var hasListingData = data.Sources
.SelectMany(source => source switch
{