| | | 1 | | using Chronicis.Api.Infrastructure; |
| | | 2 | | using Chronicis.Api.Models; |
| | | 3 | | using Chronicis.Api.Services; |
| | | 4 | | using Chronicis.Shared.DTOs; |
| | | 5 | | using Microsoft.AspNetCore.Authorization; |
| | | 6 | | using Microsoft.AspNetCore.Mvc; |
| | | 7 | | |
| | | 8 | | namespace Chronicis.Api.Controllers; |
| | | 9 | | |
| | | 10 | | /// <summary> |
| | | 11 | | /// API endpoints for Character claiming operations. |
| | | 12 | | /// </summary> |
| | | 13 | | [ApiController] |
| | | 14 | | [Route("characters")] |
| | | 15 | | [Authorize] |
| | | 16 | | public class CharactersController : ControllerBase |
| | | 17 | | { |
| | | 18 | | private readonly ICharacterClaimService _characterClaimService; |
| | | 19 | | private readonly ICurrentUserService _currentUserService; |
| | | 20 | | private readonly ILogger<CharactersController> _logger; |
| | | 21 | | |
| | 1 | 22 | | public CharactersController( |
| | 1 | 23 | | ICharacterClaimService characterClaimService, |
| | 1 | 24 | | ICurrentUserService currentUserService, |
| | 1 | 25 | | ILogger<CharactersController> logger) |
| | | 26 | | { |
| | 1 | 27 | | _characterClaimService = characterClaimService; |
| | 1 | 28 | | _currentUserService = currentUserService; |
| | 1 | 29 | | _logger = logger; |
| | 1 | 30 | | } |
| | | 31 | | |
| | | 32 | | /// <summary> |
| | | 33 | | /// GET /api/characters/claimed - Get all characters claimed by the current user. |
| | | 34 | | /// </summary> |
| | | 35 | | [HttpGet("claimed")] |
| | | 36 | | public async Task<ActionResult<List<ClaimedCharacterDto>>> GetClaimedCharacters() |
| | | 37 | | { |
| | | 38 | | var user = await _currentUserService.GetRequiredUserAsync(); |
| | | 39 | | _logger.LogTraceSanitized("Getting claimed characters for user {UserId}", user.Id); |
| | | 40 | | var claimedCharacters = await _characterClaimService.GetClaimedCharactersAsync(user.Id); |
| | | 41 | | return Ok(claimedCharacters); |
| | | 42 | | } |
| | | 43 | | |
| | | 44 | | /// <summary> |
| | | 45 | | /// GET /api/characters/{id}/claim - Get the claim status of a character. |
| | | 46 | | /// </summary> |
| | | 47 | | [HttpGet("{id:guid}/claim")] |
| | | 48 | | public async Task<ActionResult<CharacterClaimStatusDto>> GetClaimStatus(Guid id) |
| | | 49 | | { |
| | | 50 | | var user = await _currentUserService.GetRequiredUserAsync(); |
| | | 51 | | _logger.LogTraceSanitized("Getting claim status for character {CharacterId}", id); |
| | | 52 | | |
| | | 53 | | var result = await _characterClaimService.GetClaimStatusAsync(id); |
| | | 54 | | if (!result.Found) |
| | | 55 | | { |
| | | 56 | | return NotFound(new { error = "Character not found" }); |
| | | 57 | | } |
| | | 58 | | |
| | | 59 | | var status = new CharacterClaimStatusDto |
| | | 60 | | { |
| | | 61 | | CharacterId = id, |
| | | 62 | | IsClaimed = result.PlayerId.HasValue, |
| | | 63 | | IsClaimedByMe = result.PlayerId == user.Id, |
| | | 64 | | ClaimedByName = result.PlayerName |
| | | 65 | | }; |
| | | 66 | | |
| | | 67 | | return Ok(status); |
| | | 68 | | } |
| | | 69 | | |
| | | 70 | | /// <summary> |
| | | 71 | | /// POST /api/characters/{id}/claim - Claim a character for the current user. |
| | | 72 | | /// </summary> |
| | | 73 | | [HttpPost("{id:guid}/claim")] |
| | | 74 | | public async Task<IActionResult> ClaimCharacter(Guid id) |
| | | 75 | | { |
| | | 76 | | var user = await _currentUserService.GetRequiredUserAsync(); |
| | | 77 | | _logger.LogTraceSanitized("User {UserId} claiming character {CharacterId}", user.Id, id); |
| | | 78 | | var result = await _characterClaimService.ClaimCharacterAsync(id, user.Id); |
| | | 79 | | return result.Status switch |
| | | 80 | | { |
| | | 81 | | ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }), |
| | | 82 | | ServiceStatus.Conflict => Conflict(new { error = result.ErrorMessage }), |
| | | 83 | | _ => NoContent() |
| | | 84 | | }; |
| | | 85 | | } |
| | | 86 | | |
| | | 87 | | /// <summary> |
| | | 88 | | /// DELETE /api/characters/{id}/claim - Unclaim a character (remove current user's claim). |
| | | 89 | | /// </summary> |
| | | 90 | | [HttpDelete("{id:guid}/claim")] |
| | | 91 | | public async Task<IActionResult> UnclaimCharacter(Guid id) |
| | | 92 | | { |
| | | 93 | | var user = await _currentUserService.GetRequiredUserAsync(); |
| | | 94 | | _logger.LogTraceSanitized("User {UserId} unclaiming character {CharacterId}", user.Id, id); |
| | | 95 | | var result = await _characterClaimService.UnclaimCharacterAsync(id, user.Id); |
| | | 96 | | return result.Status == ServiceStatus.NotFound |
| | | 97 | | ? NotFound(new { error = result.ErrorMessage }) |
| | | 98 | | : NoContent(); |
| | | 99 | | } |
| | | 100 | | } |
| | | 101 | | |
| | | 102 | | /// <summary> |
| | | 103 | | /// Status of a character's claim. |
| | | 104 | | /// </summary> |
| | | 105 | | public class CharacterClaimStatusDto |
| | | 106 | | { |
| | | 107 | | public Guid CharacterId { get; set; } |
| | | 108 | | public bool IsClaimed { get; set; } |
| | | 109 | | public bool IsClaimedByMe { get; set; } |
| | | 110 | | public string? ClaimedByName { get; set; } |
| | | 111 | | } |