feat: multi-word per object + {objectID.wordID} placeholders
- Annotate: multiple words per object via db_objects_db_words M2M, word chips with add/remove per object card
- Generate sidebar: objects shown with comma-separated word list as display name
- Generate pair form: all object words as suggestion chips, click inserts {objectId.wordId} at cursor
- Preview resolves {objectId.wordId} → actual word text
- Backend: POST adds single word (no replace), new DELETE /db-objects/<id>/words/<junctionId>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
29
app.py
29
app.py
@@ -1916,24 +1916,37 @@ def directus_db_object_words(obj_id):
|
||||
if word.get("status") == "archived":
|
||||
continue
|
||||
items.append({
|
||||
"junction_id": entry.get("id"),
|
||||
"word_id": word["id"],
|
||||
"titel_de": word.get("titel_de", ""),
|
||||
"level": word.get("level") or 50,
|
||||
"status": word.get("status", ""),
|
||||
})
|
||||
return jsonify({"data": items})
|
||||
else: # POST — replace with single word
|
||||
else: # POST — add a single word to the object (M2M, allows multiple)
|
||||
body = request.get_json(force=True, silent=True) or {}
|
||||
titel_de = (body.get("titel_de") or "").strip()
|
||||
level = int(body.get("level") or 50)
|
||||
# Delete all existing junctions for this object
|
||||
existing, _ = _directus("GET", f"/items/db_objects_db_words?filter[db_objects_id][_eq]={obj_id}&fields=id&limit=20", token)
|
||||
for e in (existing.get("data") or []):
|
||||
_directus("DELETE", f"/items/db_objects_db_words/{e['id']}", token)
|
||||
if not titel_de:
|
||||
return jsonify({"ok": True, "cleared": True})
|
||||
return jsonify({"error": "titel_de required"}), 400
|
||||
wid, _ = _find_or_create_db_word(titel_de, level, token)
|
||||
_directus("POST", "/items/db_objects_db_words", token, {"db_objects_id": obj_id, "db_words_id": wid})
|
||||
return jsonify({"ok": True, "word_id": wid})
|
||||
# Check if already linked to avoid duplicates
|
||||
existing, _ = _directus("GET",
|
||||
f"/items/db_objects_db_words?filter[db_objects_id][_eq]={obj_id}&filter[db_words_id][_eq]={wid}&fields=id&limit=1",
|
||||
token)
|
||||
if existing.get("data"):
|
||||
return jsonify({"ok": True, "already_exists": True, "word_id": wid, "junction_id": existing["data"][0]["id"]})
|
||||
resp, s = _directus("POST", "/items/db_objects_db_words", token,
|
||||
{"db_objects_id": obj_id, "db_words_id": wid})
|
||||
junction_id = resp["data"]["id"] if s in (200, 201) else None
|
||||
return jsonify({"ok": True, "word_id": wid, "junction_id": junction_id})
|
||||
|
||||
|
||||
@app.route("/api/directus/db-objects/<obj_id>/words/<junction_id>", methods=["DELETE"])
|
||||
def directus_db_object_word_delete(obj_id, junction_id):
|
||||
token = request.headers.get("Authorization", "")
|
||||
_directus("DELETE", f"/items/db_objects_db_words/{junction_id}", token)
|
||||
return jsonify({"ok": True})
|
||||
|
||||
|
||||
@app.route("/api/directus/db-pairs/<pair_id>", methods=["PATCH", "DELETE"])
|
||||
|
||||
Reference in New Issue
Block a user