Compare commits
240 Commits
d8e08b237d
...
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 | |||
| e96773f3c4 | |||
| 06e92b588f | |||
| b922cbbb30 | |||
| 6c56375e3e | |||
| fa9aa23f32 | |||
| b86d0c0f99 | |||
| b0d89ceba4 | |||
| 11ebfdd21e | |||
| 1467acc4a1 | |||
| e761fbd1ca | |||
| 2e83d4a24a | |||
| 37ba85d681 | |||
| a46cd08122 | |||
| 3d46901af5 | |||
| 90e8adbd36 | |||
| aef59def7f | |||
| d7783b6e81 | |||
| 4126f984e4 | |||
| 0e2328c287 | |||
| e04e054151 | |||
| 6082a637fe | |||
| 93669a6358 | |||
| fecd9219b4 | |||
| bd07b4482c | |||
| 520aec427b | |||
| 26b7a82451 | |||
| 08c0d29d84 | |||
| 405b5f3ab1 | |||
| 32af65d30c | |||
| 30ccf05c57 | |||
| a14d5ff112 | |||
| fec125b0d5 | |||
| 82ae4c5957 | |||
| 894b7bb070 | |||
| a707cce6e4 | |||
| 2ca85a2372 | |||
| dbe09cd07b | |||
| 690dcea7a8 | |||
| fdae4d26be | |||
| 2883cf9be4 | |||
| 9410c5dc0d | |||
| 35e99d9f2a | |||
| 5fd65e52a3 | |||
| 2508a8b986 | |||
| daff1477be | |||
| dcfa47c68d | |||
| e691faf620 | |||
| cac33c46df | |||
| de503cac5b | |||
| 4999beda3b | |||
| 5df36d94e0 | |||
| d3d24a0fb6 | |||
| a6b0cbaf9d | |||
| 0162d059da | |||
| 302fee4908 | |||
| 3e10176d98 | |||
| 4f0f99e0f8 | |||
| 8fb4b4005c | |||
| b3bb7144ef | |||
| eff6350d77 | |||
| 114b5de71d | |||
| f786192786 | |||
| 50741bfdd3 | |||
| 561eafe48c | |||
| 84358ced96 | |||
| d2e97a2fef | |||
| d505c8415e | |||
| a590ffd2dc | |||
| 94da75ce37 | |||
| 9c1ffd7df8 | |||
| e31d034266 | |||
| 649d7eff8c | |||
| 401d67de4c | |||
| ed94415a33 | |||
| 04513a3d08 | |||
| d390c3f7b6 | |||
| a40f20f6d9 | |||
| ee1f6a8753 | |||
| 1e35b6e263 | |||
| e152e9a37a | |||
| 554aaa8b6c | |||
| 329d156d08 | |||
| 246362812a | |||
| 71430918ac | |||
| 7a1705365b | |||
| acf136e689 | |||
| 6b4897702a | |||
| 7d4e082958 | |||
| d1dd021952 | |||
| 5afc1791b0 | |||
| 2ec07d7e96 | |||
| cbe4f1ba3c | |||
| 16155da033 | |||
| 0aa1414ea6 | |||
| 181a9a83fd | |||
| 5e3e12bad8 | |||
| 6dcc128ad5 | |||
| 754ef88644 | |||
| 95ece6fdcf | |||
| 87194df697 | |||
| b38d53248c | |||
| 56b604bd35 | |||
| f67579dba9 | |||
| 636397efb8 | |||
| ef4d0767e9 | |||
| f15725ade2 | |||
| 382eef0089 | |||
| 5d316e43b9 | |||
| 0c8d7f6b3c | |||
| 0e7870b556 | |||
| ec119a3045 | |||
| 776813d05d | |||
| 0a3761921d | |||
| 23246d4ebf | |||
| 27d731a5b0 | |||
| b8f797f14d | |||
| 6feef53733 | |||
| 878e096c57 | |||
| 2ded140ad5 | |||
| e2ca249d13 | |||
| e782eab62a |
@@ -25,7 +25,7 @@ public class CommonController(IMediator mediator) : ControllerBase
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
public async Task<IActionResult> DeleteObject([FromBody] DeleteObjectProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> DeleteObject([FromQuery] DeleteObjectProcedure procedure, CancellationToken cancel)
|
||||
{
|
||||
var result = await mediator.Send(procedure, cancel);
|
||||
return Ok(result);
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
namespace ReC.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EndpointAuthController(IMediator mediator, IConfiguration config) : ControllerBase
|
||||
public class EndpointAuthController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Inserts an endpoint authentication record via the ENDPOINT_AUTH insert procedure.
|
||||
@@ -19,38 +17,38 @@ public class EndpointAuthController(IMediator mediator, IConfiguration config) :
|
||||
/// <returns>The created ENDPOINT_AUTH identifier.</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Post([FromBody] InsertEndpointAuthProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Post([FromBody] InsertEndpointAuthCommand procedure, CancellationToken cancel)
|
||||
{
|
||||
var id = await mediator.ExecuteInsertProcedure(procedure, config["AddedWho"], cancel);
|
||||
var id = await mediator.Send(procedure, cancel);
|
||||
return StatusCode(StatusCodes.Status201Created, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an endpoint authentication record via the ENDPOINT_AUTH update procedure.
|
||||
/// </summary>
|
||||
/// <param name="id">ENDPOINT_AUTH identifier to update.</param>
|
||||
/// <param name="procedure">UpdateEndpointAuthProcedure payload.</param>
|
||||
/// <param name="id">The identifier of the ENDPOINT_AUTH record to update.</param>
|
||||
/// <param name="data">UpdateEndpointAuthProcedure payload.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpPut("{id:long}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointAuthProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointAuthDto data, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel);
|
||||
await mediator.Send(new UpdateEndpointAuthCommand() { Id = id, Data = data}, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes endpoint authentication records via the ENDPOINT_AUTH delete procedure for the specified id range.
|
||||
/// </summary>
|
||||
/// <param name="procedure">DeleteEndpointAuthProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="command">DeleteEndpointAuthProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromBody] DeleteEndpointAuthProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteEndpointAuthCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteDeleteProcedure(procedure, cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.EndpointParams.Commands;
|
||||
|
||||
namespace ReC.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EndpointParamsController(IMediator mediator, IConfiguration config) : ControllerBase
|
||||
public class EndpointParamsController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Inserts endpoint parameter records via the ENDPOINT_PARAMS insert procedure.
|
||||
@@ -19,38 +17,38 @@ public class EndpointParamsController(IMediator mediator, IConfiguration config)
|
||||
/// <returns>The created ENDPOINT_PARAMS identifier.</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Post([FromBody] InsertEndpointParamsProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Post([FromBody] InsertEndpointParamsCommand procedure, CancellationToken cancel)
|
||||
{
|
||||
var id = await mediator.ExecuteInsertProcedure(procedure, config["AddedWho"], cancel);
|
||||
var id = await mediator.Send(procedure, cancel);
|
||||
return StatusCode(StatusCodes.Status201Created, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates endpoint parameter records via the ENDPOINT_PARAMS update procedure.
|
||||
/// </summary>
|
||||
/// <param name="id">ENDPOINT_PARAMS identifier to update.</param>
|
||||
/// <param name="procedure">UpdateEndpointParamsProcedure payload.</param>
|
||||
/// <param name="id">The identifier of the ENDPOINT_PARAMS record to update.</param>
|
||||
/// <param name="data">UpdateEndpointParamsProcedure payload.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpPut("{id:long}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointParamsProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointParamsDto data, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel);
|
||||
await mediator.Send(new UpdateEndpointParamsCommand() { Id = id, Data = data }, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes endpoint parameter records via the ENDPOINT_PARAMS delete procedure for the specified id range.
|
||||
/// </summary>
|
||||
/// <param name="procedure">DeleteEndpointParamsProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="command">DeleteEndpointParamsProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromBody] DeleteEndpointParamsProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteEndpointParamsCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteDeleteProcedure(procedure, cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Endpoints.Commands;
|
||||
|
||||
namespace ReC.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class EndpointsController(IMediator mediator, IConfiguration config) : ControllerBase
|
||||
public class EndpointsController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Inserts an endpoint via the ENDPOINT insert procedure.
|
||||
@@ -19,38 +17,38 @@ public class EndpointsController(IMediator mediator, IConfiguration config) : Co
|
||||
/// <returns>The created ENDPOINT identifier.</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Post([FromBody] InsertEndpointProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Post([FromBody] InsertEndpointCommand procedure, CancellationToken cancel)
|
||||
{
|
||||
var id = await mediator.ExecuteInsertProcedure(procedure, config["AddedWho"], cancel);
|
||||
var id = await mediator.Send(procedure, cancel);
|
||||
return StatusCode(StatusCodes.Status201Created, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an endpoint via the ENDPOINT update procedure.
|
||||
/// </summary>
|
||||
/// <param name="id">ENDPOINT identifier to update.</param>
|
||||
/// <param name="procedure">UpdateEndpointProcedure payload.</param>
|
||||
/// <param name="id">The identifier of the ENDPOINT record to update.</param>
|
||||
/// <param name="data">UpdateEndpointProcedure payload.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpPut("{id:long}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateEndpointDto data, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel);
|
||||
await mediator.Send(new UpdateEndpointCommand() { Id = id, Data = data }, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes endpoints via the ENDPOINT delete procedure for the specified id range.
|
||||
/// </summary>
|
||||
/// <param name="procedure">DeleteEndpointProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="command">DeleteEndpointProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromBody] DeleteEndpointProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteEndpointCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteDeleteProcedure(procedure, cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Profile.Commands;
|
||||
using ReC.Application.Profile.Queries;
|
||||
|
||||
@@ -26,38 +24,38 @@ public class ProfileController(IMediator mediator) : ControllerBase
|
||||
/// <returns>The created profile identifier.</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Post([FromBody] InsertProfileProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Post([FromBody] InsertProfileCommand procedure, CancellationToken cancel)
|
||||
{
|
||||
var id = await mediator.ExecuteInsertProcedure(procedure, cancel: cancel);
|
||||
var id = await mediator.Send(procedure, cancel);
|
||||
return CreatedAtAction(nameof(Get), new { id }, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a profile via the PROFILE update procedure.
|
||||
/// </summary>
|
||||
/// <param name="id">Profile identifier to update.</param>
|
||||
/// <param name="procedure">UpdateProfileProcedure payload.</param>
|
||||
/// <param name="id">The identifier of the PROFILE record to update.</param>
|
||||
/// <param name="data">UpdateProfileProcedure payload.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpPut("{id:long}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateProfileProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateProfileDto data, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel);
|
||||
await mediator.Send(new UpdateProfileCommand() { Id = id, Data = data }, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes profile records via the PROFILE delete procedure for the specified id range.
|
||||
/// </summary>
|
||||
/// <param name="procedure">DeleteProfileProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="command">DeleteProfileProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromBody] DeleteProfileProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteProfileCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteDeleteProcedure(procedure, cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.RecActions.Commands;
|
||||
using ReC.Application.RecActions.Queries;
|
||||
|
||||
@@ -10,19 +8,24 @@ namespace ReC.API.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class RecActionController(IMediator mediator, IConfiguration config) : ControllerBase
|
||||
public class RecActionController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Invokes a batch of RecActions for a given profile.
|
||||
/// </summary>
|
||||
/// <param name="profileId">The ID of the profile.</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>
|
||||
/// <returns>An HTTP 202 Accepted response indicating the process has been started.</returns>
|
||||
[HttpPost("invoke/{profileId}")]
|
||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||
public async Task<IActionResult> Invoke([FromRoute] int profileId, CancellationToken cancel)
|
||||
public async Task<IActionResult> Invoke([FromRoute] long profileId, [FromBody] InvokeReferences references, CancellationToken cancel = default)
|
||||
{
|
||||
await mediator.InvokeBatchRecActionView(profileId, cancel);
|
||||
await mediator.Send(new InvokeBatchRecActionViewsCommand
|
||||
{
|
||||
ProfileId = profileId,
|
||||
References = references
|
||||
}, cancel);
|
||||
return Accepted();
|
||||
}
|
||||
|
||||
@@ -45,9 +48,9 @@ public class RecActionController(IMediator mediator, IConfiguration config) : Co
|
||||
/// <returns>An HTTP 201 Created response.</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Create([FromBody] InsertActionProcedure command, CancellationToken cancel)
|
||||
public async Task<IActionResult> Create([FromBody] InsertActionCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteInsertProcedure(command, config["AddedWho"], cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
|
||||
return StatusCode(StatusCodes.Status201Created);
|
||||
}
|
||||
@@ -55,29 +58,29 @@ public class RecActionController(IMediator mediator, IConfiguration config) : Co
|
||||
/// <summary>
|
||||
/// Updates a RecAction via the ACTION update procedure.
|
||||
/// </summary>
|
||||
/// <param name="id">RecAction identifier to update.</param>
|
||||
/// <param name="procedure">UpdateActionProcedure payload.</param>
|
||||
/// <param name="id">The identifier of the ACTION record to update.</param>
|
||||
/// <param name="data">UpdateActionProcedure payload.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpPut("{id:long}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Update([FromRoute] long id, [FromBody] UpdateActionProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Update([FromRoute] long id, [FromBody] UpdateActionDto data, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel);
|
||||
await mediator.Send(new UpdateActionCommand() { Id = id, Data = data }, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes RecActions via the ACTION delete procedure for the specified id range.
|
||||
/// </summary>
|
||||
/// <param name="procedure">DeleteActionProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="command">DeleteActionProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>An HTTP 204 No Content response upon successful deletion.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromBody] DeleteActionProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteActionCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteDeleteProcedure(procedure, cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
#endregion CRUD
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using ReC.API.Extensions;
|
||||
using ReC.API.Models;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Results.Commands;
|
||||
using ReC.Application.Results.Queries;
|
||||
|
||||
@@ -32,38 +28,38 @@ public class ResultController(IMediator mediator) : ControllerBase
|
||||
/// <returns>The created RESULT identifier.</returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status201Created)]
|
||||
public async Task<IActionResult> Post([FromBody] InsertResultProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Post([FromBody] InsertResultCommand procedure, CancellationToken cancel)
|
||||
{
|
||||
var id = await mediator.ExecuteInsertProcedure(procedure, cancel: cancel);
|
||||
var id = await mediator.Send(procedure, cancel);
|
||||
return CreatedAtAction(nameof(Get), new { actionId = procedure.ActionId }, new { id, procedure.ActionId });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates a RESULT record via the update procedure.
|
||||
/// </summary>
|
||||
/// <param name="id">RESULT identifier to update.</param>
|
||||
/// <param name="procedure">UpdateResultProcedure payload.</param>
|
||||
/// <param name="id">The identifier of the RESULT record to update.</param>
|
||||
/// <param name="data">UpdateResultProcedure payload.</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpPut("{id:long}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateResultProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Put([FromRoute] long id, [FromBody] UpdateResultDto data, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteUpdateProcedure(procedure, id, cancel: cancel);
|
||||
await mediator.Send(new UpdateResultCommand() { Id = id, Data = data }, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes RESULT records via the delete procedure for the specified id range.
|
||||
/// </summary>
|
||||
/// <param name="procedure">DeleteResultProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="command">DeleteResultProcedure payload (Start, End, Force).</param>
|
||||
/// <param name="cancel">A token to cancel the operation.</param>
|
||||
/// <returns>No content on success.</returns>
|
||||
[HttpDelete]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
public async Task<IActionResult> Delete([FromBody] DeleteResultProcedure procedure, CancellationToken cancel)
|
||||
public async Task<IActionResult> Delete([FromQuery] DeleteResultCommand command, CancellationToken cancel)
|
||||
{
|
||||
await mediator.ExecuteDeleteProcedure(procedure, cancel);
|
||||
await mediator.Send(command, cancel);
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace ReC.API.Extensions;
|
||||
|
||||
public static class ConfigurationExtensions
|
||||
{
|
||||
public static int GetFakeProfileId(this IConfiguration config) => config.GetValue("FakeProfileId", 2);
|
||||
}
|
||||
@@ -7,13 +7,11 @@ using System.Text.Json;
|
||||
|
||||
namespace ReC.API.Middleware;
|
||||
|
||||
//TODO: Fix and use DigitalData.Core.Exceptions.Middleware
|
||||
/// <summary>
|
||||
/// Middleware for handling exceptions globally in the application.
|
||||
/// Captures exceptions thrown during the request pipeline execution,
|
||||
/// logs them, and returns an appropriate HTTP response with a JSON error details.
|
||||
/// </summary>
|
||||
[Obsolete("Use DigitalData.Core.Exceptions.Middleware")]
|
||||
public class ExceptionHandlingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
@@ -164,6 +162,22 @@ public class ExceptionHandlingMiddleware
|
||||
};
|
||||
break;
|
||||
|
||||
case RecActionException recActionEx:
|
||||
logger.LogWarning(
|
||||
recActionEx,
|
||||
"Rec action failed. ActionId: {ActionId}, ProfileId: {ProfileId}",
|
||||
recActionEx.ActionId,
|
||||
recActionEx.ProfileId);
|
||||
|
||||
context.Response.StatusCode = (int)HttpStatusCode.UnprocessableEntity;
|
||||
details = new()
|
||||
{
|
||||
Title = "Rec Action Failed",
|
||||
Detail = recActionEx.InnerException?.Message
|
||||
?? "An error occurred while executing the rec action. Check the logs for more details."
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
logger.LogError(exception, "Unhandled exception occurred.");
|
||||
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -70,9 +70,7 @@ try
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
#pragma warning disable CS0618
|
||||
app.UseMiddleware<ExceptionHandlingMiddleware>();
|
||||
#pragma warning restore CS0618
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment() || config.GetValue<bool>("UseSwagger"))
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
|
||||
<ExcludeApp_Data>false</ExcludeApp_Data>
|
||||
<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>
|
||||
<DeployIisAppPath>Rec.API</DeployIisAppPath>
|
||||
<_TargetId>IISWebDeployPackage</_TargetId>
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
<Product>ReC.API</Product>
|
||||
<PackageIcon>Assets\icon.ico</PackageIcon>
|
||||
<PackageTags>digital data rest-caller rec api</PackageTags>
|
||||
<Version>1.0.3-beta</Version>
|
||||
<AssemblyVersion>1.0.3.0</AssemblyVersion>
|
||||
<FileVersion>1.0.3.0</FileVersion>
|
||||
<InformationalVersion>1.0.3-beta</InformationalVersion>
|
||||
<Version>2.2.0-beta</Version>
|
||||
<AssemblyVersion>2.2.0.0</AssemblyVersion>
|
||||
<FileVersion>2.2.0.0</FileVersion>
|
||||
<InformationalVersion>2.2.0-beta</InformationalVersion>
|
||||
<Copyright>Copyright © 2025 Digital Data GmbH. All rights reserved.</Copyright>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||
<UserSecretsId>cf893b96-c71a-4a96-a6a7-40004249e1a3</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
"AllowedHosts": "*",
|
||||
"LuckyPennySoftwareLicenseKey": "eyJhbGciOiJSUzI1NiIsImtpZCI6Ikx1Y2t5UGVubnlTb2Z0d2FyZUxpY2Vuc2VLZXkvYmJiMTNhY2I1OTkwNGQ4OWI0Y2IxYzg1ZjA4OGNjZjkiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2x1Y2t5cGVubnlzb2Z0d2FyZS5jb20iLCJhdWQiOiJMdWNreVBlbm55U29mdHdhcmUiLCJleHAiOiIxNzg0ODUxMjAwIiwiaWF0IjoiMTc1MzM2MjQ5MSIsImFjY291bnRfaWQiOiIwMTk4M2M1OWU0YjM3MjhlYmZkMzEwM2MyYTQ4NmU4NSIsImN1c3RvbWVyX2lkIjoiY3RtXzAxazB5NmV3MmQ4YTk4Mzg3aDJnbTRuOWswIiwic3ViX2lkIjoiLSIsImVkaXRpb24iOiIwIiwidHlwZSI6IjIifQ.ZqsFG7kv_-xGfxS6ACk3i0iuNiVUXX2AvPI8iAcZ6-z2170lGv__aO32tWpQccD9LCv5931lBNLWSblKS0MT3gOt-5he2TEftwiSQGFwoIBgtOHWsNRMinUrg2trceSp3IhyS3UaMwnxZDrCvx4-0O-kpOzVpizeHUAZNr5U7oSCWO34bpKdae6grtM5e3f93Z1vs7BW_iPgItd-aLvPwApbaG9VhmBTKlQ7b4Jh64y7UXJ9mKP7Qb_Oa97oEg0oY5DPHOWTZWeE1EzORgVr2qkK2DELSHuZ_EIUhODojkClPNAKtvEl_qEjpq0HZCIvGwfCCRlKlSkQqIeZdFkiXg",
|
||||
"RecAction": {
|
||||
"MaxConcurrentInvocations": 5
|
||||
"AddedWho": "ReC.API",
|
||||
"UseHttp1ForNtlm": false
|
||||
},
|
||||
// Bad request SqlException numbers numbers can be updated at runtime; no restart required.
|
||||
"SqlException": {
|
||||
// https://learn.microsoft.com/en-us/dotnet/api/system.data.sqlclient.sqlexception.number
|
||||
"SqlExceptionNumber": [ 515, 547, 2601, 2627 ]
|
||||
},
|
||||
"AddedWho": "ReC.API",
|
||||
"FakeProfileId": 2
|
||||
"BadRequestSqlExceptionNumbers": [ 515, 547, 2601, 2627, 50000 ]
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using ReC.Application.Common.Dto;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ReC.Application.Common.Behaviors;
|
||||
namespace ReC.Application.Common.Behaviors.Action;
|
||||
|
||||
public class BodyQueryBehavior<TRequest, TResponse>(IRecDbContext dbContext) : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : RecActionViewDto
|
||||
@@ -5,7 +5,7 @@ using ReC.Application.Common.Dto;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
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>
|
||||
where TRequest : RecActionViewDto
|
||||
@@ -0,0 +1,53 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using ReC.Application.RecActions.Commands;
|
||||
using ReC.Application.Results.Commands;
|
||||
using ReC.Domain.Constants;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ReC.Application.Common.Behaviors.InvokeAction;
|
||||
|
||||
public class PostprocessingBehavior(IRecDbContext context, ISender sender) : IPipelineBehavior<InvokeRecActionViewCommand, Unit>
|
||||
{
|
||||
public async Task<Unit> Handle(InvokeRecActionViewCommand request, RequestHandlerDelegate<Unit> next, CancellationToken cancel)
|
||||
{
|
||||
await next(cancel);
|
||||
|
||||
try
|
||||
{
|
||||
if (request.Action.PostprocessingQuery is string query)
|
||||
{
|
||||
var result = await context.ExecuteDynamicSqlAsync(query, cancel);
|
||||
var info = JsonSerializer.Serialize(result);
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.OK,
|
||||
ActionId = request.Action.Id,
|
||||
InfoDetail = info,
|
||||
Type = ResultType.Post,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var error = ex.ToString();
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.Error,
|
||||
ActionId = request.Action.Id,
|
||||
Error = error,
|
||||
Type = ResultType.Post,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
|
||||
if (request.Action.ErrorAction == ErrorAction.Stop)
|
||||
throw new RecActionException(request.Action.Id, request.Action.ProfileId, ex);
|
||||
}
|
||||
|
||||
return Unit.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Interfaces;
|
||||
using ReC.Application.RecActions.Commands;
|
||||
using ReC.Application.Results.Commands;
|
||||
using ReC.Domain.Constants;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ReC.Application.Common.Behaviors.InvokeAction;
|
||||
|
||||
public class PreprocessingBehavior(IRecDbContext context, ISender sender) : IPipelineBehavior<InvokeRecActionViewCommand, Unit>
|
||||
{
|
||||
public async Task<Unit> Handle(InvokeRecActionViewCommand request, RequestHandlerDelegate<Unit> next, CancellationToken cancel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (request.Action.PreprocessingQuery is string query)
|
||||
{
|
||||
var result = await context.ExecuteDynamicSqlAsync(query, cancel);
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.OK,
|
||||
ActionId = request.Action.Id,
|
||||
InfoDetail = JsonSerializer.Serialize(result),
|
||||
Type = ResultType.Pre,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.Error,
|
||||
ActionId = request.Action.Id,
|
||||
Error = ex.ToString(),
|
||||
Type = ResultType.Pre,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
|
||||
if (request.Action.ErrorAction == ErrorAction.Stop)
|
||||
throw new RecActionException(request.Action.Id, request.Action.ProfileId, ex);
|
||||
}
|
||||
|
||||
return await next(cancel);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -6,7 +6,12 @@ public class DtoMappingProfile : AutoMapper.Profile
|
||||
{
|
||||
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<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,20 +0,0 @@
|
||||
namespace ReC.Application.Common.Dto;
|
||||
|
||||
public record OutResDto
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public long ActionId { get; set; }
|
||||
|
||||
public string? Header { get; set; }
|
||||
|
||||
public string? Body { get; set; }
|
||||
|
||||
public string AddedWho { get; set; } = null!;
|
||||
|
||||
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 ProfileViewDto? Profile { get; init; }
|
||||
|
||||
public string? ProfileName { get; init; }
|
||||
|
||||
public ProfileType? ProfileType { get; init; }
|
||||
@@ -20,7 +22,7 @@ public record RecActionViewDto
|
||||
|
||||
public long? EndpointAuthId { get; init; }
|
||||
|
||||
public EndpointAuthType? EndpointAuthType { get; init; }
|
||||
public EndpointAuthType EndpointAuthType { get; init; } = EndpointAuthType.NoAuth;
|
||||
|
||||
public string? EndpointAuthTypeName { get; init; }
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
namespace ReC.Application.Common.Dto;
|
||||
using ReC.Domain.Constants;
|
||||
|
||||
namespace ReC.Application.Common.Dto;
|
||||
|
||||
public record ResultViewDto
|
||||
{
|
||||
public long Id { get; init; }
|
||||
|
||||
public OutResDto? Root { get; init; }
|
||||
|
||||
public long? ActionId { get; init; }
|
||||
|
||||
public RecActionViewDto? Action { get; init; }
|
||||
@@ -16,7 +16,7 @@ public record ResultViewDto
|
||||
|
||||
public string? ProfileName { get; init; }
|
||||
|
||||
public short? StatusCode { get; init; }
|
||||
public RecStatus Status { get; set; }
|
||||
|
||||
public string? StatusName { get; init; }
|
||||
|
||||
@@ -24,6 +24,14 @@ public record ResultViewDto
|
||||
|
||||
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 DateTime? AddedWhen { get; init; }
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace ReC.Application.Common.Exceptions;
|
||||
|
||||
public class RecActionException(long actionId, long? profileId, Exception innerException)
|
||||
: Exception($"Rec action failed. ActionId: {actionId}, ProfileId: {profileId}", innerException)
|
||||
{
|
||||
public long ActionId { get; } = actionId;
|
||||
|
||||
public long? ProfileId { get; } = profileId;
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using ReC.Domain.Constants;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace ReC.Application.Common;
|
||||
|
||||
public static class HttpExtensions
|
||||
{
|
||||
private static readonly Dictionary<RestType, HttpMethod> _methods = new()
|
||||
{
|
||||
[RestType.Get] = HttpMethod.Get,
|
||||
[RestType.Post] = HttpMethod.Post,
|
||||
[RestType.Put] = HttpMethod.Put,
|
||||
[RestType.Delete] = HttpMethod.Delete,
|
||||
[RestType.Patch] = HttpMethod.Patch,
|
||||
[RestType.Head] = HttpMethod.Head,
|
||||
[RestType.Options] = HttpMethod.Options,
|
||||
[RestType.Trace] = HttpMethod.Trace,
|
||||
[RestType.Connect] = HttpMethod.Connect
|
||||
};
|
||||
|
||||
public static HttpMethod ToHttpMethod(this RestType method) => !method.IsValid()
|
||||
? throw new ArgumentOutOfRangeException(nameof(method), $"The RestType value '{method}' is not valid.")
|
||||
: _methods.TryGetValue(method, out var httpMethod)
|
||||
? httpMethod
|
||||
: new HttpMethod(method.ToHttpMethodName());
|
||||
|
||||
public static HttpRequestMessage ToHttpRequestMessage(this HttpMethod method, [StringSyntax(StringSyntaxAttribute.Uri)] string? requestUri)
|
||||
=> new(method, requestUri);
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using ReC.Domain.QueryOutput;
|
||||
using ReC.Domain.Views;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace ReC.Application.Common.Interfaces;
|
||||
|
||||
@@ -21,4 +23,39 @@ public interface IRecDbContext
|
||||
#endregion DbSets
|
||||
|
||||
public Task<int> SaveChangesAsync(CancellationToken cancel = default);
|
||||
|
||||
public DatabaseFacade Database { get; }
|
||||
}
|
||||
|
||||
public static class RecDbContextSaveExtensions
|
||||
{
|
||||
//TODO: Once it is finalized, move it to Common.Infrastructure
|
||||
public static async Task<IEnumerable<Dictionary<string, object?>>> ExecuteDynamicSqlAsync(this IRecDbContext context, string sql, CancellationToken cancel = default)
|
||||
{
|
||||
var result = new List<Dictionary<string, object?>>();
|
||||
|
||||
using var command = context.Database.GetDbConnection().CreateCommand();
|
||||
|
||||
command.CommandText = sql;
|
||||
|
||||
await context.Database.OpenConnectionAsync(cancel);
|
||||
|
||||
using var reader = await command.ExecuteReaderAsync(cancel);
|
||||
while (await reader.ReadAsync(cancel))
|
||||
{
|
||||
var row = new Dictionary<string, object?>();
|
||||
|
||||
for (int i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
var columnName = reader.GetName(i);
|
||||
var value = reader.IsDBNull(i) ? null : reader.GetValue(i);
|
||||
|
||||
row[columnName] = value;
|
||||
}
|
||||
|
||||
result.Add(row);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,5 @@
|
||||
|
||||
public class RecActionOptions
|
||||
{
|
||||
public int MaxConcurrentInvocations { get; set; } = 5;
|
||||
}
|
||||
public bool UseHttp1ForNtlm { get; set; } = false;
|
||||
}
|
||||
@@ -2,5 +2,5 @@ namespace ReC.Application.Common.Options;
|
||||
|
||||
public class SqlExceptionOptions
|
||||
{
|
||||
public HashSet<int> SqlExceptionNumber { get; set; } = [];
|
||||
public HashSet<int> BadRequestSqlExceptionNumbers { get; set; } = [];
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using MediatR;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Options;
|
||||
|
||||
@@ -10,9 +11,9 @@ namespace ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
public record DeleteObjectProcedure : IRequest<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
|
||||
/// Target entity for the delete operation.
|
||||
/// </summary>
|
||||
public string Entity { get; set; } = null!;
|
||||
public required EntityType Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
@@ -30,48 +31,20 @@ public record DeleteObjectProcedure : IRequest<int>
|
||||
public bool Force { get; set; }
|
||||
}
|
||||
|
||||
public static class DeleteObjectProcedureExtensions
|
||||
{
|
||||
public static Task<int> ExecuteDeleteProcedure(this ISender sender, IDeleteProcedure procedure, CancellationToken cancel = default)
|
||||
{
|
||||
return sender.Send(procedure.ToObjectProcedure(), cancel);
|
||||
}
|
||||
|
||||
public static Task<int> ExecuteDeleteProcedure(this ISender sender, string entity, long start, long end = 0, bool force = false, CancellationToken cancel = default)
|
||||
{
|
||||
return sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = entity,
|
||||
Start = start,
|
||||
End = end,
|
||||
Force = force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public class DeleteObjectProcedureHandler(IRepository repo, SqlExceptionOptions sqlExceptionOptions) : IRequestHandler<DeleteObjectProcedure, int>
|
||||
public class DeleteObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<DeleteObjectProcedure, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteObjectProcedure request, CancellationToken cancel)
|
||||
{
|
||||
var parameters = new[]
|
||||
{
|
||||
new SqlParameter("@pENTITY", request.Entity ?? (object)DBNull.Value),
|
||||
new SqlParameter("@pSTART", request.Start.ToString()),
|
||||
new SqlParameter("@pEND", request.End.ToString()),
|
||||
new SqlParameter("@pFORCE", (object?)request.Force ?? DBNull.Value)
|
||||
};
|
||||
var sp = new StoredProcedureBuilder("[dbo].[PRREC_DELETE_OBJECT]", "RC")
|
||||
.Add("pENTITY", request.Entity)
|
||||
.Add("pSTART", request.Start.ToString())
|
||||
.Add("pEND", request.End.ToString())
|
||||
.Add("pFORCE", request.Force);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await repo.ExecuteQueryRawAsync(
|
||||
"DECLARE @RC SMALLINT = 0; " +
|
||||
"EXEC @RC = [dbo].[PRREC_DELETE_OBJECT] " +
|
||||
"@pENTITY, @pSTART, @pEND, @pFORCE; " +
|
||||
"SELECT @RC;",
|
||||
parameters,
|
||||
cancel);
|
||||
var result = await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||
|
||||
// The stored procedure returns 0 on success, error codes > 0 on failure
|
||||
if (result > 0)
|
||||
{
|
||||
throw new DeleteObjectFailedException(request, $"DeleteObject stored procedure failed with error code: {result}");
|
||||
@@ -81,7 +54,7 @@ public class DeleteObjectProcedureHandler(IRepository repo, SqlExceptionOptions
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
if (sqlExceptionOptions.SqlExceptionNumber.Contains(ex.Number))
|
||||
if (sqlExOpt.CurrentValue.BadRequestSqlExceptionNumbers.Contains(ex.Number))
|
||||
throw new BadRequestException(ex.Message, ex);
|
||||
else
|
||||
throw;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using MediatR;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
public interface IDeleteProcedure
|
||||
public interface IDeleteProcedure : IRequest<int>
|
||||
{
|
||||
public DeleteObjectProcedure ToObjectProcedure();
|
||||
}
|
||||
|
||||
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}")
|
||||
};
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
namespace ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using MediatR;
|
||||
|
||||
public interface IInsertProcedure
|
||||
namespace ReC.Application.Common.Procedures.InsertProcedure;
|
||||
|
||||
public interface IInsertProcedure : IRequest<long>
|
||||
{
|
||||
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null);
|
||||
}
|
||||
@@ -2,145 +2,119 @@
|
||||
using DigitalData.Core.Exceptions;
|
||||
using MediatR;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Options;
|
||||
using ReC.Application.EndpointAuth.Commands;
|
||||
using ReC.Application.EndpointParams.Commands;
|
||||
using ReC.Application.Endpoints.Commands;
|
||||
using ReC.Application.Results.Commands;
|
||||
using ReC.Application.Profile.Commands;
|
||||
using ReC.Application.Common.Options;
|
||||
using ReC.Application.RecActions.Commands;
|
||||
using ReC.Application.Results.Commands;
|
||||
using System.Data;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.InsertProcedure;
|
||||
|
||||
public record InsertObjectProcedure : IRequest<long>
|
||||
{
|
||||
/// <summary>
|
||||
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
|
||||
/// Target entity for the insert operation.
|
||||
/// </summary>
|
||||
public string Entity { get; set; } = null!;
|
||||
public required EntityType Entity { get; set; }
|
||||
|
||||
internal string? AddedWho { get; private set; }
|
||||
//TODO: update to set in authentication middleware or similar, and remove from procedure properties
|
||||
internal string? AddedWho { get; private set; } = "ReC.API";
|
||||
|
||||
public InsertObjectProcedure AddedBy(string? addedWho = null)
|
||||
{
|
||||
AddedWho = addedWho ?? "ReC.API";
|
||||
return this;
|
||||
}
|
||||
|
||||
public InsertActionProcedure Action { get; set; } = new();
|
||||
public InsertEndpointProcedure Endpoint { get; set; } = new();
|
||||
public InsertEndpointAuthProcedure EndpointAuth { get; set; } = new();
|
||||
public InsertProfileProcedure Profile { get; set; } = new();
|
||||
public InsertResultProcedure Result { get; set; } = new();
|
||||
public InsertEndpointParamsProcedure EndpointParams { get; set; } = new();
|
||||
public InsertActionCommand? Action { get; set; }
|
||||
public InsertEndpointCommand? Endpoint { get; set; }
|
||||
public InsertEndpointAuthCommand? EndpointAuth { get; set; }
|
||||
public InsertProfileCommand? Profile { get; set; }
|
||||
public InsertResultCommand? Result { get; set; }
|
||||
public InsertEndpointParamsCommand? EndpointParams { get; set; }
|
||||
}
|
||||
|
||||
public static class InsertObjectProcedureExtensions
|
||||
{
|
||||
public static Task<long> ExecuteInsertProcedure(this ISender sender, IInsertProcedure procedure, string? addedWho = null, CancellationToken cancel = default)
|
||||
{
|
||||
return sender.Send(procedure.ToObjectProcedure(addedWho ?? "Rec.API"), cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public class InsertObjectProcedureHandler(IRepository repo, SqlExceptionOptions sqlExceptionOptions) : IRequestHandler<InsertObjectProcedure, long>
|
||||
public class InsertObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<InsertObjectProcedure, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertObjectProcedure request, CancellationToken cancel)
|
||||
{
|
||||
var parameters = new[]
|
||||
{
|
||||
new SqlParameter("@pENTITY", request.Entity ?? (object)DBNull.Value),
|
||||
|
||||
new SqlParameter("@pADDED_WHO", (object?)request.AddedWho ?? DBNull.Value),
|
||||
new SqlParameter("@pADDED_WHEN", (object?)DateTime.UtcNow ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pACTION_PROFILE_ID", (object?)request.Action.ProfileId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ACTIVE", (object?)request.Action.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_SEQUENCE", (object?)request.Action.Sequence ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ENDPOINT_ID", (object?)request.Action.EndpointId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ENDPOINT_AUTH_ID", (object?)request.Action.EndpointAuthId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ENDPOINT_PARAMS_ID", (object?)request.Action.EndpointParamsId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_SQL_CONNECTION_ID", (object?)request.Action.SqlConnectionId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_TYPE_ID", (object?)request.Action.TypeId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_PRE_SQL", (object?)request.Action.PreSql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_HEADER_SQL", (object?)request.Action.HeaderSql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_BODY_SQL", (object?)request.Action.BodySql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_POST_SQL", (object?)request.Action.PostSql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ERROR_ACTION_ID", (object?)request.Action.ErrorActionId ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pENDPOINT_ACTIVE", (object?)request.Endpoint.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_DESCRIPTION", (object?)request.Endpoint.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_URI", (object?)request.Endpoint.Uri ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pENDPOINT_AUTH_ACTIVE", (object?)request.EndpointAuth.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_DESCRIPTION", (object?)request.EndpointAuth.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_TYPE_ID", (object?)request.EndpointAuth.TypeId ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY", (object?)request.EndpointAuth.ApiKey ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_API_VALUE", (object?)request.EndpointAuth.ApiValue ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY_ADD_TO_ID", (object?)request.EndpointAuth.ApiKeyAddToId ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_TOKEN", (object?)request.EndpointAuth.Token ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_USERNAME", (object?)request.EndpointAuth.Username ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_PASSWORD", (object?)request.EndpointAuth.Password ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_DOMAIN", (object?)request.EndpointAuth.Domain ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_WORKSTATION", (object?)request.EndpointAuth.Workstation ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pPROFILE_ACTIVE", (object?)request.Profile.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_TYPE_ID", (object?)request.Profile.TypeId ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_MANDANTOR", (object?)request.Profile.Mandantor ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_NAME", (object?)request.Profile.Name ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_DESCRIPTION", (object?)request.Profile.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_LOG_LEVEL_ID", (object?)request.Profile.LogLevelId ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_LANGUAGE_ID", (object?)request.Profile.LanguageId ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pRESULT_ACTION_ID", (object?)request.Result.ActionId ?? DBNull.Value),
|
||||
new SqlParameter("@pRESULT_STATUS_ID", (object?)request.Result.StatusId ?? DBNull.Value),
|
||||
new SqlParameter("@pRESULT_HEADER", (object?)request.Result.Header ?? DBNull.Value),
|
||||
new SqlParameter("@pRESULT_BODY", (object?)request.Result.Body ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pENDPOINT_PARAMS_ACTIVE", (object?)request.EndpointParams.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_DESCRIPTION", (object?)request.EndpointParams.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_GROUP_ID", (object?)request.EndpointParams.GroupId ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_SEQUENCE", (object?)request.EndpointParams.Sequence ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_KEY", (object?)request.EndpointParams.Key ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_VALUE", (object?)request.EndpointParams.Value ?? DBNull.Value),
|
||||
|
||||
new SqlParameter
|
||||
{
|
||||
ParameterName = "@oGUID",
|
||||
SqlDbType = System.Data.SqlDbType.BigInt,
|
||||
Direction = System.Data.ParameterDirection.Output
|
||||
}
|
||||
};
|
||||
var sp = new StoredProcedureBuilder("[dbo].[PRREC_INSERT_OBJECT]")
|
||||
.Add("pENTITY", request.Entity)
|
||||
.Add("pADDED_WHO", request.AddedWho)
|
||||
.Add("pADDED_WHEN", DateTime.UtcNow)
|
||||
.Add("pACTION_PROFILE_ID", request.Action?.ProfileId)
|
||||
.Add("pACTION_ACTIVE", request.Action?.Active)
|
||||
.Add("pACTION_SEQUENCE", request.Action?.Sequence, SqlDbType.TinyInt)
|
||||
.Add("pACTION_ENDPOINT_ID", request.Action?.EndpointId)
|
||||
.Add("pACTION_ENDPOINT_AUTH_ID", request.Action?.EndpointAuthId)
|
||||
.Add("pACTION_ENDPOINT_PARAMS_ID", request.Action?.EndpointParamsId, SqlDbType.SmallInt)
|
||||
.Add("pACTION_SQL_CONNECTION_ID", request.Action?.SqlConnectionId, SqlDbType.SmallInt)
|
||||
.Add("pACTION_TYPE_ID", request.Action?.TypeId is not null ? (byte)request.Action.TypeId : null, SqlDbType.TinyInt)
|
||||
.Add("pACTION_PRE_SQL", request.Action?.PreSql)
|
||||
.Add("pACTION_HEADER_SQL", request.Action?.HeaderSql)
|
||||
.Add("pACTION_BODY_SQL", request.Action?.BodySql)
|
||||
.Add("pACTION_POST_SQL", request.Action?.PostSql)
|
||||
.Add("pACTION_ERROR_ACTION_ID", request.Action?.ErrorActionId, SqlDbType.TinyInt)
|
||||
.Add("pENDPOINT_ACTIVE", request.Endpoint?.Active)
|
||||
.Add("pENDPOINT_DESCRIPTION", request.Endpoint?.Description)
|
||||
.Add("pENDPOINT_URI", request.Endpoint?.Uri)
|
||||
.Add("pENDPOINT_AUTH_ACTIVE", request.EndpointAuth?.Active)
|
||||
.Add("pENDPOINT_AUTH_DESCRIPTION", request.EndpointAuth?.Description)
|
||||
.Add("pENDPOINT_AUTH_TYPE_ID", request.EndpointAuth?.TypeId, SqlDbType.TinyInt)
|
||||
.Add("pENDPOINT_AUTH_API_KEY", request.EndpointAuth?.ApiKey)
|
||||
.Add("pENDPOINT_AUTH_API_VALUE", request.EndpointAuth?.ApiValue)
|
||||
.Add("pENDPOINT_AUTH_API_KEY_ADD_TO_ID", request.EndpointAuth?.ApiKeyAddToId)
|
||||
.Add("pENDPOINT_AUTH_TOKEN", request.EndpointAuth?.Token)
|
||||
.Add("pENDPOINT_AUTH_USERNAME", request.EndpointAuth?.Username)
|
||||
.Add("pENDPOINT_AUTH_PASSWORD", request.EndpointAuth?.Password)
|
||||
.Add("pENDPOINT_AUTH_DOMAIN", request.EndpointAuth?.Domain)
|
||||
.Add("pENDPOINT_AUTH_WORKSTATION", request.EndpointAuth?.Workstation)
|
||||
.Add("pPROFILE_ACTIVE", request.Profile?.Active)
|
||||
.Add("pPROFILE_TYPE_ID", request.Profile?.TypeId, SqlDbType.TinyInt)
|
||||
.Add("pPROFILE_MANDANTOR", request.Profile?.Mandantor)
|
||||
.Add("pPROFILE_NAME", request.Profile?.Name)
|
||||
.Add("pPROFILE_DESCRIPTION", request.Profile?.Description)
|
||||
.Add("pPROFILE_LOG_LEVEL_ID", request.Profile?.LogLevelId, SqlDbType.TinyInt)
|
||||
.Add("pPROFILE_LANGUAGE_ID", request.Profile?.LanguageId, SqlDbType.SmallInt)
|
||||
.Add("pRESULT_ACTION_ID", request.Result?.ActionId)
|
||||
.Add("pRESULT_STATUS_ID", request.Result?.Status, SqlDbType.TinyInt)
|
||||
.Add("pRESULT_TYPE_ID", request.Result?.Type is not null ? (byte)request.Result.Type : null, SqlDbType.TinyInt)
|
||||
.Add("pRESULT_HEADER", request.Result?.Header)
|
||||
.Add("pRESULT_BODY", request.Result?.Body)
|
||||
.Add("pRESULT_INFO_ID", request.Result?.Info, SqlDbType.SmallInt)
|
||||
.Add("pRESULT_INFO_DETAIL", request.Result?.InfoDetail)
|
||||
.Add("pRESULT_ERROR", request.Result?.Error)
|
||||
.Add("pRESULT_BATCH_ID", request.Result?.References?.BatchId)
|
||||
.Add("pRESULT_REFERENCE1", request.Result?.References?.Reference1)
|
||||
.Add("pRESULT_REFERENCE2", request.Result?.References?.Reference2)
|
||||
.Add("pRESULT_REFERENCE3", request.Result?.References?.Reference3)
|
||||
.Add("pRESULT_REFERENCE4", request.Result?.References?.Reference4)
|
||||
.Add("pRESULT_REFERENCE5", request.Result?.References?.Reference5)
|
||||
.Add("pENDPOINT_PARAMS_ACTIVE", request.EndpointParams?.Active)
|
||||
.Add("pENDPOINT_PARAMS_DESCRIPTION", request.EndpointParams?.Description)
|
||||
.Add("pENDPOINT_PARAMS_GROUP_ID", request.EndpointParams?.GroupId, SqlDbType.SmallInt)
|
||||
.Add("pENDPOINT_PARAMS_SEQUENCE", request.EndpointParams?.Sequence, SqlDbType.TinyInt)
|
||||
.Add("pENDPOINT_PARAMS_KEY", request.EndpointParams?.Key)
|
||||
.Add("pENDPOINT_PARAMS_VALUE", request.EndpointParams?.Value)
|
||||
.AddOutput("oGUID", SqlDbType.BigInt);
|
||||
|
||||
try
|
||||
{
|
||||
await repo.ExecuteQueryRawAsync(
|
||||
"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, " +
|
||||
"@pENDPOINT_PARAMS_ACTIVE, @pENDPOINT_PARAMS_DESCRIPTION, @pENDPOINT_PARAMS_GROUP_ID, @pENDPOINT_PARAMS_SEQUENCE, @pENDPOINT_PARAMS_KEY, @pENDPOINT_PARAMS_VALUE, " +
|
||||
"@oGUID OUTPUT",
|
||||
parameters,
|
||||
cancel);
|
||||
await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
if (sqlExceptionOptions.SqlExceptionNumber.Contains(ex.Number))
|
||||
if (sqlExOpt.CurrentValue.BadRequestSqlExceptionNumbers.Contains(ex.Number))
|
||||
throw new BadRequestException(ex.Message, ex);
|
||||
else
|
||||
throw;
|
||||
}
|
||||
|
||||
var guidParam = parameters.Last();
|
||||
var guidParam = sp.GetParameter("oGUID");
|
||||
|
||||
if (guidParam.Value != DBNull.Value)
|
||||
if (guidParam.Value is long longValue)
|
||||
if (guidParam?.Value != DBNull.Value)
|
||||
if (guidParam!.Value is long 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;
|
||||
|
||||
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,6 +1,6 @@
|
||||
namespace ReC.Application.Common.Procedures.InsertProcedure;
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
|
||||
public record InsertActionProcedure : IInsertProcedure
|
||||
public record UpdateActionDto
|
||||
{
|
||||
public long? ProfileId { get; set; }
|
||||
public bool? Active { get; set; }
|
||||
@@ -15,13 +15,4 @@ public record InsertActionProcedure : IInsertProcedure
|
||||
public string? BodySql { get; set; }
|
||||
public string? PostSql { get; set; }
|
||||
public byte? ErrorActionId { get; set; }
|
||||
|
||||
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
|
||||
{
|
||||
return new InsertObjectProcedure
|
||||
{
|
||||
Entity = "ACTION",
|
||||
Action = this
|
||||
}.AddedBy(addedWho);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
|
||||
namespace ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
public record InsertEndpointAuthProcedure : IInsertProcedure
|
||||
public record UpdateEndpointAuthDto
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
@@ -15,13 +13,4 @@ public record InsertEndpointAuthProcedure : IInsertProcedure
|
||||
public string? Password { get; set; }
|
||||
public string? Domain { get; set; }
|
||||
public string? Workstation { get; set; }
|
||||
|
||||
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
|
||||
{
|
||||
return new InsertObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT_AUTH",
|
||||
EndpointAuth = this
|
||||
}.AddedBy(addedWho);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
|
||||
public record UpdateEndpointDto
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Uri { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
|
||||
public record UpdateEndpointParamsDto
|
||||
{
|
||||
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; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
|
||||
public record UpdateProfileDto
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public string? Mandantor { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public byte? LogLevelId { get; set; }
|
||||
public short? LanguageId { get; set; }
|
||||
public DateTime? FirstRun { get; set; }
|
||||
public DateTime? LastRun { get; set; }
|
||||
public string? LastResult { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using ReC.Application.RecActions.Commands;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
|
||||
public record UpdateResultDto
|
||||
{
|
||||
public long? ActionId { get; set; }
|
||||
public short? StatusId { get; set; }
|
||||
public string? Header { 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; }
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
using MediatR;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
public interface IUpdateProcedure
|
||||
public interface IUpdateProcedure<T> : IRequest<int>
|
||||
{
|
||||
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null);
|
||||
}
|
||||
public long Id { get; set; }
|
||||
|
||||
public T Data { get; set; }
|
||||
}
|
||||
@@ -2,136 +2,107 @@ using DigitalData.Core.Abstraction.Application.Repository;
|
||||
using DigitalData.Core.Exceptions;
|
||||
using MediatR;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Options;
|
||||
using ReC.Application.EndpointAuth.Commands;
|
||||
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;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using System.Data;
|
||||
|
||||
namespace ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
public record UpdateObjectProcedure : IRequest<int>
|
||||
{
|
||||
/// <summary>
|
||||
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
|
||||
/// Target entity for the update operation.
|
||||
/// </summary>
|
||||
public string Entity { get; set; } = null!;
|
||||
public required EntityType Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Target GUID to update (required)
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
internal string? ChangedWho { get; private set; }
|
||||
//TODO: update to set in authentication middleware or similar, and remove from procedure properties
|
||||
internal string? ChangedWho { get; private set; } = "ReC.API";
|
||||
|
||||
public UpdateObjectProcedure ChangedBy(string? changedWho = null)
|
||||
{
|
||||
ChangedWho = changedWho ?? "ReC.API";
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateActionProcedure Action { get; set; } = new();
|
||||
public UpdateEndpointProcedure Endpoint { get; set; } = new();
|
||||
public UpdateEndpointAuthProcedure EndpointAuth { get; set; } = new();
|
||||
public UpdateProfileProcedure Profile { get; set; } = new();
|
||||
public UpdateResultProcedure Result { get; set; } = new();
|
||||
public UpdateEndpointParamsProcedure EndpointParams { get; set; } = new();
|
||||
public UpdateActionDto Action { get; set; } = new();
|
||||
public UpdateEndpointDto Endpoint { get; set; } = new();
|
||||
public UpdateEndpointAuthDto EndpointAuth { get; set; } = new();
|
||||
public UpdateProfileDto Profile { get; set; } = new();
|
||||
public UpdateResultDto Result { get; set; } = new();
|
||||
public UpdateEndpointParamsDto EndpointParams { get; set; } = new();
|
||||
}
|
||||
|
||||
public static class UpdateObjectProcedureExtensions
|
||||
{
|
||||
public static Task<int> ExecuteUpdateProcedure(this ISender sender, IUpdateProcedure procedure, long id, string? changedWho = null, CancellationToken cancel = default)
|
||||
{
|
||||
return sender.Send(procedure.ToObjectProcedure(id, changedWho ?? "ReC.API"), cancel);
|
||||
}
|
||||
}
|
||||
|
||||
public class UpdateObjectProcedureHandler(IRepository repo, SqlExceptionOptions sqlExceptionOptions) : IRequestHandler<UpdateObjectProcedure, int>
|
||||
public class UpdateObjectProcedureHandler(IRepository repo, IOptionsMonitor<SqlExceptionOptions> sqlExOpt) : IRequestHandler<UpdateObjectProcedure, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateObjectProcedure request, CancellationToken cancel)
|
||||
{
|
||||
var parameters = new[]
|
||||
{
|
||||
new SqlParameter("@pENTITY", request.Entity ?? (object)DBNull.Value),
|
||||
new SqlParameter("@pGUID", (object?)request.Id ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pCHANGED_WHO", (object?)request.ChangedWho ?? DBNull.Value),
|
||||
new SqlParameter("@pCHANGED_WHEN", (object?)DateTime.UtcNow ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pACTION_PROFILE_ID", (object?)request.Action.ProfileId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ACTIVE", (object?)request.Action.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_SEQUENCE", (object?)request.Action.Sequence ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ENDPOINT_ID", (object?)request.Action.EndpointId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ENDPOINT_AUTH_ID", (object?)request.Action.EndpointAuthId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ENDPOINT_PARAMS_ID", (object?)request.Action.EndpointParamsId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_SQL_CONNECTION_ID", (object?)request.Action.SqlConnectionId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_TYPE_ID", (object?)request.Action.TypeId ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_PRE_SQL", (object?)request.Action.PreSql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_HEADER_SQL", (object?)request.Action.HeaderSql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_BODY_SQL", (object?)request.Action.BodySql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_POST_SQL", (object?)request.Action.PostSql ?? DBNull.Value),
|
||||
new SqlParameter("@pACTION_ERROR_ACTION_ID", (object?)request.Action.ErrorActionId ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pENDPOINT_ACTIVE", (object?)request.Endpoint.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_DESCRIPTION", (object?)request.Endpoint.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_URI", (object?)request.Endpoint.Uri ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pENDPOINT_AUTH_ACTIVE", (object?)request.EndpointAuth.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_DESCRIPTION", (object?)request.EndpointAuth.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_TYPE_ID", (object?)request.EndpointAuth.TypeId ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY", (object?)request.EndpointAuth.ApiKey ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_API_VALUE", (object?)request.EndpointAuth.ApiValue ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_API_KEY_ADD_TO_ID", (object?)request.EndpointAuth.ApiKeyAddToId ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_TOKEN", (object?)request.EndpointAuth.Token ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_USERNAME", (object?)request.EndpointAuth.Username ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_PASSWORD", (object?)request.EndpointAuth.Password ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_DOMAIN", (object?)request.EndpointAuth.Domain ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_AUTH_WORKSTATION", (object?)request.EndpointAuth.Workstation ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pENDPOINT_PARAMS_ACTIVE", (object?)request.EndpointParams.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_DESCRIPTION", (object?)request.EndpointParams.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_GROUP_ID", (object?)request.EndpointParams.GroupId ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_SEQUENCE", (object?)request.EndpointParams.Sequence ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_KEY", (object?)request.EndpointParams.Key ?? DBNull.Value),
|
||||
new SqlParameter("@pENDPOINT_PARAMS_VALUE", (object?)request.EndpointParams.Value ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pPROFILE_ACTIVE", (object?)request.Profile.Active ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_TYPE_ID", (object?)request.Profile.TypeId ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_MANDANTOR", (object?)request.Profile.Mandantor ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_NAME", (object?)request.Profile.Name ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_DESCRIPTION", (object?)request.Profile.Description ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_LOG_LEVEL_ID", (object?)request.Profile.LogLevelId ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_LANGUAGE_ID", (object?)request.Profile.LanguageId ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_FIRST_RUN", (object?)request.Profile.FirstRun ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_LAST_RUN", (object?)request.Profile.LastRun ?? DBNull.Value),
|
||||
new SqlParameter("@pPROFILE_LAST_RESULT", (object?)request.Profile.LastResult ?? DBNull.Value),
|
||||
|
||||
new SqlParameter("@pRESULT_ACTION_ID", (object?)request.Result.ActionId ?? DBNull.Value),
|
||||
new SqlParameter("@pRESULT_STATUS_ID", (object?)request.Result.StatusId ?? DBNull.Value),
|
||||
new SqlParameter("@pRESULT_HEADER", (object?)request.Result.Header ?? DBNull.Value),
|
||||
new SqlParameter("@pRESULT_BODY", (object?)request.Result.Body ?? DBNull.Value)
|
||||
};
|
||||
var sp = new StoredProcedureBuilder("[dbo].[PRREC_UPDATE_OBJECT]", "RC")
|
||||
.Add("pENTITY", request.Entity)
|
||||
.Add("pGUID", request.Id)
|
||||
.Add("pCHANGED_WHO", request.ChangedWho)
|
||||
.Add("pCHANGED_WHEN", DateTime.UtcNow)
|
||||
.Add("pACTION_PROFILE_ID", request.Action.ProfileId)
|
||||
.Add("pACTION_ACTIVE", request.Action.Active)
|
||||
.Add("pACTION_SEQUENCE", request.Action.Sequence, SqlDbType.TinyInt)
|
||||
.Add("pACTION_ENDPOINT_ID", request.Action.EndpointId)
|
||||
.Add("pACTION_ENDPOINT_AUTH_ID", request.Action.EndpointAuthId)
|
||||
.Add("pACTION_ENDPOINT_PARAMS_ID", request.Action.EndpointParamsId, SqlDbType.SmallInt)
|
||||
.Add("pACTION_SQL_CONNECTION_ID", request.Action.SqlConnectionId, SqlDbType.SmallInt)
|
||||
.Add("pACTION_TYPE_ID", request.Action.TypeId, SqlDbType.TinyInt)
|
||||
.Add("pACTION_PRE_SQL", request.Action.PreSql)
|
||||
.Add("pACTION_HEADER_SQL", request.Action.HeaderSql)
|
||||
.Add("pACTION_BODY_SQL", request.Action.BodySql)
|
||||
.Add("pACTION_POST_SQL", request.Action.PostSql)
|
||||
.Add("pACTION_ERROR_ACTION_ID", request.Action.ErrorActionId, SqlDbType.TinyInt)
|
||||
.Add("pENDPOINT_ACTIVE", request.Endpoint.Active)
|
||||
.Add("pENDPOINT_DESCRIPTION", request.Endpoint.Description)
|
||||
.Add("pENDPOINT_URI", request.Endpoint.Uri)
|
||||
.Add("pENDPOINT_AUTH_ACTIVE", request.EndpointAuth.Active)
|
||||
.Add("pENDPOINT_AUTH_DESCRIPTION", request.EndpointAuth.Description)
|
||||
.Add("pENDPOINT_AUTH_TYPE_ID", request.EndpointAuth.TypeId, SqlDbType.TinyInt)
|
||||
.Add("pENDPOINT_AUTH_API_KEY", request.EndpointAuth.ApiKey)
|
||||
.Add("pENDPOINT_AUTH_API_VALUE", request.EndpointAuth.ApiValue)
|
||||
.Add("pENDPOINT_AUTH_API_KEY_ADD_TO_ID", request.EndpointAuth.ApiKeyAddToId)
|
||||
.Add("pENDPOINT_AUTH_TOKEN", request.EndpointAuth.Token)
|
||||
.Add("pENDPOINT_AUTH_USERNAME", request.EndpointAuth.Username)
|
||||
.Add("pENDPOINT_AUTH_PASSWORD", request.EndpointAuth.Password)
|
||||
.Add("pENDPOINT_AUTH_DOMAIN", request.EndpointAuth.Domain)
|
||||
.Add("pENDPOINT_AUTH_WORKSTATION", request.EndpointAuth.Workstation)
|
||||
.Add("pENDPOINT_PARAMS_ACTIVE", request.EndpointParams.Active)
|
||||
.Add("pENDPOINT_PARAMS_DESCRIPTION", request.EndpointParams.Description)
|
||||
.Add("pENDPOINT_PARAMS_GROUP_ID", request.EndpointParams.GroupId, SqlDbType.SmallInt)
|
||||
.Add("pENDPOINT_PARAMS_SEQUENCE", request.EndpointParams.Sequence, SqlDbType.TinyInt)
|
||||
.Add("pENDPOINT_PARAMS_KEY", request.EndpointParams.Key)
|
||||
.Add("pENDPOINT_PARAMS_VALUE", request.EndpointParams.Value)
|
||||
.Add("pPROFILE_ACTIVE", request.Profile.Active)
|
||||
.Add("pPROFILE_TYPE_ID", request.Profile.TypeId, SqlDbType.TinyInt)
|
||||
.Add("pPROFILE_MANDANTOR", request.Profile.Mandantor)
|
||||
.Add("pPROFILE_NAME", request.Profile.Name)
|
||||
.Add("pPROFILE_DESCRIPTION", request.Profile.Description)
|
||||
.Add("pPROFILE_LOG_LEVEL_ID", request.Profile.LogLevelId, SqlDbType.TinyInt)
|
||||
.Add("pPROFILE_LANGUAGE_ID", request.Profile.LanguageId, SqlDbType.SmallInt)
|
||||
.Add("pPROFILE_FIRST_RUN", request.Profile.FirstRun)
|
||||
.Add("pPROFILE_LAST_RUN", request.Profile.LastRun)
|
||||
.Add("pPROFILE_LAST_RESULT", request.Profile.LastResult)
|
||||
.Add("pRESULT_ACTION_ID", request.Result.ActionId)
|
||||
.Add("pRESULT_STATUS_ID", request.Result.StatusId, SqlDbType.TinyInt)
|
||||
.Add("pRESULT_HEADER", request.Result.Header)
|
||||
.Add("pRESULT_BODY", request.Result.Body)
|
||||
.Add("pRESULT_INFO_ID", request.Result.Info, SqlDbType.SmallInt)
|
||||
.Add("pRESULT_INFO_DETAIL", request.Result.InfoDetail)
|
||||
.Add("pRESULT_ERROR", request.Result.Error)
|
||||
.Add("pRESULT_BATCH_ID", request.Result.References?.BatchId)
|
||||
.Add("pRESULT_REFERENCE1", request.Result.References?.Reference1)
|
||||
.Add("pRESULT_REFERENCE2", request.Result.References?.Reference2)
|
||||
.Add("pRESULT_REFERENCE3", request.Result.References?.Reference3)
|
||||
.Add("pRESULT_REFERENCE4", request.Result.References?.Reference4)
|
||||
.Add("pRESULT_REFERENCE5", request.Result.References?.Reference5);
|
||||
|
||||
try
|
||||
{
|
||||
var result = await repo.ExecuteQueryRawAsync(
|
||||
"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);
|
||||
var result = await repo.ExecuteQueryRawAsync(sp.BuildSql(), sp.BuildParameters(), cancel);
|
||||
|
||||
// The stored procedure returns 0 on success, error codes > 0 on failure
|
||||
if (result > 0)
|
||||
{
|
||||
throw new UpdateObjectFailedException(request, $"UpdateObject stored procedure failed with error code: {result}");
|
||||
@@ -141,7 +112,7 @@ public class UpdateObjectProcedureHandler(IRepository repo, SqlExceptionOptions
|
||||
}
|
||||
catch (SqlException ex)
|
||||
{
|
||||
if (sqlExceptionOptions.SqlExceptionNumber.Contains(ex.Number))
|
||||
if (sqlExOpt.CurrentValue.BadRequestSqlExceptionNumbers.Contains(ex.Number))
|
||||
throw new BadRequestException(ex.Message, ex);
|
||||
else
|
||||
throw;
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
// ENTITY must be one of the allowed values
|
||||
RuleFor(x => x.Entity)
|
||||
.NotEmpty()
|
||||
.Must(e => e is "ACTION" or "ENDPOINT" or "ENDPOINT_AUTH" or "ENDPOINT_PARAMS" or "PROFILE" or "RESULT")
|
||||
.WithMessage("ENTITY must be one of: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT.");
|
||||
.IsInEnum()
|
||||
.WithMessage("ENTITY must be a valid EntityType value.");
|
||||
|
||||
// ACTION validation
|
||||
When(x => x.Entity == "ACTION", () =>
|
||||
When(x => x.Action != null, () =>
|
||||
{
|
||||
RuleFor(x => x.Action.ProfileId)
|
||||
RuleFor(x => x.Action!.ProfileId)
|
||||
.NotNull()
|
||||
.WithMessage("ACTION requires ActionProfileId (maps to @pACTION_PROFILE_ID).");
|
||||
|
||||
RuleFor(x => x.Action.EndpointId)
|
||||
RuleFor(x => x.Action!.EndpointId)
|
||||
.NotNull()
|
||||
.WithMessage("ACTION requires ActionEndpointId (maps to @pACTION_ENDPOINT_ID).");
|
||||
});
|
||||
|
||||
// ENDPOINT validation
|
||||
When(x => x.Entity == "ENDPOINT", () =>
|
||||
When(x => x.Endpoint != null, () =>
|
||||
{
|
||||
RuleFor(x => x.Endpoint.Uri)
|
||||
RuleFor(x => x.Endpoint!.Uri)
|
||||
.NotEmpty()
|
||||
.WithMessage("ENDPOINT requires EndpointUri (maps to @pENDPOINT_URI).")
|
||||
.MaximumLength(2000);
|
||||
});
|
||||
|
||||
// PROFILE validation
|
||||
When(x => x.Entity == "PROFILE", () =>
|
||||
When(x => x.Profile != null, () =>
|
||||
{
|
||||
RuleFor(x => x.Profile.Name)
|
||||
RuleFor(x => x.Profile!.Name)
|
||||
.NotEmpty()
|
||||
.WithMessage("PROFILE requires ProfileName (maps to @pPROFILE_NAME).")
|
||||
.MaximumLength(50);
|
||||
|
||||
RuleFor(x => x.Profile.Mandantor)
|
||||
RuleFor(x => x.Profile!.Mandantor)
|
||||
.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)
|
||||
.When(x => x.Profile.Description != null);
|
||||
.When(x => x.Profile!.Description != null);
|
||||
});
|
||||
|
||||
// RESULT validation
|
||||
When(x => x.Entity == "RESULT", () =>
|
||||
When(x => x.Result != null, () =>
|
||||
{
|
||||
RuleFor(x => x.Result.ActionId)
|
||||
RuleFor(x => x.Result!.ActionId)
|
||||
.NotNull()
|
||||
.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
|
||||
When(x => x.Entity == "ENDPOINT_PARAMS", () =>
|
||||
When(x => x.EndpointParams != null, () =>
|
||||
{
|
||||
RuleFor(x => x.EndpointParams.GroupId)
|
||||
RuleFor(x => x.EndpointParams!.GroupId)
|
||||
.NotNull()
|
||||
.WithMessage("ENDPOINT_PARAMS requires EndpointParamsGroupId (maps to @pENDPOINT_PARAMS_GROUP_ID).");
|
||||
});
|
||||
@@ -76,12 +70,12 @@ public class InsertObjectProcedureValidator : AbstractValidator<InsertObjectProc
|
||||
.MaximumLength(50)
|
||||
.When(x => x.AddedWho != null);
|
||||
|
||||
RuleFor(x => x.Endpoint.Description)
|
||||
RuleFor(x => x.Endpoint!.Description)
|
||||
.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)
|
||||
.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);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using ReC.Application.Common.Behaviors;
|
||||
using ReC.Application.Common.Behaviors.Action;
|
||||
using ReC.Application.Common.Behaviors.InvokeAction;
|
||||
using ReC.Application.Common.Constants;
|
||||
using ReC.Application.Common.Options;
|
||||
using ReC.Application.Common.Procedures;
|
||||
using ReC.Application.RecActions.Commands;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ReC.Application;
|
||||
@@ -35,6 +36,8 @@ public static class DependencyInjection
|
||||
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
|
||||
cfg.AddOpenBehaviors([typeof(BodyQueryBehavior<,>), typeof(HeaderQueryBehavior<,>)]);
|
||||
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
||||
cfg.AddBehavior(typeof(IPipelineBehavior<InvokeRecActionViewCommand, Unit>), typeof(PostprocessingBehavior));
|
||||
cfg.AddBehavior(typeof(IPipelineBehavior<InvokeRecActionViewCommand, Unit>), typeof(PreprocessingBehavior));
|
||||
cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
public record DeleteEndpointAuthCommand : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteEndpointAuthProcedureHandler(ISender sender) : IRequestHandler<DeleteEndpointAuthCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteEndpointAuthCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = EntityType.EndpointAuth,
|
||||
Start = request.Start,
|
||||
End = request.End,
|
||||
Force = request.Force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
namespace ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
public record DeleteEndpointAuthProcedure : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
|
||||
public DeleteObjectProcedure ToObjectProcedure()
|
||||
{
|
||||
return new DeleteObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT_AUTH",
|
||||
Start = Start,
|
||||
End = End,
|
||||
Force = Force
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
public record InsertEndpointAuthCommand : IInsertProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public string? ApiKey { get; set; }
|
||||
public string? ApiValue { get; set; }
|
||||
public bool? ApiKeyAddToId { 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 class InsertEndpointAuthProcedureHandler(ISender sender) : IRequestHandler<InsertEndpointAuthCommand, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertEndpointAuthCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new InsertObjectProcedure
|
||||
{
|
||||
Entity = EntityType.EndpointAuth,
|
||||
EndpointAuth = request
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
public record UpdateEndpointAuthCommand : IUpdateProcedure<UpdateEndpointAuthDto>
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public UpdateEndpointAuthDto Data { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class UpdateEndpointAuthProcedureHandler(ISender sender) : IRequestHandler<UpdateEndpointAuthCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateEndpointAuthCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new UpdateObjectProcedure
|
||||
{
|
||||
Entity = EntityType.EndpointAuth,
|
||||
Id = request.Id,
|
||||
EndpointAuth = request.Data
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
namespace ReC.Application.EndpointAuth.Commands;
|
||||
|
||||
public record UpdateEndpointAuthProcedure : IUpdateProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public string? ApiKey { get; set; }
|
||||
public string? ApiValue { get; set; }
|
||||
public bool? ApiKeyAddToId { 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 UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
|
||||
{
|
||||
return new UpdateObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT_AUTH",
|
||||
Id = id,
|
||||
EndpointAuth = this
|
||||
}.ChangedBy(changedWho);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.EndpointParams.Commands;
|
||||
|
||||
public record DeleteEndpointParamsCommand : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteEndpointParamsProcedureHandler(ISender sender) : IRequestHandler<DeleteEndpointParamsCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteEndpointParamsCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = EntityType.EndpointParams,
|
||||
Start = request.Start,
|
||||
End = request.End,
|
||||
Force = request.Force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
namespace ReC.Application.EndpointParams.Commands;
|
||||
|
||||
public record DeleteEndpointParamsProcedure : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
|
||||
public DeleteObjectProcedure ToObjectProcedure()
|
||||
{
|
||||
return new DeleteObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT_PARAMS",
|
||||
Start = Start,
|
||||
End = End,
|
||||
Force = Force
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.EndpointParams.Commands;
|
||||
|
||||
public record InsertEndpointParamsCommand : IInsertProcedure
|
||||
{
|
||||
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 class InsertEndpointParamsProcedureHandler(ISender sender) : IRequestHandler<InsertEndpointParamsCommand, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertEndpointParamsCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new InsertObjectProcedure
|
||||
{
|
||||
Entity = EntityType.EndpointParams,
|
||||
EndpointParams = request
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
|
||||
namespace ReC.Application.EndpointParams.Commands;
|
||||
|
||||
public record InsertEndpointParamsProcedure : IInsertProcedure
|
||||
{
|
||||
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 InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
|
||||
{
|
||||
return new InsertObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT_PARAMS",
|
||||
EndpointParams = this
|
||||
}.AddedBy(addedWho);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.EndpointParams.Commands;
|
||||
|
||||
public record UpdateEndpointParamsCommand : IUpdateProcedure<UpdateEndpointParamsDto>
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public UpdateEndpointParamsDto Data { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class UpdateEndpointParamsProcedureHandler(ISender sender) : IRequestHandler<UpdateEndpointParamsCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateEndpointParamsCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new UpdateObjectProcedure
|
||||
{
|
||||
Entity = EntityType.EndpointParams,
|
||||
Id = request.Id,
|
||||
EndpointParams = request.Data
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
namespace ReC.Application.EndpointParams.Commands;
|
||||
|
||||
public record UpdateEndpointParamsProcedure : IUpdateProcedure
|
||||
{
|
||||
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 UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
|
||||
{
|
||||
return new UpdateObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT_PARAMS",
|
||||
Id = id,
|
||||
EndpointParams = this
|
||||
}.ChangedBy(changedWho);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Endpoints.Commands;
|
||||
|
||||
public record DeleteEndpointCommand : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteEndpointProcedureHandler(ISender sender) : IRequestHandler<DeleteEndpointCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteEndpointCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Endpoint,
|
||||
Start = request.Start,
|
||||
End = request.End,
|
||||
Force = request.Force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
namespace ReC.Application.Endpoints.Commands;
|
||||
|
||||
public record DeleteEndpointProcedure : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
|
||||
public DeleteObjectProcedure ToObjectProcedure()
|
||||
{
|
||||
return new DeleteObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT",
|
||||
Start = Start,
|
||||
End = End,
|
||||
Force = Force
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Endpoints.Commands;
|
||||
|
||||
public record InsertEndpointCommand : IInsertProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Uri { get; set; }
|
||||
}
|
||||
|
||||
public class InsertEndpointProcedureHandler(ISender sender) : IRequestHandler<InsertEndpointCommand, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertEndpointCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new InsertObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Endpoint,
|
||||
Endpoint = request
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
|
||||
namespace ReC.Application.Endpoints.Commands;
|
||||
|
||||
public record InsertEndpointProcedure : IInsertProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Uri { get; set; }
|
||||
|
||||
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
|
||||
{
|
||||
return new InsertObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT",
|
||||
Endpoint = this
|
||||
}.AddedBy(addedWho);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Endpoints.Commands;
|
||||
|
||||
public record UpdateEndpointCommand : IUpdateProcedure<UpdateEndpointDto>
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public UpdateEndpointDto Data { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class UpdateEndpointProcedureHandler(ISender sender) : IRequestHandler<UpdateEndpointCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateEndpointCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new UpdateObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Endpoint,
|
||||
Id = request.Id,
|
||||
Endpoint = request.Data
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
namespace ReC.Application.Endpoints.Commands;
|
||||
|
||||
public record UpdateEndpointProcedure : IUpdateProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Uri { get; set; }
|
||||
|
||||
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
|
||||
{
|
||||
return new UpdateObjectProcedure
|
||||
{
|
||||
Entity = "ENDPOINT",
|
||||
Id = id,
|
||||
Endpoint = this
|
||||
}.ChangedBy(changedWho);
|
||||
}
|
||||
}
|
||||
37
src/ReC.Application/Profile/Commands/DeleteProfileCommand.cs
Normal file
37
src/ReC.Application/Profile/Commands/DeleteProfileCommand.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Profile.Commands;
|
||||
|
||||
public record DeleteProfileCommand : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteProfileProcedureHandler(ISender sender) : IRequestHandler<DeleteProfileCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteProfileCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Profile,
|
||||
Start = request.Start,
|
||||
End = request.End,
|
||||
Force = request.Force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
namespace ReC.Application.Profile.Commands;
|
||||
|
||||
public record DeleteProfileProcedure : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent ACTION data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
|
||||
public DeleteObjectProcedure ToObjectProcedure()
|
||||
{
|
||||
return new DeleteObjectProcedure
|
||||
{
|
||||
Entity = "PROFILE",
|
||||
Start = Start,
|
||||
End = End,
|
||||
Force = Force
|
||||
};
|
||||
}
|
||||
}
|
||||
28
src/ReC.Application/Profile/Commands/InsertProfileCommand.cs
Normal file
28
src/ReC.Application/Profile/Commands/InsertProfileCommand.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Profile.Commands;
|
||||
|
||||
public record InsertProfileCommand : IInsertProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public string? Mandantor { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public byte? LogLevelId { get; set; }
|
||||
public short? LanguageId { get; set; }
|
||||
}
|
||||
|
||||
public class InsertProfileProcedureHandler(ISender sender) : IRequestHandler<InsertProfileCommand, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertProfileCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new InsertObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Profile,
|
||||
Profile = request
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
|
||||
namespace ReC.Application.Profile.Commands;
|
||||
|
||||
public record InsertProfileProcedure : IInsertProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public string? Mandantor { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public byte? LogLevelId { get; set; }
|
||||
public short? LanguageId { get; set; }
|
||||
|
||||
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
|
||||
{
|
||||
return new InsertObjectProcedure
|
||||
{
|
||||
Entity = "PROFILE",
|
||||
Profile = this
|
||||
}.AddedBy(addedWho);
|
||||
}
|
||||
}
|
||||
26
src/ReC.Application/Profile/Commands/UpdateProfileCommand.cs
Normal file
26
src/ReC.Application/Profile/Commands/UpdateProfileCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Profile.Commands;
|
||||
|
||||
public record UpdateProfileCommand : IUpdateProcedure<UpdateProfileDto>
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public UpdateProfileDto Data { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class UpdateProfileProcedureHandler(ISender sender) : IRequestHandler<UpdateProfileCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateProfileCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new UpdateObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Profile,
|
||||
Id = request.Id,
|
||||
Profile = request.Data
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
namespace ReC.Application.Profile.Commands;
|
||||
|
||||
public record UpdateProfileProcedure : IUpdateProcedure
|
||||
{
|
||||
public bool? Active { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public string? Mandantor { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public byte? LogLevelId { get; set; }
|
||||
public short? LanguageId { get; set; }
|
||||
public DateTime? FirstRun { get; set; }
|
||||
public DateTime? LastRun { get; set; }
|
||||
public string? LastResult { get; set; }
|
||||
|
||||
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
|
||||
{
|
||||
return new UpdateObjectProcedure
|
||||
{
|
||||
Entity = "PROFILE",
|
||||
Id = id,
|
||||
Profile = this
|
||||
}.ChangedBy(changedWho);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<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.Application" Version="3.4.0" />
|
||||
<PackageReference Include="DigitalData.Core.Exceptions" Version="1.1.1" />
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public record DeleteActionCommand : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent RESULT data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
}
|
||||
|
||||
public class DeleteActionProcedureHandler(ISender sender) : IRequestHandler<DeleteActionCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteActionCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Action,
|
||||
Start = request.Start,
|
||||
End = request.End,
|
||||
Force = request.Force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public record DeleteActionProcedure : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
/// </summary>
|
||||
public long Start { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// End GUID/ID (inclusive). If 0, will be set to Start value.
|
||||
/// </summary>
|
||||
public long End { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true, delete even if dependent RESULT data exists
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
|
||||
public DeleteObjectProcedure ToObjectProcedure()
|
||||
{
|
||||
return new DeleteObjectProcedure
|
||||
{
|
||||
Entity = "ACTION",
|
||||
Start = Start,
|
||||
End = End,
|
||||
Force = Force
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Domain.Constants;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public record UpdateActionProcedure : IUpdateProcedure
|
||||
public record InsertActionCommand : IInsertProcedure
|
||||
{
|
||||
public long? ProfileId { get; set; }
|
||||
public bool? Active { get; set; }
|
||||
@@ -11,20 +14,22 @@ public record UpdateActionProcedure : IUpdateProcedure
|
||||
public long? EndpointAuthId { get; set; }
|
||||
public short? EndpointParamsId { get; set; }
|
||||
public short? SqlConnectionId { get; set; }
|
||||
public byte? TypeId { get; set; }
|
||||
public RestType? TypeId { get; set; }
|
||||
public string? PreSql { get; set; }
|
||||
public string? HeaderSql { get; set; }
|
||||
public string? BodySql { get; set; }
|
||||
public string? PostSql { get; set; }
|
||||
public byte? ErrorActionId { get; set; }
|
||||
|
||||
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
|
||||
{
|
||||
return new UpdateObjectProcedure
|
||||
{
|
||||
Entity = "ACTION",
|
||||
Id = id,
|
||||
Action = this
|
||||
}.ChangedBy(changedWho);
|
||||
}
|
||||
}
|
||||
|
||||
public class InsertActionProcedureHandler(ISender sender) : IRequestHandler<InsertActionCommand, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertActionCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new InsertObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Action,
|
||||
Action = request
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.RecActions.Queries;
|
||||
using ReC.Domain.Constants;
|
||||
|
||||
@@ -7,31 +9,49 @@ namespace ReC.Application.RecActions.Commands;
|
||||
public record InvokeBatchRecActionViewsCommand : IRequest
|
||||
{
|
||||
public long ProfileId { get; init; }
|
||||
public required InvokeReferences References { get; init; }
|
||||
}
|
||||
|
||||
public static class InvokeBatchRecActionViewsCommandExtensions
|
||||
{
|
||||
public static Task InvokeBatchRecActionView(this ISender sender, long profileId, CancellationToken cancel = default)
|
||||
=> sender.Send(new InvokeBatchRecActionViewsCommand { ProfileId = profileId }, cancel);
|
||||
}
|
||||
|
||||
public class InvokeRecActionViewsCommandHandler(ISender sender) : IRequestHandler<InvokeBatchRecActionViewsCommand>
|
||||
public class InvokeRecActionViewsCommandHandler(ISender sender, ILogger<InvokeRecActionViewsCommandHandler>? logger = null) : IRequestHandler<InvokeBatchRecActionViewsCommand>
|
||||
{
|
||||
public async Task Handle(InvokeBatchRecActionViewsCommand request, CancellationToken cancel)
|
||||
{
|
||||
var actions = await sender.Send(new ReadRecActionViewQuery() { ProfileId = request.ProfileId, Invoked = false }, cancel);
|
||||
var actions = await sender.Send(new ReadRecActionViewQuery() { ProfileId = request.ProfileId }, cancel);
|
||||
|
||||
foreach (var action in actions)
|
||||
{
|
||||
var ok = await sender.Send(action.ToInvokeCommand(), cancel);
|
||||
if (!ok)
|
||||
try
|
||||
{
|
||||
await sender.Send(new InvokeRecActionViewCommand()
|
||||
{
|
||||
Action = action,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
}
|
||||
catch (RecActionException ex)
|
||||
{
|
||||
switch (action.ErrorAction)
|
||||
{
|
||||
case ErrorAction.Continue:
|
||||
logger?.LogWarning(ex, "Rec action failed but continuing. ActionId: {ActionId}, ProfileId: {ProfileId}", ex.ActionId, ex.ProfileId);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
// Rethrow the exception to stop processing further actions
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
switch (action.ErrorAction)
|
||||
{
|
||||
case ErrorAction.Continue:
|
||||
logger?.LogError(ex, "Unexpected error during rec action. ActionId: {ActionId}, ProfileId: {ProfileId}", action.Id, action.ProfileId);
|
||||
break;
|
||||
default:
|
||||
// Rethrow the exception to stop processing further actions
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
using MediatR;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using ReC.Application.Common;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ReC.Application.Common.Constants;
|
||||
using ReC.Application.Common.Dto;
|
||||
using ReC.Application.Common.Exceptions;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.Common.Options;
|
||||
using ReC.Application.Results.Commands;
|
||||
using ReC.Domain.Constants;
|
||||
using ReC.Domain.Views;
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
@@ -14,134 +15,193 @@ using System.Text.Json;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public record InvokeRecActionViewCommand : IRequest<bool>
|
||||
public record InvokeRecActionViewCommand : IRequest
|
||||
{
|
||||
public RecActionViewDto Action { get; set; } = null!;
|
||||
public required InvokeReferences References { get; set; }
|
||||
}
|
||||
|
||||
public static class InvokeRecActionViewCommandExtensions
|
||||
public record InvokeReferences
|
||||
{
|
||||
public static InvokeRecActionViewCommand ToInvokeCommand(this RecActionViewDto dto) => new() { Action = dto };
|
||||
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(
|
||||
IOptions<RecActionOptions> options,
|
||||
ISender sender,
|
||||
IHttpClientFactory clientFactory,
|
||||
IConfiguration? config = null
|
||||
) : IRequestHandler<InvokeRecActionViewCommand, bool>
|
||||
) : IRequestHandler<InvokeRecActionViewCommand>
|
||||
{
|
||||
public async Task<bool> Handle(InvokeRecActionViewCommand request, CancellationToken cancel)
|
||||
private readonly RecActionOptions _options = options.Value;
|
||||
|
||||
public async Task Handle(InvokeRecActionViewCommand request, CancellationToken cancel)
|
||||
{
|
||||
var action = request.Action;
|
||||
HttpClient? ntlmClient = null;
|
||||
|
||||
using var http = clientFactory.CreateClient(Http.ClientName);
|
||||
|
||||
if (action.RestType is not RestType restType)
|
||||
throw new DataIntegrityException(
|
||||
$"Rec action could not be invoked because the RestType value is null. " +
|
||||
$"ProfileId: {action.ProfileId}, " +
|
||||
$"Id: {action.Id}"
|
||||
);
|
||||
|
||||
using var httpReq = restType
|
||||
.ToHttpMethod()
|
||||
.ToHttpRequestMessage(action.EndpointUri);
|
||||
|
||||
if (action.Body is not null)
|
||||
try
|
||||
{
|
||||
using var reqBody = new StringContent(action.Body);
|
||||
httpReq.Content = reqBody;
|
||||
}
|
||||
|
||||
if (action.Headers is not null)
|
||||
foreach (var header in action.Headers)
|
||||
httpReq.Headers.Add(header.Key, header.Value);
|
||||
|
||||
switch (action.EndpointAuthType)
|
||||
{
|
||||
case EndpointAuthType.NoAuth:
|
||||
break;
|
||||
|
||||
case EndpointAuthType.ApiKey:
|
||||
if (action.EndpointAuthApiKey is string apiKey && action.EndpointAuthApiValue is string apiValue)
|
||||
{
|
||||
switch (action.EndpointAuthApiKeyAddTo)
|
||||
{
|
||||
case ApiKeyLocation.Header:
|
||||
httpReq.Headers.Add(apiKey, apiValue);
|
||||
break;
|
||||
case ApiKeyLocation.Query:
|
||||
var uriBuilder = new UriBuilder(httpReq.RequestUri!);
|
||||
var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
|
||||
query[apiKey] = apiValue;
|
||||
uriBuilder.Query = query.ToString();
|
||||
httpReq.RequestUri = uriBuilder.Uri;
|
||||
break;
|
||||
default:
|
||||
throw new DataIntegrityException(
|
||||
$"The API key location '{action.EndpointAuthApiKeyAddTo}' is not supported. " +
|
||||
$"ProfileId: {action.ProfileId}, " +
|
||||
$"Id: {action.Id}"
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EndpointAuthType.BearerToken:
|
||||
case EndpointAuthType.JwtBearer:
|
||||
case EndpointAuthType.OAuth2:
|
||||
if (action.EndpointAuthToken is string authToken)
|
||||
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
|
||||
break;
|
||||
|
||||
case EndpointAuthType.BasicAuth:
|
||||
if (action.EndpointAuthUsername is string authUsername && action.EndpointAuthPassword is string authPassword)
|
||||
{
|
||||
var basicAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{authUsername}:{authPassword}"));
|
||||
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Basic", basicAuth);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndpointAuthType.NtlmAuth:
|
||||
if (!string.IsNullOrWhiteSpace(action.EndpointAuthUsername))
|
||||
{
|
||||
var credentials = new NetworkCredential(
|
||||
action.EndpointAuthUsername,
|
||||
action.EndpointAuthPassword,
|
||||
action.EndpointAuthDomain);
|
||||
var credentialCache = new CredentialCache { { httpReq.RequestUri!, "NTLM", credentials } };
|
||||
httpReq.Options.Set(new HttpRequestOptionsKey<CredentialCache>("Credentials"), credentialCache);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndpointAuthType.DigestAuth:
|
||||
case EndpointAuthType.OAuth1:
|
||||
case EndpointAuthType.AwsSignature:
|
||||
// These authentication methods require more complex implementations,
|
||||
// often involving multi-step handshakes or specialized libraries.
|
||||
// They are left as placeholders for future implementation.
|
||||
default:
|
||||
throw new NotImplementedException(
|
||||
$"The authentication type '{action.EndpointAuthType}' is not supported yet. " +
|
||||
if (action.RestType is not RestType restType)
|
||||
throw new DataIntegrityException(
|
||||
$"Rec action could not be invoked because the RestType value is null. " +
|
||||
$"ProfileId: {action.ProfileId}, " +
|
||||
$"Id: {action.Id}"
|
||||
);
|
||||
|
||||
using var httpReq = CreateHttpRequestMessage(restType, action.EndpointUri);
|
||||
|
||||
if (action.Body is not null)
|
||||
httpReq.Content = new StringContent(action.Body);
|
||||
|
||||
if (action.Headers is not null)
|
||||
foreach (var header in action.Headers)
|
||||
httpReq.Headers.Add(header.Key, header.Value);
|
||||
|
||||
switch (action.EndpointAuthType)
|
||||
{
|
||||
case EndpointAuthType.NoAuth:
|
||||
break;
|
||||
|
||||
case EndpointAuthType.ApiKey:
|
||||
if (action.EndpointAuthApiKey is string apiKey && action.EndpointAuthApiValue is string apiValue)
|
||||
{
|
||||
switch (action.EndpointAuthApiKeyAddTo)
|
||||
{
|
||||
case ApiKeyLocation.Header:
|
||||
httpReq.Headers.Add(apiKey, apiValue);
|
||||
break;
|
||||
case ApiKeyLocation.Query:
|
||||
var uriBuilder = new UriBuilder(httpReq.RequestUri!);
|
||||
var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
|
||||
query[apiKey] = apiValue;
|
||||
uriBuilder.Query = query.ToString();
|
||||
httpReq.RequestUri = uriBuilder.Uri;
|
||||
break;
|
||||
default:
|
||||
throw new DataIntegrityException(
|
||||
$"The API key location '{action.EndpointAuthApiKeyAddTo}' is not supported. " +
|
||||
$"ProfileId: {action.ProfileId}, " +
|
||||
$"Id: {action.Id}"
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EndpointAuthType.BearerToken:
|
||||
case EndpointAuthType.JwtBearer:
|
||||
case EndpointAuthType.OAuth2:
|
||||
if (action.EndpointAuthToken is string authToken)
|
||||
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
|
||||
break;
|
||||
|
||||
case EndpointAuthType.BasicAuth:
|
||||
if (action.EndpointAuthUsername is string authUsername && action.EndpointAuthPassword is string authPassword)
|
||||
{
|
||||
var basicAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{authUsername}:{authPassword}"));
|
||||
httpReq.Headers.Authorization = new AuthenticationHeaderValue("Basic", basicAuth);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndpointAuthType.NtlmAuth:
|
||||
if (!string.IsNullOrWhiteSpace(action.EndpointAuthUsername))
|
||||
{
|
||||
if (_options.UseHttp1ForNtlm)
|
||||
{
|
||||
httpReq.Version = HttpVersion.Version11;
|
||||
httpReq.VersionPolicy = HttpVersionPolicy.RequestVersionExact;
|
||||
}
|
||||
var endpointAuthPassword = action.EndpointAuthPassword
|
||||
#if DEBUG
|
||||
?.Replace("%NTLM_PW%", config?.GetValue<string>("%NTLM_PW%"))
|
||||
#endif
|
||||
;
|
||||
var credentials = new NetworkCredential(
|
||||
action.EndpointAuthUsername,
|
||||
endpointAuthPassword,
|
||||
action.EndpointAuthDomain);
|
||||
var credentialCache = new CredentialCache { { httpReq.RequestUri!, "NTLM", credentials } };
|
||||
var ntlmHandler = new HttpClientHandler
|
||||
{
|
||||
Credentials = credentialCache,
|
||||
UseDefaultCredentials = false
|
||||
};
|
||||
ntlmClient = new HttpClient(ntlmHandler, disposeHandler: true);
|
||||
}
|
||||
break;
|
||||
|
||||
case EndpointAuthType.DigestAuth:
|
||||
case EndpointAuthType.OAuth1:
|
||||
case EndpointAuthType.AwsSignature:
|
||||
// These authentication methods require more complex implementations,
|
||||
// often involving multi-step handshakes or specialized libraries.
|
||||
// They are left as placeholders for future implementation.
|
||||
default:
|
||||
throw new NotImplementedException(
|
||||
$"The authentication type '{action.EndpointAuthType}' is not supported yet. " +
|
||||
$"ProfileId: {action.ProfileId}, " +
|
||||
$"Id: {action.Id}"
|
||||
);
|
||||
}
|
||||
|
||||
var http = ntlmClient ?? clientFactory.CreateClient(Http.ClientName);
|
||||
using var response = await http.SendAsync(httpReq, cancel);
|
||||
var resBody = await response.Content.ReadAsStringAsync(cancel);
|
||||
var resHeaders = response.Headers.ToDictionary();
|
||||
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = response.StatusCode.ToRecStatus(),
|
||||
ActionId = action.Id,
|
||||
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
||||
Body = resBody,
|
||||
Info = (short)response.StatusCode,
|
||||
Type = ResultType.Main,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
}
|
||||
|
||||
using var response = await http.SendAsync(httpReq, cancel);
|
||||
var resBody = await response.Content.ReadAsStringAsync(cancel);
|
||||
var resHeaders = response.Headers.ToDictionary();
|
||||
|
||||
var statusCode = (short)response.StatusCode;
|
||||
|
||||
await sender.ExecuteInsertProcedure(new InsertResultProcedure()
|
||||
catch(Exception ex)
|
||||
{
|
||||
StatusId = statusCode,
|
||||
ActionId = action.Id,
|
||||
Header = JsonSerializer.Serialize(resHeaders, options: new() { WriteIndented = false }),
|
||||
Body = resBody
|
||||
}, config?["AddedWho"], cancel);
|
||||
await sender.Send(new InsertResultCommand()
|
||||
{
|
||||
Status = RecStatus.Error,
|
||||
ActionId = action.Id,
|
||||
Error = ex.ToString(),
|
||||
Type = ResultType.Main,
|
||||
References = request.References
|
||||
}, cancel);
|
||||
|
||||
return response.IsSuccessStatusCode;
|
||||
if (action.ErrorAction == ErrorAction.Stop)
|
||||
throw new RecActionException(action.Id, action.ProfileId, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ntlmClient?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static HttpRequestMessage CreateHttpRequestMessage(RestType restType, string? endpointUri)
|
||||
{
|
||||
var method = restType switch
|
||||
{
|
||||
RestType.Get => HttpMethod.Get,
|
||||
RestType.Post => HttpMethod.Post,
|
||||
RestType.Put => HttpMethod.Put,
|
||||
RestType.Delete => HttpMethod.Delete,
|
||||
RestType.Patch => HttpMethod.Patch,
|
||||
RestType.Head => HttpMethod.Head,
|
||||
RestType.Options => HttpMethod.Options,
|
||||
RestType.Trace => HttpMethod.Trace,
|
||||
RestType.Connect => HttpMethod.Connect,
|
||||
RestType.None => throw new ArgumentOutOfRangeException(nameof(restType), $"The RestType value '{restType}' is not valid."),
|
||||
_ => new HttpMethod(restType.ToString().ToUpperInvariant())
|
||||
};
|
||||
|
||||
return new HttpRequestMessage(method, endpointUri);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.RecActions.Commands;
|
||||
|
||||
public record UpdateActionCommand : IUpdateProcedure<UpdateActionDto>
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public UpdateActionDto Data { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class UpdateActionProcedureHandler(ISender sender) : IRequestHandler<UpdateActionCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateActionCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new UpdateObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Action,
|
||||
Id = request.Id,
|
||||
Action = request.Data
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.DeleteProcedure;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Results.Commands;
|
||||
|
||||
public record DeleteResultProcedure : IDeleteProcedure
|
||||
public record DeleteResultCommand : IDeleteProcedure
|
||||
{
|
||||
/// <summary>
|
||||
/// Start GUID/ID (inclusive)
|
||||
@@ -18,15 +20,18 @@ public record DeleteResultProcedure : IDeleteProcedure
|
||||
/// Force parameter (not used for RESULT entity as it has no dependencies)
|
||||
/// </summary>
|
||||
public bool Force { get; set; }
|
||||
|
||||
public DeleteObjectProcedure ToObjectProcedure()
|
||||
{
|
||||
return new DeleteObjectProcedure
|
||||
{
|
||||
Entity = "RESULT",
|
||||
Start = Start,
|
||||
End = End,
|
||||
Force = Force
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class DeleteResultProcedureHandler(ISender sender) : IRequestHandler<DeleteResultCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(DeleteResultCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new DeleteObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Result,
|
||||
Start = request.Start,
|
||||
End = request.End,
|
||||
Force = request.Force
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
32
src/ReC.Application/Results/Commands/InsertResultCommand.cs
Normal file
32
src/ReC.Application/Results/Commands/InsertResultCommand.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
using ReC.Application.RecActions.Commands;
|
||||
using ReC.Domain.Constants;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Results.Commands;
|
||||
|
||||
public record InsertResultCommand : IInsertProcedure
|
||||
{
|
||||
public long? ActionId { get; set; }
|
||||
public required RecStatus Status { get; set; }
|
||||
public string? Header { get; set; }
|
||||
public string? Body { get; set; }
|
||||
public short Info { get; set; }
|
||||
public string? InfoDetail { get; set; }
|
||||
public string? Error { get; set; }
|
||||
public required ResultType Type { get; set; }
|
||||
public required InvokeReferences References { get; set; }
|
||||
}
|
||||
|
||||
public class InsertResultProcedureHandler(ISender sender) : IRequestHandler<InsertResultCommand, long>
|
||||
{
|
||||
public async Task<long> Handle(InsertResultCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new InsertObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Result,
|
||||
Result = request
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.InsertProcedure;
|
||||
|
||||
namespace ReC.Application.Results.Commands;
|
||||
|
||||
public record InsertResultProcedure : IInsertProcedure
|
||||
{
|
||||
public long? ActionId { get; set; }
|
||||
public short? StatusId { get; set; }
|
||||
public string? Header { get; set; }
|
||||
public string? Body { get; set; }
|
||||
|
||||
public InsertObjectProcedure ToObjectProcedure(string? addedWho = null)
|
||||
{
|
||||
return new InsertObjectProcedure
|
||||
{
|
||||
Entity = "RESULT",
|
||||
Result = this
|
||||
}.AddedBy(addedWho ?? "Rec.API");
|
||||
}
|
||||
}
|
||||
26
src/ReC.Application/Results/Commands/UpdateResultCommand.cs
Normal file
26
src/ReC.Application/Results/Commands/UpdateResultCommand.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using MediatR;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure.Dto;
|
||||
using ReC.Application.Common.Procedures;
|
||||
|
||||
namespace ReC.Application.Results.Commands;
|
||||
|
||||
public record UpdateResultCommand : IUpdateProcedure<UpdateResultDto>
|
||||
{
|
||||
public long Id { get; set; }
|
||||
|
||||
public UpdateResultDto Data { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class UpdateResultProcedureHandler(ISender sender) : IRequestHandler<UpdateResultCommand, int>
|
||||
{
|
||||
public async Task<int> Handle(UpdateResultCommand request, CancellationToken cancel)
|
||||
{
|
||||
return await sender.Send(new UpdateObjectProcedure
|
||||
{
|
||||
Entity = EntityType.Result,
|
||||
Id = request.Id,
|
||||
Result = request.Data
|
||||
}, cancel);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using ReC.Application.Common.Procedures.UpdateProcedure;
|
||||
|
||||
namespace ReC.Application.Results.Commands;
|
||||
|
||||
public record UpdateResultProcedure : IUpdateProcedure
|
||||
{
|
||||
public long? ActionId { get; set; }
|
||||
public short? StatusId { get; set; }
|
||||
public string? Header { get; set; }
|
||||
public string? Body { get; set; }
|
||||
|
||||
public UpdateObjectProcedure ToObjectProcedure(long id, string? changedWho = null)
|
||||
{
|
||||
return new UpdateObjectProcedure
|
||||
{
|
||||
Entity = "RESULT",
|
||||
Id = id,
|
||||
Result = this
|
||||
}.ChangedBy(changedWho);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,14 @@ public record ReadResultViewQuery : IRequest<IEnumerable<ResultViewDto>>
|
||||
public long? ActionId { get; init; } = null;
|
||||
|
||||
public long? ProfileId { get; init; } = null;
|
||||
|
||||
public string? BatchId { get; init; } = null;
|
||||
|
||||
public bool IncludeAction { get; init; } = true;
|
||||
|
||||
public bool IncludeProfile { get; init; } = false;
|
||||
|
||||
public bool LastBatch { get; init; } = false;
|
||||
}
|
||||
|
||||
public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper mapper) : IRequestHandler<ReadResultViewQuery, IEnumerable<ResultViewDto>>
|
||||
@@ -33,7 +41,18 @@ public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper ma
|
||||
if(request.ProfileId is long profileId)
|
||||
q = q.Where(rv => rv.ProfileId == profileId);
|
||||
|
||||
var entities = await q.ToListAsync(cancel);
|
||||
if(request.BatchId is string batchId)
|
||||
q = q.Where(rv => rv.BatchId == batchId);
|
||||
|
||||
if (request.IncludeAction)
|
||||
q = q.Include(rv => rv.Action);
|
||||
|
||||
if(request.IncludeProfile)
|
||||
q = q.Include(rv => rv.Profile);
|
||||
|
||||
var entities = request.LastBatch
|
||||
? await GetLastBatchEntitiesAsync(q, cancel)
|
||||
: await q.ToListAsync(cancel);
|
||||
|
||||
if (entities.Count == 0)
|
||||
throw new NotFoundException($"No result views found for the given criteria. Criteria: {
|
||||
@@ -46,4 +65,20 @@ public class ReadResultViewQueryHandler(IRepository<ResultView> repo, IMapper ma
|
||||
|
||||
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.
|
||||
/// </summary>
|
||||
/// <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>
|
||||
/// <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;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Retrieves Rec actions.
|
||||
/// </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;
|
||||
}
|
||||
}
|
||||
8
src/ReC.Domain/Constants/ResultType.cs
Normal file
8
src/ReC.Domain/Constants/ResultType.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace ReC.Domain.Constants;
|
||||
|
||||
public enum ResultType : byte
|
||||
{
|
||||
Pre = 1,
|
||||
Main,
|
||||
Post
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user