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.

91 lines
3.0KB

  1. using System.Security.Claims;
  2. using Campaign_Tracker.Server.Audit;
  3. using Campaign_Tracker.Server.Authorization;
  4. using Campaign_Tracker.Server.LegacyData.Schema;
  5. using Microsoft.AspNetCore.Authorization;
  6. using Microsoft.AspNetCore.Mvc;
  7. namespace Campaign_Tracker.Server.Controllers;
  8. /// <summary>
  9. /// Admin-only API for the legacy schema compatibility check (Story 1.7 AC #5).
  10. /// Exposes a manual trigger and a recent-history view.
  11. /// </summary>
  12. [ApiController]
  13. [Authorize(Policy = ApplicationPolicy.AdminAccess)]
  14. [Route("api/admin/legacy-schema")]
  15. public sealed class LegacySchemaController : ControllerBase
  16. {
  17. private readonly ILegacySchemaCompatibilityCheck _check;
  18. private readonly ILegacySchemaCheckHistory _history;
  19. private readonly IAuditService _audit;
  20. private readonly TimeProvider _timeProvider;
  21. public LegacySchemaController(
  22. ILegacySchemaCompatibilityCheck check,
  23. ILegacySchemaCheckHistory history,
  24. IAuditService audit,
  25. TimeProvider timeProvider)
  26. {
  27. _check = check;
  28. _history = history;
  29. _audit = audit;
  30. _timeProvider = timeProvider;
  31. }
  32. [HttpPost("check")]
  33. public async Task<ActionResult<LegacySchemaCheckResponse>> RunCheck(CancellationToken cancellationToken)
  34. {
  35. var result = await _check.RunAsync(cancellationToken);
  36. _history.Record(result);
  37. var actor = User.Identity?.Name
  38. ?? User.FindFirstValue(ClaimTypes.NameIdentifier)
  39. ?? "unknown";
  40. _audit.Record(new AuditEvent(
  41. EventType: result.Passed
  42. ? "LEGACY_SCHEMA_CHECK_PASSED"
  43. : "LEGACY_SCHEMA_CHECK_FAILED",
  44. ActorIdentity: actor,
  45. Resource: "legacy-schema/compatibility-check",
  46. Outcome: result.Passed ? "pass" : "fail",
  47. TraceIdentifier: HttpContext.TraceIdentifier,
  48. RecordedAt: _timeProvider.GetUtcNow()));
  49. return Ok(LegacySchemaCheckResponse.From(result));
  50. }
  51. [HttpGet("history")]
  52. public ActionResult<IReadOnlyList<LegacySchemaCheckResponse>> GetHistory([FromQuery] int max = 50)
  53. {
  54. var items = _history.GetRecent(max);
  55. return Ok(items.Select(LegacySchemaCheckResponse.From).ToArray());
  56. }
  57. }
  58. public sealed record LegacySchemaCheckResponse(
  59. bool Passed,
  60. int TablesVerified,
  61. int DriftCount,
  62. DateTimeOffset CheckedAt,
  63. string BaselineSource,
  64. IReadOnlyList<LegacySchemaDriftResponse> Drifts)
  65. {
  66. public static LegacySchemaCheckResponse From(LegacySchemaCheckResult result) =>
  67. new(result.Passed,
  68. result.TablesVerified,
  69. result.DriftCount,
  70. result.CheckedAt,
  71. result.BaselineSource,
  72. result.Drifts
  73. .Select(d => new LegacySchemaDriftResponse(
  74. d.TableName, d.ColumnName, d.ChangeType.ToString(), d.Detail))
  75. .ToArray());
  76. }
  77. public sealed record LegacySchemaDriftResponse(
  78. string TableName,
  79. string? ColumnName,
  80. string ChangeType,
  81. string Detail);

Powered by TurnKey Linux.