Compare commits
119 Commits
e96773f3c4
...
refactor/r
| Author | SHA1 | Date | |
|---|---|---|---|
| 6681e56afc | |||
| d61f5ce885 | |||
| 6374a5c257 | |||
| 3b4954d387 | |||
| 42d586604e | |||
| 4088a52196 | |||
| 58b3c8ec95 | |||
| 68b3eb53c0 | |||
| 0d9489203f | |||
| 0a564d8aa8 | |||
| f5b2db0296 | |||
| 7a22024624 | |||
| c9cd92a55a | |||
| 93adaba322 | |||
| c16cb2a1c4 | |||
| c20162e051 | |||
| 70c2f7342d | |||
| a10f917084 | |||
| e1c3f74cd4 | |||
| e45aeea2b9 | |||
| 38f91aae84 | |||
| 9bb5c97df6 | |||
| d8c7499436 | |||
| 6d86760354 | |||
| 6b1daf77cb | |||
| d3d5ebac61 | |||
| b1924f2a4a | |||
| c27ed1e744 | |||
| 9eb54565cb | |||
| 05dfb6f424 | |||
| cf6c90ad05 | |||
| 4a9c4341c2 | |||
| ead12b6095 | |||
| 3c7fcb71c0 | |||
| 0b01b4a658 | |||
| 8d511ec81a | |||
| 685c5abca7 | |||
| b7aea848a9 | |||
| e5eb0f19e7 | |||
| 859ff5902e | |||
| 42789567f0 | |||
| 46eef255ca | |||
| aae42949b6 | |||
| bdf273c8e1 | |||
| ba8ab28b03 | |||
| 4cc8d22756 | |||
| 2a4378eb9a | |||
| cb5bbfb722 | |||
| 2736a78d4f | |||
| ddb8b2673e | |||
| a70aee6e28 | |||
| f329543793 | |||
| 645891150c | |||
| 95cb34394c | |||
| 83d6832236 | |||
| e816340755 | |||
| 64e8e2a5cc | |||
| 0edf2626a7 | |||
| 1d16276a8a | |||
| 4eae092031 | |||
| ce7fe03525 | |||
| a93780df5c | |||
| d7a2a01421 | |||
| 329e441ede | |||
| 1ad7ff3b34 | |||
| bcfbd851bd | |||
| 2e157656a7 | |||
| 8042a6f898 | |||
| f25fc627fe | |||
| d6af24cd91 | |||
| bb5eac023c | |||
| 77baf395ce | |||
| 6c9eab6df6 | |||
| c64794755d | |||
| de2185bf0a | |||
| fde9735b27 | |||
| 0342b9e0c6 | |||
| 47698b9046 | |||
| a03d21ebc6 | |||
| acff0aca89 | |||
| ce0e53baf6 | |||
| 620c0eff22 | |||
| 68f4486fa1 | |||
| 2b5e63cb45 | |||
| e9e697fa0d | |||
| 606eccb855 | |||
| 3146acfa45 | |||
| f363872e7a | |||
| ed4683323d | |||
| 4aeef10ef7 | |||
| e04e90d8c6 | |||
| 93b5f976d3 | |||
| b66a49f74d | |||
| 70dc52139d | |||
| 210ed9be8d | |||
| b2544b64e3 | |||
| 0b1e0d25ca | |||
| c1027abfc6 | |||
| 40c8fa359c | |||
| 1375f5f0e4 | |||
| 29bc0cf8b5 | |||
| c8b264cef6 | |||
| 078525d85d | |||
| b3dfdd1e5c | |||
| bd78ada686 | |||
| 2b4773a4c0 | |||
| ff7d6c99ae | |||
| fa438e70cb | |||
| 4931d3b8aa | |||
| 6aae26bfb6 | |||
| 38d8ef6e93 | |||
| 7bc5428bd4 | |||
| c405f369ac | |||
| c2e073dade | |||
| 7a11ac3635 | |||
| a91e3264b4 | |||
| 2ae5251550 | |||
| 56730c0d4e | |||
| d8aa032a57 |
@@ -13,14 +13,19 @@ public class RecActionController(IMediator mediator) : ControllerBase
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invokes a batch of RecActions for a given profile.
|
/// Invokes a batch of RecActions for a given profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command">The command containing the profile ID.</param>
|
/// <param name="profileId">The identifier of the profile whose RecActions should be invoked.</param>
|
||||||
|
/// <param name="references">Optional reference values that are passed through to all result records.</param>
|
||||||
/// <param name="cancel">A token to cancel the operation.</param>
|
/// <param name="cancel">A token to cancel the operation.</param>
|
||||||
/// <returns>An HTTP 202 Accepted response indicating the process has been started.</returns>
|
/// <returns>An HTTP 202 Accepted response indicating the process has been started.</returns>
|
||||||
[HttpPost("invoke/{command}")]
|
[HttpPost("invoke/{profileId}")]
|
||||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||||
public async Task<IActionResult> Invoke([FromRoute] InvokeBatchRecActionViewsCommand command, CancellationToken cancel)
|
public async Task<IActionResult> Invoke([FromRoute] long profileId, [FromBody] InvokeReferences references, CancellationToken cancel = default)
|
||||||
{
|
{
|
||||||
await mediator.Send(command, cancel);
|
await mediator.Send(new InvokeBatchRecActionViewsCommand
|
||||||
|
{
|
||||||
|
ProfileId = profileId,
|
||||||
|
References = references
|
||||||
|
}, cancel);
|
||||||
return Accepted();
|
return Accepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace ReC.API.Models;
|
|
||||||
|
|
||||||
public class FakeRequest
|
|
||||||
{
|
|
||||||
public Dictionary<string, object>? Body { get; init; }
|
|
||||||
|
|
||||||
public Dictionary<string, object>? Header { get; init; }
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace ReC.API.Models;
|
|
||||||
|
|
||||||
public enum ResultType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Return the full result object.
|
|
||||||
/// </summary>
|
|
||||||
Full,
|
|
||||||
/// <summary>
|
|
||||||
/// Return only the header part of the result.
|
|
||||||
/// </summary>
|
|
||||||
OnlyHeader,
|
|
||||||
/// <summary>
|
|
||||||
/// Return only the body part of the result.
|
|
||||||
/// </summary>
|
|
||||||
OnlyBody
|
|
||||||
}
|
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||||
<ProjectGuid>420218ad-3c27-4003-9a84-36c92352f175</ProjectGuid>
|
<ProjectGuid>420218ad-3c27-4003-9a84-36c92352f175</ProjectGuid>
|
||||||
<DesktopBuildPackageLocation>P:\Install .Net\0 DD - Smart UP\ReC\API\$(Version)\Rec.API.zip</DesktopBuildPackageLocation>
|
<DesktopBuildPackageLocation>M:\App&Service\0 DD - Smart UP\ReC\API\$(Version)\Rec.API.zip</DesktopBuildPackageLocation>
|
||||||
<PackageAsSingleFile>true</PackageAsSingleFile>
|
<PackageAsSingleFile>true</PackageAsSingleFile>
|
||||||
<DeployIisAppPath>Rec.API</DeployIisAppPath>
|
<DeployIisAppPath>Rec.API</DeployIisAppPath>
|
||||||
<_TargetId>IISWebDeployPackage</_TargetId>
|
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
<Product>ReC.API</Product>
|
<Product>ReC.API</Product>
|
||||||
<PackageIcon>Assets\icon.ico</PackageIcon>
|
<PackageIcon>Assets\icon.ico</PackageIcon>
|
||||||
<PackageTags>digital data rest-caller rec api</PackageTags>
|
<PackageTags>digital data rest-caller rec api</PackageTags>
|
||||||
<Version>2.0.2-beta</Version>
|
<Version>2.2.0-beta</Version>
|
||||||
<AssemblyVersion>2.0.2.0</AssemblyVersion>
|
<AssemblyVersion>2.2.0.0</AssemblyVersion>
|
||||||
<FileVersion>2.0.2.0</FileVersion>
|
<FileVersion>2.2.0.0</FileVersion>
|
||||||
<InformationalVersion>2.0.1-beta</InformationalVersion>
|
<InformationalVersion>2.2.0-beta</InformationalVersion>
|
||||||
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
|
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using ReC.Application.Common.Dto;
|
|||||||
using ReC.Application.Common.Interfaces;
|
using ReC.Application.Common.Interfaces;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Behaviors;
|
namespace ReC.Application.Common.Behaviors.Action;
|
||||||
|
|
||||||
public class BodyQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext) : IPipelineBehavior<TRequest, TResponse>
|
public class BodyQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext) : IPipelineBehavior<TRequest, TResponse>
|
||||||
where TRequest : RecActionViewDto
|
where TRequest : RecActionViewDto
|
||||||
@@ -5,7 +5,7 @@ using ReC.Application.Common.Dto;
|
|||||||
using ReC.Application.Common.Interfaces;
|
using ReC.Application.Common.Interfaces;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Behaviors;
|
namespace ReC.Application.Common.Behaviors.Action;
|
||||||
|
|
||||||
public class HeaderQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext, ILogger<HeaderQueryBehavior<TRequest, TResponse>>? logger = null) : IPipelineBehavior<TRequest, TResponse>
|
public class HeaderQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext, ILogger<HeaderQueryBehavior<TRequest, TResponse>>? logger = null) : IPipelineBehavior<TRequest, TResponse>
|
||||||
where TRequest : RecActionViewDto
|
where TRequest : RecActionViewDto
|
||||||
@@ -23,9 +23,11 @@ public class PostprocessingBehavior(IRecDbContext context, ISender sender) : IPi
|
|||||||
|
|
||||||
await sender.Send(new InsertResultCommand()
|
await sender.Send(new InsertResultCommand()
|
||||||
{
|
{
|
||||||
|
Status = RecStatus.OK,
|
||||||
ActionId = request.Action.Id,
|
ActionId = request.Action.Id,
|
||||||
Info = info,
|
InfoDetail = info,
|
||||||
Type = ResultType.Post
|
Type = ResultType.Post,
|
||||||
|
References = request.References
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,9 +37,11 @@ public class PostprocessingBehavior(IRecDbContext context, ISender sender) : IPi
|
|||||||
|
|
||||||
await sender.Send(new InsertResultCommand()
|
await sender.Send(new InsertResultCommand()
|
||||||
{
|
{
|
||||||
|
Status = RecStatus.Error,
|
||||||
ActionId = request.Action.Id,
|
ActionId = request.Action.Id,
|
||||||
Error = error,
|
Error = error,
|
||||||
Type = ResultType.Post
|
Type = ResultType.Post,
|
||||||
|
References = request.References
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|
||||||
if (request.Action.ErrorAction == ErrorAction.Stop)
|
if (request.Action.ErrorAction == ErrorAction.Stop)
|
||||||
|
|||||||
@@ -20,9 +20,11 @@ public class PreprocessingBehavior(IRecDbContext context, ISender sender) : IPip
|
|||||||
|
|
||||||
await sender.Send(new InsertResultCommand()
|
await sender.Send(new InsertResultCommand()
|
||||||
{
|
{
|
||||||
|
Status = RecStatus.OK,
|
||||||
ActionId = request.Action.Id,
|
ActionId = request.Action.Id,
|
||||||
Info = JsonSerializer.Serialize(result),
|
InfoDetail = JsonSerializer.Serialize(result),
|
||||||
Type = ResultType.Pre
|
Type = ResultType.Pre,
|
||||||
|
References = request.References
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,9 +32,11 @@ public class PreprocessingBehavior(IRecDbContext context, ISender sender) : IPip
|
|||||||
{
|
{
|
||||||
await sender.Send(new InsertResultCommand()
|
await sender.Send(new InsertResultCommand()
|
||||||
{
|
{
|
||||||
|
Status = RecStatus.Error,
|
||||||
ActionId = request.Action.Id,
|
ActionId = request.Action.Id,
|
||||||
Error = ex.ToString(),
|
Error = ex.ToString(),
|
||||||
Type = ResultType.Pre
|
Type = ResultType.Pre,
|
||||||
|
References = request.References
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|
||||||
if (request.Action.ErrorAction == ErrorAction.Stop)
|
if (request.Action.ErrorAction == ErrorAction.Stop)
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record ConnectionDto
|
|
||||||
{
|
|
||||||
public short? Id { get; set; }
|
|
||||||
|
|
||||||
public string? Bezeichnung { get; set; }
|
|
||||||
|
|
||||||
public string? SqlProvider { get; set; }
|
|
||||||
|
|
||||||
public string? Server { get; set; }
|
|
||||||
|
|
||||||
public string? Datenbank { get; set; }
|
|
||||||
|
|
||||||
public string? Username { get; set; }
|
|
||||||
|
|
||||||
public string? Password { get; set; }
|
|
||||||
|
|
||||||
public string? Bemerkung { get; set; }
|
|
||||||
|
|
||||||
public bool? Aktiv { get; set; }
|
|
||||||
|
|
||||||
public string? ErstelltWer { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ErstelltWann { get; set; }
|
|
||||||
|
|
||||||
public string? GeandertWer { get; set; }
|
|
||||||
|
|
||||||
public DateTime? GeaendertWann { get; set; }
|
|
||||||
|
|
||||||
public bool? SysConnection { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using ReC.Domain.Views;
|
using ReC.Domain.Views;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
namespace ReC.Application.Common.Dto;
|
||||||
|
|
||||||
@@ -6,7 +6,12 @@ public class DtoMappingProfile : AutoMapper.Profile
|
|||||||
{
|
{
|
||||||
public DtoMappingProfile()
|
public DtoMappingProfile()
|
||||||
{
|
{
|
||||||
CreateMap<RecActionView, RecActionViewDto>();
|
CreateMap<RecActionView, RecActionViewDto>()
|
||||||
|
.ForMember(dest => dest.PreprocessingQuery, opt => opt.MapFrom((src, _) =>
|
||||||
|
src.PreprocessingQuery?.ReplacePlaceholders(src)))
|
||||||
|
.ForMember(dest => dest.PostprocessingQuery, opt => opt.MapFrom((src, _) =>
|
||||||
|
src.PostprocessingQuery?.ReplacePlaceholders(src)));
|
||||||
|
|
||||||
CreateMap<ResultView, ResultViewDto>();
|
CreateMap<ResultView, ResultViewDto>();
|
||||||
CreateMap<ProfileView, ProfileViewDto>();
|
CreateMap<ProfileView, ProfileViewDto>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using ReC.Domain.Constants;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record EndpointAuthDto
|
|
||||||
{
|
|
||||||
public long? Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public EndpointAuthType? Type { get; set; }
|
|
||||||
|
|
||||||
public string? ApiKey { get; set; }
|
|
||||||
|
|
||||||
public string? ApiValue { get; set; }
|
|
||||||
|
|
||||||
public ApiKeyLocation? ApiKeyAddTo { get; set; }
|
|
||||||
|
|
||||||
public string? Token { get; set; }
|
|
||||||
|
|
||||||
public string? Username { get; set; }
|
|
||||||
|
|
||||||
public string? Password { get; set; }
|
|
||||||
|
|
||||||
public string? Domain { get; set; }
|
|
||||||
|
|
||||||
public string? Workstation { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record EndpointDto
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public string? Uri { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the TBREC_CFG_ENDPOINT_PARAMS table.
|
|
||||||
/// All properties are nullable to provide flexibility on the database side,
|
|
||||||
/// preventing breaking changes if columns are altered to be nullable in production.
|
|
||||||
/// </summary>
|
|
||||||
public record EndpointParamDto
|
|
||||||
{
|
|
||||||
public long? Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public short? GroupId { get; set; }
|
|
||||||
|
|
||||||
public byte? Sequence { get; set; }
|
|
||||||
|
|
||||||
public string? Key { get; set; }
|
|
||||||
|
|
||||||
public string? Value { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using ReC.Domain.Constants;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record OutResDto
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public long? ActionId { get; set; }
|
|
||||||
|
|
||||||
public RecActionDto? Action { get; set; }
|
|
||||||
|
|
||||||
public long? ProfileId { get; set; }
|
|
||||||
|
|
||||||
public ProfileDto? Profile { get; set; }
|
|
||||||
|
|
||||||
public string? ProfileName { get; set; }
|
|
||||||
|
|
||||||
public short? StatusCode { get; set; }
|
|
||||||
|
|
||||||
public string? StatusName { get; set; }
|
|
||||||
|
|
||||||
public ResultType? Type { get; set; }
|
|
||||||
|
|
||||||
public string? Header { get; set; }
|
|
||||||
|
|
||||||
public string? Body { get; set; }
|
|
||||||
|
|
||||||
public string? Info { get; set; }
|
|
||||||
|
|
||||||
public string? Error { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
60
src/ReC.Application/Common/Dto/PlaceholderExtensions.cs
Normal file
60
src/ReC.Application/Common/Dto/PlaceholderExtensions.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Dto;
|
||||||
|
|
||||||
|
public static partial class PlaceholderExtensions
|
||||||
|
{
|
||||||
|
[GeneratedRegex(@"\{#[^#]+#[^}]+\}")]
|
||||||
|
private static partial Regex PlaceholderRegex();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces placeholders in the format <c>{#ANY_STRING#COLUMN_NAME}</c> with the corresponding
|
||||||
|
/// property value resolved via <see cref="GetValueByColumnName{T}"/> from the provided objects.
|
||||||
|
/// Values are converted to SQL-compatible string representations.
|
||||||
|
/// If a placeholder cannot be resolved, it is replaced with <c>NULL</c>.
|
||||||
|
/// </summary>
|
||||||
|
public static string ReplacePlaceholders(this string str, params object?[] objects)
|
||||||
|
{
|
||||||
|
return PlaceholderRegex().Replace(str, match =>
|
||||||
|
{
|
||||||
|
var placeholder = match.Value;
|
||||||
|
var inner = placeholder[2..^1]; // remove {# and }
|
||||||
|
var lastHash = inner.LastIndexOf('#');
|
||||||
|
var columnName = inner[(lastHash + 1)..];
|
||||||
|
|
||||||
|
foreach (var obj in objects)
|
||||||
|
{
|
||||||
|
if (obj is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var value = obj.GetValueByColumnName(columnName);
|
||||||
|
if (value is not null)
|
||||||
|
return ToSqlLiteral(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "NULL";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToSqlLiteral(object value) => value switch
|
||||||
|
{
|
||||||
|
bool b => b ? "TRUE" : "FALSE",
|
||||||
|
DateTime dt => dt.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||||
|
DateTimeOffset dto => dto.ToString("yyyy-MM-dd HH:mm:ss zzz"),
|
||||||
|
_ => value.ToString() ?? string.Empty
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the value of a property by its column name defined in <see cref="ColumnAttribute"/>.
|
||||||
|
/// Returns <c>null</c> if no property with the given column name exists.
|
||||||
|
/// </summary>
|
||||||
|
public static object? GetValueByColumnName<T>(this T obj, string columnName) where T : class
|
||||||
|
{
|
||||||
|
var property = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
||||||
|
.FirstOrDefault(p => p.GetCustomAttribute<ColumnAttribute>()?.Name == columnName);
|
||||||
|
|
||||||
|
return property?.GetValue(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record ProfileDto
|
|
||||||
{
|
|
||||||
public long Id { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public string? Type { get; set; }
|
|
||||||
|
|
||||||
public string? Mandantor { get; set; }
|
|
||||||
|
|
||||||
public string? Name { get; set; }
|
|
||||||
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
public string? LogLevel { get; set; }
|
|
||||||
|
|
||||||
public string? Language { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
using ReC.Domain.Constants;
|
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Dto;
|
|
||||||
|
|
||||||
public record RecActionDto
|
|
||||||
{
|
|
||||||
public long? Id { get; set; }
|
|
||||||
|
|
||||||
public long? ProfileId { get; set; }
|
|
||||||
|
|
||||||
public ProfileDto? Profile { get; set; }
|
|
||||||
|
|
||||||
public bool? Active { get; set; }
|
|
||||||
|
|
||||||
public byte? Sequence { get; set; }
|
|
||||||
|
|
||||||
public long? EndpointId { get; set; }
|
|
||||||
|
|
||||||
public EndpointDto? Endpoint { get; set; }
|
|
||||||
|
|
||||||
public long? EndpointAuthId { get; set; }
|
|
||||||
|
|
||||||
public EndpointAuthDto? EndpointAuth { get; set; }
|
|
||||||
|
|
||||||
public short? EndpointParamsId { get; set; }
|
|
||||||
|
|
||||||
public short? SqlConnectionId { get; set; }
|
|
||||||
|
|
||||||
public ConnectionDto? SqlConnection { get; set; }
|
|
||||||
|
|
||||||
public string? Type { get; set; }
|
|
||||||
|
|
||||||
public string? PreprocessingQuery { get; set; }
|
|
||||||
|
|
||||||
public string? HeaderQuery { get; set; }
|
|
||||||
|
|
||||||
public string? BodyQuery { get; set; }
|
|
||||||
|
|
||||||
public string? PostprocessingQuery { get; set; }
|
|
||||||
|
|
||||||
public ErrorAction? ErrorAction { get; set; }
|
|
||||||
|
|
||||||
public string? AddedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; set; }
|
|
||||||
|
|
||||||
public string? ChangedWho { get; set; }
|
|
||||||
|
|
||||||
public DateTime? ChangedWhen { get; set; }
|
|
||||||
|
|
||||||
public OutResDto? OutRes { get; set; }
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,8 @@ public record RecActionViewDto
|
|||||||
|
|
||||||
public long? ProfileId { get; init; }
|
public long? ProfileId { get; init; }
|
||||||
|
|
||||||
|
public ProfileViewDto? Profile { get; init; }
|
||||||
|
|
||||||
public string? ProfileName { get; init; }
|
public string? ProfileName { get; init; }
|
||||||
|
|
||||||
public ProfileType? ProfileType { get; init; }
|
public ProfileType? ProfileType { get; init; }
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
namespace ReC.Application.Common.Dto;
|
using ReC.Domain.Constants;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Dto;
|
||||||
|
|
||||||
public record ResultViewDto
|
public record ResultViewDto
|
||||||
{
|
{
|
||||||
public long Id { get; init; }
|
public long Id { get; init; }
|
||||||
|
|
||||||
public OutResDto? Root { get; init; }
|
|
||||||
|
|
||||||
public long? ActionId { get; init; }
|
public long? ActionId { get; init; }
|
||||||
|
|
||||||
public RecActionViewDto? Action { get; init; }
|
public RecActionViewDto? Action { get; init; }
|
||||||
@@ -16,7 +16,7 @@ public record ResultViewDto
|
|||||||
|
|
||||||
public string? ProfileName { get; init; }
|
public string? ProfileName { get; init; }
|
||||||
|
|
||||||
public short? StatusCode { get; init; }
|
public RecStatus Status { get; set; }
|
||||||
|
|
||||||
public string? StatusName { get; init; }
|
public string? StatusName { get; init; }
|
||||||
|
|
||||||
@@ -24,6 +24,14 @@ public record ResultViewDto
|
|||||||
|
|
||||||
public string? Body { get; init; }
|
public string? Body { get; init; }
|
||||||
|
|
||||||
|
public string? Info { get; set; }
|
||||||
|
|
||||||
|
public string? InfoDetail { get; set; }
|
||||||
|
|
||||||
|
public string? Error { get; set; }
|
||||||
|
|
||||||
|
public string? BatchId { get; set; }
|
||||||
|
|
||||||
public string? AddedWho { get; init; }
|
public string? AddedWho { get; init; }
|
||||||
|
|
||||||
public DateTime? AddedWhen { get; init; }
|
public DateTime? AddedWhen { get; init; }
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ namespace ReC.Application.Common.Procedures.DeleteProcedure;
|
|||||||
public record DeleteObjectProcedure : IRequest<int>
|
public record DeleteObjectProcedure : IRequest<int>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
|
/// Target entity for the delete operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Entity { get; set; } = null!;
|
public required EntityType Entity { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start GUID/ID (inclusive)
|
/// Start GUID/ID (inclusive)
|
||||||
@@ -35,25 +35,16 @@ public class DeleteObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
|||||||
{
|
{
|
||||||
public async Task<int> Handle(DeleteObjectProcedure request, CancellationToken cancel)
|
public async Task<int> Handle(DeleteObjectProcedure request, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var parameters = new[]
|
var sp = new StoredProcedureBuilder("[dbo].[PRREC_DELETE_OBJECT]", "RC")
|
||||||
{
|
.Add("pENTITY", request.Entity)
|
||||||
new SqlParameter("@pENTITY", request.Entity ?? (object)DBNull.Value),
|
.Add("pSTART", request.Start.ToString())
|
||||||
new SqlParameter("@pSTART", request.Start.ToString()),
|
.Add("pEND", request.End.ToString())
|
||||||
new SqlParameter("@pEND", request.End.ToString()),
|
.Add("pFORCE", request.Force);
|
||||||
new SqlParameter("@pFORCE", (object?)request.Force ?? DBNull.Value)
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await repo.ExecuteQueryRawAsync(
|
var result = await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||||
"DECLARE @RC SMALLINT = 0; " +
|
|
||||||
"EXEC @RC = [dbo].[PRREC_DELETE_OBJECT] " +
|
|
||||||
"@pENTITY, @pSTART, @pEND, @pFORCE; " +
|
|
||||||
"SELECT @RC;",
|
|
||||||
parameters,
|
|
||||||
cancel);
|
|
||||||
|
|
||||||
// The stored procedure returns 0 on success, error codes > 0 on failure
|
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
{
|
{
|
||||||
throw new DeleteObjectFailedException(request, $"DeleteObject stored procedure failed with error code: {result}");
|
throw new DeleteObjectFailedException(request, $"DeleteObject stored procedure failed with error code: {result}");
|
||||||
|
|||||||
51
src/ReC.Application/Common/Procedures/EntityType.cs
Normal file
51
src/ReC.Application/Common/Procedures/EntityType.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
namespace ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the target entity type for stored procedure operations (Insert, Update, Delete).
|
||||||
|
/// </summary>
|
||||||
|
public enum EntityType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A scheduled or configured action within a profile that invokes an endpoint (maps to TBREC_CFG_ACTION).
|
||||||
|
/// </summary>
|
||||||
|
Action,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A REST endpoint URI configuration (maps to TBREC_CFG_ENDPOINT).
|
||||||
|
/// </summary>
|
||||||
|
Endpoint,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Authentication credentials for an endpoint such as API key, Bearer token, or NTLM (maps to TBREC_CFG_ENDPOINT_AUTH).
|
||||||
|
/// </summary>
|
||||||
|
EndpointAuth,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Key-value parameters attached to an endpoint (maps to TBREC_CFG_ENDPOINT_PARAMS).
|
||||||
|
/// </summary>
|
||||||
|
EndpointParams,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A profile that groups one or more actions and defines execution settings (maps to TBREC_CFG_PROFILE).
|
||||||
|
/// </summary>
|
||||||
|
Profile,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The outcome of an action invocation including HTTP status, headers, body, and error details (maps to TBREC_OUT_RESULT).
|
||||||
|
/// </summary>
|
||||||
|
Result
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EntityTypeExtensions
|
||||||
|
{
|
||||||
|
public static string ToDbString(this EntityType entityType) => entityType switch
|
||||||
|
{
|
||||||
|
EntityType.Action => "ACTION",
|
||||||
|
EntityType.Endpoint => "ENDPOINT",
|
||||||
|
EntityType.EndpointAuth => "ENDPOINT_AUTH",
|
||||||
|
EntityType.EndpointParams => "ENDPOINT_PARAMS",
|
||||||
|
EntityType.Profile => "PROFILE",
|
||||||
|
EntityType.Result => "RESULT",
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(entityType), $"Not expected entity type value: {entityType}")
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -11,15 +11,16 @@ using ReC.Application.Endpoints.Commands;
|
|||||||
using ReC.Application.Profile.Commands;
|
using ReC.Application.Profile.Commands;
|
||||||
using ReC.Application.RecActions.Commands;
|
using ReC.Application.RecActions.Commands;
|
||||||
using ReC.Application.Results.Commands;
|
using ReC.Application.Results.Commands;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
namespace ReC.Application.Common.Procedures.InsertProcedure;
|
namespace ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
|
|
||||||
public record InsertObjectProcedure : IRequest<long>
|
public record InsertObjectProcedure : IRequest<long>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
|
/// Target entity for the insert operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Entity { get; set; } = null!;
|
public required EntityType Entity { get; set; }
|
||||||
|
|
||||||
//TODO: update to set in authentication middleware or similar, and remove from procedure properties
|
//TODO: update to set in authentication middleware or similar, and remove from procedure properties
|
||||||
internal string? AddedWho { get; private set; } = "ReC.API";
|
internal string? AddedWho { get; private set; } = "ReC.API";
|
||||||
@@ -36,88 +37,69 @@ public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
|||||||
{
|
{
|
||||||
public async Task<long> Handle(InsertObjectProcedure request, CancellationToken cancel)
|
public async Task<long> Handle(InsertObjectProcedure request, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var parameters = new[]
|
var sp = new StoredProcedureBuilder("[dbo].[PRREC_INSERT_OBJECT]")
|
||||||
{
|
.Add("pENTITY", request.Entity)
|
||||||
new SqlParameter("@pENTITY", request.Entity ?? (object)DBNull.Value),
|
.Add("pADDED_WHO", request.AddedWho)
|
||||||
|
.Add("pADDED_WHEN", DateTime.UtcNow)
|
||||||
new SqlParameter("@pADDED_WHO", (object?)request.AddedWho ?? DBNull.Value),
|
.Add("pACTION_PROFILE_ID", request.Action?.ProfileId)
|
||||||
new SqlParameter("@pADDED_WHEN", (object?)DateTime.UtcNow ?? DBNull.Value),
|
.Add("pACTION_ACTIVE", request.Action?.Active)
|
||||||
|
.Add("pACTION_SEQUENCE", request.Action?.Sequence, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pACTION_PROFILE_ID", (object?)request.Action?.ProfileId ?? DBNull.Value),
|
.Add("pACTION_ENDPOINT_ID", request.Action?.EndpointId)
|
||||||
new SqlParameter("@pACTION_ACTIVE", (object?)request.Action?.Active ?? DBNull.Value),
|
.Add("pACTION_ENDPOINT_AUTH_ID", request.Action?.EndpointAuthId)
|
||||||
new SqlParameter("@pACTION_SEQUENCE", (object?)request.Action?.Sequence ?? DBNull.Value),
|
.Add("pACTION_ENDPOINT_PARAMS_ID", request.Action?.EndpointParamsId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pACTION_ENDPOINT_ID", (object?)request.Action?.EndpointId ?? DBNull.Value),
|
.Add("pACTION_SQL_CONNECTION_ID", request.Action?.SqlConnectionId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pACTION_ENDPOINT_AUTH_ID", (object?)request.Action?.EndpointAuthId ?? DBNull.Value),
|
.Add("pACTION_TYPE_ID", request.Action?.TypeId is not null ? (byte)request.Action.TypeId : null, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pACTION_ENDPOINT_PARAMS_ID", (object?)request.Action?.EndpointParamsId ?? DBNull.Value),
|
.Add("pACTION_PRE_SQL", request.Action?.PreSql)
|
||||||
new SqlParameter("@pACTION_SQL_CONNECTION_ID", (object?)request.Action?.SqlConnectionId ?? DBNull.Value),
|
.Add("pACTION_HEADER_SQL", request.Action?.HeaderSql)
|
||||||
new SqlParameter("@pACTION_TYPE_ID", (object?)(byte?)request.Action?.TypeId ?? DBNull.Value),
|
.Add("pACTION_BODY_SQL", request.Action?.BodySql)
|
||||||
new SqlParameter("@pACTION_PRE_SQL", (object?)request.Action?.PreSql ?? DBNull.Value),
|
.Add("pACTION_POST_SQL", request.Action?.PostSql)
|
||||||
new SqlParameter("@pACTION_HEADER_SQL", (object?)request.Action?.HeaderSql ?? DBNull.Value),
|
.Add("pACTION_ERROR_ACTION_ID", request.Action?.ErrorActionId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pACTION_BODY_SQL", (object?)request.Action?.BodySql ?? DBNull.Value),
|
.Add("pENDPOINT_ACTIVE", request.Endpoint?.Active)
|
||||||
new SqlParameter("@pACTION_POST_SQL", (object?)request.Action?.PostSql ?? DBNull.Value),
|
.Add("pENDPOINT_DESCRIPTION", request.Endpoint?.Description)
|
||||||
new SqlParameter("@pACTION_ERROR_ACTION_ID", (object?)request.Action?.ErrorActionId ?? DBNull.Value),
|
.Add("pENDPOINT_URI", request.Endpoint?.Uri)
|
||||||
|
.Add("pENDPOINT_AUTH_ACTIVE", request.EndpointAuth?.Active)
|
||||||
new SqlParameter("@pENDPOINT_ACTIVE", (object?)request.Endpoint?.Active ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_DESCRIPTION", request.EndpointAuth?.Description)
|
||||||
new SqlParameter("@pENDPOINT_DESCRIPTION", (object?)request.Endpoint?.Description ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_TYPE_ID", request.EndpointAuth?.TypeId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pENDPOINT_URI", (object?)request.Endpoint?.Uri ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_API_KEY", request.EndpointAuth?.ApiKey)
|
||||||
|
.Add("pENDPOINT_AUTH_API_VALUE", request.EndpointAuth?.ApiValue)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_ACTIVE", (object?)request.EndpointAuth?.Active ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_API_KEY_ADD_TO_ID", request.EndpointAuth?.ApiKeyAddToId)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_DESCRIPTION", (object?)request.EndpointAuth?.Description ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_TOKEN", request.EndpointAuth?.Token)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_TYPE_ID", (object?)request.EndpointAuth?.TypeId ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_USERNAME", request.EndpointAuth?.Username)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY", (object?)request.EndpointAuth?.ApiKey ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_PASSWORD", request.EndpointAuth?.Password)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_API_VALUE", (object?)request.EndpointAuth?.ApiValue ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_DOMAIN", request.EndpointAuth?.Domain)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY_ADD_TO_ID", (object?)request.EndpointAuth?.ApiKeyAddToId ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_WORKSTATION", request.EndpointAuth?.Workstation)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_TOKEN", (object?)request.EndpointAuth?.Token ?? DBNull.Value),
|
.Add("pPROFILE_ACTIVE", request.Profile?.Active)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_USERNAME", (object?)request.EndpointAuth?.Username ?? DBNull.Value),
|
.Add("pPROFILE_TYPE_ID", request.Profile?.TypeId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_PASSWORD", (object?)request.EndpointAuth?.Password ?? DBNull.Value),
|
.Add("pPROFILE_MANDANTOR", request.Profile?.Mandantor)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_DOMAIN", (object?)request.EndpointAuth?.Domain ?? DBNull.Value),
|
.Add("pPROFILE_NAME", request.Profile?.Name)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_WORKSTATION", (object?)request.EndpointAuth?.Workstation ?? DBNull.Value),
|
.Add("pPROFILE_DESCRIPTION", request.Profile?.Description)
|
||||||
|
.Add("pPROFILE_LOG_LEVEL_ID", request.Profile?.LogLevelId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pPROFILE_ACTIVE", (object?)request.Profile?.Active ?? DBNull.Value),
|
.Add("pPROFILE_LANGUAGE_ID", request.Profile?.LanguageId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pPROFILE_TYPE_ID", (object?)request.Profile?.TypeId ?? DBNull.Value),
|
.Add("pRESULT_ACTION_ID", request.Result?.ActionId)
|
||||||
new SqlParameter("@pPROFILE_MANDANTOR", (object?)request.Profile?.Mandantor ?? DBNull.Value),
|
.Add("pRESULT_STATUS_ID", request.Result?.Status, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pPROFILE_NAME", (object?)request.Profile?.Name ?? DBNull.Value),
|
.Add("pRESULT_TYPE_ID", request.Result?.Type is not null ? (byte)request.Result.Type : null, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pPROFILE_DESCRIPTION", (object?)request.Profile?.Description ?? DBNull.Value),
|
.Add("pRESULT_HEADER", request.Result?.Header)
|
||||||
new SqlParameter("@pPROFILE_LOG_LEVEL_ID", (object?)request.Profile?.LogLevelId ?? DBNull.Value),
|
.Add("pRESULT_BODY", request.Result?.Body)
|
||||||
new SqlParameter("@pPROFILE_LANGUAGE_ID", (object?)request.Profile?.LanguageId ?? DBNull.Value),
|
.Add("pRESULT_INFO_ID", request.Result?.Info, SqlDbType.SmallInt)
|
||||||
|
.Add("pRESULT_INFO_DETAIL", request.Result?.InfoDetail)
|
||||||
new SqlParameter("@pRESULT_ACTION_ID", (object?)request.Result?.ActionId ?? DBNull.Value),
|
.Add("pRESULT_ERROR", request.Result?.Error)
|
||||||
new SqlParameter("@pRESULT_STATUS_ID", (object?)request.Result?.StatusId ?? DBNull.Value),
|
.Add("pRESULT_BATCH_ID", request.Result?.References?.BatchId)
|
||||||
new SqlParameter("@pRESULT_HEADER", (object?)request.Result?.Header ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE1", request.Result?.References?.Reference1)
|
||||||
new SqlParameter("@pRESULT_BODY", (object?)request.Result?.Body ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE2", request.Result?.References?.Reference2)
|
||||||
new SqlParameter("@pRESULT_INFO", (object?)request.Result?.Info ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE3", request.Result?.References?.Reference3)
|
||||||
new SqlParameter("@pRESULT_ERROR", (object?)request.Result?.Error ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE4", request.Result?.References?.Reference4)
|
||||||
new SqlParameter("@pRESULT_TYPE_ID", (object?)(byte?)request.Result?.Type ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE5", request.Result?.References?.Reference5)
|
||||||
|
.Add("pENDPOINT_PARAMS_ACTIVE", request.EndpointParams?.Active)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_ACTIVE", (object?)request.EndpointParams?.Active ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_DESCRIPTION", request.EndpointParams?.Description)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_DESCRIPTION", (object?)request.EndpointParams?.Description ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_GROUP_ID", request.EndpointParams?.GroupId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_GROUP_ID", (object?)request.EndpointParams?.GroupId ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_SEQUENCE", request.EndpointParams?.Sequence, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_SEQUENCE", (object?)request.EndpointParams?.Sequence ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_KEY", request.EndpointParams?.Key)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_KEY", (object?)request.EndpointParams?.Key ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_VALUE", request.EndpointParams?.Value)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_VALUE", (object?)request.EndpointParams?.Value ?? DBNull.Value),
|
.AddOutput("oGUID", SqlDbType.BigInt);
|
||||||
|
|
||||||
new SqlParameter
|
|
||||||
{
|
|
||||||
ParameterName = "@oGUID",
|
|
||||||
SqlDbType = System.Data.SqlDbType.BigInt,
|
|
||||||
Direction = System.Data.ParameterDirection.Output
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await repo.ExecuteQueryRawAsync(
|
await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||||
"EXEC [dbo].[PRREC_INSERT_OBJECT] " +
|
|
||||||
"@pENTITY, @pADDED_WHO, @pADDED_WHEN, " +
|
|
||||||
"@pACTION_PROFILE_ID, @pACTION_ACTIVE, @pACTION_SEQUENCE, @pACTION_ENDPOINT_ID, @pACTION_ENDPOINT_AUTH_ID, @pACTION_ENDPOINT_PARAMS_ID, @pACTION_SQL_CONNECTION_ID, @pACTION_TYPE_ID, @pACTION_PRE_SQL, @pACTION_HEADER_SQL, @pACTION_BODY_SQL, @pACTION_POST_SQL, @pACTION_ERROR_ACTION_ID, " +
|
|
||||||
"@pENDPOINT_ACTIVE, @pENDPOINT_DESCRIPTION, @pENDPOINT_URI, " +
|
|
||||||
"@pENDPOINT_AUTH_ACTIVE, @pENDPOINT_AUTH_DESCRIPTION, @pENDPOINT_AUTH_TYPE_ID, @pENDPOINT_AUTH_API_KEY, @pENDPOINT_AUTH_API_VALUE, @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, @pENDPOINT_AUTH_TOKEN, @pENDPOINT_AUTH_USERNAME, @pENDPOINT_AUTH_PASSWORD, @pENDPOINT_AUTH_DOMAIN, @pENDPOINT_AUTH_WORKSTATION, " +
|
|
||||||
"@pPROFILE_ACTIVE, @pPROFILE_TYPE_ID, @pPROFILE_MANDANTOR, @pPROFILE_NAME, @pPROFILE_DESCRIPTION, @pPROFILE_LOG_LEVEL_ID, @pPROFILE_LANGUAGE_ID, " +
|
|
||||||
"@pRESULT_ACTION_ID, @pRESULT_STATUS_ID, @pRESULT_HEADER, @pRESULT_BODY, @pRESULT_INFO, @pRESULT_ERROR, @pRESULT_TYPE_ID, " +
|
|
||||||
"@pENDPOINT_PARAMS_ACTIVE, @pENDPOINT_PARAMS_DESCRIPTION, @pENDPOINT_PARAMS_GROUP_ID, @pENDPOINT_PARAMS_SEQUENCE, @pENDPOINT_PARAMS_KEY, @pENDPOINT_PARAMS_VALUE, " +
|
|
||||||
"@oGUID OUTPUT",
|
|
||||||
parameters,
|
|
||||||
cancel);
|
|
||||||
}
|
}
|
||||||
catch (SqlException ex)
|
catch (SqlException ex)
|
||||||
{
|
{
|
||||||
@@ -127,12 +109,12 @@ public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
var guidParam = parameters.Last();
|
var guidParam = sp.GetParameter("oGUID");
|
||||||
|
|
||||||
if (guidParam.Value != DBNull.Value)
|
if (guidParam?.Value != DBNull.Value)
|
||||||
if (guidParam.Value is long longValue)
|
if (guidParam!.Value is long longValue)
|
||||||
return longValue;
|
return longValue;
|
||||||
else if (long.TryParse(guidParam.Value.ToString(), out var guid))
|
else if (long.TryParse(guidParam.Value?.ToString(), out var guid))
|
||||||
return guid;
|
return guid;
|
||||||
|
|
||||||
throw new InsertObjectFailedException(request, "InsertObject stored procedure did not return a valid identifier.");
|
throw new InsertObjectFailedException(request, "InsertObject stored procedure did not return a valid identifier.");
|
||||||
|
|||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using Microsoft.Data.SqlClient;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Internal;
|
||||||
|
using System.Data;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
|
internal sealed class StoredProcedureBuilder(string procedureName, string? returnVariable = null)
|
||||||
|
{
|
||||||
|
private readonly StringBuilder _execSql = returnVariable is not null
|
||||||
|
? new StringBuilder($"EXEC @{returnVariable} = {procedureName}")
|
||||||
|
: new StringBuilder($"EXEC {procedureName}");
|
||||||
|
private readonly List<SqlParameter> _parameters = [];
|
||||||
|
private char _separator = ' ';
|
||||||
|
|
||||||
|
public StoredProcedureBuilder Add(string name, object? value, SqlDbType? dbType = null)
|
||||||
|
{
|
||||||
|
if (value is null) return this;
|
||||||
|
|
||||||
|
_execSql.AppendLine($"{_separator}@{name} = @{name}");
|
||||||
|
_separator = ',';
|
||||||
|
|
||||||
|
if (!dbType.HasValue && value is DateTime)
|
||||||
|
dbType = SqlDbType.DateTime;
|
||||||
|
|
||||||
|
if (dbType.HasValue)
|
||||||
|
_parameters.Add(new SqlParameter($"@{name}", dbType.Value) { Value = value });
|
||||||
|
else
|
||||||
|
_parameters.Add(new SqlParameter($"@{name}", value));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoredProcedureBuilder Add(string name, EntityType entityType)
|
||||||
|
{
|
||||||
|
var entityTypeStr = entityType switch
|
||||||
|
{
|
||||||
|
EntityType.Action => "ACTION",
|
||||||
|
EntityType.Endpoint => "ENDPOINT",
|
||||||
|
EntityType.EndpointAuth => "ENDPOINT_AUTH",
|
||||||
|
EntityType.EndpointParams => "ENDPOINT_PARAMS",
|
||||||
|
EntityType.Profile => "PROFILE",
|
||||||
|
EntityType.Result => "RESULT",
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(entityType), $"Not expected entity type value: {entityType}")
|
||||||
|
};
|
||||||
|
|
||||||
|
return Add(name, entityTypeStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StoredProcedureBuilder AddOutput(string name, SqlDbType dbType)
|
||||||
|
{
|
||||||
|
_execSql.AppendLine($"{_separator}@{name} = @{name} OUTPUT");
|
||||||
|
_separator = ',';
|
||||||
|
|
||||||
|
_parameters.Add(new SqlParameter
|
||||||
|
{
|
||||||
|
ParameterName = $"@{name}",
|
||||||
|
SqlDbType = dbType,
|
||||||
|
Direction = ParameterDirection.Output
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BuildSql()
|
||||||
|
{
|
||||||
|
if (returnVariable is null)
|
||||||
|
return _execSql.ToString();
|
||||||
|
|
||||||
|
return new StringBuilder()
|
||||||
|
.AppendLine($"DECLARE @{returnVariable} SMALLINT = 0;")
|
||||||
|
.Append(_execSql).AppendLine(";")
|
||||||
|
.AppendLine($"SELECT @{returnVariable};")
|
||||||
|
.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SqlParameter[] BuildParameters() => [.. _parameters];
|
||||||
|
|
||||||
|
public SqlParameter? GetParameter(string name) =>
|
||||||
|
_parameters.Find(p => p.ParameterName == $"@{name}");
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.RecActions.Commands;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
|
||||||
public record UpdateResultDto
|
public record UpdateResultDto
|
||||||
{
|
{
|
||||||
@@ -6,4 +8,8 @@ public record UpdateResultDto
|
|||||||
public short? StatusId { get; set; }
|
public short? StatusId { get; set; }
|
||||||
public string? Header { get; set; }
|
public string? Header { get; set; }
|
||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
|
public short? Info { get; set; }
|
||||||
|
public string? InfoDetail { get; set; }
|
||||||
|
public string? Error { get; set; }
|
||||||
|
public InvokeReferences? References { get; set; }
|
||||||
}
|
}
|
||||||
@@ -6,21 +6,16 @@ using Microsoft.Extensions.Options;
|
|||||||
using ReC.Application.Common.Exceptions;
|
using ReC.Application.Common.Exceptions;
|
||||||
using ReC.Application.Common.Options;
|
using ReC.Application.Common.Options;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
using ReC.Application.EndpointAuth.Commands;
|
using System.Data;
|
||||||
using ReC.Application.EndpointParams.Commands;
|
|
||||||
using ReC.Application.Endpoints.Commands;
|
|
||||||
using ReC.Application.Profile.Commands;
|
|
||||||
using ReC.Application.RecActions.Commands;
|
|
||||||
using ReC.Application.Results.Commands;
|
|
||||||
|
|
||||||
namespace ReC.Application.Common.Procedures.UpdateProcedure;
|
namespace ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
|
|
||||||
public record UpdateObjectProcedure : IRequest<int>
|
public record UpdateObjectProcedure : IRequest<int>
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
|
/// Target entity for the update operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Entity { get; set; } = null!;
|
public required EntityType Entity { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Target GUID to update (required)
|
/// Target GUID to update (required)
|
||||||
@@ -42,85 +37,72 @@ public class UpdateObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlE
|
|||||||
{
|
{
|
||||||
public async Task<int> Handle(UpdateObjectProcedure request, CancellationToken cancel)
|
public async Task<int> Handle(UpdateObjectProcedure request, CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var parameters = new[]
|
var sp = new StoredProcedureBuilder("[dbo].[PRREC_UPDATE_OBJECT]", "RC")
|
||||||
{
|
.Add("pENTITY", request.Entity)
|
||||||
new SqlParameter("@pENTITY", request.Entity ?? (object)DBNull.Value),
|
.Add("pGUID", request.Id)
|
||||||
new SqlParameter("@pGUID", (object?)request.Id ?? DBNull.Value),
|
.Add("pCHANGED_WHO", request.ChangedWho)
|
||||||
|
.Add("pCHANGED_WHEN", DateTime.UtcNow)
|
||||||
new SqlParameter("@pCHANGED_WHO", (object?)request.ChangedWho ?? DBNull.Value),
|
.Add("pACTION_PROFILE_ID", request.Action.ProfileId)
|
||||||
new SqlParameter("@pCHANGED_WHEN", (object?)DateTime.UtcNow ?? DBNull.Value),
|
.Add("pACTION_ACTIVE", request.Action.Active)
|
||||||
|
.Add("pACTION_SEQUENCE", request.Action.Sequence, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pACTION_PROFILE_ID", (object?)request.Action.ProfileId ?? DBNull.Value),
|
.Add("pACTION_ENDPOINT_ID", request.Action.EndpointId)
|
||||||
new SqlParameter("@pACTION_ACTIVE", (object?)request.Action.Active ?? DBNull.Value),
|
.Add("pACTION_ENDPOINT_AUTH_ID", request.Action.EndpointAuthId)
|
||||||
new SqlParameter("@pACTION_SEQUENCE", (object?)request.Action.Sequence ?? DBNull.Value),
|
.Add("pACTION_ENDPOINT_PARAMS_ID", request.Action.EndpointParamsId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pACTION_ENDPOINT_ID", (object?)request.Action.EndpointId ?? DBNull.Value),
|
.Add("pACTION_SQL_CONNECTION_ID", request.Action.SqlConnectionId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pACTION_ENDPOINT_AUTH_ID", (object?)request.Action.EndpointAuthId ?? DBNull.Value),
|
.Add("pACTION_TYPE_ID", request.Action.TypeId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pACTION_ENDPOINT_PARAMS_ID", (object?)request.Action.EndpointParamsId ?? DBNull.Value),
|
.Add("pACTION_PRE_SQL", request.Action.PreSql)
|
||||||
new SqlParameter("@pACTION_SQL_CONNECTION_ID", (object?)request.Action.SqlConnectionId ?? DBNull.Value),
|
.Add("pACTION_HEADER_SQL", request.Action.HeaderSql)
|
||||||
new SqlParameter("@pACTION_TYPE_ID", (object?)request.Action.TypeId ?? DBNull.Value),
|
.Add("pACTION_BODY_SQL", request.Action.BodySql)
|
||||||
new SqlParameter("@pACTION_PRE_SQL", (object?)request.Action.PreSql ?? DBNull.Value),
|
.Add("pACTION_POST_SQL", request.Action.PostSql)
|
||||||
new SqlParameter("@pACTION_HEADER_SQL", (object?)request.Action.HeaderSql ?? DBNull.Value),
|
.Add("pACTION_ERROR_ACTION_ID", request.Action.ErrorActionId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pACTION_BODY_SQL", (object?)request.Action.BodySql ?? DBNull.Value),
|
.Add("pENDPOINT_ACTIVE", request.Endpoint.Active)
|
||||||
new SqlParameter("@pACTION_POST_SQL", (object?)request.Action.PostSql ?? DBNull.Value),
|
.Add("pENDPOINT_DESCRIPTION", request.Endpoint.Description)
|
||||||
new SqlParameter("@pACTION_ERROR_ACTION_ID", (object?)request.Action.ErrorActionId ?? DBNull.Value),
|
.Add("pENDPOINT_URI", request.Endpoint.Uri)
|
||||||
|
.Add("pENDPOINT_AUTH_ACTIVE", request.EndpointAuth.Active)
|
||||||
new SqlParameter("@pENDPOINT_ACTIVE", (object?)request.Endpoint.Active ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_DESCRIPTION", request.EndpointAuth.Description)
|
||||||
new SqlParameter("@pENDPOINT_DESCRIPTION", (object?)request.Endpoint.Description ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_TYPE_ID", request.EndpointAuth.TypeId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pENDPOINT_URI", (object?)request.Endpoint.Uri ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_API_KEY", request.EndpointAuth.ApiKey)
|
||||||
|
.Add("pENDPOINT_AUTH_API_VALUE", request.EndpointAuth.ApiValue)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_ACTIVE", (object?)request.EndpointAuth.Active ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_API_KEY_ADD_TO_ID", request.EndpointAuth.ApiKeyAddToId)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_DESCRIPTION", (object?)request.EndpointAuth.Description ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_TOKEN", request.EndpointAuth.Token)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_TYPE_ID", (object?)request.EndpointAuth.TypeId ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_USERNAME", request.EndpointAuth.Username)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY", (object?)request.EndpointAuth.ApiKey ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_PASSWORD", request.EndpointAuth.Password)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_API_VALUE", (object?)request.EndpointAuth.ApiValue ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_DOMAIN", request.EndpointAuth.Domain)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY_ADD_TO_ID", (object?)request.EndpointAuth.ApiKeyAddToId ?? DBNull.Value),
|
.Add("pENDPOINT_AUTH_WORKSTATION", request.EndpointAuth.Workstation)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_TOKEN", (object?)request.EndpointAuth.Token ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_ACTIVE", request.EndpointParams.Active)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_USERNAME", (object?)request.EndpointAuth.Username ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_DESCRIPTION", request.EndpointParams.Description)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_PASSWORD", (object?)request.EndpointAuth.Password ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_GROUP_ID", request.EndpointParams.GroupId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_DOMAIN", (object?)request.EndpointAuth.Domain ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_SEQUENCE", request.EndpointParams.Sequence, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pENDPOINT_AUTH_WORKSTATION", (object?)request.EndpointAuth.Workstation ?? DBNull.Value),
|
.Add("pENDPOINT_PARAMS_KEY", request.EndpointParams.Key)
|
||||||
|
.Add("pENDPOINT_PARAMS_VALUE", request.EndpointParams.Value)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_ACTIVE", (object?)request.EndpointParams.Active ?? DBNull.Value),
|
.Add("pPROFILE_ACTIVE", request.Profile.Active)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_DESCRIPTION", (object?)request.EndpointParams.Description ?? DBNull.Value),
|
.Add("pPROFILE_TYPE_ID", request.Profile.TypeId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_GROUP_ID", (object?)request.EndpointParams.GroupId ?? DBNull.Value),
|
.Add("pPROFILE_MANDANTOR", request.Profile.Mandantor)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_SEQUENCE", (object?)request.EndpointParams.Sequence ?? DBNull.Value),
|
.Add("pPROFILE_NAME", request.Profile.Name)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_KEY", (object?)request.EndpointParams.Key ?? DBNull.Value),
|
.Add("pPROFILE_DESCRIPTION", request.Profile.Description)
|
||||||
new SqlParameter("@pENDPOINT_PARAMS_VALUE", (object?)request.EndpointParams.Value ?? DBNull.Value),
|
.Add("pPROFILE_LOG_LEVEL_ID", request.Profile.LogLevelId, SqlDbType.TinyInt)
|
||||||
|
.Add("pPROFILE_LANGUAGE_ID", request.Profile.LanguageId, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pPROFILE_ACTIVE", (object?)request.Profile.Active ?? DBNull.Value),
|
.Add("pPROFILE_FIRST_RUN", request.Profile.FirstRun)
|
||||||
new SqlParameter("@pPROFILE_TYPE_ID", (object?)request.Profile.TypeId ?? DBNull.Value),
|
.Add("pPROFILE_LAST_RUN", request.Profile.LastRun)
|
||||||
new SqlParameter("@pPROFILE_MANDANTOR", (object?)request.Profile.Mandantor ?? DBNull.Value),
|
.Add("pPROFILE_LAST_RESULT", request.Profile.LastResult)
|
||||||
new SqlParameter("@pPROFILE_NAME", (object?)request.Profile.Name ?? DBNull.Value),
|
.Add("pRESULT_ACTION_ID", request.Result.ActionId)
|
||||||
new SqlParameter("@pPROFILE_DESCRIPTION", (object?)request.Profile.Description ?? DBNull.Value),
|
.Add("pRESULT_STATUS_ID", request.Result.StatusId, SqlDbType.TinyInt)
|
||||||
new SqlParameter("@pPROFILE_LOG_LEVEL_ID", (object?)request.Profile.LogLevelId ?? DBNull.Value),
|
.Add("pRESULT_HEADER", request.Result.Header)
|
||||||
new SqlParameter("@pPROFILE_LANGUAGE_ID", (object?)request.Profile.LanguageId ?? DBNull.Value),
|
.Add("pRESULT_BODY", request.Result.Body)
|
||||||
new SqlParameter("@pPROFILE_FIRST_RUN", (object?)request.Profile.FirstRun ?? DBNull.Value),
|
.Add("pRESULT_INFO_ID", request.Result.Info, SqlDbType.SmallInt)
|
||||||
new SqlParameter("@pPROFILE_LAST_RUN", (object?)request.Profile.LastRun ?? DBNull.Value),
|
.Add("pRESULT_INFO_DETAIL", request.Result.InfoDetail)
|
||||||
new SqlParameter("@pPROFILE_LAST_RESULT", (object?)request.Profile.LastResult ?? DBNull.Value),
|
.Add("pRESULT_ERROR", request.Result.Error)
|
||||||
|
.Add("pRESULT_BATCH_ID", request.Result.References?.BatchId)
|
||||||
new SqlParameter("@pRESULT_ACTION_ID", (object?)request.Result.ActionId ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE1", request.Result.References?.Reference1)
|
||||||
new SqlParameter("@pRESULT_STATUS_ID", (object?)request.Result.StatusId ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE2", request.Result.References?.Reference2)
|
||||||
new SqlParameter("@pRESULT_HEADER", (object?)request.Result.Header ?? DBNull.Value),
|
.Add("pRESULT_REFERENCE3", request.Result.References?.Reference3)
|
||||||
new SqlParameter("@pRESULT_BODY", (object?)request.Result.Body ?? DBNull.Value)
|
.Add("pRESULT_REFERENCE4", request.Result.References?.Reference4)
|
||||||
};
|
.Add("pRESULT_REFERENCE5", request.Result.References?.Reference5);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = await repo.ExecuteQueryRawAsync(
|
var result = await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||||
"DECLARE @RC SMALLINT = 0; " +
|
|
||||||
"EXEC @RC = [dbo].[PRREC_UPDATE_OBJECT] " +
|
|
||||||
"@pENTITY, @pGUID, @pCHANGED_WHO, @pCHANGED_WHEN, " +
|
|
||||||
"@pACTION_PROFILE_ID, @pACTION_ACTIVE, @pACTION_SEQUENCE, @pACTION_ENDPOINT_ID, @pACTION_ENDPOINT_AUTH_ID, @pACTION_ENDPOINT_PARAMS_ID, @pACTION_SQL_CONNECTION_ID, @pACTION_TYPE_ID, @pACTION_PRE_SQL, @pACTION_HEADER_SQL, @pACTION_BODY_SQL, @pACTION_POST_SQL, @pACTION_ERROR_ACTION_ID, " +
|
|
||||||
"@pENDPOINT_ACTIVE, @pENDPOINT_DESCRIPTION, @pENDPOINT_URI, " +
|
|
||||||
"@pENDPOINT_AUTH_ACTIVE, @pENDPOINT_AUTH_DESCRIPTION, @pENDPOINT_AUTH_TYPE_ID, @pENDPOINT_AUTH_API_KEY, @pENDPOINT_AUTH_API_VALUE, @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, @pENDPOINT_AUTH_TOKEN, @pENDPOINT_AUTH_USERNAME, @pENDPOINT_AUTH_PASSWORD, @pENDPOINT_AUTH_DOMAIN, @pENDPOINT_AUTH_WORKSTATION, " +
|
|
||||||
"@pENDPOINT_PARAMS_ACTIVE, @pENDPOINT_PARAMS_DESCRIPTION, @pENDPOINT_PARAMS_GROUP_ID, @pENDPOINT_PARAMS_SEQUENCE, @pENDPOINT_PARAMS_KEY, @pENDPOINT_PARAMS_VALUE, " +
|
|
||||||
"@pPROFILE_ACTIVE, @pPROFILE_TYPE_ID, @pPROFILE_MANDANTOR, @pPROFILE_NAME, @pPROFILE_DESCRIPTION, @pPROFILE_LOG_LEVEL_ID, @pPROFILE_LANGUAGE_ID, @pPROFILE_FIRST_RUN, @pPROFILE_LAST_RUN, @pPROFILE_LAST_RESULT, " +
|
|
||||||
"@pRESULT_ACTION_ID, @pRESULT_STATUS_ID, @pRESULT_HEADER, @pRESULT_BODY; " +
|
|
||||||
"SELECT @RC;",
|
|
||||||
parameters,
|
|
||||||
cancel);
|
|
||||||
|
|
||||||
// The stored procedure returns 0 on success, error codes > 0 on failure
|
|
||||||
if (result > 0)
|
if (result > 0)
|
||||||
{
|
{
|
||||||
throw new UpdateObjectFailedException(request, $"UpdateObject stored procedure failed with error code: {result}");
|
throw new UpdateObjectFailedException(request, $"UpdateObject stored procedure failed with error code: {result}");
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class DeleteObjectProcedureValidator : AbstractValidator<DeleteObjectProcedure>
|
||||||
|
{
|
||||||
|
public DeleteObjectProcedureValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Entity)
|
||||||
|
.IsInEnum()
|
||||||
|
.WithMessage("ENTITY must be a valid EntityType value.");
|
||||||
|
|
||||||
|
RuleFor(x => x.Start)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.WithMessage("Start GUID/ID must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.End)
|
||||||
|
.GreaterThanOrEqualTo(x => x.Start)
|
||||||
|
.WithMessage("End GUID/ID must be greater than or equal to Start GUID/ID.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,66 +7,60 @@ public class InsertObjectProcedureValidator : AbstractValidator<InsertObjectProc
|
|||||||
{
|
{
|
||||||
public InsertObjectProcedureValidator()
|
public InsertObjectProcedureValidator()
|
||||||
{
|
{
|
||||||
// ENTITY must be one of the allowed values
|
|
||||||
RuleFor(x => x.Entity)
|
RuleFor(x => x.Entity)
|
||||||
.NotEmpty()
|
.IsInEnum()
|
||||||
.Must(e => e is "ACTION" or "ENDPOINT" or "ENDPOINT_AUTH" or "ENDPOINT_PARAMS" or "PROFILE" or "RESULT")
|
.WithMessage("ENTITY must be a valid EntityType value.");
|
||||||
.WithMessage("ENTITY must be one of: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT.");
|
|
||||||
|
|
||||||
// ACTION validation
|
// ACTION validation
|
||||||
When(x => x.Entity == "ACTION", () =>
|
When(x => x.Action != null, () =>
|
||||||
{
|
{
|
||||||
RuleFor(x => x.Action.ProfileId)
|
RuleFor(x => x.Action!.ProfileId)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.WithMessage("ACTION requires ActionProfileId (maps to @pACTION_PROFILE_ID).");
|
.WithMessage("ACTION requires ActionProfileId (maps to @pACTION_PROFILE_ID).");
|
||||||
|
|
||||||
RuleFor(x => x.Action.EndpointId)
|
RuleFor(x => x.Action!.EndpointId)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.WithMessage("ACTION requires ActionEndpointId (maps to @pACTION_ENDPOINT_ID).");
|
.WithMessage("ACTION requires ActionEndpointId (maps to @pACTION_ENDPOINT_ID).");
|
||||||
});
|
});
|
||||||
|
|
||||||
// ENDPOINT validation
|
// ENDPOINT validation
|
||||||
When(x => x.Entity == "ENDPOINT", () =>
|
When(x => x.Endpoint != null, () =>
|
||||||
{
|
{
|
||||||
RuleFor(x => x.Endpoint.Uri)
|
RuleFor(x => x.Endpoint!.Uri)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("ENDPOINT requires EndpointUri (maps to @pENDPOINT_URI).")
|
.WithMessage("ENDPOINT requires EndpointUri (maps to @pENDPOINT_URI).")
|
||||||
.MaximumLength(2000);
|
.MaximumLength(2000);
|
||||||
});
|
});
|
||||||
|
|
||||||
// PROFILE validation
|
// PROFILE validation
|
||||||
When(x => x.Entity == "PROFILE", () =>
|
When(x => x.Profile != null, () =>
|
||||||
{
|
{
|
||||||
RuleFor(x => x.Profile.Name)
|
RuleFor(x => x.Profile!.Name)
|
||||||
.NotEmpty()
|
.NotEmpty()
|
||||||
.WithMessage("PROFILE requires ProfileName (maps to @pPROFILE_NAME).")
|
.WithMessage("PROFILE requires ProfileName (maps to @pPROFILE_NAME).")
|
||||||
.MaximumLength(50);
|
.MaximumLength(50);
|
||||||
|
|
||||||
RuleFor(x => x.Profile.Mandantor)
|
RuleFor(x => x.Profile!.Mandantor)
|
||||||
.MaximumLength(50)
|
.MaximumLength(50)
|
||||||
.When(x => x.Profile.Mandantor != null);
|
.When(x => x.Profile!.Mandantor != null);
|
||||||
|
|
||||||
RuleFor(x => x.Profile.Description)
|
RuleFor(x => x.Profile!.Description)
|
||||||
.MaximumLength(250)
|
.MaximumLength(250)
|
||||||
.When(x => x.Profile.Description != null);
|
.When(x => x.Profile!.Description != null);
|
||||||
});
|
});
|
||||||
|
|
||||||
// RESULT validation
|
// RESULT validation
|
||||||
When(x => x.Entity == "RESULT", () =>
|
When(x => x.Result != null, () =>
|
||||||
{
|
{
|
||||||
RuleFor(x => x.Result.ActionId)
|
RuleFor(x => x.Result!.ActionId)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.WithMessage("RESULT requires ResultActionId (maps to @pRESULT_ACTION_ID).");
|
.WithMessage("RESULT requires ResultActionId (maps to @pRESULT_ACTION_ID).");
|
||||||
|
|
||||||
RuleFor(x => x.Result.StatusId)
|
|
||||||
.NotNull()
|
|
||||||
.WithMessage("RESULT requires ResultStatusId (maps to @pRESULT_STATUS_ID).");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// ENDPOINT_PARAMS validation
|
// ENDPOINT_PARAMS validation
|
||||||
When(x => x.Entity == "ENDPOINT_PARAMS", () =>
|
When(x => x.EndpointParams != null, () =>
|
||||||
{
|
{
|
||||||
RuleFor(x => x.EndpointParams.GroupId)
|
RuleFor(x => x.EndpointParams!.GroupId)
|
||||||
.NotNull()
|
.NotNull()
|
||||||
.WithMessage("ENDPOINT_PARAMS requires EndpointParamsGroupId (maps to @pENDPOINT_PARAMS_GROUP_ID).");
|
.WithMessage("ENDPOINT_PARAMS requires EndpointParamsGroupId (maps to @pENDPOINT_PARAMS_GROUP_ID).");
|
||||||
});
|
});
|
||||||
@@ -76,12 +70,12 @@ public class InsertObjectProcedureValidator : AbstractValidator<InsertObjectProc
|
|||||||
.MaximumLength(50)
|
.MaximumLength(50)
|
||||||
.When(x => x.AddedWho != null);
|
.When(x => x.AddedWho != null);
|
||||||
|
|
||||||
RuleFor(x => x.Endpoint.Description)
|
RuleFor(x => x.Endpoint!.Description)
|
||||||
.MaximumLength(250)
|
.MaximumLength(250)
|
||||||
.When(x => x.Endpoint.Description != null);
|
.When(x => x.Endpoint is { Description: not null });
|
||||||
|
|
||||||
RuleFor(x => x.EndpointAuth.Description)
|
RuleFor(x => x.EndpointAuth!.Description)
|
||||||
.MaximumLength(250)
|
.MaximumLength(250)
|
||||||
.When(x => x.EndpointAuth.Description != null);
|
.When(x => x.EndpointAuth is { Description: not null });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using ReC.Application.Results.Commands;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class InsertResultCommandValidator : AbstractValidator<InsertResultCommand>
|
||||||
|
{
|
||||||
|
public InsertResultCommandValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.ActionId)
|
||||||
|
.NotNull()
|
||||||
|
.WithMessage("ActionId is required.")
|
||||||
|
.GreaterThan(0L)
|
||||||
|
.When(x => x.ActionId.HasValue)
|
||||||
|
.WithMessage("ActionId must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.References.BatchId)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("BatchId is required.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using MediatR;
|
||||||
|
using ReC.Application.RecActions.Commands;
|
||||||
|
using ReC.Application.Results.Queries;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class InvokeBatchRecActionViewsCommandValidator : AbstractValidator<InvokeBatchRecActionViewsCommand>
|
||||||
|
{
|
||||||
|
public InvokeBatchRecActionViewsCommandValidator(ISender sender)
|
||||||
|
{
|
||||||
|
RuleFor(x => x.References.BatchId)
|
||||||
|
.NotEmpty()
|
||||||
|
.WithMessage("BatchId is required.")
|
||||||
|
.MustAsync(async (batchId, cancel) =>
|
||||||
|
{
|
||||||
|
var any = await sender.Send(new AnyResultViewQuery(BatchId: batchId), cancel);
|
||||||
|
return !any;
|
||||||
|
})
|
||||||
|
.WithMessage(x => $"Cannot invoke rec actions for batch '{x.References.BatchId}' because there are already results associated with it.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using ReC.Application.Profile.Queries;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class ReadProfileViewQueryValidator : AbstractValidator<ReadProfileViewQuery>
|
||||||
|
{
|
||||||
|
public ReadProfileViewQueryValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Id)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.When(x => x.Id.HasValue)
|
||||||
|
.WithMessage("Id must be greater than 0.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using ReC.Application.RecActions.Queries;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class ReadRecActionViewQueryValidator : AbstractValidator<ReadRecActionViewQuery>
|
||||||
|
{
|
||||||
|
public ReadRecActionViewQueryValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.ProfileId)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.When(x => x.ProfileId.HasValue)
|
||||||
|
.WithMessage("ProfileId must be greater than 0.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using ReC.Application.Results.Queries;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class ReadResultViewQueryValidator : AbstractValidator<ReadResultViewQuery>
|
||||||
|
{
|
||||||
|
public ReadResultViewQueryValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x)
|
||||||
|
.Must(x => x.Id.HasValue || x.ActionId.HasValue || x.ProfileId.HasValue || x.BatchId is not null)
|
||||||
|
.WithMessage("At least one filter (Id, ActionId, ProfileId or BatchId) must be provided.");
|
||||||
|
|
||||||
|
RuleFor(x => x.Id)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.When(x => x.Id.HasValue)
|
||||||
|
.WithMessage("Id must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.ActionId)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.When(x => x.ActionId.HasValue)
|
||||||
|
.WithMessage("ActionId must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.ProfileId)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.When(x => x.ProfileId.HasValue)
|
||||||
|
.WithMessage("ProfileId must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.BatchId)
|
||||||
|
.NotEmpty()
|
||||||
|
.When(x => x.BatchId is not null)
|
||||||
|
.WithMessage("BatchId must not be empty when provided.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
|
|
||||||
|
namespace ReC.Application.Common.Validations;
|
||||||
|
|
||||||
|
public class UpdateObjectProcedureValidator : AbstractValidator<UpdateObjectProcedure>
|
||||||
|
{
|
||||||
|
public UpdateObjectProcedureValidator()
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Entity)
|
||||||
|
.IsInEnum()
|
||||||
|
.WithMessage("ENTITY must be a valid EntityType value.");
|
||||||
|
|
||||||
|
RuleFor(x => x.Id)
|
||||||
|
.GreaterThan(0)
|
||||||
|
.WithMessage("Target GUID/ID must be greater than 0.");
|
||||||
|
|
||||||
|
RuleFor(x => x.ChangedWho)
|
||||||
|
.MaximumLength(50)
|
||||||
|
.When(x => x.ChangedWho != null);
|
||||||
|
|
||||||
|
When(x => x.Endpoint is { Description: not null }, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Endpoint.Description)
|
||||||
|
.MaximumLength(250);
|
||||||
|
});
|
||||||
|
|
||||||
|
When(x => x.EndpointAuth is { Description: not null }, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.EndpointAuth.Description)
|
||||||
|
.MaximumLength(250);
|
||||||
|
});
|
||||||
|
|
||||||
|
When(x => x.Profile is { Name: not null }, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Profile.Name)
|
||||||
|
.MaximumLength(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
When(x => x.Profile is { Mandantor: not null }, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Profile.Mandantor)
|
||||||
|
.MaximumLength(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
When(x => x.Profile is { Description: not null }, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Profile.Description)
|
||||||
|
.MaximumLength(250);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ using MediatR;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using ReC.Application.Common.Behaviors;
|
using ReC.Application.Common.Behaviors;
|
||||||
|
using ReC.Application.Common.Behaviors.Action;
|
||||||
using ReC.Application.Common.Behaviors.InvokeAction;
|
using ReC.Application.Common.Behaviors.InvokeAction;
|
||||||
using ReC.Application.Common.Constants;
|
using ReC.Application.Common.Constants;
|
||||||
using ReC.Application.Common.Options;
|
using ReC.Application.Common.Options;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.EndpointAuth.Commands;
|
namespace ReC.Application.EndpointAuth.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class DeleteEndpointAuthProcedureHandler(ISender sender) : IRequestHandle
|
|||||||
{
|
{
|
||||||
return await sender.Send(new DeleteObjectProcedure
|
return await sender.Send(new DeleteObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT_AUTH",
|
Entity = EntityType.EndpointAuth,
|
||||||
Start = request.Start,
|
Start = request.Start,
|
||||||
End = request.End,
|
End = request.End,
|
||||||
Force = request.Force
|
Force = request.Force
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.EndpointAuth.Commands;
|
namespace ReC.Application.EndpointAuth.Commands;
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ public class InsertEndpointAuthProcedureHandler(ISender sender) : IRequestHandle
|
|||||||
{
|
{
|
||||||
return await sender.Send(new InsertObjectProcedure
|
return await sender.Send(new InsertObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT_AUTH",
|
Entity = EntityType.EndpointAuth,
|
||||||
EndpointAuth = request
|
EndpointAuth = request
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.EndpointAuth.Commands;
|
namespace ReC.Application.EndpointAuth.Commands;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class UpdateEndpointAuthProcedureHandler(ISender sender) : IRequestHandle
|
|||||||
{
|
{
|
||||||
return await sender.Send(new UpdateObjectProcedure
|
return await sender.Send(new UpdateObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT_AUTH",
|
Entity = EntityType.EndpointAuth,
|
||||||
Id = request.Id,
|
Id = request.Id,
|
||||||
EndpointAuth = request.Data
|
EndpointAuth = request.Data
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.EndpointParams.Commands;
|
namespace ReC.Application.EndpointParams.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class DeleteEndpointParamsProcedureHandler(ISender sender) : IRequestHand
|
|||||||
{
|
{
|
||||||
return await sender.Send(new DeleteObjectProcedure
|
return await sender.Send(new DeleteObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT_PARAMS",
|
Entity = EntityType.EndpointParams,
|
||||||
Start = request.Start,
|
Start = request.Start,
|
||||||
End = request.End,
|
End = request.End,
|
||||||
Force = request.Force
|
Force = request.Force
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.EndpointParams.Commands;
|
namespace ReC.Application.EndpointParams.Commands;
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ public class InsertEndpointParamsProcedureHandler(ISender sender) : IRequestHand
|
|||||||
{
|
{
|
||||||
return await sender.Send(new InsertObjectProcedure
|
return await sender.Send(new InsertObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT_PARAMS",
|
Entity = EntityType.EndpointParams,
|
||||||
EndpointParams = request
|
EndpointParams = request
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.EndpointParams.Commands;
|
namespace ReC.Application.EndpointParams.Commands;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class UpdateEndpointParamsProcedureHandler(ISender sender) : IRequestHand
|
|||||||
{
|
{
|
||||||
return await sender.Send(new UpdateObjectProcedure
|
return await sender.Send(new UpdateObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT_PARAMS",
|
Entity = EntityType.EndpointParams,
|
||||||
Id = request.Id,
|
Id = request.Id,
|
||||||
EndpointParams = request.Data
|
EndpointParams = request.Data
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Endpoints.Commands;
|
namespace ReC.Application.Endpoints.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class DeleteEndpointProcedureHandler(ISender sender) : IRequestHandler<De
|
|||||||
{
|
{
|
||||||
return await sender.Send(new DeleteObjectProcedure
|
return await sender.Send(new DeleteObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT",
|
Entity = EntityType.Endpoint,
|
||||||
Start = request.Start,
|
Start = request.Start,
|
||||||
End = request.End,
|
End = request.End,
|
||||||
Force = request.Force
|
Force = request.Force
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Endpoints.Commands;
|
namespace ReC.Application.Endpoints.Commands;
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ public class InsertEndpointProcedureHandler(ISender sender) : IRequestHandler<In
|
|||||||
{
|
{
|
||||||
return await sender.Send(new InsertObjectProcedure
|
return await sender.Send(new InsertObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT",
|
Entity = EntityType.Endpoint,
|
||||||
Endpoint = request
|
Endpoint = request
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Endpoints.Commands;
|
namespace ReC.Application.Endpoints.Commands;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class UpdateEndpointProcedureHandler(ISender sender) : IRequestHandler<Up
|
|||||||
{
|
{
|
||||||
return await sender.Send(new UpdateObjectProcedure
|
return await sender.Send(new UpdateObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ENDPOINT",
|
Entity = EntityType.Endpoint,
|
||||||
Id = request.Id,
|
Id = request.Id,
|
||||||
Endpoint = request.Data
|
Endpoint = request.Data
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Profile.Commands;
|
namespace ReC.Application.Profile.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class DeleteProfileProcedureHandler(ISender sender) : IRequestHandler<Del
|
|||||||
{
|
{
|
||||||
return await sender.Send(new DeleteObjectProcedure
|
return await sender.Send(new DeleteObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "PROFILE",
|
Entity = EntityType.Profile,
|
||||||
Start = request.Start,
|
Start = request.Start,
|
||||||
End = request.End,
|
End = request.End,
|
||||||
Force = request.Force
|
Force = request.Force
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Profile.Commands;
|
namespace ReC.Application.Profile.Commands;
|
||||||
|
|
||||||
@@ -20,7 +21,7 @@ public class InsertProfileProcedureHandler(ISender sender) : IRequestHandler<Ins
|
|||||||
{
|
{
|
||||||
return await sender.Send(new InsertObjectProcedure
|
return await sender.Send(new InsertObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "PROFILE",
|
Entity = EntityType.Profile,
|
||||||
Profile = request
|
Profile = request
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Profile.Commands;
|
namespace ReC.Application.Profile.Commands;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class UpdateProfileProcedureHandler(ISender sender) : IRequestHandler<Upd
|
|||||||
{
|
{
|
||||||
return await sender.Send(new UpdateObjectProcedure
|
return await sender.Send(new UpdateObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "PROFILE",
|
Entity = EntityType.Profile,
|
||||||
Id = request.Id,
|
Id = request.Id,
|
||||||
Profile = request.Data
|
Profile = request.Data
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AutoMapper" Version="15.1.0" />
|
<PackageReference Include="AutoMapper" Version="16.1.1" />
|
||||||
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.6.0" />
|
<PackageReference Include="DigitalData.Core.Abstraction.Application" Version="1.6.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
<PackageReference Include="DigitalData.Core.Application" Version="3.4.0" />
|
||||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.1" />
|
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.1" />
|
||||||
@@ -23,9 +23,4 @@
|
|||||||
<ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" />
|
<ProjectReference Include="..\ReC.Domain\ReC.Domain.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Common\Behaviors\Action\" />
|
|
||||||
<Folder Include="Common\Options\DbModel\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.RecActions.Commands;
|
namespace ReC.Application.RecActions.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class DeleteActionProcedureHandler(ISender sender) : IRequestHandler<Dele
|
|||||||
{
|
{
|
||||||
return await sender.Send(new DeleteObjectProcedure
|
return await sender.Send(new DeleteObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ACTION",
|
Entity = EntityType.Action,
|
||||||
Start = request.Start,
|
Start = request.Start,
|
||||||
End = request.End,
|
End = request.End,
|
||||||
Force = request.Force
|
Force = request.Force
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
using ReC.Domain.Constants;
|
using ReC.Domain.Constants;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.RecActions.Commands;
|
namespace ReC.Application.RecActions.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class InsertActionProcedureHandler(ISender sender) : IRequestHandler<Inse
|
|||||||
{
|
{
|
||||||
return await sender.Send(new InsertObjectProcedure
|
return await sender.Send(new InsertObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ACTION",
|
Entity = EntityType.Action,
|
||||||
Action = request
|
Action = request
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ namespace ReC.Application.RecActions.Commands;
|
|||||||
public record InvokeBatchRecActionViewsCommand : IRequest
|
public record InvokeBatchRecActionViewsCommand : IRequest
|
||||||
{
|
{
|
||||||
public long ProfileId { get; init; }
|
public long ProfileId { get; init; }
|
||||||
|
public required InvokeReferences References { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InvokeRecActionViewsCommandHandler(ISender sender, ILogger<InvokeRecActionViewsCommandHandler>? logger = null) : IRequestHandler<InvokeBatchRecActionViewsCommand>
|
public class InvokeRecActionViewsCommandHandler(ISender sender, ILogger<InvokeRecActionViewsCommandHandler>? logger = null) : IRequestHandler<InvokeBatchRecActionViewsCommand>
|
||||||
@@ -21,7 +22,11 @@ public class InvokeRecActionViewsCommandHandler(ISender sender, ILogger<InvokeRe
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await sender.Send(new InvokeRecActionViewCommand() { Action = action }, cancel);
|
await sender.Send(new InvokeRecActionViewCommand()
|
||||||
|
{
|
||||||
|
Action = action,
|
||||||
|
References = request.References
|
||||||
|
}, cancel);
|
||||||
}
|
}
|
||||||
catch (RecActionException ex)
|
catch (RecActionException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using ReC.Application.Common.Exceptions;
|
|||||||
using ReC.Application.Common.Options;
|
using ReC.Application.Common.Options;
|
||||||
using ReC.Application.Results.Commands;
|
using ReC.Application.Results.Commands;
|
||||||
using ReC.Domain.Constants;
|
using ReC.Domain.Constants;
|
||||||
|
using ReC.Domain.Views;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -17,6 +18,17 @@ namespace ReC.Application.RecActions.Commands;
|
|||||||
public record InvokeRecActionViewCommand : IRequest
|
public record InvokeRecActionViewCommand : IRequest
|
||||||
{
|
{
|
||||||
public RecActionViewDto Action { get; set; } = null!;
|
public RecActionViewDto Action { get; set; } = null!;
|
||||||
|
public required InvokeReferences References { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record InvokeReferences
|
||||||
|
{
|
||||||
|
public required string BatchId { get; init; }
|
||||||
|
public string? Reference1 { get; init; }
|
||||||
|
public string? Reference2 { get; init; }
|
||||||
|
public string? Reference3 { get; init; }
|
||||||
|
public string? Reference4 { get; init; }
|
||||||
|
public string? Reference5 { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InvokeRecActionViewCommandHandler(
|
public class InvokeRecActionViewCommandHandler(
|
||||||
@@ -142,24 +154,26 @@ public class InvokeRecActionViewCommandHandler(
|
|||||||
var resBody = await response.Content.ReadAsStringAsync(cancel);
|
var resBody = await response.Content.ReadAsStringAsync(cancel);
|
||||||
var resHeaders = response.Headers.ToDictionary();
|
var resHeaders = response.Headers.ToDictionary();
|
||||||
|
|
||||||
var statusCode = (short)response.StatusCode;
|
|
||||||
|
|
||||||
await sender.Send(new InsertResultCommand()
|
await sender.Send(new InsertResultCommand()
|
||||||
{
|
{
|
||||||
StatusId = statusCode,
|
Status = response.StatusCode.ToRecStatus(),
|
||||||
ActionId = action.Id,
|
ActionId = action.Id,
|
||||||
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
||||||
Body = resBody,
|
Body = resBody,
|
||||||
Type = ResultType.Main
|
Info = (short)response.StatusCode,
|
||||||
|
Type = ResultType.Main,
|
||||||
|
References = request.References
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
await sender.Send(new InsertResultCommand()
|
await sender.Send(new InsertResultCommand()
|
||||||
{
|
{
|
||||||
|
Status = RecStatus.Error,
|
||||||
ActionId = action.Id,
|
ActionId = action.Id,
|
||||||
Error = ex.ToString(),
|
Error = ex.ToString(),
|
||||||
Type = ResultType.Main
|
Type = ResultType.Main,
|
||||||
|
References = request.References
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|
||||||
if (action.ErrorAction == ErrorAction.Stop)
|
if (action.ErrorAction == ErrorAction.Stop)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.RecActions.Commands;
|
namespace ReC.Application.RecActions.Commands;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class UpdateActionProcedureHandler(ISender sender) : IRequestHandler<Upda
|
|||||||
{
|
{
|
||||||
return await sender.Send(new UpdateObjectProcedure
|
return await sender.Send(new UpdateObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "ACTION",
|
Entity = EntityType.Action,
|
||||||
Id = request.Id,
|
Id = request.Id,
|
||||||
Action = request.Data
|
Action = request.Data
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Results.Commands;
|
namespace ReC.Application.Results.Commands;
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ public class DeleteResultProcedureHandler(ISender sender) : IRequestHandler<Dele
|
|||||||
{
|
{
|
||||||
return await sender.Send(new DeleteObjectProcedure
|
return await sender.Send(new DeleteObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "RESULT",
|
Entity = EntityType.Result,
|
||||||
Start = request.Start,
|
Start = request.Start,
|
||||||
End = request.End,
|
End = request.End,
|
||||||
Force = request.Force
|
Force = request.Force
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
|
using ReC.Application.RecActions.Commands;
|
||||||
using ReC.Domain.Constants;
|
using ReC.Domain.Constants;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Results.Commands;
|
namespace ReC.Application.Results.Commands;
|
||||||
|
|
||||||
public record InsertResultCommand : IInsertProcedure
|
public record InsertResultCommand : IInsertProcedure
|
||||||
{
|
{
|
||||||
public long? ActionId { get; set; }
|
public long? ActionId { get; set; }
|
||||||
public short? StatusId { get; set; }
|
public required RecStatus Status { get; set; }
|
||||||
public string? Header { get; set; }
|
public string? Header { get; set; }
|
||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
public string? Info { get; set; }
|
public short Info { get; set; }
|
||||||
|
public string? InfoDetail { get; set; }
|
||||||
public string? Error { get; set; }
|
public string? Error { get; set; }
|
||||||
public required ResultType Type { get; set; }
|
public required ResultType Type { get; set; }
|
||||||
|
public required InvokeReferences References { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class InsertResultProcedureHandler(ISender sender) : IRequestHandler<InsertResultCommand, long>
|
public class InsertResultProcedureHandler(ISender sender) : IRequestHandler<InsertResultCommand, long>
|
||||||
@@ -21,7 +25,7 @@ public class InsertResultProcedureHandler(ISender sender) : IRequestHandler<Inse
|
|||||||
{
|
{
|
||||||
return await sender.Send(new InsertObjectProcedure
|
return await sender.Send(new InsertObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "RESULT",
|
Entity = EntityType.Result,
|
||||||
Result = request
|
Result = request
|
||||||
}, cancel);
|
}, cancel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using MediatR;
|
using MediatR;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||||
|
using ReC.Application.Common.Procedures;
|
||||||
|
|
||||||
namespace ReC.Application.Results.Commands;
|
namespace ReC.Application.Results.Commands;
|
||||||
|
|
||||||
@@ -17,7 +18,7 @@ public class UpdateResultProcedureHandler(ISender sender) : IRequestHandler<Upda
|
|||||||
{
|
{
|
||||||
return await sender.Send(new UpdateObjectProcedure
|
return await sender.Send(new UpdateObjectProcedure
|
||||||
{
|
{
|
||||||
Entity = "RESULT",
|
Entity = EntityType.Result,
|
||||||
Id = request.Id,
|
Id = request.Id,
|
||||||
Result = request.Data
|
Result = request.Data
|
||||||
}, cancel);
|
}, cancel);
|
||||||
|
|||||||
35
src/ReC.Application/Results/Queries/AnyResultViewQuery.cs
Normal file
35
src/ReC.Application/Results/Queries/AnyResultViewQuery.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using DigitalData.Core.Abstraction.Application.Repository;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using ReC.Domain.Views;
|
||||||
|
|
||||||
|
namespace ReC.Application.Results.Queries;
|
||||||
|
|
||||||
|
public record AnyResultViewQuery(
|
||||||
|
long? Id = null,
|
||||||
|
long? ActionId = null,
|
||||||
|
long? ProfileId = null,
|
||||||
|
string? BatchId = null
|
||||||
|
) : IRequest<bool>;
|
||||||
|
|
||||||
|
public class AnyResultViewQueryHandler(IRepository<ResultView> repo) : IRequestHandler<AnyResultViewQuery, bool>
|
||||||
|
{
|
||||||
|
public Task<bool> Handle(AnyResultViewQuery request, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
var q = repo.Query;
|
||||||
|
|
||||||
|
if(request.Id is long id)
|
||||||
|
q = q.Where(rv => rv.Id == id);
|
||||||
|
|
||||||
|
if(request.ActionId is long actionId)
|
||||||
|
q = q.Where(rv => rv.ActionId == actionId);
|
||||||
|
|
||||||
|
if(request.ProfileId is long profileId)
|
||||||
|
q = q.Where(rv => rv.ProfileId == profileId);
|
||||||
|
|
||||||
|
if(request.BatchId is string batchId)
|
||||||
|
q = q.Where(rv => rv.BatchId == batchId);
|
||||||
|
|
||||||
|
return q.AnyAsync(cancel);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,13 @@ public record ReadResultViewQuery : IRequest<IEnumerable<ResultViewDto>>
|
|||||||
|
|
||||||
public long? ProfileId { get; init; } = null;
|
public long? ProfileId { get; init; } = null;
|
||||||
|
|
||||||
|
public string? BatchId { get; init; } = null;
|
||||||
|
|
||||||
public bool IncludeAction { get; init; } = true;
|
public bool IncludeAction { get; init; } = true;
|
||||||
|
|
||||||
public bool IncludeProfile { get; init; } = false;
|
public bool IncludeProfile { get; init; } = false;
|
||||||
|
|
||||||
public bool Last { get; init; } = false;
|
public bool LastBatch { get; init; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper mapper) : IRequestHandler<ReadResultViewQuery, IEnumerable<ResultViewDto>>
|
public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper mapper) : IRequestHandler<ReadResultViewQuery, IEnumerable<ResultViewDto>>
|
||||||
@@ -39,13 +41,18 @@ public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper ma
|
|||||||
if(request.ProfileId is long profileId)
|
if(request.ProfileId is long profileId)
|
||||||
q = q.Where(rv => rv.ProfileId == profileId);
|
q = q.Where(rv => rv.ProfileId == profileId);
|
||||||
|
|
||||||
if(request.IncludeAction)
|
if(request.BatchId is string batchId)
|
||||||
|
q = q.Where(rv => rv.BatchId == batchId);
|
||||||
|
|
||||||
|
if (request.IncludeAction)
|
||||||
q = q.Include(rv => rv.Action);
|
q = q.Include(rv => rv.Action);
|
||||||
|
|
||||||
if(request.IncludeProfile)
|
if(request.IncludeProfile)
|
||||||
q = q.Include(rv => rv.Profile);
|
q = q.Include(rv => rv.Profile);
|
||||||
|
|
||||||
var entities = request.Last ? [await q.OrderBy(rv => rv.AddedWhen).LastOrDefaultAsync(cancel)] : await q.ToListAsync(cancel);
|
var entities = request.LastBatch
|
||||||
|
? await GetLastBatchEntitiesAsync(q, cancel)
|
||||||
|
: await q.ToListAsync(cancel);
|
||||||
|
|
||||||
if (entities.Count == 0)
|
if (entities.Count == 0)
|
||||||
throw new NotFoundException($"No result views found for the given criteria. Criteria: {
|
throw new NotFoundException($"No result views found for the given criteria. Criteria: {
|
||||||
@@ -58,4 +65,20 @@ public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper ma
|
|||||||
|
|
||||||
return mapper.Map<IEnumerable<ResultViewDto>>(entities);
|
return mapper.Map<IEnumerable<ResultViewDto>>(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task<List<ResultView>> GetLastBatchEntitiesAsync(IQueryable<ResultView> q, CancellationToken cancel)
|
||||||
|
{
|
||||||
|
var lastBatchId = await q
|
||||||
|
.Where(rv => rv.BatchId != null)
|
||||||
|
.OrderByDescending(rv => rv.AddedWhen)
|
||||||
|
.Select(rv => rv.BatchId)
|
||||||
|
.FirstOrDefaultAsync(cancel);
|
||||||
|
|
||||||
|
if (lastBatchId is null)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return await q
|
||||||
|
.Where(rv => rv.BatchId == lastBatchId)
|
||||||
|
.ToListAsync(cancel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
50
src/ReC.Client/Api/InvokeReferences.cs
Normal file
50
src/ReC.Client/Api/InvokeReferences.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
namespace ReC.Client.Api
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Optional reference values that are passed through to all result records when invoking a profile.
|
||||||
|
/// </summary>
|
||||||
|
public class InvokeReferences
|
||||||
|
{
|
||||||
|
/// <summary>Batch identifier.</summary>
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
BatchId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Reference value 1.</summary>
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Reference1 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Reference value 2.</summary>
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Reference2 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Reference value 3.</summary>
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Reference3 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Reference value 4.</summary>
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Reference4 { get; set; }
|
||||||
|
|
||||||
|
/// <summary>Reference value 5.</summary>
|
||||||
|
public string
|
||||||
|
#if NET
|
||||||
|
?
|
||||||
|
#endif
|
||||||
|
Reference5 { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,14 +21,28 @@ namespace ReC.Client.Api
|
|||||||
/// Invokes a ReC action for the specified profile.
|
/// Invokes a ReC action for the specified profile.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="profileId">The profile identifier.</param>
|
/// <param name="profileId">The profile identifier.</param>
|
||||||
|
/// <param name="references">Optional reference values to pass through to all result records.</param>
|
||||||
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||||
/// <returns><see langword="true"/> if the request succeeds; otherwise, <see langword="false"/>.</returns>
|
/// <returns><see langword="true"/> if the request succeeds; otherwise, <see langword="false"/>.</returns>
|
||||||
public async Task<bool> InvokeAsync(int profileId, CancellationToken cancellationToken = default)
|
public async Task<bool> InvokeAsync(int profileId, InvokeReferences references, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var resp = await Http.PostAsync($"{ResourcePath}/invoke/{profileId}", content: null, cancellationToken);
|
var content = references != null ? ReCClientHelpers.ToJsonContent(references) : null;
|
||||||
|
var resp = await Http.PostAsync($"{ResourcePath}/invoke/{profileId}", content, cancellationToken);
|
||||||
return resp.IsSuccessStatusCode;
|
return resp.IsSuccessStatusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes a ReC action for the specified profile.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="profileId">The profile identifier.</param>
|
||||||
|
/// <param name="batchId">Batch identifier.</param>
|
||||||
|
/// <param name="cancellationToken">A token to cancel the operation.</param>
|
||||||
|
/// <returns><see langword="true"/> if the request succeeds; otherwise, <see langword="false"/>.</returns>
|
||||||
|
public Task<bool> InvokeAsync(int profileId, string batchId, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return InvokeAsync(profileId, new InvokeReferences() { BatchId = batchId }, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves Rec actions.
|
/// Retrieves Rec actions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
23
src/ReC.Domain/Constants/RecStatus.cs
Normal file
23
src/ReC.Domain/Constants/RecStatus.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
namespace ReC.Domain.Constants;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the general outcome of an operation, independent of any specific technology or protocol.
|
||||||
|
/// <para>
|
||||||
|
/// Technology-specific details (e.g., HTTP status codes) are stored separately
|
||||||
|
/// in the <c>RESULT_INFO</c> and <c>RESULT_INFO_DETAIL</c> fields.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="RecStatusExtensions"/>
|
||||||
|
public enum RecStatus : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the operation completed successfully (value 0).
|
||||||
|
/// </summary>
|
||||||
|
OK = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates that the operation failed (value 1).
|
||||||
|
/// When set, the <c>RESULT_ERROR</c> field should contain the error details.
|
||||||
|
/// </summary>
|
||||||
|
Error = 1
|
||||||
|
}
|
||||||
16
src/ReC.Domain/Constants/RecStatusExtensions.cs
Normal file
16
src/ReC.Domain/Constants/RecStatusExtensions.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System.Net;
|
||||||
|
|
||||||
|
namespace ReC.Domain.Constants;
|
||||||
|
|
||||||
|
public static class RecStatusExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts an <see cref="HttpStatusCode"/> to a general <see cref="RecStatus"/>
|
||||||
|
/// based on whether the HTTP status represents a success (2xx) or an error.
|
||||||
|
/// </summary>
|
||||||
|
public static RecStatus ToRecStatus(this HttpStatusCode code)
|
||||||
|
{
|
||||||
|
int value = (int)code;
|
||||||
|
return value >= 200 && value <= 299 ? RecStatus.OK : RecStatus.Error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
namespace ReC.Domain.Constants;
|
namespace ReC.Domain.Constants;
|
||||||
|
|
||||||
public enum ResultType
|
public enum ResultType : byte
|
||||||
{
|
{
|
||||||
Pre = 1,
|
Pre = 1,
|
||||||
Main,
|
Main,
|
||||||
|
|||||||
@@ -33,6 +33,9 @@ public class RecActionView
|
|||||||
[Column("PROFILE_TYPE_ID")]
|
[Column("PROFILE_TYPE_ID")]
|
||||||
public ProfileType? ProfileType { get; set; }
|
public ProfileType? ProfileType { get; set; }
|
||||||
|
|
||||||
|
[Column("PROFILE_TYPE")]
|
||||||
|
public string? ProfileTypeName { get; set; }
|
||||||
|
|
||||||
[Column("SEQUENCE")]
|
[Column("SEQUENCE")]
|
||||||
public byte? Sequence { get; set; }
|
public byte? Sequence { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public class ResultView
|
|||||||
public string? ProfileName { get; set; }
|
public string? ProfileName { get; set; }
|
||||||
|
|
||||||
[Column("STATUS_ID")]
|
[Column("STATUS_ID")]
|
||||||
public short? StatusCode { get; set; }
|
public RecStatus Status { get; set; }
|
||||||
|
|
||||||
[Column("STATUS")]
|
[Column("STATUS")]
|
||||||
public string? StatusName { get; set; }
|
public string? StatusName { get; set; }
|
||||||
@@ -42,12 +42,36 @@ public class ResultView
|
|||||||
[Column("RESULT_BODY")]
|
[Column("RESULT_BODY")]
|
||||||
public string? Body { get; set; }
|
public string? Body { get; set; }
|
||||||
|
|
||||||
|
[Column("RESULT_INFO_ID")]
|
||||||
|
public short? InfoId { get; set; }
|
||||||
|
|
||||||
[Column("RESULT_INFO")]
|
[Column("RESULT_INFO")]
|
||||||
public string? Info { get; set; }
|
public string? Info { get; set; }
|
||||||
|
|
||||||
|
[Column("RESULT_INFO_DETAIL")]
|
||||||
|
public string? InfoDetail { get; set; }
|
||||||
|
|
||||||
[Column("RESULT_ERROR")]
|
[Column("RESULT_ERROR")]
|
||||||
public string? Error { get; set; }
|
public string? Error { get; set; }
|
||||||
|
|
||||||
|
[Column("BATCH_ID")]
|
||||||
|
public string? BatchId { get; set; }
|
||||||
|
|
||||||
|
[Column("REFERENCE1")]
|
||||||
|
public string? Reference1 { get; set; }
|
||||||
|
|
||||||
|
[Column("REFERENCE2")]
|
||||||
|
public string? Reference2 { get; set; }
|
||||||
|
|
||||||
|
[Column("REFERENCE3")]
|
||||||
|
public string? Reference3 { get; set; }
|
||||||
|
|
||||||
|
[Column("REFERENCE4")]
|
||||||
|
public string? Reference4 { get; set; }
|
||||||
|
|
||||||
|
[Column("REFERENCE5")]
|
||||||
|
public string? Reference5 { get; set; }
|
||||||
|
|
||||||
[Column("ADDED_WHO")]
|
[Column("ADDED_WHO")]
|
||||||
public string? AddedWho { get; set; }
|
public string? AddedWho { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public static class DependencyInjection
|
|||||||
opt.RegisterDefaultRepository<TRecDbContext>();
|
opt.RegisterDefaultRepository<TRecDbContext>();
|
||||||
});
|
});
|
||||||
|
|
||||||
services.AddValidatorsFromAssembly(typeof(AuthScopedValidator).Assembly);
|
services.AddValidatorsFromAssembly(typeof(InsertObjectProcedureValidator).Assembly);
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
250
tests/ReC.Tests/Application/Behaviors/InvokeActionTests.cs
Normal file
250
tests/ReC.Tests/Application/Behaviors/InvokeActionTests.cs
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using ReC.Application.Common.Dto;
|
||||||
|
|
||||||
|
namespace ReC.Tests.Application.Behaviors;
|
||||||
|
|
||||||
|
#region Test Models
|
||||||
|
|
||||||
|
public class Foo
|
||||||
|
{
|
||||||
|
[Column("BAZ")]
|
||||||
|
public int Baz { get; set; }
|
||||||
|
|
||||||
|
[Column("FOO_NAME")]
|
||||||
|
public string FooName { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Bar
|
||||||
|
{
|
||||||
|
[Column("QUX")]
|
||||||
|
public bool Qux { get; set; }
|
||||||
|
|
||||||
|
[Column("BAR_DATE")]
|
||||||
|
public DateTime BarDate { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Fuz
|
||||||
|
{
|
||||||
|
[Column("QUZ")]
|
||||||
|
public string Quz { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[Column("FUZ_OFFSET")]
|
||||||
|
public DateTimeOffset FuzOffset { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NoColumnModel
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class InvokeActionTests
|
||||||
|
{
|
||||||
|
private Foo _foo = null!;
|
||||||
|
private Bar _bar = null!;
|
||||||
|
private Fuz _fuz = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_foo = new Foo { Baz = 2, FooName = "TestFoo" };
|
||||||
|
_bar = new Bar { Qux = true, BarDate = new DateTime(2025, 6, 15, 14, 30, 0) };
|
||||||
|
_fuz = new Fuz { Quz = "QuZ", FuzOffset = new DateTimeOffset(2025, 6, 15, 14, 30, 0, TimeSpan.FromHours(3)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
#region GetValueByColumnName Tests
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_ExistingColumn_ReturnsValue()
|
||||||
|
{
|
||||||
|
var result = _foo.GetValueByColumnName("BAZ");
|
||||||
|
Assert.That(result, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_NonExistingColumn_ReturnsNull()
|
||||||
|
{
|
||||||
|
var result = _foo.GetValueByColumnName("NON_EXISTING");
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_PropertyNameInsteadOfColumnName_ReturnsNull()
|
||||||
|
{
|
||||||
|
var result = _foo.GetValueByColumnName("Baz");
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetValueByColumnName_ModelWithoutColumnAttribute_ReturnsNull()
|
||||||
|
{
|
||||||
|
var model = new NoColumnModel { Id = 1, Name = "Test" };
|
||||||
|
var result = model.GetValueByColumnName("Id");
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Basic Type Tests
|
||||||
|
|
||||||
|
[TestCase("SELECT * FROM T WHERE BAZ = {#INT#BAZ}", "SELECT * FROM T WHERE BAZ = 2")]
|
||||||
|
[TestCase("... WHERE BAZ = {#INT#BAZ}", "... WHERE BAZ = 2")]
|
||||||
|
public void ReplacePlaceholders_IntValue_ReplacesCorrectly(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("SELECT * FROM T WHERE QUX = {#BOOL#QUX}", "SELECT * FROM T WHERE QUX = TRUE")]
|
||||||
|
[TestCase("... WHERE QUX = {#INT#QUX}", "... WHERE QUX = TRUE")]
|
||||||
|
public void ReplacePlaceholders_BoolTrueValue_ReplacesWithTRUE(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_BoolFalseValue_ReplacesWithFALSE()
|
||||||
|
{
|
||||||
|
var bar = new Bar { Qux = false };
|
||||||
|
var result = "WHERE QUX = {#BOOL#QUX}".ReplacePlaceholders(bar);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE QUX = FALSE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("... WHERE QUZ <> '{#STR#QUZ}'", "... WHERE QUZ <> 'QuZ'")]
|
||||||
|
[TestCase("SELECT * FROM T WHERE QUZ = '{#TEXT#QUZ}'", "SELECT * FROM T WHERE QUZ = 'QuZ'")]
|
||||||
|
public void ReplacePlaceholders_StringValue_ReplacesCorrectly(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_DateTimeValue_FormatsAsSqlDateTime()
|
||||||
|
{
|
||||||
|
var result = "WHERE D = '{#DATE#BAR_DATE}'".ReplacePlaceholders(_bar);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE D = '2025-06-15 14:30:00'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_DateTimeOffsetValue_FormatsWithOffset()
|
||||||
|
{
|
||||||
|
var result = "WHERE D = '{#DTO#FUZ_OFFSET}'".ReplacePlaceholders(_fuz);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE D = '2025-06-15 14:30:00 +03:00'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Multiple Placeholders
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_MultiplePlaceholdersInSameString_ReplacesAll()
|
||||||
|
{
|
||||||
|
var input = "WHERE BAZ = {#INT#BAZ} AND QUX = {#BOOL#QUX} AND QUZ = '{#STR#QUZ}'";
|
||||||
|
var expected = "WHERE BAZ = 2 AND QUX = TRUE AND QUZ = 'QuZ'";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_SamePlaceholderTwice_ReplacesBoth()
|
||||||
|
{
|
||||||
|
var input = "WHERE BAZ = {#INT#BAZ} OR BAZ = {#INT#BAZ}";
|
||||||
|
var expected = "WHERE BAZ = 2 OR BAZ = 2";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(_foo);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Object Resolution Order
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_ValueFoundInSecondObject_ReturnsValueFromSecondObject()
|
||||||
|
{
|
||||||
|
var result = "WHERE QUX = {#BOOL#QUX}".ReplacePlaceholders(_foo, _bar);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE QUX = TRUE"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_ValueFoundInThirdObject_ReturnsValueFromThirdObject()
|
||||||
|
{
|
||||||
|
var result = "WHERE QUZ = '{#STR#QUZ}'".ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE QUZ = 'QuZ'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - No Placeholder
|
||||||
|
|
||||||
|
[TestCase("SELECT * FROM T WHERE X = 1")]
|
||||||
|
[TestCase("")]
|
||||||
|
[TestCase("some random text")]
|
||||||
|
public void ReplacePlaceholders_NoPlaceholders_ReturnsOriginalString(string input)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Different Prefix Strings
|
||||||
|
|
||||||
|
[TestCase("WHERE BAZ = {#VAR#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
[TestCase("WHERE BAZ = {#PARAM#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
[TestCase("WHERE BAZ = {#X#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
[TestCase("WHERE BAZ = {#SOME_LONG_PREFIX#BAZ}", "WHERE BAZ = 2")]
|
||||||
|
public void ReplacePlaceholders_DifferentPrefixes_AllResolveCorrectly(string input, string expected)
|
||||||
|
{
|
||||||
|
var result = input.ReplacePlaceholders(_foo);
|
||||||
|
Assert.That(result, Is.EqualTo(expected));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region ReplacePlaceholders - Exception Tests
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_UnresolvableColumn_ReturnsNull()
|
||||||
|
{
|
||||||
|
var input = "WHERE X = {#INT#NON_EXISTING}";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE X = NULL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_NoObjectsProvided_ReturnsNull()
|
||||||
|
{
|
||||||
|
var input = "WHERE X = {#INT#BAZ}";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders();
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE X = NULL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_ObjectWithoutColumnAttributes_ReturnsNull()
|
||||||
|
{
|
||||||
|
var model = new NoColumnModel { Id = 1, Name = "Test" };
|
||||||
|
var input = "WHERE X = {#INT#Id}";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(model);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE X = NULL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReplacePlaceholders_MixedResolvableAndUnresolvable_ReturnsNullForUnresolvable()
|
||||||
|
{
|
||||||
|
var input = "WHERE BAZ = {#INT#BAZ} AND X = {#INT#UNKNOWN}";
|
||||||
|
|
||||||
|
var result = input.ReplacePlaceholders(_foo, _bar, _fuz);
|
||||||
|
Assert.That(result, Is.EqualTo("WHERE BAZ = 2 AND X = NULL"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FluentValidation;
|
||||||
|
using MediatR;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using ReC.Application.RecActions.Commands;
|
||||||
|
using ReC.Application.Results.Queries;
|
||||||
|
|
||||||
|
namespace ReC.Tests.Application.RecActions;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class InvokeBatchDuplicateGuardTests : RecApplicationTestBase
|
||||||
|
{
|
||||||
|
private const long ProfileId = 3;
|
||||||
|
|
||||||
|
private (ISender Sender, IServiceScope Scope) CreateScopedSender()
|
||||||
|
{
|
||||||
|
var scope = ServiceProvider.CreateScope();
|
||||||
|
var sender = scope.ServiceProvider.GetRequiredService<ISender>();
|
||||||
|
return (sender, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Invoke_with_existing_batchId_throws_ValidationException()
|
||||||
|
{
|
||||||
|
var (sender, scope) = CreateScopedSender();
|
||||||
|
using var _ = scope;
|
||||||
|
|
||||||
|
// Arrange: read an existing result to get a real BatchId from the database
|
||||||
|
var results = await sender.Send(new ReadResultViewQuery
|
||||||
|
{
|
||||||
|
ProfileId = ProfileId,
|
||||||
|
IncludeAction = false,
|
||||||
|
LastBatch = true
|
||||||
|
});
|
||||||
|
|
||||||
|
var existingBatchId = results.FirstOrDefault()?.BatchId;
|
||||||
|
Assert.That(existingBatchId, Is.Not.Null.And.Not.Empty,
|
||||||
|
$"No results with a BatchId found for ProfileId {ProfileId}. Ensure test data exists in the database.");
|
||||||
|
|
||||||
|
// Act & Assert: invoking with the same BatchId should throw ValidationException
|
||||||
|
var ex = Assert.ThrowsAsync<ValidationException>(async () =>
|
||||||
|
await sender.Send(new InvokeBatchRecActionViewsCommand
|
||||||
|
{
|
||||||
|
ProfileId = ProfileId,
|
||||||
|
References = new InvokeReferences
|
||||||
|
{
|
||||||
|
BatchId = existingBatchId!
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
Assert.That(ex!.Errors.Any(e => e.PropertyName.Contains("BatchId")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Invoke_with_new_batchId_does_not_throw_duplicate_guard()
|
||||||
|
{
|
||||||
|
var (sender, scope) = CreateScopedSender();
|
||||||
|
using var _ = scope;
|
||||||
|
|
||||||
|
var uniqueBatchId = $"test-{System.Guid.NewGuid():N}";
|
||||||
|
|
||||||
|
// This should NOT throw ValidationException for duplicate BatchId.
|
||||||
|
// It may throw other exceptions (e.g., no actions found, endpoint errors),
|
||||||
|
// but the duplicate guard should pass.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sender.Send(new InvokeBatchRecActionViewsCommand
|
||||||
|
{
|
||||||
|
ProfileId = ProfileId,
|
||||||
|
References = new InvokeReferences
|
||||||
|
{
|
||||||
|
BatchId = uniqueBatchId
|
||||||
|
}
|
||||||
|
}).GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
catch (ValidationException valEx) when (valEx.Errors.Any(e => e.PropertyName.Contains("BatchId")))
|
||||||
|
{
|
||||||
|
Assert.Fail("Duplicate guard should not trigger for a unique BatchId.");
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Other exceptions (endpoint errors, etc.) are acceptable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@@ -5,7 +6,9 @@ using NUnit.Framework;
|
|||||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||||
|
using ReC.Application.RecActions.Commands;
|
||||||
using ReC.Application.Results.Commands;
|
using ReC.Application.Results.Commands;
|
||||||
|
using ReC.Domain.Constants;
|
||||||
using ReC.Tests.Application;
|
using ReC.Tests.Application;
|
||||||
|
|
||||||
namespace ReC.Tests.Application.Results;
|
namespace ReC.Tests.Application.Results;
|
||||||
@@ -23,7 +26,7 @@ public class ResultProcedureTests : RecApplicationTestBase
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task InsertResultProcedure_runs_via_mediator()
|
public async Task InsertResultProcedure_runs_via_mediator()
|
||||||
{
|
{
|
||||||
var procedure = new InsertResultCommand { ActionId = 1, StatusId = 200, Header = "h", Body = "b", Type = Domain.Constants.ResultType.Main };
|
var procedure = new InsertResultCommand { ActionId = 1, Status = HttpStatusCode.OK.ToRecStatus(), Header = "h", Body = "b", Info = 200, Type = ResultType.Main, References = new () { BatchId = DateTime.Now.ToString() } };
|
||||||
|
|
||||||
var (sender, scope) = CreateScopedSender();
|
var (sender, scope) = CreateScopedSender();
|
||||||
using var _ = scope;
|
using var _ = scope;
|
||||||
|
|||||||
Reference in New Issue
Block a user