Update release notes and deploy workspace
This commit is contained in:
@@ -44,6 +44,13 @@ public static partial class AdminSeasonManagementEndpoints
|
||||
string ChannelSlug,
|
||||
string? ClipCompilationUrl);
|
||||
|
||||
private sealed record WinnerPublicationSnapshot(
|
||||
int CategoryId,
|
||||
int? StreamerIdentityId,
|
||||
string DisplayName,
|
||||
string ChannelSlug,
|
||||
string? ClipCompilationUrl);
|
||||
|
||||
private static IResult? ValidateSeasonRequest(CreateSeasonRequest request)
|
||||
{
|
||||
if (request.Year < 2020 || request.Year > 2100)
|
||||
@@ -108,11 +115,6 @@ public static partial class AdminSeasonManagementEndpoints
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string NormalizeSeasonStreamUrl(string? showStreamUrl)
|
||||
{
|
||||
return SeasonMappings.NormalizeSeasonStreamUrl(showStreamUrl);
|
||||
}
|
||||
|
||||
private static bool IsKnownSeasonPhase(string? currentPhase)
|
||||
{
|
||||
var value = currentPhase?.Trim().ToLowerInvariant() ?? string.Empty;
|
||||
@@ -156,7 +158,17 @@ public static partial class AdminSeasonManagementEndpoints
|
||||
var issueList = issues.ToArray();
|
||||
return Results.BadRequest(new
|
||||
{
|
||||
message = $"Public-/Archiv-Readiness blockiert: {string.Join(" ", issueList)}",
|
||||
message = $"Landingpage-Freigabe blockiert: {string.Join(" ", issueList)}",
|
||||
issues = issueList,
|
||||
});
|
||||
}
|
||||
|
||||
private static IResult CreateWinnerPublicationError(IEnumerable<string> issues)
|
||||
{
|
||||
var issueList = issues.ToArray();
|
||||
return Results.BadRequest(new
|
||||
{
|
||||
message = $"Gewinner-Freigabe blockiert: {string.Join(" ", issueList)}",
|
||||
issues = issueList,
|
||||
});
|
||||
}
|
||||
@@ -421,6 +433,87 @@ public static partial class AdminSeasonManagementEndpoints
|
||||
return issues.ToArray();
|
||||
}
|
||||
|
||||
private static async Task<string[]> BuildWinnerPublicationIssuesAsync(
|
||||
AwardsDbContext db,
|
||||
int seasonId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var categoryIds = await db.Categories
|
||||
.AsNoTracking()
|
||||
.Where(item => item.SeasonId == seasonId)
|
||||
.Select(item => item.Id)
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
var issues = new List<string>();
|
||||
if (categoryIds.Length == 0)
|
||||
{
|
||||
issues.Add("Mindestens eine Kategorie ist erforderlich.");
|
||||
return issues.ToArray();
|
||||
}
|
||||
|
||||
var resultSnapshots = await db.Results
|
||||
.AsNoTracking()
|
||||
.Where(item => item.SeasonId == seasonId)
|
||||
.Select(item => new WinnerPublicationSnapshot(
|
||||
item.CategoryId,
|
||||
item.Candidate.StreamerIdentityId,
|
||||
item.Candidate.DisplayName,
|
||||
item.Candidate.ChannelSlug,
|
||||
item.Candidate.ClipCompilationUrl))
|
||||
.ToArrayAsync(cancellationToken);
|
||||
|
||||
var categoriesWithResults = resultSnapshots
|
||||
.Select(item => item.CategoryId)
|
||||
.Distinct()
|
||||
.Count();
|
||||
var missingResults = Math.Max(0, categoryIds.Length - categoriesWithResults);
|
||||
if (missingResults > 0)
|
||||
{
|
||||
issues.Add($"{missingResults} Kategorien haben noch keinen Gewinner.");
|
||||
}
|
||||
|
||||
var openReviewCount = await db.Nominations
|
||||
.AsNoTracking()
|
||||
.CountAsync(item => item.SeasonId == seasonId && item.Status == "pending", cancellationToken);
|
||||
if (openReviewCount > 0)
|
||||
{
|
||||
issues.Add($"{openReviewCount} Nominierungs-Review(s) sind noch offen.");
|
||||
}
|
||||
|
||||
var workflowRules = await LoadWorkflowRulesAsync(db, seasonId, cancellationToken);
|
||||
var winnerRequiresClipRule = WorkflowRuleSettings.Find(workflowRules, WorkflowRuleSettings.WinnerRequiresClip);
|
||||
if (WorkflowRuleSettings.ShouldBlock(winnerRequiresClipRule))
|
||||
{
|
||||
var missingWinnerClipCount = resultSnapshots.Count(item => string.IsNullOrWhiteSpace(item.ClipCompilationUrl));
|
||||
if (missingWinnerClipCount > 0)
|
||||
{
|
||||
issues.Add($"{missingWinnerClipCount} Gewinner haben noch keinen gepflegten Clip-Link.");
|
||||
}
|
||||
}
|
||||
|
||||
var winnerPlacementsRule = WorkflowRuleSettings.Find(workflowRules, WorkflowRuleSettings.MaxWinnerPlacements);
|
||||
if (WorkflowRuleSettings.ShouldBlock(winnerPlacementsRule))
|
||||
{
|
||||
var winnerOverflow = resultSnapshots
|
||||
.GroupBy(item => ResolveCandidateIdentityKey(item.StreamerIdentityId, item.DisplayName, item.ChannelSlug))
|
||||
.Select(group => new
|
||||
{
|
||||
Count = group.Count(),
|
||||
DisplayName = group.Select(item => item.DisplayName).FirstOrDefault(name => !string.IsNullOrWhiteSpace(name)) ?? "Unbekannt",
|
||||
})
|
||||
.Where(item => item.Count > winnerPlacementsRule.Limit)
|
||||
.OrderByDescending(item => item.Count)
|
||||
.FirstOrDefault();
|
||||
if (winnerOverflow is not null)
|
||||
{
|
||||
issues.Add(
|
||||
$"Workflow-Regel blockiert: {winnerOverflow.DisplayName} hat bereits {winnerOverflow.Count} Gewinnerplatz(e). Limit: {winnerPlacementsRule.Limit}.");
|
||||
}
|
||||
}
|
||||
|
||||
return issues.ToArray();
|
||||
}
|
||||
|
||||
private static string ResolveCandidateIdentityKey(int? streamerIdentityId, string displayName, string channelSlug)
|
||||
{
|
||||
if (streamerIdentityId.HasValue)
|
||||
|
||||
Reference in New Issue
Block a user