Kampagnen: auswaehlen, wo die Kachel hingehoert -- TikTok oder Agentur
Filipe, mit einem Bild des Einlesekastens: "das sind die von der agentur selbst. die krieg ich so, perfektioniere das und auch das ich auswaehlen kann wo es hingehoert, zu tiktok oder der agentur." Dazu sein echter Link: https://vm.tiktok.com/ZSbACwAnK/ ZWEI FRAGEN, DIE BISHER EINE WAREN. "Woher kam der Link" und "wem gehoert das Event" wurden beide aus `kampagne_id` beantwortet: Wer ueber eine Einladung eingelesen wurde, stand links. Die Agentur schickt ihre eigenen Events aber ebenfalls als TikTok-Link -- damit war die Zuordnung zwangslaeufig falsch. Neue Spalte `kampagne_seite` mit DREI Zustaenden, und NULL ist einer davon: niemand hat gewaehlt -> wie bisher nach der Herkunft. Alle bestehenden Kacheln behalten dadurch genau ihren Platz, ohne dass etwas umgestellt werden musste. Gewaehlt wird im Einlesekasten (Automatisch / TikTok / Agentur, "Automatisch" vorbelegt) und nachtraeglich an der Kachel ("zur Agentur" / "zu TikTok"). Nur die Leitung; bei einem Creator wird das Feld stillschweigend entfernt. GEMESSEN AN SEINEM ECHTEN LINK, mit Gegenprobe: vm.tiktok.com/ZSbACwAnK/ -> www.tiktok.com/tcn/activity?activity_id=7691301069758087175 -> 233 KB reine Huelle, kein __MODERN_ROUTER_DATA__ dieselbe Nummer auf dem Weg der oeffentlichen Kampagnenseite -> 42 KB, ebenfalls ohne Datenpaket eine echte Kampagne auf demselben Weg -> 967 KB MIT Datenpaket Die Kampagne existiert also nicht als oeffentliche Seite: Das Creator Network baut seine Seiten erst im Browser auf, angemeldet. Von aussen kann das niemand lesen -- auch kein anderes Programm. Daraus zwei Dinge: - `nummerAusAdresse` liest jetzt BEIDE Schreibweisen (`activityId` auf der Kampagnenseite, `activity_id` im Creator Network). - `istCreatorNetwork` erkennt solche Links VOR dem Abruf. Statt 502 "TikTok hat nicht geantwortet" (eine Ursache, die es nicht gibt) kommt 422 mit dem, was wirklich los ist -- und mit dem Weg daneben: das Event von Hand anlegen, Link in die Beschreibung. BERICHTIGT: Der PATCH-Weg stand als '/workspace/api/bereich/agentur/' + e.id im Browser und war fuer pruef-struktur nicht mehr zuzuordnen -- jetzt `${bereich}` wie bei den Nachbarn, was nebenbei den zweiten Ort mit "agentur" im Text wegnimmt. Und "Automatisch" hatte keinen eigenen Ton und fiel auf `--akzent` zurueck: auf dem Agenturbrett genau das Gelb der rechten Spalte, die vorbelegte Moeglichkeit sah also aus wie "Agentur". GEPRUEFT: 169 (Route, +22), 170 (Kachel, +12), 67 (Agentur), 67 Messungen (Bild), 107 (Haus-Trennung, unveraendert), dazu struktur, css-klassen, zeichen, deutsche-texte, formulare, tippziele. Drei Gegenproben: Auswahl verwerfen, Creator-Network durchlassen, Kachel wieder nur nach Herkunft -- alle drei werden bemerkt, alle Dateien byte-gleich wiederhergestellt. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -149,11 +149,22 @@ const ID_GIPFEL = "7691493175936699143";
|
||||
const ID_BEENDET = "7657456323453405959";
|
||||
const ID_OHNEPREISE = "7670899782609996552";
|
||||
const ID_TEXTBANNER = "7600000000000000001";
|
||||
/* Die vierte gespeicherte Seite -- bis zum 07.10.2026 benutzte sie
|
||||
nur pruef-kampagne-lesen.mjs. Hier wird sie gebraucht, weil die
|
||||
Seitenwahl eine Kampagne braucht, die es noch NICHT gibt: Bei
|
||||
einer schon eingelesenen kaeme „schon da", und dann entstuende
|
||||
gar keine neue Kachel, an der sich etwas messen liesse. */
|
||||
const ID_GLOWUP = "7690927903777262344";
|
||||
/* Die Nummer aus Filipes echtem Agenturlink -- sie steht hier,
|
||||
damit die Pruefung dieselbe Form misst, die wirklich ankommt
|
||||
(snake_case `activity_id`, nicht `activityId`). */
|
||||
const ID_TCN = "7691301069758087175";
|
||||
|
||||
const SEITEN = {
|
||||
[ID_GIPFEL]: bannerHierher(seiteLesen("kampagne-gipfelstuermer.html.br")),
|
||||
[ID_BEENDET]: bannerHierher(seiteLesen("kampagne-beendet.html.br")),
|
||||
[ID_OHNEPREISE]: bannerHierher(seiteLesen("kampagne-ohne-preise.html.br")),
|
||||
[ID_GLOWUP]: bannerHierher(seiteLesen("kampagne-aufgabengruppe.html.br")),
|
||||
};
|
||||
const ROH_GIPFEL = seiteLesen("kampagne-gipfelstuermer.html.br");
|
||||
const SEITE_KAPUTT = seiteLesen("kampagne-kaputt.html");
|
||||
@@ -207,7 +218,21 @@ const tikDienst = createServer((anfrage, antwort) => {
|
||||
if (u.pathname === "/t/gipfel-zweiter-versand") return leite(`/falcon/home?activityId=${ID_GIPFEL}&campaign_traffic_id=2`);
|
||||
if (u.pathname === "/t/beendet") return leite(`/falcon/home?activityId=${ID_BEENDET}`);
|
||||
if (u.pathname === "/t/ohnepreise") return leite(`/falcon/home?activityId=${ID_OHNEPREISE}`);
|
||||
if (u.pathname === "/t/glowup") return leite(`/falcon/home?activityId=${ID_GLOWUP}`);
|
||||
if (u.pathname === "/t/textbanner") return leite(`/falcon/home?activityId=${ID_TEXTBANNER}`);
|
||||
/* DAS CREATOR NETWORK (07.10.2026). Nachgemessen am echten
|
||||
Agenturlink von Filipe: `vm.tiktok.com/ZSbACwAnK/` leitet auf
|
||||
`www.tiktok.com/tcn/activity?activity_id=...` -- eine Seite,
|
||||
die TikTok erst im Browser aufbaut, angemeldet. Von aussen
|
||||
steht dort nichts.
|
||||
|
||||
Der Weg wird hier nachgebaut, damit die Pruefung nicht das
|
||||
echte TikTok braucht: Sie misst dann fremde Verfuegbarkeit
|
||||
statt unseren Code. Die ANTWORT auf diesen Weg ist
|
||||
absichtlich eine leere Huelle -- genau wie draussen. */
|
||||
if (u.pathname === "/t/agentur") {
|
||||
return leite(`/tcn/activity?activity_id=${ID_TCN}&activity_type=ranklist`);
|
||||
}
|
||||
if (u.pathname === "/t/fremd") return leite("https://beispiel.de/ganz-woanders");
|
||||
if (u.pathname === "/t/kreis") return leite("/t/kreis");
|
||||
if (u.pathname === "/t/kaputt") return leite("/falcon/kaputt");
|
||||
@@ -819,6 +844,132 @@ melde("=== 9. Was schiefgehen kann, wird verständlich gesagt ===");
|
||||
"und die Kachel selbst sagt, dass etwas nachzutragen ist");
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
9b. DER AGENTURLINK — UND WOHIN DIE KACHEL GEHÖRT (07.10.2026)
|
||||
|
||||
Filipe: „das sind die von der agentur selbst. die krieg ich so,
|
||||
perfektioniere das und auch das ich auswählen kann wo es
|
||||
hingehört, zu tiktok oder der agentur.“
|
||||
===================================================================== */
|
||||
melde("");
|
||||
melde("=== 9b. Agenturlink und Seitenwahl ===");
|
||||
|
||||
{
|
||||
/* AUS DEM ECHTEN MODUL, nicht nachgebaut: Geprüft wird die
|
||||
Funktion, die im Betrieb läuft. Eine Abschrift hier wäre eine
|
||||
zweite Fassung derselben Regel -- und die läuft auseinander. */
|
||||
const { nummerAusAdresse, istCreatorNetwork } = await import("./workspace-kampagne.js");
|
||||
/* ---- Die Nummer in BEIDEN Schreibweisen ------------------- */
|
||||
ok(nummerAusAdresse(`${TIK}/falcon/home?activityId=${ID_GIPFEL}`) === ID_GIPFEL,
|
||||
"activityId wird gelesen (die Kampagnenseite)");
|
||||
ok(nummerAusAdresse(`${TIK}/tcn/activity?activity_id=${ID_TCN}`) === ID_TCN,
|
||||
"activity_id ebenso (das Creator Network)");
|
||||
/* GEGENPROBE: Etwas, das keine Nummer ist, gibt auch keine --
|
||||
sonst wäre „beide Schreibweisen“ auch bei einer Funktion
|
||||
grün, die immer irgendetwas zurückgibt. */
|
||||
ok(nummerAusAdresse(`${TIK}/tcn/activity?activity_id=hallo`) === null,
|
||||
" und Buchstaben sind keine Nummer");
|
||||
ok(nummerAusAdresse(`${TIK}/tcn/activity`) === null,
|
||||
" und ohne Angabe kommt nichts");
|
||||
|
||||
/* ---- Die Erkennung selbst, mit beiden Richtungen ---------- */
|
||||
ok(istCreatorNetwork(`${TIK}/tcn/activity?activity_id=${ID_TCN}`),
|
||||
"eine /tcn/-Adresse wird als Creator Network erkannt");
|
||||
/* GEGENPROBE: Die echte Kampagnenseite NICHT -- sonst wäre jede
|
||||
Einladung ein Agenturlink und nichts ließe sich mehr einlesen. */
|
||||
ok(!istCreatorNetwork(`${TIK}/falcon/campaign/fusion_cosmic_runtime/home?activityId=${ID_GIPFEL}`),
|
||||
" die echte Kampagnenseite dagegen nicht");
|
||||
ok(!istCreatorNetwork(`${TIK}/tcnx/activity`),
|
||||
" und ein Pfad, der nur so anfängt, auch nicht");
|
||||
|
||||
/* ---- Der Agenturlink wird ERKANNT, nicht blind geholt ----- */
|
||||
const vorher = abrufe;
|
||||
const tcn = await einlesen(`Hier die Einladung: ${TIK}/t/agentur`);
|
||||
ok(tcn.code === 422,
|
||||
`ein Creator-Network-Link gibt 422, nicht 502 (HTTP ${tcn.code})`);
|
||||
ok(/Creator Network/.test(tcn.j.fehler || ""),
|
||||
`und sagt, was für eine Seite das ist: „${tcn.j.fehler}“`);
|
||||
/* DIE MELDUNG SAGT, WAS ZU TUN IST. Eine Ursache ohne Ausweg
|
||||
lässt den Menschen davor stehen. */
|
||||
ok(/von Hand/.test(tcn.j.fehler || ""),
|
||||
" und was man stattdessen tun kann");
|
||||
/* UND DIE SEITE WIRD GAR NICHT ERST GEHOLT. 233 KB für eine
|
||||
Hülle, von der wir schon wissen, dass nichts drinsteht --
|
||||
und danach eine falsche Ursache melden. Gezählt werden die
|
||||
Abrufe beim nachgebauten Dienst: die Weiterleitung ja, die
|
||||
Seite selbst nicht. */
|
||||
const geholt = abrufe - vorher;
|
||||
ok(geholt <= 2,
|
||||
`nur der Weg wurde verfolgt, die Hülle nicht geholt (${geholt} Abrufe)`);
|
||||
|
||||
/* ---- DIE SEITENWAHL BEIM EINLESEN ------------------------- */
|
||||
const mitSeite = await roh("/workspace/api/kampagne/einlesen", {
|
||||
methode: "POST", keks: keksDogi, wirt: HOST,
|
||||
rumpf: { text: `Klick: ${TIK}/t/glowup`, seite: "agentur" },
|
||||
});
|
||||
const neuId = JSON.parse(mitSeite.text || "{}").id;
|
||||
ok(mitSeite.code === 201 && Number.isInteger(neuId),
|
||||
`eine Kampagne mit Seitenwahl entsteht (HTTP ${mitSeite.code}, #${neuId})`);
|
||||
const gz = dbLesen("SELECT kampagne_id, kampagne_seite FROM eintraege WHERE id = ?", neuId)[0];
|
||||
ok(gz?.kampagne_seite === "agentur",
|
||||
`und steht auf der gewählten Seite: ${JSON.stringify(gz?.kampagne_seite)}`);
|
||||
/* GEGENPROBE: Sie kommt trotzdem von TikTok -- die Herkunft wird
|
||||
nicht verfälscht, nur die Zuordnung gewählt. Das ist der
|
||||
ganze Unterschied zwischen beiden Angaben. */
|
||||
ok(gz?.kampagne_id === ID_GLOWUP,
|
||||
`die Herkunft bleibt unberührt (${gz?.kampagne_id})`);
|
||||
|
||||
/* OHNE WAHL BLEIBT ES NULL -- „niemand hat gewählt“ ist etwas
|
||||
anderes als „links“. Die zuerst eingelesene Kachel hatte keine
|
||||
Wahl dabei. */
|
||||
const alt = dbLesen("SELECT kampagne_seite FROM eintraege WHERE id = ?", kachelId)[0];
|
||||
ok(alt?.kampagne_seite === null,
|
||||
`ohne Wahl bleibt die Seite offen (${JSON.stringify(alt?.kampagne_seite)})`);
|
||||
|
||||
/* Ein erfundener Wert wird NICHT stillschweigend übernommen. */
|
||||
const quatsch = await roh(`/workspace/api/bereich/agentur/${kachelId}`, {
|
||||
methode: "PATCH", keks: keksDogi, wirt: HOST,
|
||||
rumpf: { kampagne_seite: "mond" },
|
||||
});
|
||||
ok(quatsch.code === 400,
|
||||
`ein erfundener Wert wird abgelehnt (HTTP ${quatsch.code})`);
|
||||
const unberuehrt = dbLesen("SELECT kampagne_seite FROM eintraege WHERE id = ?", kachelId)[0];
|
||||
ok(unberuehrt?.kampagne_seite === null,
|
||||
" und die Kachel bleibt, wie sie war");
|
||||
|
||||
/* ---- NACHTRÄGLICH VERSCHIEBEN ----------------------------- */
|
||||
const schieben = await roh(`/workspace/api/bereich/agentur/${kachelId}`, {
|
||||
methode: "PATCH", keks: keksDogi, wirt: HOST,
|
||||
rumpf: { kampagne_seite: "agentur" },
|
||||
});
|
||||
ok(schieben.code === 200, `die Seite lässt sich ändern (HTTP ${schieben.code})`);
|
||||
const nachher = dbLesen("SELECT kampagne_seite FROM eintraege WHERE id = ?", kachelId)[0];
|
||||
ok(nachher?.kampagne_seite === "agentur",
|
||||
`und steht jetzt rechts (${nachher?.kampagne_seite})`);
|
||||
|
||||
/* ZURÜCKNEHMEN GEHT AUCH. Eine Wahl ohne Weg zurück ist beim
|
||||
ersten Versehen ein Dauerzustand. */
|
||||
const zurueck = await roh(`/workspace/api/bereich/agentur/${kachelId}`, {
|
||||
methode: "PATCH", keks: keksDogi, wirt: HOST,
|
||||
rumpf: { kampagne_seite: "" },
|
||||
});
|
||||
const offen = dbLesen("SELECT kampagne_seite FROM eintraege WHERE id = ?", kachelId)[0];
|
||||
ok(zurueck.code === 200 && offen?.kampagne_seite === null,
|
||||
`und wieder auf automatisch (${JSON.stringify(offen?.kampagne_seite)})`);
|
||||
|
||||
/* ---- EIN CREATOR DARF DAS NICHT --------------------------- */
|
||||
/* Wo eine Kachel steht, ist eine Entscheidung über das Brett,
|
||||
nicht über den eigenen Eintrag. */
|
||||
const alsCreator = await roh(`/workspace/api/bereich/agentur/${kachelId}`, {
|
||||
methode: "PATCH", keks: keksLuna, wirt: HOST,
|
||||
rumpf: { kampagne_seite: "tiktok" },
|
||||
});
|
||||
const danach = dbLesen("SELECT kampagne_seite FROM eintraege WHERE id = ?", kachelId)[0];
|
||||
ok(danach?.kampagne_seite === null,
|
||||
`ein Creator verschiebt nichts (HTTP ${alsCreator.code}, `
|
||||
+ `Seite ${JSON.stringify(danach?.kampagne_seite)})`);
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
10. EIN STUMMER SERVER HÄNGT DIE ROUTE NICHT AUF
|
||||
===================================================================== */
|
||||
|
||||
Reference in New Issue
Block a user