diff --git a/.gitignore b/.gitignore index bc353e8..06b3256 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ __pycache__/ .venv/ venv/ .DS_Store +.sqlite3 diff --git a/app/services/session_service.py b/app/services/session_service.py index 5b6d450..733eb23 100644 --- a/app/services/session_service.py +++ b/app/services/session_service.py @@ -341,6 +341,21 @@ class SessionService: return self.list_selected_episodes(session_id) with self._connect() as conn: + existing_rows = conn.execute( + """ + SELECT payload_json + FROM selected_episodes + WHERE session_id = ? + """, + (session_id,), + ).fetchall() + existing_episode_ids: set[str] = set() + for row in existing_rows: + payload = json.loads(row["payload_json"]) + episode_id = str(payload.get("id") or "").strip() + if episode_id: + existing_episode_ids.add(episode_id) + current_max = conn.execute( """ SELECT COALESCE(MAX(position), -1) AS max_position @@ -352,6 +367,9 @@ class SessionService: next_position = int(current_max["max_position"]) + 1 for item in items: + episode_id = str(item.get("id") or "").strip() + if episode_id and episode_id in existing_episode_ids: + continue conn.execute( """ INSERT INTO selected_episodes (session_id, position, payload_json) @@ -359,6 +377,8 @@ class SessionService: """, (session_id, next_position, json.dumps(item, ensure_ascii=True)), ) + if episode_id: + existing_episode_ids.add(episode_id) next_position += 1 return self.list_selected_episodes(session_id) diff --git a/data/session_state.sqlite3 b/data/session_state.sqlite3 index 3e6d2aa..f083fe3 100644 Binary files a/data/session_state.sqlite3 and b/data/session_state.sqlite3 differ diff --git a/feature_tests_selected_episodes.sh b/feature_tests_selected_episodes.sh index 5444e83..3085513 100755 --- a/feature_tests_selected_episodes.sh +++ b/feature_tests_selected_episodes.sh @@ -66,6 +66,24 @@ assert data["items"][1]["episode"]["title"] == "A Classic New York Character", " print("add/list validation passed") PY +curl --fail --silent --show-error \ + -X POST "${BASE_URL}/api/session/selected-episodes?session_id=${SESSION_ID}" \ + -H "Content-Type: application/json" \ + --data @"${TMP_DIR}/add_payload.json" \ + -o "${TMP_DIR}/add_duplicate_response.json" + +python3 - "${TMP_DIR}/add_duplicate_response.json" <<'PY' +import json +import sys +from pathlib import Path + +data = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8")) +items = data.get("items") +assert isinstance(items, list), "items must be a list" +assert len(items) == 2, "duplicate add should be skipped; still expected 2 selected episodes" +print("duplicate skip validation passed") +PY + echo echo "== Feature test 2: reorder selected episodes ==" cat > "${TMP_DIR}/reorder_payload.json" <<'JSON'