18b61bed52
- Widen AdminCandidateEditorModal to size lg for better readability - Rename "Clip-Compilation" section to "Clip / Compilation", update copy to reflect single clips too, drop upload hint and Clip-Plattform field, rename label to "Link" - Fix NativeSelect dropdown clipping inside overflow-y-auto modals by teleporting the menu to body with fixed positioning, flip-up logic, and dynamic maxHeight capped to viewport - Add ClipAdminMenuVisible setting (backend domain, contracts, endpoint, migration) with matching frontend types, defaults, form wiring, and toggle in the Clip-Workflow modal — hides the Clips nav item from the admin sidebar when disabled Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
132 lines
5.0 KiB
C#
132 lines
5.0 KiB
C#
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<IResult> 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<IResult> 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));
|
|
}
|