< Summary

Information
Class: Chronicis.Api.Controllers.WorldDocumentsController
Assembly: Chronicis.Api
File(s): /home/runner/work/chronicis/chronicis/src/Chronicis.Api/Controllers/WorldDocumentsController.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 87
Coverable lines: 87
Total lines: 213
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
GetWorldDocuments()100%210%
GetDocumentContentAsync()100%210%
RequestDocumentUpload()0%620%
ConfirmDocumentUpload()100%210%
UpdateWorldDocument()0%620%
DeleteWorldDocument()100%210%

File(s)

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

#LineLine coverage
 1using Chronicis.Api.Infrastructure;
 2using Chronicis.Api.Services;
 3using Chronicis.Shared.DTOs;
 4using Microsoft.AspNetCore.Authorization;
 5using Microsoft.AspNetCore.Mvc;
 6
 7namespace Chronicis.Api.Controllers;
 8
 9/// <summary>
 10/// API endpoints for World Document management (file uploads to blob storage).
 11/// </summary>
 12[Route("worlds/{worldId:guid}/documents")]
 13[Authorize]
 14public class WorldDocumentsController : ControllerBase
 15{
 16    private readonly IWorldDocumentService _documentService;
 17    private readonly ICurrentUserService _currentUserService;
 18    private readonly ILogger<WorldDocumentsController> _logger;
 19
 020    public WorldDocumentsController(
 021        IWorldDocumentService documentService,
 022        ICurrentUserService currentUserService,
 023        ILogger<WorldDocumentsController> logger)
 24    {
 025        _documentService = documentService;
 026        _currentUserService = currentUserService;
 027        _logger = logger;
 028    }
 29
 30    /// <summary>
 31    /// GET /worlds/{worldId}/documents - Get all documents for a world.
 32    /// </summary>
 33    [HttpGet]
 34    public async Task<ActionResult<IEnumerable<WorldDocumentDto>>> GetWorldDocuments(Guid worldId)
 35    {
 036        var user = await _currentUserService.GetRequiredUserAsync();
 037        _logger.LogDebug("User {UserId} getting documents for world {WorldId}", user.Id, worldId);
 38
 39        try
 40        {
 041            var documents = await _documentService.GetWorldDocumentsAsync(worldId, user.Id);
 042            return Ok(documents);
 43        }
 044        catch (UnauthorizedAccessException ex)
 45        {
 046            _logger.LogWarning(ex, "Unauthorized access to world documents");
 047            return StatusCode(403, new { error = ex.Message });
 48        }
 049    }
 50
 51    /// <summary>
 52    /// Get a download URL for a document.
 53    /// </summary>
 54    [HttpGet("documents/{documentId:guid}/content")]
 55    [HttpGet("/documents/{documentId:guid}/content")]
 56    public async Task<ActionResult<WorldDocumentDownloadDto>> GetDocumentContentAsync(Guid documentId)
 57    {
 058        var user = await _currentUserService.GetRequiredUserAsync();
 059        _logger.LogDebug("User {UserId} requesting download URL for document {DocumentId}", user.Id, documentId);
 60
 61        try
 62        {
 063            var result = await _documentService.GetDocumentContentAsync(documentId, user.Id);
 64
 065            return Ok(new WorldDocumentDownloadDto
 066            {
 067                DownloadUrl = result.DownloadUrl,
 068                FileName = result.FileName,
 069                ContentType = result.ContentType,
 070                FileSizeBytes = result.FileSizeBytes
 071            });
 72        }
 073        catch (UnauthorizedAccessException ex)
 74        {
 075            _logger.LogWarning(ex, "Unauthorized document content request");
 076            return StatusCode(403, new { error = ex.Message });
 77        }
 078        catch (InvalidOperationException ex)
 79        {
 080            _logger.LogWarning(ex, "Document not found for content request");
 081            return NotFound(new { error = ex.Message });
 82        }
 083        catch (FileNotFoundException ex)
 84        {
 085            _logger.LogDebug(ex, "File not found in storage");
 086            return NotFound(new { error = "File not found in storage" });
 87        }
 088        catch (Exception ex)
 89        {
 090            _logger.LogError(ex, "Error generating download URL");
 091            return StatusCode(500, new { error = "Failed to generate download URL" });
 92        }
 093    }
 94
 95    /// <summary>
 96    /// POST /worlds/{worldId}/documents/request-upload - Request a document upload (generates SAS URL).
 97    /// </summary>
 98    [HttpPost("request-upload")]
 99    public async Task<ActionResult<WorldDocumentUploadResponseDto>> RequestDocumentUpload(
 100        Guid worldId,
 101        [FromBody] WorldDocumentUploadRequestDto request)
 102    {
 0103        var user = await _currentUserService.GetRequiredUserAsync();
 0104        _logger.LogDebug("User {UserId} requesting document upload for world {WorldId}", user.Id, worldId);
 105
 0106        if (request == null)
 107        {
 0108            return BadRequest(new { error = "Invalid request body" });
 109        }
 110
 111        try
 112        {
 0113            var result = await _documentService.RequestUploadAsync(worldId, user.Id, request);
 0114            return Ok(result);
 115        }
 0116        catch (UnauthorizedAccessException ex)
 117        {
 0118            _logger.LogWarning(ex, "Unauthorized upload request");
 0119            return StatusCode(403, new { error = ex.Message });
 120        }
 0121        catch (ArgumentException ex)
 122        {
 0123            _logger.LogWarning(ex, "Invalid upload request");
 0124            return BadRequest(new { error = ex.Message });
 125        }
 0126    }
 127
 128    /// <summary>
 129    /// POST /worlds/{worldId}/documents/{documentId}/confirm - Confirm a document upload completed.
 130    /// </summary>
 131    [HttpPost("{documentId:guid}/confirm")]
 132    public async Task<ActionResult<WorldDocumentDto>> ConfirmDocumentUpload(Guid worldId, Guid documentId)
 133    {
 0134        var user = await _currentUserService.GetRequiredUserAsync();
 0135        _logger.LogDebug("User {UserId} confirming document upload {DocumentId}", user.Id, documentId);
 136
 137        try
 138        {
 0139            var result = await _documentService.ConfirmUploadAsync(worldId, documentId, user.Id);
 0140            return Ok(result);
 141        }
 0142        catch (UnauthorizedAccessException ex)
 143        {
 0144            _logger.LogWarning(ex, "Unauthorized confirm upload");
 0145            return StatusCode(403, new { error = ex.Message });
 146        }
 0147        catch (InvalidOperationException ex)
 148        {
 0149            _logger.LogWarning(ex, "Invalid confirm upload request");
 0150            return NotFound(new { error = ex.Message });
 151        }
 0152    }
 153
 154    /// <summary>
 155    /// PUT /worlds/{worldId}/documents/{documentId} - Update document metadata.
 156    /// </summary>
 157    [HttpPut("{documentId:guid}")]
 158    public async Task<ActionResult<WorldDocumentDto>> UpdateWorldDocument(
 159        Guid worldId,
 160        Guid documentId,
 161        [FromBody] WorldDocumentUpdateDto update)
 162    {
 0163        var user = await _currentUserService.GetRequiredUserAsync();
 0164        _logger.LogDebug("User {UserId} updating document {DocumentId}", user.Id, documentId);
 165
 0166        if (update == null)
 167        {
 0168            return BadRequest(new { error = "Invalid request body" });
 169        }
 170
 171        try
 172        {
 0173            var result = await _documentService.UpdateDocumentAsync(worldId, documentId, user.Id, update);
 0174            return Ok(result);
 175        }
 0176        catch (UnauthorizedAccessException ex)
 177        {
 0178            _logger.LogWarning(ex, "Unauthorized update request");
 0179            return StatusCode(403, new { error = ex.Message });
 180        }
 0181        catch (InvalidOperationException ex)
 182        {
 0183            _logger.LogWarning(ex, "Document not found for update");
 0184            return NotFound(new { error = ex.Message });
 185        }
 0186    }
 187
 188    /// <summary>
 189    /// DELETE /worlds/{worldId}/documents/{documentId} - Delete a document.
 190    /// </summary>
 191    [HttpDelete("{documentId:guid}")]
 192    public async Task<IActionResult> DeleteWorldDocument(Guid worldId, Guid documentId)
 193    {
 0194        var user = await _currentUserService.GetRequiredUserAsync();
 0195        _logger.LogDebug("User {UserId} deleting document {DocumentId}", user.Id, documentId);
 196
 197        try
 198        {
 0199            await _documentService.DeleteDocumentAsync(worldId, documentId, user.Id);
 0200            return NoContent();
 201        }
 0202        catch (UnauthorizedAccessException ex)
 203        {
 0204            _logger.LogWarning(ex, "Unauthorized delete request");
 0205            return StatusCode(403, new { error = ex.Message });
 206        }
 0207        catch (InvalidOperationException ex)
 208        {
 0209            _logger.LogWarning(ex, "Document not found for deletion");
 0210            return NotFound(new { error = ex.Message });
 211        }
 0212    }
 213}