From 1f7cbc7d100c3bcff77d02cf54df0cf8b89c56da Mon Sep 17 00:00:00 2001 From: Saberlve Date: Wed, 15 Apr 2026 19:03:36 +0800 Subject: [PATCH] fix: add missing projects.py to worktree Co-Authored-By: Claude Opus 4.6 --- src/zotero_kb/projects.py | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/zotero_kb/projects.py diff --git a/src/zotero_kb/projects.py b/src/zotero_kb/projects.py new file mode 100644 index 0000000..b21900c --- /dev/null +++ b/src/zotero_kb/projects.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import json +from pathlib import Path + + +class ProjectService: + def __init__(self, workspace_dir: Path) -> None: + self.workspace_dir = workspace_dir + self.projects_dir = workspace_dir / "projects" + self.index_dir = workspace_dir / "library" / "index" + + def add_items(self, project_id: str, item_keys: list[str]) -> dict[str, object]: + selected_items = self._read_selected_items(project_id) + selected_items = sorted(set(selected_items + item_keys)) + self._write_json(self._project_dir(project_id) / "selected-items.json", selected_items) + return self._rebuild_project_index(project_id, selected_items) + + def remove_item(self, project_id: str, item_key: str) -> dict[str, object]: + selected_items = [key for key in self._read_selected_items(project_id) if key != item_key] + self._write_json(self._project_dir(project_id) / "selected-items.json", selected_items) + return self._rebuild_project_index(project_id, selected_items) + + def get_project_view(self, project_id: str) -> dict[str, object]: + index_path = self._project_dir(project_id) / "project-index.json" + if not index_path.exists(): + selected_items = self._read_selected_items(project_id) + return self._rebuild_project_index(project_id, selected_items) + return json.loads(index_path.read_text(encoding="utf-8")) + + def _rebuild_project_index(self, project_id: str, selected_items: list[str]) -> dict[str, object]: + cards_index = self._read_json(self.index_dir / "cards.json") + collections_index = self._read_json(self.index_dir / "collections.json") + project_cards = [cards_index[item_key] for item_key in selected_items if item_key in cards_index] + project_collections = [ + payload + for payload in collections_index.values() + if set(payload.get("item_keys", [])) & set(selected_items) + ] + payload = { + "project_id": project_id, + "selected_items": selected_items, + "cards": project_cards, + "collections": project_collections, + } + self._write_json(self._project_dir(project_id) / "project-index.json", payload) + return payload + + def _read_selected_items(self, project_id: str) -> list[str]: + path = self._project_dir(project_id) / "selected-items.json" + if not path.exists(): + return [] + return [str(value) for value in json.loads(path.read_text(encoding="utf-8"))] + + def _project_dir(self, project_id: str) -> Path: + return self.projects_dir / project_id + + @staticmethod + def _read_json(path: Path) -> dict[str, object]: + if not path.exists(): + return {} + return json.loads(path.read_text(encoding="utf-8")) + + @staticmethod + def _write_json(path: Path, payload: object) -> None: + path.write_text(json.dumps(payload, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") +