From 5f5fd6445d5f594e88355ee5221474fe91f26b66 Mon Sep 17 00:00:00 2001 From: Arthur Bassi Date: Fri, 17 Jul 2026 13:38:57 -0300 Subject: [PATCH] fix(work-orders): align stacked services with CI build --- .../Implementation/WorkOrderCommentService.cs | 63 +++++++++++++++++-- .../Interfaces/IWorkOrderCommentService.cs | 8 ++- 2 files changed, 66 insertions(+), 5 deletions(-) diff --git a/SeaHaven.Services/Implementation/WorkOrderCommentService.cs b/SeaHaven.Services/Implementation/WorkOrderCommentService.cs index d91599e..aa17d38 100644 --- a/SeaHaven.Services/Implementation/WorkOrderCommentService.cs +++ b/SeaHaven.Services/Implementation/WorkOrderCommentService.cs @@ -1,4 +1,4 @@ -using Data.SeaHavenIndustries; +using Data.SeaHavenIndustries; using SeaHaven.DataServices.Interfaces; using SeaHaven.Services.DTOs; using SeaHaven.Services.Exceptions; @@ -11,13 +11,16 @@ namespace SeaHaven.Services.Implementation { private readonly IWorkOrderDetailDataService _detailData; private readonly ICommentDataService _commentData; + private readonly IUserDataService _userDataService; public WorkOrderCommentService( IWorkOrderDetailDataService detailData, - ICommentDataService commentData) + ICommentDataService commentData, + IUserDataService userDataService) { _detailData = detailData; _commentData = commentData; + _userDataService = userDataService; } public async Task?> GetCommentsAsync(int workOrderId) @@ -26,7 +29,8 @@ namespace SeaHaven.Services.Implementation return null; var comments = await _detailData.GetCommentsAsync(workOrderId); - return WorkOrderCommentProjection.ToDtos(comments); + var authorNames = await ResolveAuthorNamesAsync(comments); + return WorkOrderCommentProjection.ToDtos(comments, authorNames); } public async Task AddCommentAsync( @@ -53,7 +57,58 @@ namespace SeaHaven.Services.Implementation }; var saved = await _commentData.AddAsync(comment); - return WorkOrderCommentProjection.ToDto(saved); + var authorNames = await ResolveAuthorNamesAsync(new[] { saved }); + return WorkOrderCommentProjection.ToDto(saved, authorNames); + } + + public async Task UpdateCommentAsync( + int workOrderId, + int commentId, + WorkOrderCommentCreateDto request, + string? actorId, + bool isAdmin) + { + var workOrder = await _detailData.GetWorkOrderForMediaAsync(workOrderId); + if (workOrder == null) + throw new WorkOrderBoardValidationException("NotFound", "Work order not found."); + + if (WorkOrderBoardMutationRules.IsReadOnly(workOrder.LifecycleStatus)) + throw new WorkOrderBoardValidationException("ReadOnly", "Work order is read-only in its current status."); + + if (string.IsNullOrWhiteSpace(request.Text)) + throw new WorkOrderBoardValidationException("InvalidValue", "Comment text is required."); + + var comment = await _commentData.GetByIdAsync(commentId); + if (comment == null || comment.WorkerOrderId != workOrderId || comment.IsDeleted == true) + throw new WorkOrderBoardValidationException("NotFound", "Comment not found."); + + if (!IsBoardEditableComment(comment)) + throw new WorkOrderBoardValidationException( + "NotEditable", + "Only board comments (CommentType General) can be edited via this endpoint."); + + var isAuthor = !string.IsNullOrWhiteSpace(actorId) + && string.Equals(comment.UserId, actorId, StringComparison.Ordinal); + if (!isAuthor && !isAdmin) + throw new WorkOrderBoardValidationException("Forbidden", "You are not allowed to edit this comment."); + + comment.Commenttext = request.Text.Trim(); + comment.LastModificationTime = DateTime.UtcNow; + await _commentData.UpdateAsync(comment); + + var authorNames = await ResolveAuthorNamesAsync(new[] { comment }); + return WorkOrderCommentProjection.ToDto(comment, authorNames); + } + + private static bool IsBoardEditableComment(Comments comment) + => string.Equals(comment.CommentType, "General", StringComparison.OrdinalIgnoreCase) + && string.Equals(comment.RecordType, "WorkOrder", StringComparison.OrdinalIgnoreCase); + + private async Task> ResolveAuthorNamesAsync( + IEnumerable comments) + { + var authorIds = WorkOrderCommentProjection.CollectAuthorUserIds(comments); + return await _userDataService.GetDisplayNamesByIdsAsync(authorIds); } } } diff --git a/SeaHaven.Services/Interfaces/IWorkOrderCommentService.cs b/SeaHaven.Services/Interfaces/IWorkOrderCommentService.cs index 9b1e2a2..5e6a4ea 100644 --- a/SeaHaven.Services/Interfaces/IWorkOrderCommentService.cs +++ b/SeaHaven.Services/Interfaces/IWorkOrderCommentService.cs @@ -1,4 +1,4 @@ -using Data.SeaHavenIndustries.Enums; +using Data.SeaHavenIndustries.Enums; using SeaHaven.Services.DTOs; namespace SeaHaven.Services.Interfaces @@ -7,5 +7,11 @@ namespace SeaHaven.Services.Interfaces { Task?> GetCommentsAsync(int workOrderId); Task AddCommentAsync(int workOrderId, WorkOrderCommentCreateDto request, string? actorId, string? documentUrl = null); + Task UpdateCommentAsync( + int workOrderId, + int commentId, + WorkOrderCommentCreateDto request, + string? actorId, + bool isAdmin); } }