Refactor error handling in Bumper, Media, Group, and Junction components to include contextual information
Updated error definitions in BumperErrors, MediaErrors, GroupErrors, and TemplateErrors to accept a parameter for contextual information, enhancing the clarity of error messages. Refactored related command handlers to utilize these updated error messages, ensuring that users receive specific details about the usage context when attempting to delete resources. Adjusted unit tests to verify the correctness of the new error handling logic.
This commit is contained in:
+46
-1
@@ -34,10 +34,55 @@ public sealed class DeleteGroupCommandHandler(IAppDbContext dbContext)
|
||||
t => t.FallbackGroupId == group.Id,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
// Сам факт занятости и адрес — разные вопросы: адрес собирается по цепочке слой → шаблон →
|
||||
// канал, и если она неполна, имени не будет, а запрещать удаление всё равно надо.
|
||||
if (used)
|
||||
return Result.Failure(GroupErrors.InUse);
|
||||
return Result.Failure(
|
||||
GroupErrors.InUse(await UsedByAsync(group.Id, cancellationToken))
|
||||
);
|
||||
|
||||
dbContext.Groups.Remove(group);
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
/// <summary>Кто держит группу: слоты каналов, стыки и аварийная группа шаблона.</summary>
|
||||
private async Task<string> UsedByAsync(Guid groupId, CancellationToken cancellationToken)
|
||||
{
|
||||
var slots = await (
|
||||
from slot in dbContext.Slots
|
||||
join layer in dbContext.GridLayers on slot.LayerId equals layer.Id
|
||||
join template in dbContext.ScheduleTemplates on layer.TemplateId equals template.Id
|
||||
join channel in dbContext.Channels on template.ChannelId equals channel.Id
|
||||
where slot.GroupId == groupId
|
||||
select channel.Name
|
||||
)
|
||||
.Distinct()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var junctions = await (
|
||||
from element in dbContext.JunctionElements
|
||||
join junction in dbContext.JunctionTemplates
|
||||
on element.JunctionTemplateId equals junction.Id
|
||||
where element.GroupId == groupId
|
||||
select junction.Name
|
||||
)
|
||||
.Distinct()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var fallback = await (
|
||||
from template in dbContext.ScheduleTemplates
|
||||
join channel in dbContext.Channels on template.ChannelId equals channel.Id
|
||||
where template.FallbackGroupId == groupId
|
||||
select channel.Name
|
||||
)
|
||||
.Distinct()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return UsageText.Join(
|
||||
UsageText.Part("слоты каналов", slots),
|
||||
UsageText.Part("врезки стыков", junctions),
|
||||
UsageText.Part("аварийная группа каналов", fallback)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,19 @@ public static class GroupErrors
|
||||
"Шоу или коллекция не найдены."
|
||||
);
|
||||
|
||||
public static readonly Error InUse = Error.Conflict(
|
||||
"Groups.InUse",
|
||||
"Группа используется в сетке: на неё ссылается слот, врезка стыка или запасная группа шаблона."
|
||||
);
|
||||
/// <summary>
|
||||
/// Где именно занята группа: без адреса «используется в сетке» отправляет обходить все каналы.
|
||||
/// Пустой <paramref name="where"/> — связи неполны (слой без шаблона, шаблон без канала),
|
||||
/// и тогда честнее общий текст, чем пустые скобки.
|
||||
/// </summary>
|
||||
public static Error InUse(string where) =>
|
||||
Error.Conflict(
|
||||
"Groups.InUse",
|
||||
where.Length > 0
|
||||
? $"Группа используется в сетке ({where}) — сначала отвяжите её там."
|
||||
: "Группа используется в сетке: на неё ссылается слот, врезка стыка "
|
||||
+ "или запасная группа шаблона."
|
||||
);
|
||||
|
||||
public static readonly Error FilterNotSet = Error.Validation(
|
||||
"Groups.FilterNotSet",
|
||||
|
||||
+35
-1
@@ -30,10 +30,44 @@ public sealed class DeleteJunctionCommandHandler(IAppDbContext dbContext)
|
||||
t => t.DefaultJunctionId == junction.Id,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
// Факт и адрес — разные вопросы: имя канала берётся по цепочке связей, и её неполнота
|
||||
// не должна превращать запрет в разрешение.
|
||||
if (usedBySlot || usedByDefault)
|
||||
return Result.Failure(TemplateErrors.JunctionInUse);
|
||||
return Result.Failure(
|
||||
TemplateErrors.JunctionInUse(await UsedByAsync(junction.Id, cancellationToken))
|
||||
);
|
||||
|
||||
dbContext.JunctionTemplates.Remove(junction);
|
||||
return Result.Success();
|
||||
}
|
||||
|
||||
/// <summary>Кто держит стык: слоты каналов и каналы, где он выбран стыком по умолчанию.</summary>
|
||||
private async Task<string> UsedByAsync(Guid junctionId, CancellationToken cancellationToken)
|
||||
{
|
||||
var slots = await (
|
||||
from slot in dbContext.Slots
|
||||
join layer in dbContext.GridLayers on slot.LayerId equals layer.Id
|
||||
join template in dbContext.ScheduleTemplates on layer.TemplateId equals template.Id
|
||||
join channel in dbContext.Channels on template.ChannelId equals channel.Id
|
||||
where slot.JunctionBetweenId == junctionId || slot.JunctionAfterId == junctionId
|
||||
select channel.Name
|
||||
)
|
||||
.Distinct()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var byDefault = await (
|
||||
from template in dbContext.ScheduleTemplates
|
||||
join channel in dbContext.Channels on template.ChannelId equals channel.Id
|
||||
where template.DefaultJunctionId == junctionId
|
||||
select channel.Name
|
||||
)
|
||||
.Distinct()
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
return UsageText.Join(
|
||||
UsageText.Part("слоты каналов", slots),
|
||||
UsageText.Part("стык по умолчанию у каналов", byDefault)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,10 +49,14 @@ public static class TemplateErrors
|
||||
"Врезка не найдена."
|
||||
);
|
||||
|
||||
public static readonly Error JunctionInUse = Error.Conflict(
|
||||
"Templates.JunctionInUse",
|
||||
"Стык используется слотами — сначала отвяжите его."
|
||||
);
|
||||
/// <summary>Стык общий, поэтому держать его может слот чужого канала — называем какого.</summary>
|
||||
public static Error JunctionInUse(string where) =>
|
||||
Error.Conflict(
|
||||
"Templates.JunctionInUse",
|
||||
where.Length > 0
|
||||
? $"Стык используется ({where}) — сначала отвяжите его там."
|
||||
: "Стык используется слотами — сначала отвяжите его."
|
||||
);
|
||||
|
||||
public static readonly Error JunctionGroupRequired = Error.Validation(
|
||||
"Templates.JunctionGroupRequired",
|
||||
|
||||
Reference in New Issue
Block a user