import { submitDomainForReview } from "../../../db/domains"; import { getProfile } from "../../../db/profile"; import { getPlanLimits } from "../../../utils/plan-features"; import { usePrisma } from "../../../utils/prisma"; export default defineEventHandler(async (event) => { const user = await requireUser(event); const id = getRouterParam(event, "id"); if (!id) throw createError({ statusCode: 400, message: "ID fehlt" }); // Only Pro/Legend can submit const profile = await getProfile(user.id); const plan = profile?.plan ?? "free"; const limits = getPlanLimits(plan); if (!limits.domainRefill) { throw createError({ statusCode: 403, message: "Nur Pro-User können Domains einreichen", }); } const db = usePrisma(); // Verify ownership + status const existing = await db.userCustomDomain.findFirst({ where: { id, userId: user.id }, select: { id: true, domain: true, status: true, type: true }, }); if (!existing) throw createError({ statusCode: 404, message: "Domain nicht gefunden" }); if (existing.status !== "active" && existing.status !== "rejected") { throw createError({ statusCode: 409, message: "Domain wurde bereits eingereicht oder genehmigt", }); } // v1.0: Display-Name-Patterns sind nicht submittable (keine BlocklistDomain-Erweiterung vor TestFlight) if (existing.type === "mail_display_name") { throw createError({ statusCode: 400, data: { error: "DISPLAY_NAME_NOT_SUBMITTABLE", message: "Display-name patterns cannot be submitted to the global blocklist in v1.0. Use them as user-private filters only.", }, }); } // Tier-Routing: // - Pro: Community-Post mit Voting-Flow erstellen // - Legend: KEIN Post — Domain/Pattern landet direkt in der Admin-Queue // // Für mail_display_name: domain-Feld enthält das Pattern-String (kein PII). // Admin-Review erkennt type via customDomain.type-Feld. let postId: string | null = null; if (plan === "pro") { // Community-Vote-Post-Text variiert je nach Type let postContent: string; if (existing.type === "mail_domain") { postContent = `Domain-Vorschlag (Mail-Absender): **${existing.domain}**\n\nIch schlage vor, diese Absender-Domain zur globalen ReBreak-Sperrliste hinzuzufügen. Casino-Affiliates nutzen oft Mailing-Listen mit harmlosen Namen. Stimme ab: Sollte **${existing.domain}** global gesperrt werden?`; } else { // type === "web" (mail_display_name ist durch Guard oben schon blockiert) postContent = `Domain-Vorschlag: **${existing.domain}**\n\nIch schlage vor, diese Domain zur globalen ReBreak-Sperrliste hinzuzufügen. Stimme ab: Sollte **${existing.domain}** global gesperrt werden?`; } const post = await db.communityPost.create({ data: { userId: user.id, category: "domain_vote", content: postContent, }, select: { id: true }, }); postId = post.id; } const { submission } = await submitDomainForReview( user.id, id, plan as "free" | "pro" | "legend", postId ?? undefined, ); return { ok: true, postId, submissionId: submission.id, domain: existing.domain, type: existing.type, route: plan === "legend" ? "admin_direct" : "community_vote", }; });