From 9d8ae5ec24c48a1e7e1bf4f3131cc0452265b30e Mon Sep 17 00:00:00 2001 From: Arthur Bassi Date: Tue, 8 Sep 2026 11:23:52 -0300 Subject: [PATCH] feat(work-orders): add authorized media content GET --- .../WorkOrderMediaControllerTests.cs | 37 +++++++++++++++++++ .../Controllers/WorkOrderMediaController.cs | 21 +++++++++++ 2 files changed, 58 insertions(+) diff --git a/Api.SeaHavenIndustries.Tests/WorkOrderMediaControllerTests.cs b/Api.SeaHavenIndustries.Tests/WorkOrderMediaControllerTests.cs index 8c4f826..b377b40 100644 --- a/Api.SeaHavenIndustries.Tests/WorkOrderMediaControllerTests.cs +++ b/Api.SeaHavenIndustries.Tests/WorkOrderMediaControllerTests.cs @@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc; using Moq; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; +using SeaHaven.Services.Exceptions; using SeaHaven.Services.Helpers; using SeaHaven.Services.Implementation; using SeaHaven.Services.Interfaces; @@ -77,6 +78,42 @@ public class WorkOrderMediaControllerTests Assert.Equal("UnsupportedMediaType", error.Code); storage.VerifyNoOtherCalls(); } + + [Fact] + public async Task GetMediaContent_DeletedMedia_ReturnsNotFound() + { + var service = new Mock(MockBehavior.Strict); + service.Setup(candidate => candidate.GetMediaContentAsync( + 1, 10, It.IsAny(), It.IsAny(), It.IsAny())) + .ThrowsAsync(new WorkOrderBoardValidationException("NotFound", "Media not found.")); + var storage = new Mock(MockBehavior.Strict); + var controller = CreateController(service, storage); + + var result = await controller.GetMediaContent(1, 10, CancellationToken.None); + + var response = Assert.IsType(result); + var error = Assert.IsType(response.Value); + Assert.Equal("NotFound", error.Code); + storage.Verify(candidate => candidate.TryDelete(It.IsAny()), Times.Never); + storage.VerifyNoOtherCalls(); + } + + [Fact] + public async Task DeleteMedia_Success_DoesNotCallTryDelete() + { + var service = new Mock(MockBehavior.Strict); + service.Setup(candidate => candidate.DeleteMediaAsync( + 1, 10, null, It.IsAny(), It.IsAny(), It.IsAny())) + .Returns(Task.CompletedTask); + var storage = new Mock(MockBehavior.Strict); + var controller = CreateController(service, storage); + + var result = await controller.DeleteMedia(1, 10); + + Assert.IsType(result); + storage.Verify(candidate => candidate.TryDelete(It.IsAny()), Times.Never); + storage.VerifyNoOtherCalls(); + } } public class WorkOrderCompletionControllerUploadLimitTests diff --git a/Api.SeaHavenIndustries/Controllers/WorkOrderMediaController.cs b/Api.SeaHavenIndustries/Controllers/WorkOrderMediaController.cs index b9bc629..62f81df 100644 --- a/Api.SeaHavenIndustries/Controllers/WorkOrderMediaController.cs +++ b/Api.SeaHavenIndustries/Controllers/WorkOrderMediaController.cs @@ -52,6 +52,27 @@ namespace Api.SeaHavenIndustries.Controllers } } + [HttpGet("{id:int}/media/{mediaId:int}/content")] + public async Task GetMediaContent(int id, int mediaId, CancellationToken cancellationToken) + { + try + { + var actorId = User.FindFirstValue(ClaimTypes.NameIdentifier); + var content = await _workOrderMediaService.GetMediaContentAsync( + id, mediaId, User, actorId, cancellationToken); + return File(content.Content, content.ContentType, content.FileName); + } + catch (WorkOrderBoardValidationException ex) when (ex.Code == "NotFound") + { + return NotFound(new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); + } + catch (WorkOrderBoardValidationException ex) when (ex.Code == "Forbidden") + { + return StatusCode(StatusCodes.Status403Forbidden, + new WorkOrderBoardValidationErrorDto { Code = ex.Code, Message = ex.Message }); + } + } + [HttpPost("{id:int}/media")] [RequestSizeLimit(MaxUploadBytes)] public async Task AddMedia(