Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

90 lines
3.1KB

  1. using System.Security.Claims;
  2. using Campaign_Tracker.Server.Audit;
  3. using Campaign_Tracker.Server.Authorization;
  4. using Campaign_Tracker.Server.ExtensionData;
  5. using Microsoft.AspNetCore.Authorization;
  6. using Microsoft.AspNetCore.Mvc;
  7. namespace Campaign_Tracker.Server.Controllers;
  8. /// <summary>
  9. /// Admin API for the extension-to-legacy referential integrity check (Story 1.8 AC #4).
  10. /// </summary>
  11. [ApiController]
  12. [Authorize(Policy = ApplicationPolicy.AdminAccess)]
  13. [Route("api/admin/legacy-link")]
  14. public sealed class LegacyLinkController : ControllerBase
  15. {
  16. private readonly ILegacyLinkIntegrityCheck _integrityCheck;
  17. private readonly IAuditService _audit;
  18. private readonly TimeProvider _timeProvider;
  19. public LegacyLinkController(
  20. ILegacyLinkIntegrityCheck integrityCheck,
  21. IAuditService audit,
  22. TimeProvider timeProvider)
  23. {
  24. _integrityCheck = integrityCheck;
  25. _audit = audit;
  26. _timeProvider = timeProvider;
  27. }
  28. /// <summary>
  29. /// Runs the extension-to-legacy link integrity check on demand and returns a report.
  30. /// Intended to be called by a scheduler for nightly runs and by admins for manual runs.
  31. /// </summary>
  32. [HttpPost("integrity-check")]
  33. public async Task<ActionResult<LegacyLinkIntegrityResponse>> RunIntegrityCheck(
  34. CancellationToken cancellationToken)
  35. {
  36. var report = await _integrityCheck.CheckAsync(cancellationToken);
  37. var actor = User.Identity?.Name
  38. ?? User.FindFirstValue(ClaimTypes.NameIdentifier)
  39. ?? "unknown";
  40. _audit.Record(new AuditEvent(
  41. EventType: report.IsConsistent
  42. ? "LEGACY_LINK_INTEGRITY_PASSED"
  43. : "LEGACY_LINK_INTEGRITY_FAILED",
  44. ActorIdentity: actor,
  45. Resource: "legacy-link/integrity-check",
  46. Outcome: $"{report.ConsistentRecords}/{report.TotalRecords} consistent ({report.ConsistencyPercentage:F2}%)",
  47. TraceIdentifier: HttpContext.TraceIdentifier,
  48. RecordedAt: _timeProvider.GetUtcNow()));
  49. return Ok(LegacyLinkIntegrityResponse.From(report));
  50. }
  51. }
  52. public sealed record LegacyLinkIntegrityResponse(
  53. bool IsConsistent,
  54. DateTimeOffset CheckedAt,
  55. int TotalRecords,
  56. int ConsistentRecords,
  57. int FailedRecords,
  58. double ConsistencyPercentage,
  59. IReadOnlyList<LegacyLinkFailureResponse> Failures)
  60. {
  61. public static LegacyLinkIntegrityResponse From(LegacyLinkIntegrityReport report) =>
  62. new(report.IsConsistent,
  63. report.CheckedAt,
  64. report.TotalRecords,
  65. report.ConsistentRecords,
  66. report.FailedRecords,
  67. report.ConsistencyPercentage,
  68. report.Failures
  69. .Select(f => new LegacyLinkFailureResponse(
  70. f.RecordType, f.RecordId,
  71. f.Reference.Type.ToString(), f.Reference.Value,
  72. f.Reason))
  73. .ToArray());
  74. }
  75. public sealed record LegacyLinkFailureResponse(
  76. string RecordType,
  77. string RecordId,
  78. string LinkType,
  79. string LinkValue,
  80. string Reason);

Powered by TurnKey Linux.