апи для работы с маршрутами согласования #2
@@ -1,5 +1,5 @@
|
||||
namespace Tnsu.ApprovalRoute.Api.Common;
|
||||
|
||||
public sealed record ApiResponse<T>(T Data, IReadOnlyList<string> Warnings);
|
||||
public sealed record ApiResponse<T>(T Data);
|
||||
|
||||
public sealed record ApiError(string Message);
|
||||
|
||||
@@ -11,8 +11,7 @@ public static class ResultExtensions
|
||||
if (result.IsFailed)
|
||||
return result.Errors[0].ToActionResult();
|
||||
|
||||
var warnings = result.Reasons.OfType<Warning>().Select(w => w.Message).ToList();
|
||||
return new OkObjectResult(new ApiResponse<T>(result.Value, warnings));
|
||||
return new OkObjectResult(new ApiResponse<T>(result.Value));
|
||||
}
|
||||
|
||||
public static IActionResult ToActionResult(this Result result)
|
||||
|
||||
@@ -8,5 +8,3 @@ public sealed class NotFoundError(string entity, object id)
|
||||
public sealed class ValidationError(string message) : Error(message);
|
||||
|
||||
public sealed class ConflictError(string message) : Error(message);
|
||||
|
||||
public sealed class Warning(string message) : Success(message);
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ public sealed record TemplateRouteStepDto(
|
||||
HeadType HeadType,
|
||||
RouteStepStatus Status,
|
||||
int RouteId,
|
||||
bool AllowReassignToOtherApprovers);
|
||||
bool AllowReassignToOtherApprovers,
|
||||
string? Warning = null);
|
||||
|
||||
public sealed record CreateTemplateRouteStepRequest(
|
||||
int OrderNo,
|
||||
|
||||
+12
-12
@@ -55,8 +55,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
|
||||
db.TemplateRouteSteps.Add(entity);
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var result = Result.Ok(ToDto(entity));
|
||||
return await AppendMissingProjectRoleWarningAsync(route, result, cancellationToken);
|
||||
return Result.Ok(await ToDtoWithWarningAsync(entity, route, cancellationToken));
|
||||
}
|
||||
|
||||
public async Task<Result<TemplateRouteStepDto>> UpdateAsync(
|
||||
@@ -83,8 +82,7 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
|
||||
entity.AllowReassignToOtherApprovers = r.AllowReassignToOtherApprovers;
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var result = Result.Ok(ToDto(entity));
|
||||
return await AppendMissingProjectRoleWarningAsync(route, result, cancellationToken);
|
||||
return Result.Ok(await ToDtoWithWarningAsync(entity, route, cancellationToken));
|
||||
}
|
||||
|
||||
public async Task<Result> DeleteAsync(int routeId, int id, CancellationToken cancellationToken)
|
||||
@@ -99,18 +97,20 @@ public sealed class TemplateRouteStepService(ApprovalRouteDbContext db)
|
||||
return Result.Ok();
|
||||
}
|
||||
|
||||
private async Task<Result<TemplateRouteStepDto>> AppendMissingProjectRoleWarningAsync(
|
||||
TemplateRoute route, Result<TemplateRouteStepDto> result, CancellationToken cancellationToken)
|
||||
// Для маршрута «по проекту» без единого шага с ролью в проекте DTO несёт предупреждение в поле Warning.
|
||||
private async Task<TemplateRouteStepDto> ToDtoWithWarningAsync(
|
||||
TemplateRouteStep entity, TemplateRoute route, CancellationToken cancellationToken)
|
||||
{
|
||||
string? warning = null;
|
||||
if (route.ByProject)
|
||||
{
|
||||
if (!route.ByProject)
|
||||
return result;
|
||||
|
||||
var hasProjectRoleStep = await db.TemplateRouteSteps
|
||||
.AnyAsync(x => x.RouteId == route.Id && x.ProjectRole != ProjectRole.None, cancellationToken);
|
||||
if (!hasProjectRoleStep)
|
||||
warning = "Должен быть хотя бы один шаг с ролью в проекте.";
|
||||
}
|
||||
|
||||
return hasProjectRoleStep
|
||||
? result
|
||||
: result.WithReason(new Warning("Должен быть хотя бы один шаг с ролью в проекте."));
|
||||
return ToDto(entity) with { Warning = warning };
|
||||
}
|
||||
|
||||
private static TemplateRouteStepDto ToDto(TemplateRouteStep e) => new(
|
||||
|
||||
+3
-2
@@ -99,7 +99,8 @@ public sealed class TemplateRouteStepServiceTests : IClassFixture<PostgresDataba
|
||||
|
||||
// Assert
|
||||
created.IsSuccess.ShouldBeTrue();
|
||||
created.Reasons.ShouldContain(r => r.Message.Contains("ролью в проекте"));
|
||||
created.Value.Warning.ShouldNotBeNull();
|
||||
created.Value.Warning.ShouldContain("ролью в проекте");
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Создание шага с ролью в проекте на маршруте «по проекту» не возвращает предупреждение")]
|
||||
@@ -116,7 +117,7 @@ public sealed class TemplateRouteStepServiceTests : IClassFixture<PostgresDataba
|
||||
|
||||
// Assert
|
||||
created.IsSuccess.ShouldBeTrue();
|
||||
created.Reasons.ShouldBeEmpty();
|
||||
created.Value.Warning.ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact(DisplayName = "Обновление шага маршрута изменяет исполнителя, статус и разрешение на переназначение")]
|
||||
|
||||
Reference in New Issue
Block a user