190 lines
11 KiB
C#
190 lines
11 KiB
C#
using adas_core.Application.Exceptions;
|
|
using adas_core.Application.Repositories.Interfaces;
|
|
using adas_core.Application.Services.Interfaces;
|
|
using adas_core.Domain.Enums;
|
|
using adas_core.Domain.Models.MongoModels;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging;
|
|
using MongoDB.Bson;
|
|
using MongoDB.Driver;
|
|
|
|
namespace adas_core.Application.Services;
|
|
|
|
/// <summary>
|
|
/// Provides operations for retrieving and managing historical configuration changes, delegating data access to an <see cref="IHistoricalConfigChangesRepository"/> and coordinating logging, HTTP context, and auditing concerns.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Implements <see cref="IHistoricalConfigChangesService"/> and uses <paramref name="historicalConfigChangesRepository"/> for persistence, <paramref name="logger"/> for diagnostics, <paramref name="httpContextAccessor"/> for request context, and <paramref name="auditService"/> to record local audit entries.
|
|
/// </remarks>
|
|
/// <!-- aidoc:v1 sig=757183c -->
|
|
public class HistoricalConfigChangesService(
|
|
IHistoricalConfigChangesRepository historicalConfigChangesRepository,
|
|
ILogger<HistoricalConfigChangesService> logger,
|
|
IHttpContextAccessor httpContextAccessor,
|
|
ILocalAuditService auditService)
|
|
: IHistoricalConfigChangesService
|
|
{
|
|
private readonly ILogger<HistoricalConfigChangesService> _logger = logger;
|
|
|
|
/// <summary>
|
|
/// Deletes a historical configuration change record by its identifier and creates an audit log entry recording the deletion.
|
|
/// </summary>
|
|
/// <param name="id">The unique identifier of the historical configuration change to delete.</param>
|
|
/// <!-- aidoc:v1 sig=86555ed body=001920f -->
|
|
public async Task DeleteHistoricalConfigChange(ObjectId id)
|
|
{
|
|
var filter = Builders<HistoricalConfigChanges>.Filter.Eq("_id", id);
|
|
var result = historicalConfigChangesRepository.FindById(id);
|
|
await historicalConfigChangesRepository.Collection.DeleteOneAsync(filter);
|
|
_logger.LogInformation("Deleted historicalConfigChanges with id: {id}", id);
|
|
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, result, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the most recent historical configuration change entry for the specified configuration type.
|
|
/// </summary>
|
|
/// <param name="configType">The configuration type used to look up the last historical change.</param>
|
|
/// <returns>The most recent <see cref="HistoricalConfigChanges"/> entry, or <c>null</c> if no changes exist for the given type.</returns>
|
|
/// <!-- aidoc:v1 sig=c35ac55 body=bbcde5b -->
|
|
public async Task<HistoricalConfigChanges?> FindLastConfigChanges(DisplayConfigEnums.ConfigTypes configType)
|
|
{
|
|
var result = await historicalConfigChangesRepository.FindLastHistoricalConfigChangesByType(configType);
|
|
|
|
return result.FirstOrDefault();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves a historical configuration change record by its unique identifier.
|
|
/// Returns null when no matching record is found in the repository.
|
|
/// </summary>
|
|
/// <param name="id">The unique identifier of the historical configuration change to retrieve.</param>
|
|
/// <returns>The matching <see cref="HistoricalConfigChanges"/> record, or null if no record is found.</returns>
|
|
/// <!-- aidoc:v1 sig=7f8de28 body=46df3de -->
|
|
public async Task<HistoricalConfigChanges?> Get(ObjectId id)
|
|
{
|
|
return await historicalConfigChangesRepository.FindById(id);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves all historical configuration changes from the repository.
|
|
/// </summary>
|
|
/// <returns>A task that represents the asynchronous operation, containing a collection of all <see cref="HistoricalConfigChanges"/> records.</returns>
|
|
/// <!-- aidoc:v1 sig=f0919e8 body=6a8aec9 -->
|
|
public async Task<ICollection<HistoricalConfigChanges>> GetAll()
|
|
{
|
|
return await historicalConfigChangesRepository.FindAll();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the most recent historical configuration changes for the specified configuration type, limited to a given number of entries.
|
|
/// </summary>
|
|
/// <param name="type">The configuration type used to filter the historical changes.</param>
|
|
/// <param name="num">The maximum number of recent changes to return. Defaults to 10.</param>
|
|
/// <returns>A collection of the latest <see cref="HistoricalConfigChanges"/> entries matching the specified type.</returns>
|
|
/// <!-- aidoc:v1 sig=eb58afd body=9a8ae02 -->
|
|
public async Task<ICollection<HistoricalConfigChanges>> GetByType(DisplayConfigEnums.ConfigTypes type, int num = 10)
|
|
{
|
|
return await historicalConfigChangesRepository.FindLastHistoricalConfigChangesByType(type, num);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Retrieves the most recent historical configuration changes for a given user, optionally filtered by configuration type and limited to a specified maximum number of entries.
|
|
/// </summary>
|
|
/// <param name="user">The identifier of the user whose historical configuration changes are being retrieved.</param>
|
|
/// <param name="configTypes">Optional filter for the configuration type; when null, all configuration types are included.</param>
|
|
/// <param name="num">The maximum number of historical change entries to return. Defaults to 10.</param>
|
|
/// <returns>A task that represents the asynchronous operation, containing a collection of the user's historical configuration changes.</returns>
|
|
/// <!-- aidoc:v1 sig=a9c5b43 body=8f686c3 -->
|
|
public async Task<ICollection<HistoricalConfigChanges>> GetByUser(string user,
|
|
DisplayConfigEnums.ConfigTypes? configTypes = null, int num = 10)
|
|
{
|
|
return await historicalConfigChangesRepository.FindLastHistoricalConfigChangesByUser(user, configTypes, num);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Inserts a new historical configuration change record into the repository and creates a corresponding audit log entry.
|
|
/// If the repository returns null, a conflict exception is thrown; on failure, the error is logged and null is returned.
|
|
/// </summary>
|
|
/// <param name="historicalConfigChanges">The historical configuration change entity to insert.</param>
|
|
/// <returns>The inserted <see cref="HistoricalConfigChanges"/> entity, or null if the operation fails.</returns>
|
|
/// <exception cref="ConflictException">Thrown when the repository returns null after the insert operation.</exception>
|
|
/// <!-- aidoc:v1 sig=06deefb body=1a2682f -->
|
|
public async Task<HistoricalConfigChanges?> InsertOne(HistoricalConfigChanges historicalConfigChanges)
|
|
{
|
|
try
|
|
{
|
|
var result = await historicalConfigChangesRepository.InsertOneAsync(historicalConfigChanges) ??
|
|
throw new ConflictException(HttpEnum.ErrorMessage.ConflictCreationFailed);
|
|
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, result);
|
|
return await historicalConfigChangesRepository.InsertOneAsync(historicalConfigChanges);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("Exception inserting historicalConfigChanges {changes} exception:{e} ",
|
|
historicalConfigChanges.ToJson(), ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates an existing historical configuration change record, creating an audit log entry for the change.
|
|
/// If the record is not found, a <see cref="ConflictException"/> is thrown; any other exception is logged and the method returns <c>null</c>.
|
|
/// </summary>
|
|
/// <param name="historicalConfigChanges">The historical configuration change entity containing the updated values to persist.</param>
|
|
/// <returns>The updated <see cref="HistoricalConfigChanges"/> entity on success, or <c>null</c> if an error occurs during the operation.</returns>
|
|
/// <exception cref="ConflictException">Thrown when no existing historical configuration change is found with the specified <c>Id</c>.</exception>
|
|
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
|
|
/// "ConflictException is thrown inside the try block but immediately caught by the outer catch (Exception ex), which logs and returns null. The exception never propagates to callers, so documenting it as thrown is misleading." -->
|
|
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
|
/// "Summary states 'If the record is not found, a ConflictException is thrown', but in practice the throw is swallowed by the catch block and the method returns null with a logged error." -->
|
|
public async Task<HistoricalConfigChanges?> UpdateHistoricalConfigChange(
|
|
HistoricalConfigChanges historicalConfigChanges)
|
|
{
|
|
try
|
|
{
|
|
var oldHistorical = await historicalConfigChangesRepository.FindById(historicalConfigChanges.Id) ??
|
|
throw new ConflictException(HttpEnum.ErrorMessage.ConflictUpdateFailed);
|
|
var result = await historicalConfigChangesRepository.Update(historicalConfigChanges);
|
|
await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, oldHistorical, result);
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError("Exception updating historicalConfigChanges {changes} exception:{e} ",
|
|
historicalConfigChanges.ToJson(), ex);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously logs a change to a display configuration, recording the user who made the change,
|
|
/// the configuration type, the previous value, and the new value. Logs an error if the insertion fails,
|
|
/// or a debug message if it succeeds.
|
|
/// </summary>
|
|
/// <param name="user">The username of the user who made the configuration change.</param>
|
|
/// <param name="configType">The type of configuration that was changed.</param>
|
|
/// <param name="newConfig">The new configuration value after the change.</param>
|
|
/// <param name="oldConfig">The previous configuration value before the change.</param>
|
|
/// <!-- aidoc:v1 sig=dd55e13 body=56cb363 -->
|
|
public async Task LogConfigChanged(string user, DisplayConfigEnums.ConfigTypes configType, string newConfig,
|
|
string oldConfig)
|
|
{
|
|
HistoricalConfigChanges historicalConfigChanges = new()
|
|
{
|
|
ConfigType = configType,
|
|
Time = DateTime.Now,
|
|
Username = user,
|
|
OldConfig = oldConfig,
|
|
NewConfig = newConfig
|
|
};
|
|
|
|
var result = await InsertOne(historicalConfigChanges);
|
|
if (result == null)
|
|
_logger.LogError("Error logging config changes. newConfig: {newConfig}, oldConfig: {oldConfig}",
|
|
historicalConfigChanges.NewConfig, historicalConfigChanges.OldConfig);
|
|
else
|
|
_logger.LogDebug("Config changes logged. newConfig: {newConfig}, oldConfig: {oldConfig}",
|
|
historicalConfigChanges.NewConfig, historicalConfigChanges.OldConfig);
|
|
}
|
|
} |