mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-03 15:03:29 +00:00
fix(work-orders): block comment creation on canceled work orders
This commit is contained in:
parent
f47264ec4d
commit
4b8a08fb10
2 changed files with 78 additions and 3 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Data.SeaHavenIndustries;
|
using Data.SeaHavenIndustries;
|
||||||
|
using Data.SeaHavenIndustries.Enums;
|
||||||
using SeaHaven.DataServices.Interfaces;
|
using SeaHaven.DataServices.Interfaces;
|
||||||
using SeaHaven.Services.DTOs;
|
using SeaHaven.Services.DTOs;
|
||||||
using SeaHaven.Services.Exceptions;
|
using SeaHaven.Services.Exceptions;
|
||||||
|
|
@ -48,9 +49,13 @@ namespace SeaHaven.Services.Implementation
|
||||||
string? documentUrl = null)
|
string? documentUrl = null)
|
||||||
{
|
{
|
||||||
var accountId = _accountResolver.ResolveAccountFilter(user);
|
var accountId = _accountResolver.ResolveAccountFilter(user);
|
||||||
if (!await _detailData.ExistsAsync(workOrderId, CancellationToken.None, accountId))
|
var workOrder = await _detailData.GetWorkOrderForMediaAsync(
|
||||||
|
workOrderId, CancellationToken.None, accountId);
|
||||||
|
if (workOrder == null)
|
||||||
throw new WorkOrderBoardValidationException("NotFound", "Work order not found.");
|
throw new WorkOrderBoardValidationException("NotFound", "Work order not found.");
|
||||||
|
|
||||||
|
EnsureCommentMutationAllowed(workOrder.LifecycleStatus);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(request.Text))
|
if (string.IsNullOrWhiteSpace(request.Text))
|
||||||
throw new WorkOrderBoardValidationException("InvalidValue", "Comment text is required.");
|
throw new WorkOrderBoardValidationException("InvalidValue", "Comment text is required.");
|
||||||
|
|
||||||
|
|
@ -83,8 +88,7 @@ namespace SeaHaven.Services.Implementation
|
||||||
if (workOrder == null)
|
if (workOrder == null)
|
||||||
throw new WorkOrderBoardValidationException("NotFound", "Work order not found.");
|
throw new WorkOrderBoardValidationException("NotFound", "Work order not found.");
|
||||||
|
|
||||||
if (!WorkOrderBoardMutationRules.CanMutateComments(workOrder.LifecycleStatus))
|
EnsureCommentMutationAllowed(workOrder.LifecycleStatus);
|
||||||
throw new WorkOrderBoardValidationException("ReadOnly", "Work order is read-only in its current status.");
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(request.Text))
|
if (string.IsNullOrWhiteSpace(request.Text))
|
||||||
throw new WorkOrderBoardValidationException("InvalidValue", "Comment text is required.");
|
throw new WorkOrderBoardValidationException("InvalidValue", "Comment text is required.");
|
||||||
|
|
@ -111,6 +115,12 @@ namespace SeaHaven.Services.Implementation
|
||||||
return WorkOrderCommentProjection.ToDto(comment, authorNames);
|
return WorkOrderCommentProjection.ToDto(comment, authorNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EnsureCommentMutationAllowed(LifecycleStatus? status)
|
||||||
|
{
|
||||||
|
if (!WorkOrderBoardMutationRules.CanMutateComments(status))
|
||||||
|
throw new WorkOrderBoardValidationException("ReadOnly", "Work order is read-only in its current status.");
|
||||||
|
}
|
||||||
|
|
||||||
private static bool IsBoardEditableComment(Comments comment)
|
private static bool IsBoardEditableComment(Comments comment)
|
||||||
=> string.Equals(comment.CommentType, "General", StringComparison.OrdinalIgnoreCase)
|
=> string.Equals(comment.CommentType, "General", StringComparison.OrdinalIgnoreCase)
|
||||||
&& string.Equals(comment.RecordType, "WorkOrder", StringComparison.OrdinalIgnoreCase);
|
&& string.Equals(comment.RecordType, "WorkOrder", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,71 @@ public class WorkOrderCompletedSelectiveLockTests
|
||||||
Assert.Equal("Follow-up", result.Text);
|
Assert.Equal("Follow-up", result.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddComment_Completed_AddsText()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
var context = new ApplicationDbContext(options);
|
||||||
|
context.workOrders.Add(CompletedWorkOrder());
|
||||||
|
context.Users.Add(new ApplicationUser
|
||||||
|
{
|
||||||
|
Id = "user-author",
|
||||||
|
UserName = "author",
|
||||||
|
FirstName = "Alice",
|
||||||
|
LastName = "Dispatcher"
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var service = new WorkOrderCommentService(
|
||||||
|
new WorkOrderDetailDataService(context),
|
||||||
|
new CommentDataService(context),
|
||||||
|
new UserDataService(context),
|
||||||
|
WorkOrderAccountTestHelpers.Resolver(context));
|
||||||
|
|
||||||
|
var result = await service.AddCommentAsync(
|
||||||
|
1,
|
||||||
|
new WorkOrderCommentCreateDto { Text = "Follow-up" },
|
||||||
|
WorkOrderAccountTestHelpers.OrgWideAdmin("user-author"),
|
||||||
|
"user-author");
|
||||||
|
|
||||||
|
Assert.Equal("Follow-up", result.Text);
|
||||||
|
Assert.Equal("user-author", result.AuthorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task AddComment_Canceled_ThrowsReadOnly()
|
||||||
|
{
|
||||||
|
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
|
||||||
|
.UseInMemoryDatabase(Guid.NewGuid().ToString())
|
||||||
|
.Options;
|
||||||
|
var context = new ApplicationDbContext(options);
|
||||||
|
context.workOrders.Add(new WorkOrder
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
LifecycleStatus = LifecycleStatus.Canceled,
|
||||||
|
RowVersion = new byte[] { 1, 0, 0, 0, 0, 0, 0, 1 }
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var service = new WorkOrderCommentService(
|
||||||
|
new WorkOrderDetailDataService(context),
|
||||||
|
new CommentDataService(context),
|
||||||
|
new UserDataService(context),
|
||||||
|
WorkOrderAccountTestHelpers.Resolver(context));
|
||||||
|
|
||||||
|
var ex = await Assert.ThrowsAsync<WorkOrderBoardValidationException>(() =>
|
||||||
|
service.AddCommentAsync(
|
||||||
|
1,
|
||||||
|
new WorkOrderCommentCreateDto { Text = "Should not persist" },
|
||||||
|
WorkOrderAccountTestHelpers.OrgWideAdmin("user-author"),
|
||||||
|
"user-author"));
|
||||||
|
|
||||||
|
Assert.Equal("ReadOnly", ex.Code);
|
||||||
|
Assert.Empty(context.Comments);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task AddMedia_Completed_AllowsExtra()
|
public async Task AddMedia_Completed_AllowsExtra()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue