Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

187 Zeilen
6.3KB

  1. using System.Security.Claims;
  2. using Campaign_Tracker.Server.Audit;
  3. using Campaign_Tracker.Server.Authorization;
  4. using Campaign_Tracker.Server.Municipalities;
  5. using Microsoft.AspNetCore.Authorization;
  6. using Microsoft.AspNetCore.Mvc;
  7. namespace Campaign_Tracker.Server.Controllers;
  8. [ApiController]
  9. [Authorize(Policy = ApplicationPolicy.ClientServicesAccess)]
  10. [Route("api/municipalities/{profileId}/addresses")]
  11. public sealed class MunicipalityAddressesController : ControllerBase
  12. {
  13. private readonly IMunicipalityAddressRepository _addresses;
  14. private readonly IAuditService _audit;
  15. private readonly TimeProvider _timeProvider;
  16. public MunicipalityAddressesController(
  17. IMunicipalityAddressRepository addresses,
  18. IAuditService audit,
  19. TimeProvider timeProvider)
  20. {
  21. _addresses = addresses;
  22. _audit = audit;
  23. _timeProvider = timeProvider;
  24. }
  25. [HttpGet]
  26. public async Task<ActionResult<IReadOnlyList<MunicipalityAddressResponse>>> GetAll(
  27. string profileId,
  28. CancellationToken cancellationToken)
  29. {
  30. var addresses = await _addresses.GetByProfileIdAsync(profileId, cancellationToken);
  31. return Ok(addresses.Select(MunicipalityAddressResponse.From).ToArray());
  32. }
  33. [HttpGet("{addressId}")]
  34. public async Task<ActionResult<MunicipalityAddressResponse>> GetById(
  35. string profileId,
  36. string addressId,
  37. CancellationToken cancellationToken)
  38. {
  39. var address = await _addresses.GetByIdAsync(addressId, cancellationToken);
  40. return address is null ? NotFound() : Ok(MunicipalityAddressResponse.From(address));
  41. }
  42. [HttpPost]
  43. public async Task<ActionResult<MunicipalityAddressResponse>> Add(
  44. string profileId,
  45. [FromBody] AddMunicipalityAddressRequest request,
  46. CancellationToken cancellationToken)
  47. {
  48. var actor = GetActor();
  49. var result = await _addresses.AddAsync(
  50. profileId,
  51. request.AddressType,
  52. request.Street,
  53. request.City,
  54. request.State,
  55. request.ZipCode,
  56. request.EffectiveDate,
  57. actor,
  58. cancellationToken);
  59. if (!result.Saved || result.Address is null)
  60. return UnprocessableEntity(new MunicipalityAddressProblem(result.Error ?? "Save failed."));
  61. _audit.Record(new AuditEvent(
  62. EventType: "MUNICIPALITY_ADDRESS_ADDED",
  63. ActorIdentity: actor,
  64. Resource: $"municipalities/{profileId}/addresses/{result.Address.AddressId}",
  65. Outcome: $"added {result.Address.AddressType} address",
  66. TraceIdentifier: HttpContext.TraceIdentifier,
  67. RecordedAt: _timeProvider.GetUtcNow()));
  68. return CreatedAtAction(nameof(GetById),
  69. new { profileId, addressId = result.Address.AddressId },
  70. MunicipalityAddressResponse.From(result.Address));
  71. }
  72. [HttpPut("{addressId}")]
  73. public async Task<ActionResult<MunicipalityAddressResponse>> Update(
  74. string profileId,
  75. string addressId,
  76. [FromBody] UpdateMunicipalityAddressRequest request,
  77. CancellationToken cancellationToken)
  78. {
  79. var actor = GetActor();
  80. var result = await _addresses.UpdateAsync(
  81. addressId,
  82. request.AddressType,
  83. request.Street,
  84. request.City,
  85. request.State,
  86. request.ZipCode,
  87. request.EffectiveDate,
  88. actor,
  89. cancellationToken);
  90. if (!result.Saved || result.Address is null)
  91. {
  92. if (result.IsNotFound)
  93. return NotFound(new MunicipalityAddressProblem(result.Error ?? "Address not found."));
  94. return UnprocessableEntity(new MunicipalityAddressProblem(result.Error ?? "Update failed."));
  95. }
  96. _audit.Record(new AuditEvent(
  97. EventType: "MUNICIPALITY_ADDRESS_UPDATED",
  98. ActorIdentity: actor,
  99. Resource: $"municipalities/{profileId}/addresses/{addressId}",
  100. Outcome: $"updated {result.Address.AddressType} address — new record {result.Address.AddressId}",
  101. TraceIdentifier: HttpContext.TraceIdentifier,
  102. RecordedAt: _timeProvider.GetUtcNow()));
  103. return Ok(MunicipalityAddressResponse.From(result.Address));
  104. }
  105. [HttpDelete("{addressId}")]
  106. public async Task<IActionResult> Delete(
  107. string profileId,
  108. string addressId,
  109. CancellationToken cancellationToken)
  110. {
  111. var actor = GetActor();
  112. var result = await _addresses.SoftDeleteAsync(addressId, actor, cancellationToken);
  113. if (!result.Saved)
  114. return result.IsNotFound ? NotFound() : UnprocessableEntity();
  115. _audit.Record(new AuditEvent(
  116. EventType: "MUNICIPALITY_ADDRESS_DELETED",
  117. ActorIdentity: actor,
  118. Resource: $"municipalities/{profileId}/addresses/{addressId}",
  119. Outcome: "soft-deleted",
  120. TraceIdentifier: HttpContext.TraceIdentifier,
  121. RecordedAt: _timeProvider.GetUtcNow()));
  122. return NoContent();
  123. }
  124. private string GetActor() =>
  125. User.Identity?.Name
  126. ?? User.FindFirstValue(ClaimTypes.NameIdentifier)
  127. ?? "unknown";
  128. }
  129. public sealed record AddMunicipalityAddressRequest(
  130. string AddressType,
  131. string Street,
  132. string City,
  133. string State,
  134. string ZipCode,
  135. DateTimeOffset EffectiveDate);
  136. public sealed record UpdateMunicipalityAddressRequest(
  137. string AddressType,
  138. string Street,
  139. string City,
  140. string State,
  141. string ZipCode,
  142. DateTimeOffset EffectiveDate);
  143. public sealed record MunicipalityAddressResponse(
  144. string AddressId,
  145. string ProfileId,
  146. string AddressType,
  147. string Street,
  148. string City,
  149. string State,
  150. string ZipCode,
  151. string EffectiveDate,
  152. bool IsCurrent,
  153. string CreatedAt,
  154. string CreatedBy,
  155. string UpdatedAt,
  156. string UpdatedBy)
  157. {
  158. public static MunicipalityAddressResponse From(MunicipalityAddress a) =>
  159. new(a.AddressId, a.ProfileId, a.AddressType, a.Street, a.City, a.State, a.ZipCode,
  160. a.EffectiveDate.ToString("O"), a.IsCurrent,
  161. a.CreatedAt.ToString("O"), a.CreatedBy,
  162. a.UpdatedAt.ToString("O"), a.UpdatedBy);
  163. }
  164. public sealed record MunicipalityAddressProblem(string Error);

Powered by TurnKey Linux.