using Backend.Contracts; using Backend.Common; using Backend.Data; using Backend.Domain; using Backend.Services; using Microsoft.EntityFrameworkCore; namespace Backend.Endpoints; public static partial class AdminModerationEndpoints { private static async Task ApproveNomination( HttpContext context, int nominationId, ApproveNominationRequest request, AwardsDbContext db, IAdminAuditService adminAuditService) { var session = AdminEndpointConventions.CurrentSession(context); var nomination = await db.Nominations .Include(item => item.Category) .FirstOrDefaultAsync(item => item.Id == nominationId); if (nomination is null) { return Results.NotFound(); } var rawDisplayName = request.DisplayName?.Trim() ?? string.Empty; if (string.IsNullOrWhiteSpace(rawDisplayName)) { return Results.BadRequest(new { message = "A display name is required to approve the nomination." }); } var channelSlug = request.ChannelSlug?.Trim() ?? string.Empty; var platform = string.IsNullOrWhiteSpace(request.Platform) ? "Twitch" : request.Platform.Trim(); var normalizedDisplayName = rawDisplayName.ToLower(); var normalizedChannelSlug = channelSlug.ToLower(); var normalizedPlatform = platform.ToLower(); var existingCandidate = await db.Candidates.FirstOrDefaultAsync(item => item.SeasonId == nomination.SeasonId && item.CategoryId == nomination.CategoryId && ( item.DisplayName.ToLower() == normalizedDisplayName || (!string.IsNullOrWhiteSpace(normalizedChannelSlug) && item.ChannelSlug.ToLower() == normalizedChannelSlug && item.Platform.ToLower() == normalizedPlatform) )); var candidate = existingCandidate; if (candidate is null) { candidate = new Candidate { SeasonId = nomination.SeasonId, CategoryId = nomination.CategoryId, DisplayName = rawDisplayName, ChannelSlug = channelSlug, Platform = platform, }; db.Candidates.Add(candidate); await db.SaveChangesAsync(context.RequestAborted); } else { candidate.DisplayName = rawDisplayName; if (!string.IsNullOrWhiteSpace(channelSlug)) { candidate.ChannelSlug = channelSlug; } if (!string.IsNullOrWhiteSpace(platform)) { candidate.Platform = platform; } } nomination.CandidateId = candidate.Id; nomination.Status = "approved"; nomination.ReviewNote = string.IsNullOrWhiteSpace(request.ReviewNote) ? null : request.ReviewNote.Trim(); nomination.ReviewedAt = DateTimeOffset.UtcNow; nomination.ReviewedByTwitchId = session.TwitchUserId; adminAuditService.AddEntry( session.TwitchUserId, "nomination.approve", "nomination", nomination.Id.ToString(), $"Nominierung {nomination.Id} wurde als Kandidat uebernommen.", new { candidateId = candidate.Id, created = existingCandidate is null, nomination.ReviewNote }, RequestMetadataReader.Read(context)); await db.SaveChangesAsync(context.RequestAborted); return Results.Ok(new { saved = true, nominationId = nomination.Id, candidateId = candidate.Id, created = existingCandidate is null }); } private static async Task RejectNomination( HttpContext context, int nominationId, RejectNominationRequest request, AwardsDbContext db, IAdminAuditService adminAuditService) { var session = AdminEndpointConventions.CurrentSession(context); var nomination = await db.Nominations.FirstOrDefaultAsync(item => item.Id == nominationId); if (nomination is null) { return Results.NotFound(); } nomination.CandidateId = null; nomination.Status = "rejected"; nomination.ReviewNote = string.IsNullOrWhiteSpace(request.ReviewNote) ? null : request.ReviewNote.Trim(); nomination.ReviewedAt = DateTimeOffset.UtcNow; nomination.ReviewedByTwitchId = session.TwitchUserId; adminAuditService.AddEntry( session.TwitchUserId, "nomination.reject", "nomination", nomination.Id.ToString(), $"Nominierung {nomination.Id} wurde verworfen.", new { nomination.ReviewNote }, RequestMetadataReader.Read(context)); await db.SaveChangesAsync(context.RequestAborted); return Results.Ok(new { saved = true, nominationId = nomination.Id, rejected = true }); } }