Vorlagen anpassen: Frist, dauerhaft und eine Anmerkung

VanVan im Support, Meldung #6, zweite Haelfte -- der Rest, der heute
frueh ausdruecklich offen stehen blieb: „Bei den Vorlagen laesst sich
weder die Frist anpassen noch ‚dauerhaft' einstellen, und eine
Anmerkung fehlt auch."

EIN ZWEITER KNOPF, NICHT EIN FENSTER FUER ALLE

„An alle" verteilt zwoelf Aufgaben mit einem Druck. Haette jedes
Uebernehmen jetzt ein Fenster geoeffnet, waere der haeufige Weg
langsamer geworden, um den seltenen moeglich zu machen. Neben
„Uebernehmen" steht deshalb „Anpassen …" -- an den Creator-Vorlagen
und am Katalog, aus derselben Funktion.

DAS FENSTER IST DAS DES HAUSES

`frageNach` kann seit heute ein DATUM und einen HAKEN, die Anmerkung
konnte es als `grund` schon. Ein eigener kleiner Dialog in
vorlagenbrett.js waere der zweite im Haus gewesen -- und der, in dem
beim naechsten Mal Esc, Fokusfalle oder der Abbruch fehlen. Beide
Felder sind standardmaessig aus; fuer die dreissig anderen Aufrufe
aendert sich nichts.

DREI ENTSCHEIDUNGEN, DIE NICHT NAHELIEGEND WAREN

 1. DIE ANMERKUNG WIRD EINE NOTIZ (`aufgaben_notizen`), kein Anhang
    an der Beschreibung. Sie traegt damit, von wem sie stammt, und
    die Aufgabe zeigt sie ohnehin an. In die Beschreibung geschrieben
    waere sie von der Vorlage nicht mehr zu unterscheiden -- und
    dieselbe Vorlage haette beim naechsten Mal einen anderen Text.

 2. EINE DAUERHAFTE AUFGABE BEKOMMT KEINE FRIST, auch wenn eine
    mitgeschickt wird. Sie waere ab dem naechsten Tag fuer immer
    ueberfaellig, und eine Warnung, die immer kommt, ist keine mehr.
    Dieselbe Regel steht seit Langem im Aenderungsweg; haette sie
    hier gefehlt, gaebe es zwei Antworten auf dieselbe Frage.
    Im Fenster wird das Datum deshalb GRAU, sobald der Haken sitzt --
    ein Datum, das dasteht und nicht gilt, ist schlimmer als keins.

 3. „DAUERHAFT" DARF NUR, WER VERTEILEN DARF. Eine dauerhafte Aufgabe
    laesst sich nicht abhaken (Commit von heute frueh); wer sie sich
    selbst anlegen koennte, haette etwas, das er nie wieder loswird.
    Der Haken fehlt deshalb im Fenster eines Creators -- und
    abgelehnt wird trotzdem am Server, nicht nur ausgeblendet.

EIN FUND, DEN DIE PRUEFUNG GEMACHT HAT

`Number(tage) || 7` -- die Untergrenze des Datumsfeldes lag dadurch
sieben Tage in der Zukunft statt heute, weil Null in JavaScript
unwahr ist. Die VORGABE („in 1 Tag") lag damit UNTER der erlaubten
Grenze: Wer das Fenster oeffnete und einfach „Uebernehmen" drueckte,
bekam eine Absage. `Number.isFinite` fragt, ob eine Zahl da ist, und
nicht, ob sie wahr ist -- derselbe Unterschied wie bei `kill -0`.

NEBENBEI BEHOBEN: Ein gerades Anfuehrungszeichen in einem deutschen
Fehlersatz (gemeldet von pruef-struktur).

GEPRUEFT

  pruef-aufgaben-vorlagen   46 -> 60 ok
    eigene Frist kommt an (und die Vorlage saehe 5 Tage vor -- die
    Angabe hat also wirklich gewirkt), Anmerkung wird woertlich zur
    Notiz mit Namen, ohne Angabe bleibt alles wie bisher, Scout 403
    und es entsteht auch nichts, DogFather 200 und KEINE Frist,
    „morgen" 400, der 45.13. 400, Vergangenheit 400, und als
    Gegenprobe dieselbe Vorlage ohne Frist 200.
    Im Browser: der Knopf, das Fenster, die Vorgabe, kein Haken fuer
    einen Creator, die Aufgabe traegt danach genau die eingetragene
    Frist samt Notiz -- und Abbrechen legt nichts an.
  pruef-nachfrage           74 -> 89 ok
    Datum mit Vorgabe und Untergrenze, Haken 44 px hoch mit 22-px-
    Kaestchen (nicht ueber die ganze Zeile), Sperre und Gegenprobe,
    beide Schranken fuer ein zu fruehes Datum einzeln.
  pruef-struktur 102 · pruef-css-klassen · pruef-modi-katalog 150 ·
  pruef-aufgabenbrett · pruef-vorlagen 24 ·
  pruef-bewerbung-aufgaben 164 · pruef-zuteilung

NUR DAS AGENTURHAUS. Vorlagenbrett und Aufgaben liegen unter
`/workspace`; am Crew-Haus aendert sich keine Zeile.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-10-02 23:57:41 +02:00
co-authored by Claude Opus 5
parent b31bd9b515
commit 018d02c3b8
52 changed files with 1399 additions and 703 deletions
+132 -16
View File
@@ -1554,17 +1554,65 @@ function gleicheHerkunft(req, res, next) {
* Leitung sie zutraegt -- dann steht bei ihr Annehmen/Ablehnen,
* und das ist richtig so: Sie hat noch nicht ja gesagt.
*/
function katalogAufgabeAnlegen(v, zielId, vonId, zustand = "offen") {
/* ==== WAS BEIM UEBERNEHMEN ANDERS SEIN DARF (02.10.2026) ============
VanVan im Support, Meldung #6, zweite Haelfte: „Bei den Vorlagen
laesst sich weder die Frist anpassen noch ‚dauerhaft' einstellen,
und eine Anmerkung fehlt auch."
DREI WUENSCHE, EINE STELLE. Sie reisen als `wunsch`-Objekt durch
beide Zweige, die aus einer Vorlage eine Aufgabe machen -- der
Katalog hier und die Creator-Vorlagen weiter unten. Drei einzelne
Parameter waeren an der naechsten Aufrufstelle drei Gelegenheiten,
einen zu vergessen.
NICHTS IST PFLICHT. Ohne Angabe bleibt alles, wie es war: Frist
aus `tage`, nicht dauerhaft, keine Notiz. Der schnelle Weg
(„An alle", zwoelf Aufgaben mit einem Druck) darf durch diesen
Umbau nicht laenger werden.
DIE ANMERKUNG WIRD EINE NOTIZ, kein Anhaengsel an der
Beschreibung. `aufgaben_notizen` gibt es seit Langem, die Aufgabe
zeigt sie ohnehin an, und sie traegt, von wem sie stammt. In die
Beschreibung geschrieben waere sie nicht mehr von der Vorlage zu
unterscheiden -- und beim naechsten Mal haette dieselbe Vorlage
einen anderen Text. */
function fristAusWunsch(v, wunsch) {
/* EINE DAUERHAFTE AUFGABE HAT KEINE FRIST. Sie waere ab dem
naechsten Tag fuer immer ueberfaellig -- und eine Warnung, die
immer kommt, ist keine mehr. Dieselbe Regel steht seit Langem im
Aenderungsweg (workspace-aufgaben.js, `if (aus.dauerhaft)
aus.frist = null`); haette sie hier gefehlt, gaebe es zwei
Antworten auf dieselbe Frage, und die hiesige waere die falsche. */
if (wunsch?.dauerhaft) return null;
if (wunsch?.frist) return wunsch.frist;
/* Die Frist wird aus `tage` gerechnet, in ORTSZEIT. Ueber
toISOString kaeme zwischen Mitternacht und zwei Uhr der Vortag
heraus -- derselbe Fehler, der im Haus schon einmal eine
Pruefung falsch rot gemacht hat. */
const d = new Date(Date.now() + (v.tage || 7) * 86400_000);
const frist = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`
+ `-${String(d.getDate()).padStart(2, "0")}`;
}
/** Die Anmerkung als erste Notiz an der frischen Aufgabe. */
function anmerkungAnlegen(aufgabeId, wunsch, vonId) {
if (!wunsch?.anmerkung) return;
db().prepare(`INSERT INTO aufgaben_notizen (aufgabe_id, person_id, text, erstellt)
VALUES (?,?,?,?)`).run(aufgabeId, vonId ?? null, wunsch.anmerkung, jetzt());
}
function katalogAufgabeAnlegen(v, zielId, vonId, zustand = "offen", wunsch = null) {
const frist = fristAusWunsch(v, wunsch);
db().prepare(`INSERT INTO aufgaben
(titel, beschreibung, status, prioritaet, verantwortlich_id, frist,
kategorie, vorlage, erstellt, erstellt_von)
VALUES (?,?,'offen',?,?,?,?,?,?,?)`)
kategorie, vorlage, dauerhaft, erstellt, erstellt_von)
VALUES (?,?,'offen',?,?,?,?,?,?,?,?)`)
.run(v.titel, v.text, v.tage <= 1 ? "hoch" : "mittel",
zielId, frist, v.kategorie, v.schluessel, jetzt(), vonId);
zielId, frist, v.kategorie, v.schluessel, wunsch?.dauerhaft ? 1 : 0,
jetzt(), vonId);
const id = db().prepare("SELECT last_insert_rowid() AS id").get().id;
anmerkungAnlegen(id, wunsch, vonId);
const nun = jetzt();
db().prepare(`INSERT INTO aufgaben_zuteilung
(aufgabe_id, person_id, zustand, zugeteilt_am, zugeteilt_von, geantwortet_am)
@@ -1580,6 +1628,12 @@ function katalogAufgabeAnlegen(v, zielId, vonId, zustand = "offen") {
drueben bei den Aufgaben -- ein Satz, kein Aufsatz. */
const BEWERBUNG_TEXT_MAX = 600;
/* Wie lang darf die Anmerkung beim Uebernehmen sein? Dieselbe Zahl wie
`NOTIZ_MAX` in workspace-aufgaben.js -- sie WIRD eine Notiz, und
zwei verschiedene Grenzen fuer dieselbe Zeile waeren die Sorte
Unterschied, die man erst bemerkt, wenn etwas abgeschnitten ist. */
const ANMERKUNG_MAX = 2000;
/* =====================================================================
WAS NACH EINER ANTWORT UEBRIG BLEIBT (30.09.2026)
@@ -2017,6 +2071,66 @@ vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
try {
const art = String(req.body.art || "");
const nr = Number(req.body.nr);
/* ==== DIE DREI WUENSCHE AUS DEM FENSTER (02.10.2026) ========
VanVan, Meldung #6: „Bei den Vorlagen laesst sich weder die
Frist anpassen noch ‚dauerhaft' einstellen, und eine
Anmerkung fehlt auch."
GEPRUEFT WIRD HIER, nicht im Browser. Das Fenster bietet ein
Datumsfeld an; was ankommt, ist trotzdem eine Zeichenkette
aus dem Netz. Ein `frist` wie „morgen" oder „2026-13-45"
stuende sonst in der Datenbank und waere beim Sortieren
stiller Unsinn.
NICHT IN DIE VERGANGENHEIT. Eine Frist, die schon vorbei
ist, macht die Aufgabe in dem Moment rot, in dem sie
entsteht -- und „ueberfaellig" verliert seine Bedeutung,
wenn es auch frisch Verteiltes trifft.
„DAUERHAFT" DARF NUR, WER VERTEILEN DARF. Eine dauerhafte
Aufgabe laesst sich nicht abhaken (siehe den Commit vom
02.10. frueh) -- wer sie sich selbst anlegen koennte, haette
etwas, das er nie wieder loswird. Die Entscheidung gehoert
zur Leitung, genau wie das Beenden.
DIE PRUEFUNG STEHT VOR ALLEN ZWEIGEN, weil beide, die
Aufgaben anlegen, sie brauchen -- zweimal dasselbe waere
zweimal zu pflegen. */
const wunsch = (() => {
const roh = req.body || {};
const w = { frist: null, dauerhaft: false, anmerkung: null };
if (typeof roh.frist === "string" && roh.frist) {
if (!/^\d{4}-\d{2}-\d{2}$/.test(roh.frist)) return { fehler: "frist_ungueltig" };
const d = new Date(roh.frist + "T12:00:00");
if (Number.isNaN(d.getTime())
|| d.toISOString().slice(0, 10) !== roh.frist) {
return { fehler: "frist_ungueltig" };
}
if (roh.frist < heuteLokal()) return { fehler: "frist_vergangen" };
w.frist = roh.frist;
}
if (roh.dauerhaft === true) {
if (!darfAufgabenVerteilen(req.person)) return { fehler: "dauerhaft_nicht_erlaubt" };
w.dauerhaft = true;
}
if (typeof roh.anmerkung === "string" && roh.anmerkung.trim()) {
w.anmerkung = roh.anmerkung.replace(/\r\n/g, "\n").trim().slice(0, ANMERKUNG_MAX);
}
return w;
})();
if (wunsch.fehler) {
const saetze = {
frist_ungueltig: "Diese Frist versteht der Server nicht – bitte ein Datum wählen.",
frist_vergangen: "Diese Frist liegt in der Vergangenheit.",
dauerhaft_nicht_erlaubt:
"„Dauerhaft“ dürfen nur DogFather und die rechte Hand setzen – "
+ "eine dauerhafte Aufgabe lässt sich nicht abhaken.",
};
return res.status(wunsch.fehler === "dauerhaft_nicht_erlaubt" ? 403 : 400)
.json({ fehler: saetze[wunsch.fehler] });
}
/* Für wen? Ein Creator immer für sich; Betreuer für den Creator,
den sie gerade ansehen. */
let creatorId = req.person.rolle === "creator"
@@ -2095,22 +2209,24 @@ vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
const auswahl = art === "aufgaben_alle" ? feld : [feld[nr]];
if (auswahl.some((v) => !v)) return res.status(400).json({ fehler: "Unbekannte Vorlage." });
for (const v of auswahl) {
/* Die Frist wird aus `tage` gerechnet, in ORTSZEIT. Ueber
toISOString kaeme zwischen Mitternacht und zwei Uhr der
Vortag heraus -- derselbe Fehler, der im Haus schon einmal
eine Pruefung falsch rot gemacht hat. */
const d = new Date(Date.now() + (v.tage || 7) * 86400_000);
const frist = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`
+ `-${String(d.getDate()).padStart(2, "0")}`;
/* Frist, „dauerhaft" und die Anmerkung kommen aus demselben
`wunsch` wie im Katalogzweig -- und aus derselben
Funktion. Zwei Rechnungen fuer dieselbe Frist waeren die
zweite, die beim naechsten Mal nicht mitgeaendert wird. */
const frist = fristAusWunsch(v, wunsch);
/* Die Kennung der Vorlage wandert mit (09.09.2026). Nur so
kann das Brett spaeter zeigen, was schon uebernommen ist --
und der Titel taugt dafuer nicht: Er darf geaendert werden. */
db().prepare(`INSERT INTO aufgaben
(titel, beschreibung, status, prioritaet, creator_id, frist,
vorlage, erstellt, erstellt_von)
VALUES (?,?,'offen',?,?,?,?,?,?)`)
vorlage, dauerhaft, erstellt, erstellt_von)
VALUES (?,?,'offen',?,?,?,?,?,?,?)`)
.run(v.titel, v.text, stufe === "anfaenger" ? "hoch" : "mittel",
creatorId, frist, v.schluessel, jetzt(), req.person.id);
creatorId, frist, v.schluessel, wunsch.dauerhaft ? 1 : 0,
jetzt(), req.person.id);
anmerkungAnlegen(
db().prepare("SELECT last_insert_rowid() AS id").get().id,
wunsch, req.person.id);
angelegt.push(v.titel);
}
@@ -2298,7 +2414,7 @@ vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
: new Set();
for (const v of auswahl) {
if (liegtSchon.has(v.schluessel)) { lagSchonDa.push(v.titel); continue; }
katalogAufgabeAnlegen(v, ziel.id, req.person.id);
katalogAufgabeAnlegen(v, ziel.id, req.person.id, "offen", wunsch);
angelegt.push(v.titel);
}
}