feat: individual word link_to (F/A/B), edit form word management, fix picture-based suggestions

- Words in pair form now linkable individually per word (Frage/Aussage/Beide toggle)
- Edit form includes full word management: view existing words with link indicator, remove/restore, add new words with link_to selector
- Fix word suggestions: load from picture words (db_words_db_pictures) instead of object words (always empty)
- Backend PATCH /api/directus/db-pairs/<id> handles words_add with link_to and words_remove with junction IDs
- Level range 1-100 throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 12:20:21 +02:00
parent 2e6cf094cb
commit 2595b8d32e
4 changed files with 236 additions and 31 deletions

57
app.py
View File

@@ -1836,6 +1836,22 @@ def directus_db_object_pairs(obj_id):
s_d, _ = _directus("GET", f"/items/db_statement/{sid}?fields=id,statement_de,level,status", token)
if s_d.get("data"):
statements.append(s_d["data"])
# Wörter für jede Question laden
for q in questions:
qid = q["id"]
qw_junc, _ = _directus("GET", f"/items/db_question_db_words?filter[db_question_id][_eq]={qid}&fields=id,db_words_id.id,db_words_id.titel_de,db_words_id.level&limit=100", token)
q["words"] = [
{"junction_id": e["id"], "word_id": e["db_words_id"]["id"], "titel_de": e["db_words_id"]["titel_de"], "level": e["db_words_id"]["level"]}
for e in (qw_junc.get("data") or []) if isinstance(e.get("db_words_id"), dict)
]
# Wörter für jedes Statement laden
for s in statements:
sid = s["id"]
sw_junc, _ = _directus("GET", f"/items/db_statement_db_words?filter[db_statement_id][_eq]={sid}&fields=id,db_words_id.id,db_words_id.titel_de,db_words_id.level&limit=100", token)
s["words"] = [
{"junction_id": e["id"], "word_id": e["db_words_id"]["id"], "titel_de": e["db_words_id"]["titel_de"], "level": e["db_words_id"]["level"]}
for e in (sw_junc.get("data") or []) if isinstance(e.get("db_words_id"), dict)
]
result.append({**pair, "questions": questions, "statements": statements})
return jsonify({"data": result})
else:
@@ -1865,12 +1881,14 @@ def directus_db_object_pairs(obj_id):
for we in words:
titel_de = (we.get("titel_de") or "").strip()
w_level = int(we.get("level") or level)
link_to = we.get("link_to", "both") # 'question', 'statement', 'both'
if not titel_de:
continue
try:
wid, _ = _find_or_create_db_word(titel_de, w_level, token)
_directus("POST", "/items/db_statement_db_words", token, {"db_statement_id": stmt_id, "db_words_id": wid})
if q_id:
if link_to in ("statement", "both"):
_directus("POST", "/items/db_statement_db_words", token, {"db_statement_id": stmt_id, "db_words_id": wid})
if link_to in ("question", "both") and q_id:
_directus("POST", "/items/db_question_db_words", token, {"db_question_id": q_id, "db_words_id": wid})
except Exception as e:
print(f"[db_object_pairs] word error '{titel_de}': {e}")
@@ -1953,6 +1971,41 @@ def directus_db_pair(pair_id):
_directus("POST", "/items/db_pairs_db_question", token,
{"db_pairs_id": pair_id, "db_question_id": qid})
# Neue Wörter hinzufügen
words_add = body.get("words_add", [])
# Statement-ID und Question-ID nochmal laden
s_junc2, _ = _directus("GET", f"/items/db_pairs_db_statement?filter[db_pairs_id][_eq]={pair_id}&fields=db_statement_id&limit=1", token)
stmt_id_edit = ((s_junc2.get("data") or [{}])[0] or {}).get("db_statement_id")
q_junc2, _ = _directus("GET", f"/items/db_pairs_db_question?filter[db_pairs_id][_eq]={pair_id}&fields=db_question_id&limit=1", token)
q_id_edit = ((q_junc2.get("data") or [{}])[0] or {}).get("db_question_id")
for we in words_add:
titel_de = (we.get("titel_de") or "").strip()
w_level = int(we.get("level") or 50)
link_to = we.get("link_to", "both")
if not titel_de:
continue
try:
wid, _ = _find_or_create_db_word(titel_de, w_level, token)
if link_to in ("statement", "both") and stmt_id_edit:
_directus("POST", "/items/db_statement_db_words", token, {"db_statement_id": stmt_id_edit, "db_words_id": wid})
if link_to in ("question", "both") and q_id_edit:
_directus("POST", "/items/db_question_db_words", token, {"db_question_id": q_id_edit, "db_words_id": wid})
except Exception as e:
print(f"[db_pair_patch] word error '{titel_de}': {e}")
# Wörter entfernen
words_remove = body.get("words_remove", [])
for wr in words_remove:
link_to = wr.get("link_to", "both")
junction_id = wr.get("junction_id")
if not junction_id:
continue
if link_to in ("statement", "both"):
_directus("DELETE", f"/items/db_statement_db_words/{junction_id}", token)
if link_to in ("question", "both"):
_directus("DELETE", f"/items/db_question_db_words/{junction_id}", token)
return jsonify({"ok": True})
else: # DELETE