Bewerbungen als echte Tickets bei Ticketanizer anlegen (statt Discord-Webhook)

Umgestellt von der ursprünglichen Discord-Webhook-Idee auf die offizielle
Ticketanizer-Inbound-Ticket-API (api.ticketanizer.com/v1/tickets) - erzeugt
echte Tickets statt nur Nachrichten, landen dadurch direkt im richtigen
Ticketanizer-Bereich in Discord.

- Neu: cloudflare-worker/src/lib/ticketanizer.js. panel_id pro Bewerbungs-
  bereich fest hinterlegt (aus dem Ticketanizer-Dashboard abgelesen):
  Modi=4, Kooperation=5, Scout=6, Creator=7 (dort "Manager-Bewerbung")
- Alte discord.js entfernt (Ansatz verworfen)
- applications.js: Aufruf entsprechend umbenannt/angepasst
- README.md: Einrichtungsanleitung aktualisiert (TICKETANIZER_API_KEY
  statt 4x DISCORD_WEBHOOK_*)
- Ticketanizer bleibt rein informativ, kein Ausfallpunkt - Bewerbung wird
  immer in der eigenen Datenbank gespeichert, unabhängig vom Ticket-Erfolg
- Secret TICKETANIZER_API_KEY bereits live gesetzt und deployed; End-to-
  End mit 3 Test-Bewerbungen geprüft (HTTP Ok geloggt), Testeinträge aus
  der DB wieder entfernt
This commit is contained in:
2026-08-01 12:56:15 +02:00
parent 992e3de446
commit 7b7fcd829b
4 changed files with 140 additions and 138 deletions
+95
View File
@@ -0,0 +1,95 @@
/* =====================================================================
lib/ticketanizer.js — Bewerbungen als echtes Ticket bei Ticketanizer
eröffnen (dort in Discord sichtbar, pro Bewerbungsbereich ein eigenes
Panel/Board).
API-Doku (aus dem Ticketanizer-Dashboard, "API & Webhooks" → "API-Keys" →
"So nutzt du sie"):
Basis-URL: https://api.ticketanizer.com
POST /v1/tickets
Header: X-API-Key, Content-Type: application/json
Body: { panel_id, visitor_name, first_message }
Wir nutzen hier bewusst NUR den ersten Schritt (Ticket eröffnen) — es
ist eine einmalige Bewerbung, kein Live-Chat, deshalb kein Nachladen
von Staff-Antworten nötig (das würde einen dauerhaft laufenden Prozess
brauchen, den ein Cloudflare Worker so nicht hat).
panel_id pro Bewerbungsbereich (aus dem Ticketanizer-Dashboard →
"Panels", von Dogi am 2026-08-01 abgelesen):
4 = Modi-Bewerbung
5 = Kooperationsbewerbung
6 = Scout-Bewerbung
7 = Manager-Bewerbung (= unsere "Creator"-Bewerbung: Streamer sucht
einen Manager bei Spicy Media)
Rein informativ, kein Ausfallpunkt: Fehlt der API-Key, oder schlägt der
Versand fehl (Ticketanizer down, falscher Key, ...), wird die Bewerbung
trotzdem ganz normal in der eigenen Datenbank gespeichert.
===================================================================== */
const TICKETANIZER_BASIS_URL = "https://api.ticketanizer.com";
const PANEL_IDS = {
modi: 4,
kooperation: 5,
scout: 6,
creator: 7, // "Manager-Bewerbung" bei Ticketanizer
};
// Menschlich lesbare Feldbeschriftungen für alle Formularfelder, die aktuell
// auf der Website vorkommen (siehe bewerben-*.html, jeweils name="...").
// Unbekannte Feldnamen (z.B. nach künftigen Formular-Änderungen) werden
// einfach unverändert als Beschriftung übernommen statt zu fehlen.
const FIELD_LABELS = {
name: "Name",
email: "E-Mail",
kontakt: "Kontakt (Discord/TikTok)",
erfahrung: "Erfahrung",
verfuegbarkeit: "Verfügbarkeit",
warum: "Warum möchtest du dabei sein?",
platform: "Plattform",
content: "Content-Art",
firma: "Firma / Projekt",
idee: "Idee / Anliegen",
};
function ersteNachrichtAufbauen(type, data) {
const zeilen = Object.entries(data || {})
.filter(([, v]) => String(v ?? "").trim() !== "")
.map(([key, value]) => `**${FIELD_LABELS[key] || key}:** ${String(value).trim()}`);
if (!zeilen.length) zeilen.push("_Keine weiteren Angaben übermittelt._");
// Ticketanizer-Nachrichten sind vermutlich nicht beliebig lang — sicherheitshalber
// deckeln, damit ein sehr langer Freitext (z.B. "warum") den Versand nicht sprengt.
const text = zeilen.join("\n");
return text.length > 3500 ? text.slice(0, 3500) + "…" : text;
}
export async function bewerbungAlsTicketAnlegen(env, type, data) {
const apiKey = env.TICKETANIZER_API_KEY;
const panelId = PANEL_IDS[type];
if (!apiKey || !panelId) return; // nicht eingerichtet für diesen Bereich — einfach überspringen
const visitorName = String(data?.name || data?.firma || "Unbekannt").trim().slice(0, 80) || "Unbekannt";
const firstMessage = ersteNachrichtAufbauen(type, data);
try {
await fetch(`${TICKETANIZER_BASIS_URL}/v1/tickets`, {
method: "POST",
headers: {
"X-API-Key": apiKey,
"Content-Type": "application/json",
},
body: JSON.stringify({
panel_id: panelId,
visitor_name: visitorName,
first_message: firstMessage,
}),
});
} catch {
// Ticketanizer nicht erreichbar o.ä. — die Bewerbung selbst ist trotzdem
// sicher in der eigenen Datenbank gelandet, das darf hier nicht scheitern.
}
}