< Summary

Information
Class: Chronicis.Api.Controllers.SessionsController
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/SessionsController.cs
Line coverage
100%
Covered lines: 8
Uncovered lines: 0
Coverable lines: 8
Total lines: 191
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/SessionsController.cs

#LineLine coverage
 1using Chronicis.Api.Infrastructure;
 2using Chronicis.Api.Models;
 3using Chronicis.Api.Services;
 4using Chronicis.Shared.DTOs;
 5using Chronicis.Shared.DTOs.Sessions;
 6using Microsoft.AspNetCore.Authorization;
 7using Microsoft.AspNetCore.Mvc;
 8
 9namespace Chronicis.Api.Controllers;
 10
 11/// <summary>
 12/// API endpoints for Session entity creation and updates.
 13/// </summary>
 14[ApiController]
 15[Authorize]
 16public class SessionsController : ControllerBase
 17{
 18    private readonly ISessionService _sessionService;
 19    private readonly ICurrentUserService _currentUserService;
 20    private readonly ILogger<SessionsController> _logger;
 21
 322    public SessionsController(
 323        ISessionService sessionService,
 324        ICurrentUserService currentUserService,
 325        ILogger<SessionsController> logger)
 26    {
 327        _sessionService = sessionService;
 328        _currentUserService = currentUserService;
 329        _logger = logger;
 330    }
 31
 32    /// <summary>
 33    /// GET /api/arcs/{arcId}/sessions - List Session entities for an arc (tree/navigation).
 34    /// </summary>
 35    [HttpGet("arcs/{arcId:guid}/sessions")]
 36    public async Task<ActionResult<List<SessionTreeDto>>> GetSessionsByArc(Guid arcId)
 37    {
 38        var user = await _currentUserService.GetRequiredUserAsync();
 39
 40        var result = await _sessionService.GetSessionsByArcAsync(arcId, user.Id);
 41
 42        return result.Status switch
 43        {
 44            ServiceStatus.Success => Ok(result.Value ?? new List<SessionTreeDto>()),
 45            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 46            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 47            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 48            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 49        };
 50    }
 51
 52    /// <summary>
 53    /// GET /api/sessions/{sessionId} - Get a Session entity by id.
 54    /// </summary>
 55    [HttpGet("sessions/{sessionId:guid}")]
 56    public async Task<ActionResult<SessionDto>> GetSession(Guid sessionId)
 57    {
 58        var user = await _currentUserService.GetRequiredUserAsync();
 59
 60        var result = await _sessionService.GetSessionAsync(sessionId, user.Id);
 61
 62        return result.Status switch
 63        {
 64            ServiceStatus.Success => Ok(result.Value),
 65            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 66            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 67            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 68            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 69        };
 70    }
 71
 72    /// <summary>
 73    /// POST /api/arcs/{arcId}/sessions - Create a session and one default public SessionNote.
 74    /// </summary>
 75    [HttpPost("arcs/{arcId:guid}/sessions")]
 76    public async Task<ActionResult<SessionDto>> CreateSession(Guid arcId, [FromBody] SessionCreateDto dto)
 77    {
 78        var user = await _currentUserService.GetRequiredUserAsync();
 79
 80        if (dto == null)
 81        {
 82            return BadRequest(new { error = "Request body is required" });
 83        }
 84
 85        _logger.LogTraceSanitized("Creating session '{Name}' in arc {ArcId} for user {UserId}",
 86            dto.Name, arcId, user.Id);
 87
 88        var result = await _sessionService.CreateSessionAsync(arcId, dto, user.Id, user.DisplayName);
 89
 90        return result.Status switch
 91        {
 92            ServiceStatus.Success => Created($"sessions/{result.Value!.Id}", result.Value),
 93            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 94            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 95            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 96            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 97        };
 98    }
 99
 100    /// <summary>
 101    /// PATCH /api/sessions/{sessionId} - Update editable Session fields (GM only).
 102    /// </summary>
 103    [HttpPatch("sessions/{sessionId:guid}")]
 104    public async Task<ActionResult<SessionDto>> UpdateSessionNotes(Guid sessionId, [FromBody] SessionUpdateDto dto)
 105    {
 106        var user = await _currentUserService.GetRequiredUserAsync();
 107
 108        if (dto == null)
 109        {
 110            return BadRequest(new { error = "Request body is required" });
 111        }
 112
 113        _logger.LogTraceSanitized("Updating session {SessionId} by user {UserId}", sessionId, user.Id);
 114
 115        var result = await _sessionService.UpdateSessionNotesAsync(sessionId, dto, user.Id);
 116
 117        return result.Status switch
 118        {
 119            ServiceStatus.Success => Ok(result.Value),
 120            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 121            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 122            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 123            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 124        };
 125    }
 126
 127    /// <summary>
 128    /// DELETE /api/sessions/{sessionId} - Delete a Session and all session-linked child content (GM only).
 129    /// </summary>
 130    [HttpDelete("sessions/{sessionId:guid}")]
 131    public async Task<IActionResult> DeleteSession(Guid sessionId)
 132    {
 133        var user = await _currentUserService.GetRequiredUserAsync();
 134
 135        _logger.LogTraceSanitized("Deleting session {SessionId} by user {UserId}", sessionId, user.Id);
 136
 137        var result = await _sessionService.DeleteSessionAsync(sessionId, user.Id);
 138
 139        return result.Status switch
 140        {
 141            ServiceStatus.Success => NoContent(),
 142            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 143            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 144            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 145        };
 146    }
 147
 148    /// <summary>
 149    /// POST /api/sessions/{sessionId}/ai-summary/generate - Generate a public-safe AI summary for a session.
 150    /// </summary>
 151    [HttpPost("sessions/{sessionId:guid}/ai-summary/generate")]
 152    public async Task<ActionResult<SummaryGenerationDto>> GenerateAiSummary(Guid sessionId)
 153    {
 154        var user = await _currentUserService.GetRequiredUserAsync();
 155
 156        _logger.LogTraceSanitized("Generating AI summary for session {SessionId} by user {UserId}", sessionId, user.Id);
 157
 158        var result = await _sessionService.GenerateAiSummaryAsync(sessionId, user.Id);
 159
 160        return result.Status switch
 161        {
 162            ServiceStatus.Success => Ok(result.Value),
 163            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 164            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 165            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 166            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 167        };
 168    }
 169
 170    /// <summary>
 171    /// DELETE /api/sessions/{sessionId}/ai-summary - Clear a session AI summary.
 172    /// </summary>
 173    [HttpDelete("sessions/{sessionId:guid}/ai-summary")]
 174    public async Task<IActionResult> ClearAiSummary(Guid sessionId)
 175    {
 176        var user = await _currentUserService.GetRequiredUserAsync();
 177
 178        _logger.LogTraceSanitized("Clearing AI summary for session {SessionId} by user {UserId}", sessionId, user.Id);
 179
 180        var result = await _sessionService.ClearAiSummaryAsync(sessionId, user.Id);
 181
 182        return result.Status switch
 183        {
 184            ServiceStatus.Success => NoContent(),
 185            ServiceStatus.NotFound => NotFound(new { error = result.ErrorMessage }),
 186            ServiceStatus.Forbidden => StatusCode(403, new { error = result.ErrorMessage }),
 187            ServiceStatus.ValidationError => BadRequest(new { error = result.ErrorMessage }),
 188            _ => StatusCode(500, new { error = "An unexpected error occurred" })
 189        };
 190    }
 191}