Перевести «не найдено» карточек на NotFoundException
CardsService (get/move/links/reminders) и CardMover бросают NotFoundException вместо null/CardResultDto(null,null)/Exists=false. CardMoveResultDto — только Error; эндпоинты без локальных 404-проверок.
This commit is contained in:
@@ -27,9 +27,16 @@ public sealed partial class CardsService
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <returns>Карточка или null — строки нет (эндпоинт отвечает 404 «Карточка не найдена»).</returns>
|
||||
public Task<CardDto?> GetCardAsync(string cardId, CancellationToken ct)
|
||||
/// <summary>
|
||||
/// Одна карточка по id.
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <returns>Карточка.</returns>
|
||||
/// <exception cref="NotFoundException">Карточка не найдена.</exception>
|
||||
public async Task<CardDto> GetCardAsync(string cardId, CancellationToken ct)
|
||||
{
|
||||
return _store.GetCardAsync(cardId, ct);
|
||||
return await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +64,7 @@ public sealed partial class CardsService
|
||||
CardDto? card = await _store.GetCardAsync(cardId, ct);
|
||||
if (card is null)
|
||||
{
|
||||
return new CardResultDto(null, null);
|
||||
throw new NotFoundException(CardEntityName, cardId);
|
||||
}
|
||||
|
||||
if (card.Col == CardIds.Archive || card.Col == CardIds.Trash)
|
||||
@@ -81,7 +88,10 @@ public sealed partial class CardsService
|
||||
await _mlClient.PushAsync(text, toCol, PushWeightUser, ct);
|
||||
}
|
||||
|
||||
return new CardResultDto(null, await _store.GetCardAsync(cardId, ct));
|
||||
return new CardResultDto(
|
||||
null,
|
||||
await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new NotFoundException(CardEntityName, cardId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Deal.Modules.Kanban.Application.Models;
|
||||
using Deal.Modules.Settings.Application.Models;
|
||||
using Deal.SharedKernel.Errors;
|
||||
|
||||
namespace Deal.Modules.Kanban.Application.Services;
|
||||
|
||||
@@ -22,17 +23,15 @@ public sealed partial class CardsService
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <param name="atMs">Время напоминания, epoch-ms.</param>
|
||||
/// <returns>Результат: Error <see cref="RemindersDisabledDetail"/> (400) | Card=null без Error (404) | Card — карточка с напоминанием.</returns>
|
||||
/// <returns>Результат: Error <see cref="RemindersDisabledDetail"/> (400) | Card — карточка с напоминанием.</returns>
|
||||
/// <exception cref="NotFoundException">Карточка не найдена.</exception>
|
||||
public async Task<CardResultDto> SetReminderAsync(
|
||||
string cardId,
|
||||
long atMs,
|
||||
CancellationToken ct)
|
||||
{
|
||||
CardDto? card = await _store.GetCardAsync(cardId, ct);
|
||||
if (card is null)
|
||||
{
|
||||
return new CardResultDto(null, null);
|
||||
}
|
||||
CardDto card = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
|
||||
if (!await ReadRemindersEnabledAsync(ct))
|
||||
{
|
||||
@@ -41,7 +40,7 @@ public sealed partial class CardsService
|
||||
|
||||
await _store.SetReminderAsync(cardId, atMs, ct);
|
||||
CardDto saved = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new InvalidOperationException("Карточка не прочиталась после установки напоминания: " + cardId);
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
return new CardResultDto(null, saved);
|
||||
}
|
||||
|
||||
@@ -49,35 +48,27 @@ public sealed partial class CardsService
|
||||
/// Снимает напоминание карточки.
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <returns>True — карточка есть и напоминание снято; false — карточки нет (404).</returns>
|
||||
public async Task<bool> ClearReminderAsync(string cardId, CancellationToken ct)
|
||||
/// <exception cref="NotFoundException">Карточка не найдена.</exception>
|
||||
public async Task ClearReminderAsync(string cardId, CancellationToken ct)
|
||||
{
|
||||
CardDto? card = await _store.GetCardAsync(cardId, ct);
|
||||
if (card is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_ = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
|
||||
await _store.ClearReminderAsync(cardId, ct);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// «Напомнить позже»
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <returns>True — карточка есть и напоминание отложено; false — карточки нет (404).</returns>
|
||||
public async Task<bool> SnoozeReminderAsync(string cardId, CancellationToken ct)
|
||||
/// <exception cref="NotFoundException">Карточка не найдена.</exception>
|
||||
public async Task SnoozeReminderAsync(string cardId, CancellationToken ct)
|
||||
{
|
||||
CardDto? card = await _store.GetCardAsync(cardId, ct);
|
||||
if (card is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_ = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
|
||||
long snoozedAtMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + ReminderSnoozeMs;
|
||||
await _store.SetReminderAsync(cardId, snoozedAtMs, ct);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace Deal.Modules.Kanban.Application.Services;
|
||||
/// </summary>
|
||||
public sealed partial class CardsService
|
||||
{
|
||||
// Имя сущности для текста ошибки «не найдено».
|
||||
private const string CardLinkEntityName = "Ссылка карточки";
|
||||
|
||||
/// <summary>
|
||||
/// 400 перенос по стадии
|
||||
/// </summary>
|
||||
@@ -159,18 +162,16 @@ public sealed partial class CardsService
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <param name="name">Название ссылки; пустое после Trim → name = url.</param>
|
||||
/// <param name="url">URL ссылки (без схемы — добавится https://).</param>
|
||||
/// <returns>Результат: Error (400 «Пустая ссылка») | Card=null без Error (404) | Card — карточка со ссылкой.</returns>
|
||||
/// <returns>Результат: Error (400 «Пустая ссылка») | Card — карточка со ссылкой.</returns>
|
||||
/// <exception cref="NotFoundException">Карточка не найдена.</exception>
|
||||
public async Task<CardResultDto> AddLinkAsync(
|
||||
string cardId,
|
||||
string name,
|
||||
string url,
|
||||
CancellationToken ct)
|
||||
{
|
||||
CardDto? card = await _store.GetCardAsync(cardId, ct);
|
||||
if (card is null)
|
||||
{
|
||||
return new CardResultDto(null, null);
|
||||
}
|
||||
CardDto card = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
|
||||
string normalizedUrl = (url ?? string.Empty).Trim();
|
||||
if (normalizedUrl.Length == 0)
|
||||
@@ -191,11 +192,11 @@ public sealed partial class CardsService
|
||||
normalizedUrl);
|
||||
if (!await _store.AddLinkAsync(cardId, link, ct))
|
||||
{
|
||||
return new CardResultDto(null, null);
|
||||
throw new NotFoundException(CardEntityName, cardId);
|
||||
}
|
||||
|
||||
CardDto saved = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new InvalidOperationException("Карточка не прочиталась после добавления ссылки: " + cardId);
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
return new CardResultDto(null, saved);
|
||||
}
|
||||
|
||||
@@ -204,7 +205,8 @@ public sealed partial class CardsService
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <param name="linkId">Id удаляемой ссылки (<c>pl_...</c>).</param>
|
||||
/// <returns>Результат: Card=null без Error (404) | Card — карточка без ссылки.</returns>
|
||||
/// <returns>Карточка без ссылки.</returns>
|
||||
/// <exception cref="NotFoundException">Карточка или ссылка не найдены.</exception>
|
||||
public async Task<CardResultDto> RemoveLinkAsync(
|
||||
string cardId,
|
||||
string linkId,
|
||||
@@ -212,11 +214,11 @@ public sealed partial class CardsService
|
||||
{
|
||||
if (!await _store.RemoveLinkAsync(cardId, linkId, ct))
|
||||
{
|
||||
return new CardResultDto(null, null);
|
||||
throw new NotFoundException(CardLinkEntityName, linkId);
|
||||
}
|
||||
|
||||
CardDto saved = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new InvalidOperationException("Карточка не прочиталась после удаления ссылки: " + cardId);
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
return new CardResultDto(null, saved);
|
||||
}
|
||||
|
||||
@@ -225,7 +227,8 @@ public sealed partial class CardsService
|
||||
/// </summary>
|
||||
/// <param name="cardId">Id карточки (<c>c_...</c>).</param>
|
||||
/// <param name="containerId">Новый контейнер-стадия — id каталога <see cref="CardsDefaultContainers"/>.</param>
|
||||
/// <returns>Результат: Error «Неизвестная стадия» (400) | Card=null без Error (карточки нет, 404) | Card — карточка после переноса.</returns>
|
||||
/// <returns>Результат: Error «Неизвестная стадия» (400) | Card — карточка после переноса.</returns>
|
||||
/// <exception cref="NotFoundException">Карточка не найдена.</exception>
|
||||
public async Task<CardResultDto> MoveStageCardAsync(
|
||||
string cardId,
|
||||
string containerId,
|
||||
@@ -241,11 +244,11 @@ public sealed partial class CardsService
|
||||
bool moved = await _store.MoveCardStageAsync(cardId, containerId, entry, nowMs, ct);
|
||||
if (!moved)
|
||||
{
|
||||
return new CardResultDto(null, null);
|
||||
throw new NotFoundException(CardEntityName, cardId);
|
||||
}
|
||||
|
||||
CardDto card = await _store.GetCardAsync(cardId, ct)
|
||||
?? throw new InvalidOperationException("Карточка не прочиталась после move: " + cardId);
|
||||
?? throw new NotFoundException(CardEntityName, cardId);
|
||||
return new CardResultDto(null, card);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user