Das Foyer: eine Seite vor dem Saal, mit Plan, Eintritt und Vorschlägen
Filipe: „diese kachel soll nicht mehr geschlossen sein, ABER wenn man
drauf drückt geht zuerst eine seite auf mit reihen/kategorien. links
eine reihe wo die nächsten geplanten videos schon bereit stehen. wan
und umd wie viel uhr … und das soll geschlossen sein außer für vanvan
und dogfather. in der mitte sollen die leute dan wenn eine sendung
läuft drauf drücken können und der sendung beitreten. auch bei der
vorschau schon und dan rechts will ich die letzte reihe/kategorie, da
sollen die leute alle mir videos anraten können … und nur ich und
vanvan sehen sie."
Haus: Team Dogi (crew.dogfather-universe.com). Die Agentur ist nicht
berührt -- pruef-haus-trennung 107/0, pruef-workspace-seiten 37/0.
WARUM EINE EIGENE SEITE UND KEIN VIERTER ZUSTAND DES SAALS
Der Saal meldet jeden an, der ihn öffnet („dabei"), baut Verbindungen
auf und hält den Ereignisstrom offen. Das ist richtig für jemanden,
der zusieht -- und falsch für jemanden, der nur nachsehen will, ob
heute Abend etwas läuft. Wäre das Foyer der vierte Zustand derselben
Seite, zählte jeder Blick als Zuschauer, und die Zahl im Regiepult
sähe nach Publikum aus, wo niemand zusieht.
Im Foyer wird nur gelesen: Stand holen, zeichnen, alle 20 Sekunden
nachfragen -- und nicht, solange der Reiter im Hintergrund liegt. Kein
Ereignisstrom: Der hielte eine Verbindung offen, und manche Browser
geben je Adresse nur sechs her; im Saal wird jede davon gebraucht.
DREI REIHEN
LINKS die Warteschlange, nach TERMIN sortiert statt nach Platz.
Was keinen hat, steht unten; was vorbei ist, bekommt
„· überfällig". Nur admin und rechte Hand -- und für alle
anderen steht sie gar nicht erst da, statt leer oder
gesperrt zu sein. Ein Kasten mit Schloss erzählt, dass es
etwas zu sehen gäbe. Entschieden wird das am Server; die
Seite fragt nicht nach der Rolle, sondern danach, ob die
Auskunft gekommen ist.
MITTE Lampe (Geschlossen / Gleich / Auf Sendung), Vorschaubild,
Titel, Satz -- und der Knopf, der NUR dasteht, wenn er auch
hineinführt. Er ist ein Link und kein Button: Wer ihn mit
der mittleren Maustaste antippt, bekommt einen neuen Reiter.
RECHTS Video anraten. Jeder darf schicken, niemand sieht fremde,
jeder sieht seine eigenen mit Stand. Vier Sperren, und jede
beantwortet etwas anderes: zu schnell (45 s), zu viele offen
(5 je Person), schon angeraten, steht schon bereit.
Am Telefon steht die MITTE oben. Dort ist „links" nur noch „vor allem
anderen", und das wäre die falsche Reihenfolge.
WAS SONST NOCH DAZUGEHÖRT
* Jede Zeile der Warteschlange im Saal hat jetzt ein Terminfeld.
* Die Kachel sagt nicht mehr „geschlossen" -- das Foyer ist immer
offen. „gleich" und „● live" bleiben: Sie sagen etwas, das man ohne
sie nicht weiß.
* reaktion.html steht in OHNE_KACHEL_UEBERALL. Die erlaubten Seiten
werden aus den Kachelzielen abgeleitet; als die Kachel aufs Foyer
zeigte, war der Saal plötzlich von keiner mehr genannt und
antwortete mit einer Umleitung.
DREI DOPPELTE ANTWORTEN BESEITIGT
* „Wie viele Vorschläge darf einer offen haben" stand VIERMAL:
dreimal als `je_person_max || 5` und einmal als Wort „fünf" im Satz
(plus ein fünftes Mal in meldung.js). Kommt jetzt vom Server.
* `maxlength="200"` im Formular neben VORSCHLAG_NOTIZ_MAX im Server.
Das Feld lernt die Grenze von der Auskunft.
* Die drei Foyer-Tafeln hatten eine eigene Fläche (Weiß mit 4,5 %) und
eine eigene Form. Beides gibt es im Haus längst: Material in
start.css (45 Klassen, gemessen), Form in module.css. Die eigene
Fläche war dazu fast durchsichtig -- über einem hellen
Hintergrundbild stand der Text ohne deckenden Grund. Gefunden hat
das nicht eine Prüfung, sondern das Bildschirmfoto.
EINE LÜCKE IN DER PRÜFUNG GESCHLOSSEN
In module.css steht dieselbe 48er-Klassenliste ACHTMAL. Sieben trugen
die Marke MODULLISTE und wurden verglichen; die achte -- die Umrandung
beim Tabben (:focus-visible) -- nicht. Sie war damit die Einzige, die
still hätte abweichen können, ausgerechnet bei der Regel, die nur
sieht, wer mit der Tastatur bedient. pruef-css-klassen erwartet jetzt
acht. Eine steigende Prüfzahl, und sie ist begründet.
UND EINER, DEN KEIN WERKZEUG FINDEN KANN
Der Satz oben lautete „Links steht, was ansteht; rechts kannst du
etwas anraten." Für die Community gibt es „links" gar nicht, und am
Telefon stehen die Reihen untereinander. Eine Richtung im Text ist
eine Aussage über das Aussehen -- und das ändert sich mit dem
Bildschirm und mit der Rolle. Jetzt steht dort, WAS geht, nicht WO.
GEMESSEN
mess-foyer (neu) 70 Messungen, 0 Fehler, 9 Bildschirmfotos
pruef-reaktion 538, 0 Fehler (vorher 478)
pruef-handy-teamdogi 263 Seitenaufrufe, 0 Befunde (vorher 244)
pruef-sackgassen 14, 0 Fehler
pruef-crew-adresse 173, 0 Fehler
pruef-haus-trennung 107, 0 Fehler
pruef-struktur 102, 0 Fehler
pruef-neue-seiten 109, 0 Fehler
pruef-portnummern 41, 0 Fehler
pruef-haus-seiten 38, 0 Fehler
pruef-workspace-seiten 37, 0 Fehler
pruef-breiten 45 Seiten auf fünf Breiten, 0 beanstandet
pruef-community-sicht 10, 0 Fehler
pruef-deutsche-texte 12, 0 Fehler
pruef-css-klassen grün
mess-foyer klickt den ganzen Weg durch: Ein Gast schickt ein Video,
DogFather sieht es mit Namen, nimmt es, und es muss links im Plan
stehen. Zum Schluss macht es sechs seiner Messungen absichtlich kaputt
und prüft, dass sie das merken.
NICHT BEHOBEN, WEIL NICHT MEINS: pruef-meldungen ist rot (28
Kennungen ohne Satz, 3 Rohanzeigen) -- gemessen im worktree auf dem
letzten Commit schon vorher, Zeichen für Zeichen dieselbe Liste. Die
Dateien gehören überwiegend der Agentur; das gehört in einen eigenen
Durchgang.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -53,6 +53,7 @@ import { einstellung } from "./workspace.js";
|
||||
import { mitZugangsdaten, wegeAusfaechern } from "./workspace-turn.js";
|
||||
import {
|
||||
SICHT_PLAETZE, GAESTE_MAX, EINLADUNG_SEKUNDEN, TEXT_MAX, SCHREIB_BREMSE,
|
||||
VORSCHLAEGE_JE_PERSON, VORSCHLAG_NOTIZ_MAX, VORSCHLAG_BREMSE_SEKUNDEN,
|
||||
STAENDE, LAYOUTS, TEMPI,
|
||||
KAMERA_GROESSEN, KAMERA_ECKEN,
|
||||
MELDUNG_TAGE,
|
||||
@@ -287,10 +288,33 @@ async function videoTitel(kennung) {
|
||||
|
||||
/** Die Warteschlange, in ihrer Reihenfolge. */
|
||||
function listeHolen() {
|
||||
return db().prepare("SELECT id, video, titel, platz FROM reaktion_liste"
|
||||
return db().prepare("SELECT id, video, titel, platz, wann FROM reaktion_liste"
|
||||
+ " ORDER BY platz, id").all();
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
DER PLAN FUERS FOYER (08.10.2026)
|
||||
|
||||
Filipe: „links eine reihe wo die nächsten geplanten videos schon
|
||||
bereit stehen. wan und umd wie viel uhr."
|
||||
|
||||
ES IST DIESELBE LISTE -- nur anders sortiert: nach TERMIN statt
|
||||
nach Platz. Im Pult ist die Reihenfolge die Aussage („was kommt
|
||||
als Naechstes im Live"), im Foyer der Termin („Donnerstag um
|
||||
acht").
|
||||
|
||||
SORTIERT WIRD IM BROWSER UND NICHT HIER. Ein zweites Feld im
|
||||
Stand waere eine zweite Antwort auf dieselbe Frage -- dieselben
|
||||
Zeilen, zweimal uebertragen, und beim naechsten Umbau pflegt
|
||||
jemand nur eine der beiden Stellen. Was hinausgeht, ist `liste`
|
||||
mit `wann`; wie man sie anschaut, entscheidet die Seite.
|
||||
|
||||
VERGANGENES FAELLT NICHT WEG. Ein Termin von gestern, den niemand
|
||||
weggeraeumt hat, steht weiter da und ist damit sichtbar
|
||||
ueberfaellig. Ihn stillschweigend auszublenden hiesse, dass eine
|
||||
Vorbereitung verschwindet, ohne dass jemand etwas getan hat.
|
||||
====================================================================== */
|
||||
|
||||
/** Das naechste Video aus der Liste ins Bild holen.
|
||||
*
|
||||
* EINE STELLE FUER ZWEI KNOEPFE. „Naechstes" und „Jetzt spielen"
|
||||
@@ -1459,6 +1483,262 @@ reaktionRouter.delete("/workspace/api/reaktion/liste/:id", nurHost, (req, res) =
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- Wann ein vorbereitetes Video laufen soll ---------------------
|
||||
Filipe: „links eine reihe wo die nächsten geplanten videos schon
|
||||
bereit stehen. wan und umd wie viel uhr."
|
||||
|
||||
EIN EIGENER WEG UND KEIN FELD AM ANHAENGEN. Der Termin entsteht
|
||||
fast nie beim Einfuegen -- man raeumt erst ein und legt danach
|
||||
fest, wann es laufen soll. Ein Pflichtfeld beim Anhaengen haette
|
||||
aus dem schnellsten Handgriff des Pults („Adresse einfuegen,
|
||||
Enter") ein Formular gemacht.
|
||||
|
||||
DER WERT WIRD GEPRUEFT UND NICHT NUR GESPEICHERT. Was hier
|
||||
hereinkommt, steht spaeter als Datum im Foyer; ein freier Text
|
||||
ergaebe dort „Invalid Date" -- und das sieht aus, als sei die
|
||||
Seite kaputt, nicht die Eingabe. */
|
||||
reaktionRouter.put("/workspace/api/reaktion/liste/:id/wann", nurHost,
|
||||
express.json({ limit: "2kb" }), (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id) || 0;
|
||||
const roh = String(req.body?.wann ?? "").trim();
|
||||
let wann = "";
|
||||
if (roh) {
|
||||
const d = new Date(roh);
|
||||
if (Number.isNaN(d.getTime())) return res.status(400).json({ fehler: "termin_unklar" });
|
||||
wann = d.toISOString();
|
||||
}
|
||||
const a = db().prepare("UPDATE reaktion_liste SET wann = ? WHERE id = ?").run(wann, id);
|
||||
if (!a.changes) return res.status(404).json({ fehler: "nicht_in_der_liste" });
|
||||
|
||||
const l = lage(req.person);
|
||||
melden("reaktion", { was: "liste", lage: oeffentlich(l) });
|
||||
res.json(l);
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Termin:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/* =======================================================================
|
||||
DIE VORSCHLAEGE (08.10.2026)
|
||||
|
||||
Filipe: „da sollen die leute alle mir videos anraten können. also
|
||||
da können die leute videos reinschicken und nur ich und vanvan
|
||||
sehen sie."
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
WER WAS SIEHT -- UND WARUM DER EINSENDER SEINEN EIGENEN SIEHT
|
||||
|
||||
„Nur ich und vanvan sehen sie" heisst: Niemand sieht die
|
||||
Vorschlaege ANDERER. Dass jemand seinen eigenen zurueckbekommt,
|
||||
ist kein Widerspruch, sondern die Voraussetzung dafuer, dass er
|
||||
ueberhaupt einen schickt: Ein Formular, das nach dem Absenden
|
||||
nichts mehr zeigt, sieht aus wie ein Loch. Er sieht seine eigene
|
||||
Zeile mit dem Stand -- offen, uebernommen, abgelehnt -- und sonst
|
||||
nichts.
|
||||
|
||||
DER TITEL WIRD BEI YOUTUBE GEHOLT, nicht vom Einsender getippt.
|
||||
Sonst stuende im Pult ein Name, den jemand frei gewaehlt hat,
|
||||
neben einer Kennung, die etwas anderes ist -- und die Entscheidung
|
||||
fiele ueber den falschen Film.
|
||||
======================================================================= */
|
||||
|
||||
/** Eine Zeile, wie sie hinausgeht. */
|
||||
function alsVorschlag(z, fuerHost) {
|
||||
return {
|
||||
id: z.id,
|
||||
video: z.video,
|
||||
titel: z.titel || "",
|
||||
notiz: z.notiz || "",
|
||||
stand: z.stand,
|
||||
erstellt: z.erstellt,
|
||||
/* WER ES WAR, SIEHT NUR DIE LEITUNG. Fuer den Einsender steht
|
||||
dort ohnehin er selbst; den Namen mitzuschicken waere eine
|
||||
Auskunft ueber andere, sobald sich die Liste einmal aendert. */
|
||||
name: fuerHost ? (z.name || "") : undefined,
|
||||
mein: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
reaktionRouter.get("/workspace/api/reaktion/vorschlaege", (req, res) => {
|
||||
try {
|
||||
const istHost = HOST_ROLLEN.has(req.person.rolle);
|
||||
const reihen = istHost
|
||||
? db().prepare(`SELECT * FROM reaktion_vorschlaege
|
||||
ORDER BY (stand = 'offen') DESC, id DESC LIMIT 200`).all()
|
||||
: db().prepare(`SELECT * FROM reaktion_vorschlaege WHERE person_id = ?
|
||||
ORDER BY id DESC LIMIT 50`).all(req.person.id);
|
||||
res.json({
|
||||
vorschlaege: reihen.map((z) => alsVorschlag(z, istHost)),
|
||||
/* WIE VIELE NOCH OFFEN SIND -- die eine Zahl, die ins Register
|
||||
und an die Kachel gehoert. Sie wird hier gerechnet und nicht
|
||||
im Browser aus der Liste gezaehlt: Wer nur seine eigenen
|
||||
bekommt, zaehlte sonst seine eigenen. */
|
||||
offen: istHost
|
||||
? (db().prepare("SELECT COUNT(*) AS n FROM reaktion_vorschlaege"
|
||||
+ " WHERE stand = 'offen'").get()?.n || 0)
|
||||
: null,
|
||||
/* Was der Einsender wissen muss, um nicht gegen eine Wand zu
|
||||
laufen: wie viele er noch offen haben darf. */
|
||||
je_person_max: VORSCHLAEGE_JE_PERSON,
|
||||
notiz_max: VORSCHLAG_NOTIZ_MAX,
|
||||
darf_entscheiden: istHost,
|
||||
});
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Vorschlaege:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
reaktionRouter.post("/workspace/api/reaktion/vorschlag", express.json({ limit: "4kb" }),
|
||||
async (req, res) => {
|
||||
try {
|
||||
const video = videoKennung(String(req.body?.video ?? ""));
|
||||
if (!video) return res.status(400).json({ fehler: "video_unklar" });
|
||||
|
||||
/* ==== DREI SPERREN, UND JEDE BEANTWORTET ETWAS ANDERES ====
|
||||
(1) Zu schnell -- gegen den Doppelklick.
|
||||
(2) Zu viele offen -- gegen die Liste, die niemand mehr
|
||||
durchsieht.
|
||||
(3) Schon da -- gegen dreimal dieselbe Entscheidung. */
|
||||
const kurz = new Date(Date.now() - VORSCHLAG_BREMSE_SEKUNDEN * 1000).toISOString();
|
||||
const eben = db().prepare(`SELECT COUNT(*) AS n FROM reaktion_vorschlaege
|
||||
WHERE person_id = ? AND erstellt > ?`).get(req.person.id, kurz);
|
||||
if ((eben?.n || 0) >= 1) return res.status(429).json({ fehler: "zu_schnell" });
|
||||
|
||||
const meine = db().prepare(`SELECT COUNT(*) AS n FROM reaktion_vorschlaege
|
||||
WHERE person_id = ? AND stand = 'offen'`).get(req.person.id);
|
||||
if ((meine?.n || 0) >= VORSCHLAEGE_JE_PERSON) {
|
||||
return res.status(409).json({ fehler: "zu_viele_vorschlaege" });
|
||||
}
|
||||
|
||||
const schonOffen = db().prepare(`SELECT id FROM reaktion_vorschlaege
|
||||
WHERE video = ? AND stand = 'offen'`).get(video);
|
||||
if (schonOffen) return res.status(409).json({ fehler: "vorschlag_doppelt" });
|
||||
|
||||
/* Und was schon in der Warteschlange liegt, braucht niemand
|
||||
mehr anzuraten -- das waere eine Bitte um etwas, das bereits
|
||||
entschieden ist. */
|
||||
const inDerListe = db().prepare("SELECT id FROM reaktion_liste WHERE video = ?")
|
||||
.get(video);
|
||||
if (inDerListe) return res.status(409).json({ fehler: "steht_schon_bereit" });
|
||||
|
||||
const notiz = String(req.body?.notiz ?? "").trim().slice(0, VORSCHLAG_NOTIZ_MAX);
|
||||
const titel = await videoTitel(video);
|
||||
const { lastInsertRowid } = db().prepare(`INSERT INTO reaktion_vorschlaege
|
||||
(person_id, name, video, titel, notiz, stand, erstellt)
|
||||
VALUES (?,?,?,?,?,'offen',?)`)
|
||||
.run(req.person.id, req.person.name, video, titel, notiz, jetzt());
|
||||
|
||||
const z = db().prepare("SELECT * FROM reaktion_vorschlaege WHERE id = ?")
|
||||
.get(Number(lastInsertRowid));
|
||||
|
||||
/* NUR DIE ZWEI ERFAHREN ES. Ein Rundruf an den Saal haette
|
||||
genau das verraten, was niemand sehen soll. */
|
||||
stromAn(
|
||||
db().prepare("SELECT id FROM personen WHERE rolle IN ('admin','hand') AND aktiv = 1")
|
||||
.all().map((p) => p.id),
|
||||
"reaktion", { was: "vorschlag" },
|
||||
);
|
||||
res.status(201).json({ ok: true, vorschlag: alsVorschlag(z, false) });
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Vorschlag:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/** Einen Vorschlag uebernehmen -- er wandert in die Warteschlange. */
|
||||
reaktionRouter.post("/workspace/api/reaktion/vorschlag/:id(\\d+)/uebernehmen", nurHost,
|
||||
(req, res) => {
|
||||
try {
|
||||
const z = db().prepare("SELECT * FROM reaktion_vorschlaege WHERE id = ?")
|
||||
.get(Number(req.params.id));
|
||||
if (!z) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
if (z.stand !== "offen") return res.status(409).json({ fehler: "schon_entschieden" });
|
||||
|
||||
const wie_viele = db().prepare("SELECT COUNT(*) AS n FROM reaktion_liste").get()?.n || 0;
|
||||
if (wie_viele >= LISTE_MAX) return res.status(409).json({ fehler: "liste_voll" });
|
||||
const schon = db().prepare("SELECT id FROM reaktion_liste WHERE video = ?").get(z.video);
|
||||
if (schon) return res.status(409).json({ fehler: "liste_doppelt" });
|
||||
|
||||
/* EIN SCHREIBVORGANG. Bricht es zwischen den beiden
|
||||
Anweisungen ab, stuende der Vorschlag als „uebernommen" da,
|
||||
ohne dass etwas in der Schlange liegt -- und niemand wuerde
|
||||
es je bemerken. */
|
||||
const letzter = db().prepare("SELECT MAX(platz) AS p FROM reaktion_liste").get()?.p || 0;
|
||||
db().exec("BEGIN IMMEDIATE");
|
||||
try {
|
||||
db().prepare("INSERT INTO reaktion_liste (video, titel, platz, von_id, gesetzt_am)"
|
||||
+ " VALUES (?,?,?,?,?)")
|
||||
.run(z.video, z.titel, letzter + 1, req.person.id, jetzt());
|
||||
db().prepare(`UPDATE reaktion_vorschlaege SET stand = 'uebernommen',
|
||||
erledigt_am = ?, erledigt_von = ? WHERE id = ?`)
|
||||
.run(jetzt(), req.person.id, z.id);
|
||||
db().exec("COMMIT");
|
||||
} catch (f) { db().exec("ROLLBACK"); throw f; }
|
||||
|
||||
protokolliere("reaktion_vorschlag", {
|
||||
personId: req.person.id,
|
||||
detail: `uebernommen: ${z.titel || z.video} (von ${z.name || "?"})`,
|
||||
ip: echteIp(req),
|
||||
});
|
||||
/* DER EINSENDER ERFAEHRT ES. Ohne diese Zeile stuende sein
|
||||
Vorschlag bei ihm bis zum naechsten Laden auf „offen" --
|
||||
und die schoenste Nachricht des Abends kaeme nie an. */
|
||||
if (z.person_id) stromAn([z.person_id], "reaktion", { was: "vorschlag" });
|
||||
|
||||
const l = lage(req.person);
|
||||
melden("reaktion", { was: "liste", lage: oeffentlich(l) });
|
||||
res.json(l);
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Vorschlag uebernehmen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
reaktionRouter.post("/workspace/api/reaktion/vorschlag/:id(\\d+)/ablehnen", nurHost,
|
||||
(req, res) => {
|
||||
try {
|
||||
const a = db().prepare(`UPDATE reaktion_vorschlaege SET stand = 'abgelehnt',
|
||||
erledigt_am = ?, erledigt_von = ? WHERE id = ? AND stand = 'offen'`)
|
||||
.run(jetzt(), req.person.id, Number(req.params.id));
|
||||
if (!a.changes) return res.status(409).json({ fehler: "schon_entschieden" });
|
||||
const z = db().prepare("SELECT person_id FROM reaktion_vorschlaege WHERE id = ?")
|
||||
.get(Number(req.params.id));
|
||||
if (z?.person_id) stromAn([z.person_id], "reaktion", { was: "vorschlag" });
|
||||
res.json({ ok: true });
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Vorschlag ablehnen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/** Wegnehmen: der Einsender seinen eigenen OFFENEN, die Leitung jeden.
|
||||
*
|
||||
* ==== WARUM DER EINSENDER NUR DEN OFFENEN ZURUECKZIEHEN DARF
|
||||
*
|
||||
* Was entschieden ist, ist Geschichte -- und zwar auch fuer ihn.
|
||||
* Koennte er einen abgelehnten loeschen, verschwaende damit die
|
||||
* Spur, dass ueberhaupt etwas entschieden wurde; der naechste
|
||||
* Vorschlag desselben Videos saehe dann aus wie der erste. */
|
||||
reaktionRouter.delete("/workspace/api/reaktion/vorschlag/:id(\\d+)", (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
const z = db().prepare("SELECT * FROM reaktion_vorschlaege WHERE id = ?").get(id);
|
||||
if (!z) return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
const istHost = HOST_ROLLEN.has(req.person.rolle);
|
||||
const meiner = z.person_id === req.person.id && z.stand === "offen";
|
||||
if (!istHost && !meiner) return res.status(403).json({ fehler: "nicht_deiner" });
|
||||
|
||||
db().prepare("DELETE FROM reaktion_vorschlaege WHERE id = ?").run(id);
|
||||
res.json({ ok: true });
|
||||
} catch (fehler) {
|
||||
console.error("[reaktion] Vorschlag weg:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/** Eins hoch oder runter.
|
||||
*
|
||||
* GETAUSCHT WIRD MIT DEM NACHBARN, nicht neu durchnummeriert. Beim
|
||||
|
||||
Reference in New Issue
Block a user