using Backend.Common; using Backend.Contracts; using Backend.Data; using Backend.Domain; using Microsoft.EntityFrameworkCore; namespace Backend.Endpoints; public static partial class PublicEndpoints { private static async Task GetSponsors(int year, AwardsDbContext db) { var season = await db.Seasons .AsNoTracking() .FirstOrDefaultAsync(item => item.Year == year); if (season is null) { return Results.NotFound(); } var settings = await db.SiteSettings.AsNoTracking().FirstOrDefaultAsync(item => item.Id == 1); if (settings is null || !settings.SponsorsVisible) { return Results.Ok(new PublicSponsorsResponse(year, [])); } var sponsors = await db.Sponsors .AsNoTracking() .Where(item => item.SeasonId == season.Id && item.IsVisible) .OrderBy(item => item.SortOrder) .ThenBy(item => item.Name) .Select(item => new SponsorDto( item.Id, item.SeasonId, item.Name, item.WebsiteUrl, item.LogoUrl, item.Description, item.Tier, item.SortOrder, item.IsVisible)) .ToArrayAsync(); return Results.Ok(new PublicSponsorsResponse(year, sponsors)); } private static async Task CreateShowactApplication( HttpContext context, CreateShowactApplicationRequest request, AwardsDbContext db) { var settings = await db.SiteSettings.AsNoTracking().FirstOrDefaultAsync(item => item.Id == 1, context.RequestAborted); if (settings is null || !settings.ShowactApplicationsEnabled) { return Results.BadRequest(new { message = string.IsNullOrWhiteSpace(settings?.ShowactApplicationDisabledMessage) ? "Showact-Bewerbungen sind aktuell geschlossen." : settings.ShowactApplicationDisabledMessage, }); } var season = await db.Seasons.FirstOrDefaultAsync(item => item.IsCurrent, context.RequestAborted); if (season is null) { return Results.NotFound(new { message = "Aktuell ist kein Award-Jahr aktiv." }); } var artistName = NormalizePublicText(request.ArtistName, 120); var contactEmail = NormalizePublicText(request.ContactEmail, 180); var contactDiscord = NormalizePublicText(request.ContactDiscord, 120); var performanceType = NormalizePublicText(request.PerformanceType, 80); var description = NormalizePublicText(request.Description, 1000); var platformUrl = NormalizePublicText(request.PlatformUrl, 500); var referenceUrl = NormalizePublicText(request.ReferenceUrl, 500); if (string.IsNullOrWhiteSpace(artistName)) { return Results.BadRequest(new { message = "Kuenstlername ist erforderlich." }); } if (string.IsNullOrWhiteSpace(contactEmail) && string.IsNullOrWhiteSpace(contactDiscord)) { return Results.BadRequest(new { message = "Bitte gib mindestens E-Mail oder Discord als Kontakt an." }); } if (string.IsNullOrWhiteSpace(performanceType) || string.IsNullOrWhiteSpace(description)) { return Results.BadRequest(new { message = "Art des Showacts und Beschreibung sind erforderlich." }); } if (!IsBlankOrHttpUrl(platformUrl) || !IsBlankOrHttpUrl(referenceUrl)) { return Results.BadRequest(new { message = "Links muessen gueltige http(s)-URLs sein." }); } var metadata = RequestMetadataReader.Read(context); var application = new ShowactApplication { SeasonId = season.Id, ArtistName = artistName, ContactEmail = contactEmail, ContactDiscord = contactDiscord, PlatformUrl = platformUrl, PerformanceType = performanceType, Description = description, TechnicalNotes = NormalizePublicText(request.TechnicalNotes, 1000), ReferenceUrl = referenceUrl, Status = "pending", CreatedFromIp = metadata.ClientIp, UserAgent = metadata.UserAgent, CreatedAt = DateTimeOffset.UtcNow, }; db.ShowactApplications.Add(application); await db.SaveChangesAsync(context.RequestAborted); return Results.Ok(new { saved = true, applicationId = application.Id }); } private static string NormalizePublicText(string? value, int maxLength) { var trimmed = (value ?? string.Empty).Trim(); return trimmed.Length <= maxLength ? trimmed : trimmed[..maxLength]; } private static bool IsBlankOrHttpUrl(string value) => string.IsNullOrWhiteSpace(value) || (Uri.TryCreate(value, UriKind.Absolute, out var uri) && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)); }