Compare commits

...

24 Commits

Author SHA1 Message Date
Developer 02
cbd86de3e8 Add handling for update and delete exceptions
Enhanced `ExceptionHandlingMiddleware` to handle
`UpdateObjectFailedException` and `DeleteObjectFailedException`.
Logs exception details, including serialized procedure data,
and sets HTTP status to `500 Internal Server Error`.
Improves error differentiation and response for specific failure cases.
2026-01-16 01:10:57 +01:00
Developer 02
a5160b35dd Add HTTP DELETE endpoint to CommonController
A new `DeleteObject` method has been added to the `CommonController` class to handle HTTP DELETE requests. This method is asynchronous and processes a `DeleteObjectProcedure` object passed in the request body using the `mediator.Send` function. The result is returned as an HTTP 200 OK response. The `[HttpDelete]` attribute has been applied to the method to designate it as a DELETE endpoint.
2026-01-16 01:08:30 +01:00
Developer 02
60e1627494 Add UpdateObject endpoint and enhance procedure support
Enhanced `CommonController` to support object operations:
- Added `using` statements for Insert, Update, and Delete procedures.
- Updated constructor to inject `IMediator` for request handling.
- Introduced `UpdateObject` endpoint with HTTP PUT support.
  - Processes `UpdateObjectProcedure` via MediatR.
  - Returns HTTP 200 OK with the result.
2026-01-16 01:08:20 +01:00
Developer 02
b9f08bc21c Add DeleteActionProcedure for ACTION entity deletion
Introduced a new `DeleteActionProcedure` record in the
`ReC.Application.Common.Procedures.DeleteProcedure` namespace.

This record implements the `IDeleteProcedure` interface and includes
the following properties:
- `Start`: Starting GUID/ID (inclusive).
- `End`: Ending GUID/ID (inclusive), defaults to `Start` if 0.
- `Force`: Allows deletion even if dependent RESULT data exists.

Added a `ToObjectProcedure` method to convert `DeleteActionProcedure`
to a `DeleteObjectProcedure` with the entity set to `"ACTION"`.
2026-01-16 01:06:56 +01:00
Developer 02
758616c95e Add DeleteEndpointAuthProcedure for endpoint deletion
Introduce the `DeleteEndpointAuthProcedure` record in the new
`ReC.Application.Common.Procedures.DeleteProcedure` namespace.
This record implements the `IDeleteProcedure` interface and
provides properties for specifying a range of GUID/IDs (`Start`
and `End`) and a `Force` flag to allow deletion despite dependent
data.

Add the `ToObjectProcedure` method to convert the record into a
`DeleteObjectProcedure` with the entity set to `"ENDPOINT_AUTH"`.
2026-01-16 01:06:45 +01:00
Developer 02
7376b49e38 Add DeleteEndpointParamsProcedure record
A new `DeleteEndpointParamsProcedure` record was introduced in the
`ReC.Application.Common.Procedures.DeleteProcedure` namespace. This
record implements the `IDeleteProcedure` interface and provides
properties for specifying a range of GUID/IDs (`Start` and `End`)
and a `Force` flag to allow deletion even with dependent data.

The record includes a `ToObjectProcedure` method to convert its
data into a `DeleteObjectProcedure` instance, setting the entity
to `"ENDPOINT_PARAMS"` and mapping the `Start`, `End`, and `Force`
properties.
2026-01-16 01:06:33 +01:00
Developer 02
b65c354ef0 Add DeleteEndpointProcedure for endpoint deletion
Introduced a new `DeleteEndpointProcedure` record in the
`ReC.Application.Common.Procedures.DeleteProcedure` namespace.

This record implements the `IDeleteProcedure` interface and includes
properties for specifying the start and end GUID/ID range, as well as
a `Force` flag to allow deletion even with dependent data.

Added a `ToObjectProcedure` method to convert the record into a
`DeleteObjectProcedure` with the entity set to "ENDPOINT".
2026-01-16 01:06:22 +01:00
Developer 02
38258a98c1 Add DeleteProfileProcedure for profile deletion logic
Introduce the `DeleteProfileProcedure` record in the new
`ReC.Application.Common.Procedures.DeleteProcedure` namespace.
This record implements the `IDeleteProcedure` interface and
provides properties for specifying a range of GUID/IDs
(`Start`, `End`) and a `Force` flag to allow deletion even
with dependent ACTION data.

Added a `ToObjectProcedure` method to convert
`DeleteProfileProcedure` instances into `DeleteObjectProcedure`
objects, setting the `Entity` to `"PROFILE"`.
2026-01-16 01:06:12 +01:00
Developer 02
7666708ab5 Add DeleteResultProcedure for RESULT entity deletion
Introduced a new `DeleteResultProcedure` record in the
`ReC.Application.Common.Procedures.DeleteProcedure` namespace.

This record implements the `IDeleteProcedure` interface and provides
properties for specifying a range of GUID/IDs (`Start` and `End`)
and a `Force` flag.

Added a `ToObjectProcedure` method to convert the record into a
`DeleteObjectProcedure` with the entity set to "RESULT".
2026-01-16 01:06:00 +01:00
Developer 02
d3b67bc429 Add IDeleteProcedure interface for delete operations
Introduced a new namespace `ReC.Application.Common.Procedures.DeleteProcedure` and added the `IDeleteProcedure` interface. This interface defines a `ToObjectProcedure` method, which returns a `DeleteObjectProcedure` object. These changes aim to standardize and encapsulate delete-related procedures in the application.
2026-01-16 01:05:46 +01:00
Developer 02
97f992aef5 Add DeleteObjectProcedure for entity deletion handling
Introduce `DeleteObjectProcedure` to encapsulate parameters for
delete operations, including entity, ID range, and force flag.
Add `DeleteObjectProcedureExtensions` for convenient invocation
via `ISender`. Implement `DeleteObjectProcedureHandler` to
execute the `[dbo].[PRREC_DELETE_OBJECT]` stored procedure
using dynamic SQL parameters.

Throw `DeleteObjectFailedException` on failure and ensure
`End` defaults to `Start` if unset. Add XML documentation
for improved code clarity. Include necessary `using`
directives for dependencies.
2026-01-16 01:05:28 +01:00
Developer 02
cc6f93ae1c Add DeleteObjectFailedException for delete operation errors
A new `DeleteObjectFailedException` class was introduced in the
`ReC.Application.Common.Exceptions` namespace to handle errors
related to failed delete operations.

This class includes:
- A `Procedure` property of type `DeleteObjectProcedure` to
  provide context about the failed operation.
- Three constructors to support different levels of detail
  (procedure only, procedure with a message, and procedure with
  a message and inner exception).

Additionally, a `using` directive for the
`ReC.Application.Common.Procedures.DeleteProcedure` namespace
was added to support the `DeleteObjectProcedure` type.
2026-01-16 01:05:10 +01:00
Developer 02
402990bd3c Add UpdateResultProcedure record for result updates
Introduced a new `UpdateResultProcedure` record in the
`ReC.Application.Common.Procedures.UpdateProcedure` namespace.
This record implements the `IUpdateProcedure` interface and
includes properties for `ActionId`, `StatusId`, `Header`, and
`Body`.

Added a `ToObjectProcedure` method to convert the record into
an `UpdateObjectProcedure` instance, setting the `Entity` to
"RESULT", and allowing optional tracking of changes via the
`ChangedBy` method.
2026-01-16 00:59:43 +01:00
Developer 02
43cdef4910 Add UpdateProfileProcedure record for profile updates
Introduced a new namespace `ReC.Application.Common.Procedures.UpdateProcedure`.
Added the `UpdateProfileProcedure` record implementing the `IUpdateProcedure` interface.
This record includes several nullable properties such as `Active`, `TypeId`, `Name`, `Description`, and others.
Added the `ToObjectProcedure` method to convert the record into an `UpdateObjectProcedure` instance, setting the entity to "PROFILE" and supporting optional change tracking via `ChangedBy`.
2026-01-16 00:59:33 +01:00
Developer 02
348a55fc60 Add UpdateEndpointProcedure record for endpoint updates
A new `UpdateEndpointProcedure` record was introduced in the
`ReC.Application.Common.Procedures.UpdateProcedure` namespace.
This record implements the `IUpdateProcedure` interface and
includes nullable properties `Active`, `Description`, and `Uri`.

The `ToObjectProcedure` method was added to convert the record
into an `UpdateObjectProcedure` instance, setting the `Entity`
to `"ENDPOINT"`, the `Guid` to the provided parameter, and the
`Endpoint` to the current instance. The method also supports
tracking changes via the optional `changedWho` parameter.
2026-01-16 00:59:23 +01:00
Developer 02
719bc9c941 Add UpdateEndpointParamsProcedure record
A new `UpdateEndpointParamsProcedure` record has been added under the `ReC.Application.Common.Procedures.UpdateProcedure` namespace. This record implements the `IUpdateProcedure` interface and includes nullable properties such as `Active`, `Description`, `GroupId`, `Sequence`, `Key`, and `Value`.

Additionally, a `ToObjectProcedure` method has been introduced, which converts the record into an `UpdateObjectProcedure` instance with the `Entity` set to `"ENDPOINT_PARAMS"`, and supports optional tracking of the user who made the change.
2026-01-16 00:59:10 +01:00
Developer 02
37381af042 Add UpdateEndpointAuthProcedure for endpoint updates
Introduce the `UpdateEndpointAuthProcedure` record in the
`ReC.Application.Common.Procedures.UpdateProcedure` namespace.

This class implements the `IUpdateProcedure` interface and includes
properties for managing endpoint authentication details such as
`Active`, `Description`, `TypeId`, `ApiKey`, `ApiValue`, `Token`,
`Username`, `Password`, `Domain`, and `Workstation`.

Add the `ToObjectProcedure` method to convert the procedure into
an `UpdateObjectProcedure` instance, setting the entity to
`ENDPOINT_AUTH` and allowing optional tracking of the user who
made the changes.
2026-01-16 00:58:55 +01:00
Developer 02
34fe996d91 Add UpdateActionProcedure record for update operations
Introduced a new `UpdateActionProcedure` record in the
`ReC.Application.Common.Procedures.UpdateProcedure` namespace.
This record implements the `IUpdateProcedure` interface and
includes several nullable properties such as `ProfileId`,
`Active`, `Sequence`, `EndpointId`, and others to support
update operations.

Added a `ToObjectProcedure` method to the record, which
creates and returns an `UpdateObjectProcedure` instance
with the entity set to "ACTION" and other relevant details.
This method also supports tracking changes via the `ChangedBy`
method.
2026-01-16 00:58:42 +01:00
Developer 02
252fc10243 Add IUpdateProcedure interface for update handling
Introduced a new namespace `ReC.Application.Common.Procedures.UpdateProcedure` and added the `IUpdateProcedure` interface. This interface defines a `ToObjectProcedure` method for converting to an `UpdateObjectProcedure`. The method accepts a `guid` parameter and an optional `changedWho` parameter to track changes. This addition establishes a contract for handling update procedures.
2026-01-16 00:58:26 +01:00
Developer 02
c8a9245b54 Add UpdateObjectProcedure for entity updates
Introduce `UpdateObjectProcedure` to handle updates for various
entities using a stored procedure. Implement MediatR-based
request/response pattern with `IRequest<int>` and add the
`UpdateObjectProcedureHandler` to execute the update logic.

Include an extension method `ExecuteUpdateProcedure` for
simplified execution of update requests. Add exception handling
via `UpdateObjectFailedException` to manage update failures.

Integrate dependencies on `DigitalData.Core.Abstraction.Application.Repository`,
`MediatR`, and `Microsoft.Data.SqlClient`. Ensure extensibility
and reliability in the update process.
2026-01-16 00:58:11 +01:00
Developer 02
c56bcc198e Add UpdateObjectFailedException for update operation errors
A new exception class, `UpdateObjectFailedException`, was added to the `ReC.Application.Common.Exceptions` namespace to handle failures during update operations.

The class includes a `Procedure` property of type `UpdateObjectProcedure` to store the associated procedure. It provides three constructors to support different levels of detail: one with just the procedure, one with a procedure and a custom message, and one with a procedure, a custom message, and an inner exception.

The `UpdateObjectProcedure` type is referenced from the `ReC.Application.Common.Procedures.UpdateProcedure` namespace, which is now included via a `using` directive.
2026-01-16 00:57:37 +01:00
Developer 02
538abec212 Add entity configurations and suppress obsolete warnings
Introduced entity configurations in `RecDbContext` for `Connection`, `Endpoint`, `EndpointAuth`, `EndpointParam`, `OutRes`, `Profile`, `ProfileView`, `RecAction`, and `RecActionView`. Mapped entities to corresponding tables or views with column configurations.

Added relationships:
- `Profile` to `Actions` (one-to-many).
- `RecAction` to `OutRes` (one-to-one with cascade delete).

Suppressed CS0618 warnings in `OnModelCreating` to handle obsolete members.
2026-01-15 23:59:13 +01:00
Developer 02
19666e649d Add obsolete DbSets and transition to Views in RecDbContext
Several new DbSet properties were added to the RecDbContext
class, marked as `[Obsolete("Use Views instead.")]`. These
include `EndpointParams`, `OutRes`, `Connections`, `Endpoints`,
`EndpointAuths`, `Profiles`, and `RecActions`.

Non-obsolete DbSets such as `RecActionViews`, `ProfileViews`,
`RecResultViews`, `HeaderQueryResults`, `BodyQueryResults`,
and `RecResults` were also added or retained.

These changes indicate a shift towards using Views for database
operations while maintaining backward compatibility with the
older DbSet properties.
2026-01-15 23:56:06 +01:00
Developer 02
1df9235036 Disambiguate Profile mapping in AutoMapper configuration
Updated the mapping configuration in `DtoMappingProfile` to use
the fully qualified name `Domain.Entities.Profile` for the
`Profile` entity. This change resolves potential ambiguity with
other classes named `Profile` in the codebase.
2026-01-15 23:54:28 +01:00
22 changed files with 655 additions and 1 deletions

View File

@@ -1,6 +1,8 @@
using MediatR;
using Microsoft.AspNetCore.Mvc;
using ReC.Application.Common.Procedures.DeleteProcedure;
using ReC.Application.Common.Procedures.InsertProcedure;
using ReC.Application.Common.Procedures.UpdateProcedure;
namespace ReC.API.Controllers;
@@ -14,4 +16,18 @@ public class CommonController(IMediator mediator) : ControllerBase
var id = await mediator.Send(procedure, cancel);
return StatusCode(StatusCodes.Status201Created, id);
}
[HttpPut]
public async Task<IActionResult> UpdateObject([FromBody] UpdateObjectProcedure procedure, CancellationToken cancel)
{
var result = await mediator.Send(procedure, cancel);
return Ok(result);
}
[HttpDelete]
public async Task<IActionResult> DeleteObject([FromBody] DeleteObjectProcedure procedure, CancellationToken cancel)
{
var result = await mediator.Send(procedure, cancel);
return Ok(result);
}
}

View File

@@ -123,6 +123,40 @@ public class ExceptionHandlingMiddleware
};
break;
case UpdateObjectFailedException updateFailedEx:
logger.LogError(
updateFailedEx,
"Update operation failed during request processing. {procedure}",
JsonSerializer.Serialize(
updateFailedEx.Procedure,
options: new() { WriteIndented = true }
));
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
details = new()
{
Title = "Update Operation Failed",
Detail = updateFailedEx.Message
};
break;
case DeleteObjectFailedException deleteFailedEx:
logger.LogError(
deleteFailedEx,
"Delete operation failed during request processing. {procedure}",
JsonSerializer.Serialize(
deleteFailedEx.Procedure,
options: new() { WriteIndented = true }
));
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
details = new()
{
Title = "Delete Operation Failed",
Detail = deleteFailedEx.Message
};
break;
default:
logger.LogError(exception, "Unhandled exception occurred.");
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

View File

@@ -15,7 +15,7 @@ public class DtoMappingProfile : AutoMapper.Profile
CreateMap<EndpointAuth, EndpointAuthDto>();
CreateMap<Endpoint, EndpointDto>();
CreateMap<EndpointParam, EndpointParamDto>();
CreateMap<Profile, ProfileDto>();
CreateMap<Domain.Entities.Profile, ProfileDto>();
CreateMap<RecAction, RecActionDto>();
CreateMap<ResultView, ResultViewDto>();

View File

@@ -0,0 +1,23 @@
using ReC.Application.Common.Procedures.DeleteProcedure;
namespace ReC.Application.Common.Exceptions;
public class DeleteObjectFailedException : Exception
{
public DeleteObjectProcedure Procedure { get; }
public DeleteObjectFailedException(DeleteObjectProcedure procedure) : base()
{
Procedure = procedure;
}
public DeleteObjectFailedException(DeleteObjectProcedure procedure, string? message) : base(message)
{
Procedure = procedure;
}
public DeleteObjectFailedException(DeleteObjectProcedure procedure, string? message, Exception? innerException) : base(message, innerException)
{
Procedure = procedure;
}
}

View File

@@ -0,0 +1,23 @@
using ReC.Application.Common.Procedures.UpdateProcedure;
namespace ReC.Application.Common.Exceptions;
public class UpdateObjectFailedException : Exception
{
public UpdateObjectProcedure Procedure { get; }
public UpdateObjectFailedException(UpdateObjectProcedure procedure) : base()
{
Procedure = procedure;
}
public UpdateObjectFailedException(UpdateObjectProcedure procedure, string? message) : base(message)
{
Procedure = procedure;
}
public UpdateObjectFailedException(UpdateObjectProcedure procedure, string? message, Exception? innerException) : base(message, innerException)
{
Procedure = procedure;
}
}

View File

@@ -0,0 +1,30 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
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
};
}
}

View File

@@ -0,0 +1,30 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
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
};
}
}

View File

@@ -0,0 +1,30 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
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
};
}
}

View File

@@ -0,0 +1,30 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
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
};
}
}

View File

@@ -0,0 +1,77 @@
using DigitalData.Core.Abstraction.Application.Repository;
using MediatR;
using Microsoft.Data.SqlClient;
using ReC.Application.Common.Exceptions;
namespace ReC.Application.Common.Procedures.DeleteProcedure;
public record DeleteObjectProcedure : IRequest<int>
{
/// <summary>
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
/// </summary>
public string Entity { get; set; } = null!;
/// <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 data exists
/// </summary>
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) : 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 result = await repo.ExecuteQueryRawAsync(
"EXEC @RC = [dbo].[PRREC_DELETE_OBJECT] " +
"@pENTITY, @pSTART, @pEND, @pFORCE; " +
"SELECT @RC;",
parameters,
cancel);
// The stored procedure returns 0 on success, error codes > 0 on failure
if (result > 0)
{
throw new DeleteObjectFailedException(request, $"DeleteObject stored procedure failed with error code: {result}");
}
return result;
}
}

View File

@@ -0,0 +1,30 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
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
};
}
}

View File

@@ -0,0 +1,30 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
public record DeleteResultProcedure : 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>
/// 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
};
}
}

View File

@@ -0,0 +1,6 @@
namespace ReC.Application.Common.Procedures.DeleteProcedure;
public interface IDeleteProcedure
{
public DeleteObjectProcedure ToObjectProcedure();
}

View File

@@ -0,0 +1,6 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
public interface IUpdateProcedure
{
public UpdateObjectProcedure ToObjectProcedure(long guid, string? changedWho = null);
}

View File

@@ -0,0 +1,28 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
public record UpdateActionProcedure : IUpdateProcedure
{
public long? ProfileId { get; set; }
public bool? Active { get; set; }
public byte? Sequence { get; set; }
public long? EndpointId { get; set; }
public long? EndpointAuthId { get; set; }
public short? EndpointParamsId { get; set; }
public short? SqlConnectionId { get; set; }
public byte? 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 guid, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ACTION",
Guid = guid,
Action = this
}.ChangedBy(changedWho);
}
}

View File

@@ -0,0 +1,26 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
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 guid, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ENDPOINT_AUTH",
Guid = guid,
EndpointAuth = this
}.ChangedBy(changedWho);
}
}

View File

@@ -0,0 +1,21 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
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 guid, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ENDPOINT_PARAMS",
Guid = guid,
EndpointParams = this
}.ChangedBy(changedWho);
}
}

View File

@@ -0,0 +1,18 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
public record UpdateEndpointProcedure : IUpdateProcedure
{
public bool? Active { get; set; }
public string? Description { get; set; }
public string? Uri { get; set; }
public UpdateObjectProcedure ToObjectProcedure(long guid, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "ENDPOINT",
Guid = guid,
Endpoint = this
}.ChangedBy(changedWho);
}
}

View File

@@ -0,0 +1,131 @@
using DigitalData.Core.Abstraction.Application.Repository;
using MediatR;
using Microsoft.Data.SqlClient;
using ReC.Application.Common.Exceptions;
namespace ReC.Application.Common.Procedures.UpdateProcedure;
public record UpdateObjectProcedure : IRequest<int>
{
/// <summary>
/// Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT
/// </summary>
public string Entity { get; set; } = null!;
/// <summary>
/// Target GUID to update (required)
/// </summary>
public long Guid { get; set; }
internal string? ChangedWho { get; private set; }
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 static class UpdateObjectProcedureExtensions
{
public static Task<int> ExecuteUpdateProcedure(this ISender sender, IUpdateProcedure procedure, long guid, string? changedWho = null, CancellationToken cancel = default)
{
return sender.Send(procedure.ToObjectProcedure(guid, changedWho ?? "ReC.API"), cancel);
}
}
public class UpdateObjectProcedureHandler(IRepository repo) : 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.Guid ?? 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 result = await repo.ExecuteQueryRawAsync(
"EXEC @RC = [dbo].[PRREC_UPDATE_OBJECT] " +
"@pENTITY, @pGUID, @pCHANGED_WHO, @pCHANGED_WHEN, " +
"@pACTION_PROFILE_ID, @pACTION_ACTIVE, @pACTION_SEQUENCE, @pACTION_ENDPOINT_ID, @pACTION_ENDPOINT_AUTH_ID, @pACTION_ENDPOINT_PARAMS_ID, @pACTION_SQL_CONNECTION_ID, @pACTION_TYPE_ID, @pACTION_PRE_SQL, @pACTION_HEADER_SQL, @pACTION_BODY_SQL, @pACTION_POST_SQL, @pACTION_ERROR_ACTION_ID, " +
"@pENDPOINT_ACTIVE, @pENDPOINT_DESCRIPTION, @pENDPOINT_URI, " +
"@pENDPOINT_AUTH_ACTIVE, @pENDPOINT_AUTH_DESCRIPTION, @pENDPOINT_AUTH_TYPE_ID, @pENDPOINT_AUTH_API_KEY, @pENDPOINT_AUTH_API_VALUE, @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, @pENDPOINT_AUTH_TOKEN, @pENDPOINT_AUTH_USERNAME, @pENDPOINT_AUTH_PASSWORD, @pENDPOINT_AUTH_DOMAIN, @pENDPOINT_AUTH_WORKSTATION, " +
"@pENDPOINT_PARAMS_ACTIVE, @pENDPOINT_PARAMS_DESCRIPTION, @pENDPOINT_PARAMS_GROUP_ID, @pENDPOINT_PARAMS_SEQUENCE, @pENDPOINT_PARAMS_KEY, @pENDPOINT_PARAMS_VALUE, " +
"@pPROFILE_ACTIVE, @pPROFILE_TYPE_ID, @pPROFILE_MANDANTOR, @pPROFILE_NAME, @pPROFILE_DESCRIPTION, @pPROFILE_LOG_LEVEL_ID, @pPROFILE_LANGUAGE_ID, @pPROFILE_FIRST_RUN, @pPROFILE_LAST_RUN, @pPROFILE_LAST_RESULT, " +
"@pRESULT_ACTION_ID, @pRESULT_STATUS_ID, @pRESULT_HEADER, @pRESULT_BODY; " +
"SELECT @RC;",
parameters,
cancel);
// The stored procedure returns 0 on success, error codes > 0 on failure
if (result > 0)
{
throw new UpdateObjectFailedException(request, $"UpdateObject stored procedure failed with error code: {result}");
}
return result;
}
}

View File

@@ -0,0 +1,25 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
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 guid, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "PROFILE",
Guid = guid,
Profile = this
}.ChangedBy(changedWho);
}
}

View File

@@ -0,0 +1,19 @@
namespace ReC.Application.Common.Procedures.UpdateProcedure;
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 guid, string? changedWho = null)
{
return new UpdateObjectProcedure
{
Entity = "RESULT",
Guid = guid,
Result = this
}.ChangedBy(changedWho);
}
}

View File

@@ -9,6 +9,7 @@ namespace ReC.Infrastructure;
public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(options), IRecDbContext
{
#region DB Sets
[Obsolete("Use Views instead.")]
public DbSet<EndpointParam> EndpointParams { get; set; }
public DbSet<RecActionView> RecActionViews { get; set; }
@@ -17,20 +18,26 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
public DbSet<ResultView> RecResultViews { get; set; }
[Obsolete("Use Views instead.")]
public DbSet<OutRes> OutRes { get; set; }
public DbSet<HeaderQueryResult> HeaderQueryResults { get; set; }
public DbSet<BodyQueryResult> BodyQueryResults { get; set; }
[Obsolete("Use Views instead.")]
public DbSet<Connection> Connections { get; set; }
[Obsolete("Use Views instead.")]
public DbSet<Endpoint> Endpoints { get; set; }
[Obsolete("Use Views instead.")]
public DbSet<EndpointAuth> EndpointAuths { get; set; }
[Obsolete("Use Views instead.")]
public DbSet<Profile> Profiles { get; set; }
[Obsolete("Use Views instead.")]
public DbSet<RecAction> RecActions { get; set; }
public DbSet<InsertObjectResult> RecResults { get; set; }
@@ -41,6 +48,7 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
{
base.OnModelCreating(modelBuilder);
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<Connection>(b =>
{
b.ToTable("TBDD_CONNECTION");
@@ -65,7 +73,9 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
b.Property(e => e.GeaendertWann).HasColumnName("GEAENDERTWANN");
b.Property(e => e.SysConnection).HasColumnName("SYS_CONNECTION");
});
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<Endpoint>(b =>
{
b.ToTable("TBREC_CFG_ENDPOINT");
@@ -84,7 +94,9 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
});
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<EndpointAuth>(b =>
{
b.ToTable("TBREC_CFG_ENDPOINT_AUTH");
@@ -111,7 +123,9 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
});
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<EndpointParam>(b =>
{
b.ToTable("TBREC_CFG_ENDPOINT_PARAMS", "dbo");
@@ -130,7 +144,9 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
});
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<OutRes>(b =>
{
b.ToTable("TBREC_OUT_RESULT", "dbo");
@@ -150,7 +166,9 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
});
#pragma warning restore CS0618 // Type or member is obsolete
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<Profile>(b =>
{
b.ToTable("TBREC_CFG_PROFILE", "dbo");
@@ -173,6 +191,7 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
b.Property(e => e.ChangedWho).HasColumnName("CHANGED_WHO");
b.Property(e => e.ChangedWhen).HasColumnName("CHANGED_WHEN");
});
#pragma warning restore CS0618 // Type or member is obsolete
modelBuilder.Entity<ProfileView>(b =>
{
@@ -203,6 +222,7 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
.HasForeignKey(a => a.ProfileId);
});
#pragma warning disable CS0618 // Type or member is obsolete
modelBuilder.Entity<RecAction>(b =>
{
b.ToTable("TBREC_CFG_ACTION");
@@ -233,6 +253,7 @@ public class RecDbContext(DbContextOptions<RecDbContext> options) : DbContext(op
.HasForeignKey<OutRes>(res => res.ActionId)
.OnDelete(DeleteBehavior.Cascade);
});
#pragma warning restore CS0618 // Type or member is obsolete
modelBuilder.Entity<RecActionView>(b =>
{