Перевести «не найдено» пользователя у оператора на исключение
ci / build-test (pull_request) Successful in 3m7s

TenantAdminService.GetAsync бросает NotFoundException вместо null; эндпоинт деталей без 404-проверки.
This commit is contained in:
2026-09-13 18:49:18 +03:00
parent 891a894aed
commit 75de70e09c
3 changed files with 15 additions and 16 deletions
@@ -144,12 +144,7 @@ public static class OperatorTenantsEndpoints
return EndpointResults.Unauthorized(AuthHelpers.OperatorUnauthorizedDetail); return EndpointResults.Unauthorized(AuthHelpers.OperatorUnauthorizedDetail);
} }
TenantDetailDto? tenant = await tenantAdminService.GetAsync(id, ct); TenantDetailDto tenant = await tenantAdminService.GetAsync(id, ct);
if (tenant is null)
{
return EndpointResults.NotFound(TenantNotFoundDetail);
}
return Results.Ok(tenant); return Results.Ok(tenant);
} }
@@ -1,6 +1,7 @@
using Deal.Modules.Tenants.Application.Abstractions; using Deal.Modules.Tenants.Application.Abstractions;
using Deal.Modules.Tenants.Application.Models; using Deal.Modules.Tenants.Application.Models;
using Deal.SharedKernel; using Deal.SharedKernel;
using Deal.SharedKernel.Errors;
using Deal.SharedKernel.Utilities; using Deal.SharedKernel.Utilities;
namespace Deal.Modules.Tenants.Application.Services; namespace Deal.Modules.Tenants.Application.Services;
@@ -17,6 +18,9 @@ public sealed class TenantAdminService(
// Случайные байты одноразового пароля владельца: 12 → ровно 16 символов Base64Url (как InviteCodeGenerator). // Случайные байты одноразового пароля владельца: 12 → ровно 16 символов Base64Url (как InviteCodeGenerator).
private const int InitialPasswordRandomByteCount = 12; private const int InitialPasswordRandomByteCount = 12;
// Имя сущности для текста ошибки «не найдено» (пользователь = тенант с его окружением).
private const string TenantEntityName = "Пользователь";
/// <summary> /// <summary>
/// Создаёт тенанта оператором /// Создаёт тенанта оператором
/// </summary> /// </summary>
@@ -103,14 +107,12 @@ public sealed class TenantAdminService(
/// Детали тенанта с пользователями /// Детали тенанта с пользователями
/// </summary> /// </summary>
/// <param name="id">Идентификатор тенанта.</param> /// <param name="id">Идентификатор тенанта.</param>
/// <returns>Детали и пользователи тенанта (по CreatedAt) или null, если тенанта нет.</returns> /// <returns>Детали и пользователи тенанта (по CreatedAt).</returns>
public async Task<TenantDetailDto?> GetAsync(Guid id, CancellationToken ct) /// <exception cref="NotFoundException">Тенант не найден.</exception>
public async Task<TenantDetailDto> GetAsync(Guid id, CancellationToken ct)
{ {
var tenant = await tenantRepository.FindByIdAsync(id, ct); var tenant = await tenantRepository.FindByIdAsync(id, ct)
if (tenant is null) ?? throw new NotFoundException(TenantEntityName, id.ToString("N"));
{
return null;
}
IReadOnlyList<UserIdentityDto> users = await authStore.ListUsersByTenantIdAsync(id, ct); IReadOnlyList<UserIdentityDto> users = await authStore.ListUsersByTenantIdAsync(id, ct);
return new TenantDetailDto(tenant.Id, tenant.Name, tenant.Status, tenant.CreatedAt, users); return new TenantDetailDto(tenant.Id, tenant.Name, tenant.Status, tenant.CreatedAt, users);
@@ -1,7 +1,8 @@
using Deal.Modules.Tenants.Application.Abstractions;
using Deal.Modules.Tenants.Application.Models; using Deal.Modules.Tenants.Application.Models;
using Deal.Modules.Tenants.Application.Services; using Deal.Modules.Tenants.Application.Services;
using Deal.SharedKernel.Errors;
using Deal.Tests.Unit.Support; using Deal.Tests.Unit.Support;
using Deal.Modules.Tenants.Application.Abstractions;
namespace Deal.Tests.Unit.Modules.Tenants; namespace Deal.Tests.Unit.Modules.Tenants;
@@ -148,11 +149,12 @@ public sealed class TenantAdminServiceTests
} }
[Fact] [Fact]
public async Task GetAsync_ForUnknownTenant_ReturnsNull() public async Task GetAsync_ForUnknownTenant_ThrowsNotFound()
{ {
var service = NewService(new TestTenantStore(), new TestAuthStore()); var service = NewService(new TestTenantStore(), new TestAuthStore());
Assert.Null(await service.GetAsync(Guid.NewGuid(), CancellationToken.None)); await Assert.ThrowsAsync<NotFoundException>(
() => service.GetAsync(Guid.NewGuid(), CancellationToken.None));
} }
[Fact] [Fact]