< Summary

Information
Class: Chronicis.Api.Controllers.QuestsController
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/QuestsController.cs
Line coverage
100%
Covered lines: 8
Uncovered lines: 0
Coverable lines: 8
Total lines: 153
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%

File(s)

/home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/QuestsController.cs

#LineLine coverage
 1using Chronicis.Api.Infrastructure;
 2using Chronicis.Api.Models;
 3using Chronicis.Api.Services;
 4using Chronicis.Shared.DTOs.Quests;
 5using Microsoft.AspNetCore.Authorization;
 6using Microsoft.AspNetCore.Mvc;
 7
 8namespace Chronicis.Api.Controllers;
 9
 10/// <summary>
 11/// API endpoints for Quest management.
 12/// </summary>
 13[ApiController]
 14[Authorize]
 15public class QuestsController : ControllerBase
 16{
 17    private readonly IQuestService _questService;
 18    private readonly ICurrentUserService _currentUserService;
 19    private readonly ILogger<QuestsController> _logger;
 20
 121    public QuestsController(
 122        IQuestService questService,
 123        ICurrentUserService currentUserService,
 124        ILogger<QuestsController> logger)
 25    {
 126        _questService = questService;
 127        _currentUserService = currentUserService;
 128        _logger = logger;
 129    }
 30
 31    /// <summary>
 32    /// GET /arcs/{arcId}/quests - Get all quests for an arc.
 33    /// </summary>
 34    [HttpGet("arcs/{arcId:guid}/quests")]
 35    public async Task<ActionResult<List<QuestDto>>> GetQuestsByArc(Guid arcId)
 36    {
 37        var user = await _currentUserService.GetRequiredUserAsync();
 38        _logger.LogTraceSanitized("Getting quests for arc {ArcId} for user {UserId}", arcId, user.Id);
 39
 40        var result = await _questService.GetQuestsByArcAsync(arcId, user.Id);
 41
 42        return result.Status switch
 43        {
 44            ServiceStatus.Success => Ok(result.Value),
 45            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 46            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 47            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 48        };
 49    }
 50
 51    /// <summary>
 52    /// POST /arcs/{arcId}/quests - Create a new quest (GM only).
 53    /// </summary>
 54    [HttpPost("arcs/{arcId:guid}/quests")]
 55    public async Task<ActionResult<QuestDto>> CreateQuest(Guid arcId, [FromBody] QuestCreateDto dto)
 56    {
 57        var user = await _currentUserService.GetRequiredUserAsync();
 58
 59        if (dto == null)
 60        {
 61            return BadRequest(new { error = "Request body is required" });
 62        }
 63
 64        _logger.LogTraceSanitized("Creating quest '{Title}' in arc {ArcId} for user {UserId}",
 65            dto.Title, arcId, user.Id);
 66
 67        var result = await _questService.CreateQuestAsync(arcId, dto, user.Id);
 68
 69        return result.Status switch
 70        {
 71            ServiceStatus.Success => CreatedAtAction(
 72                nameof(GetQuest),
 73                new { questId = result.Value!.Id },
 74                result.Value),
 75            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 76            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 77            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 78            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 79        };
 80    }
 81
 82    /// <summary>
 83    /// GET /quests/{questId} - Get a specific quest with update count.
 84    /// </summary>
 85    [HttpGet("quests/{questId:guid}")]
 86    public async Task<ActionResult<QuestDto>> GetQuest(Guid questId)
 87    {
 88        var user = await _currentUserService.GetRequiredUserAsync();
 89        _logger.LogTraceSanitized("Getting quest {QuestId} for user {UserId}", questId, user.Id);
 90
 91        var result = await _questService.GetQuestAsync(questId, user.Id);
 92
 93        return result.Status switch
 94        {
 95            ServiceStatus.Success => Ok(result.Value),
 96            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 97            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 98            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 99        };
 100    }
 101
 102    /// <summary>
 103    /// PUT /quests/{questId} - Update a quest (GM only). Includes RowVersion concurrency check.
 104    /// </summary>
 105    [HttpPut("quests/{questId:guid}")]
 106    public async Task<ActionResult<QuestDto>> UpdateQuest(Guid questId, [FromBody] QuestEditDto dto)
 107    {
 108        var user = await _currentUserService.GetRequiredUserAsync();
 109
 110        if (dto == null)
 111        {
 112            return BadRequest(new { error = "Request body is required" });
 113        }
 114
 115        _logger.LogTraceSanitized("Updating quest {QuestId} for user {UserId}", questId, user.Id);
 116
 117        var result = await _questService.UpdateQuestAsync(questId, dto, user.Id);
 118
 119        return result.Status switch
 120        {
 121            ServiceStatus.Success => Ok(result.Value),
 122            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 123            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 124            ServiceStatus.Conflict => Conflict(new
 125            {
 126                error = result.ErrorMessage,
 127                currentState = result.Value // Include current QuestDto with latest RowVersion
 128            }),
 129            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 130            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 131        };
 132    }
 133
 134    /// <summary>
 135    /// DELETE /quests/{questId} - Delete a quest and all its updates (GM only).
 136    /// </summary>
 137    [HttpDelete("quests/{questId:guid}")]
 138    public async Task<IActionResult> DeleteQuest(Guid questId)
 139    {
 140        var user = await _currentUserService.GetRequiredUserAsync();
 141        _logger.LogTraceSanitized("Deleting quest {QuestId} for user {UserId}", questId, user.Id);
 142
 143        var result = await _questService.DeleteQuestAsync(questId, user.Id);
 144
 145        return result.Status switch
 146        {
 147            ServiceStatus.Success => NoContent(),
 148            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 149            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 150            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 151        };
 152    }
 153}