""" Content Handler - Revisions, Versions, Comments Phase J.4: 10 tools - Revisions: list, get (2) - Versions: list, get, create, update, delete, promote (6) - Comments: list, create (2) """ import json from typing import Any from plugins.directus.client import DirectusClient def _parse_json_param(value: Any, param_name: str = "parameter") -> Any: """Parse a parameter that may be a JSON string or already a native type.""" if value is None: return None if isinstance(value, (dict, list)): return value if isinstance(value, str): stripped = value.strip() if stripped.startswith("{") or stripped.startswith("["): try: return json.loads(stripped) except json.JSONDecodeError as e: raise ValueError(f"Invalid JSON in '{param_name}': {e}") return value def get_tool_specifications() -> list[dict[str, Any]]: """Return tool specifications for ToolGenerator (10 tools)""" return [ # ===================== # REVISIONS (2) # ===================== { "name": "list_revisions", "method_name": "list_revisions", "description": "List revisions (history) of items.", "schema": { "type": "object", "properties": { "filter": { "anyOf": [{"type": "object"}, {"type": "null"}], "description": 'Filter object (e.g., {"collection": {"_eq": "posts"}})', }, "sort": { "anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}], "description": "Sort fields (default: ['-activity'])", }, "limit": { "type": "integer", "description": "Maximum revisions to return", "default": 100, }, }, "required": [], }, "scope": "read", }, { "name": "get_revision", "method_name": "get_revision", "description": "Get revision details by ID.", "schema": { "type": "object", "properties": {"id": {"type": "string", "description": "Revision ID"}}, "required": ["id"], }, "scope": "read", }, # ===================== # VERSIONS (6) # ===================== { "name": "list_versions", "method_name": "list_versions", "description": "List content versions (drafts).", "schema": { "type": "object", "properties": { "filter": { "anyOf": [{"type": "object"}, {"type": "null"}], "description": "Filter object", }, "sort": { "anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}], "description": "Sort fields", }, "limit": { "type": "integer", "description": "Maximum versions to return", "default": 100, }, }, "required": [], }, "scope": "read", }, { "name": "get_version", "method_name": "get_version", "description": "Get version details by ID.", "schema": { "type": "object", "properties": {"id": {"type": "string", "description": "Version UUID"}}, "required": ["id"], }, "scope": "read", }, { "name": "create_version", "method_name": "create_version", "description": "Create a new content version (draft).", "schema": { "type": "object", "properties": { "name": {"type": "string", "description": "Version name"}, "collection": {"type": "string", "description": "Collection name"}, "item": {"type": "string", "description": "Item ID"}, "key": {"type": "string", "description": "Version key (unique identifier)"}, }, "required": ["name", "collection", "item", "key"], }, "scope": "write", }, { "name": "update_version", "method_name": "update_version", "description": "Update a version.", "schema": { "type": "object", "properties": { "id": {"type": "string", "description": "Version UUID"}, "data": {"type": "object", "description": "Fields to update (name, delta)"}, }, "required": ["id", "data"], }, "scope": "write", }, { "name": "delete_version", "method_name": "delete_version", "description": "Delete a version.", "schema": { "type": "object", "properties": {"id": {"type": "string", "description": "Version UUID to delete"}}, "required": ["id"], }, "scope": "write", }, { "name": "promote_version", "method_name": "promote_version", "description": "Promote a version to main (apply changes to item).", "schema": { "type": "object", "properties": { "id": {"type": "string", "description": "Version UUID to promote"}, "mainHash": { "anyOf": [{"type": "string"}, {"type": "null"}], "description": "Expected main content hash (for conflict detection)", }, }, "required": ["id"], }, "scope": "write", }, # ===================== # COMMENTS (2) # ===================== { "name": "list_comments", "method_name": "list_comments", "description": "List comments on items.", "schema": { "type": "object", "properties": { "filter": { "anyOf": [{"type": "object"}, {"type": "null"}], "description": 'Filter object (e.g., {"collection": {"_eq": "posts"}})', }, "sort": { "anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}], "description": "Sort fields", }, "limit": { "type": "integer", "description": "Maximum comments to return", "default": 100, }, }, "required": [], }, "scope": "read", }, { "name": "create_comment", "method_name": "create_comment", "description": "Create a comment on an item.", "schema": { "type": "object", "properties": { "collection": {"type": "string", "description": "Collection name"}, "item": {"type": "string", "description": "Item ID"}, "comment": {"type": "string", "description": "Comment text"}, }, "required": ["collection", "item", "comment"], }, "scope": "write", }, ] # ===================== # HANDLER FUNCTIONS # ===================== async def list_revisions( client: DirectusClient, filter: dict | None = None, sort: list[str] | None = None, limit: int = 100, ) -> str: """List revisions.""" try: # Parse JSON string parameters parsed_filter = _parse_json_param(filter, "filter") parsed_sort = _parse_json_param(sort, "sort") result = await client.list_revisions(filter=parsed_filter, sort=parsed_sort, limit=limit) revisions = result.get("data", []) return json.dumps( {"success": True, "total": len(revisions), "revisions": revisions}, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def get_revision(client: DirectusClient, id: str) -> str: """Get revision by ID.""" try: result = await client.get_revision(id) return json.dumps( {"success": True, "revision": result.get("data")}, indent=2, ensure_ascii=False ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def list_versions( client: DirectusClient, filter: dict | None = None, sort: list[str] | None = None, limit: int = 100, ) -> str: """List versions.""" try: # Parse JSON string parameters parsed_filter = _parse_json_param(filter, "filter") parsed_sort = _parse_json_param(sort, "sort") result = await client.list_versions(filter=parsed_filter, sort=parsed_sort, limit=limit) versions = result.get("data", []) return json.dumps( {"success": True, "total": len(versions), "versions": versions}, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def get_version(client: DirectusClient, id: str) -> str: """Get version by ID.""" try: result = await client.get_version(id) return json.dumps( {"success": True, "version": result.get("data")}, indent=2, ensure_ascii=False ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def create_version( client: DirectusClient, name: str, collection: str, item: str, key: str ) -> str: """Create a new version.""" try: result = await client.create_version(name=name, collection=collection, item=item, key=key) return json.dumps( { "success": True, "message": f"Version '{name}' created", "version": result.get("data"), }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def update_version(client: DirectusClient, id: str, data: dict[str, Any]) -> str: """Update version.""" try: # Parse JSON string parameter parsed_data = _parse_json_param(data, "data") result = await client.update_version(id, parsed_data) return json.dumps( {"success": True, "message": "Version updated", "version": result.get("data")}, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def delete_version(client: DirectusClient, id: str) -> str: """Delete a version.""" try: await client.delete_version(id) return json.dumps({"success": True, "message": f"Version {id} deleted"}, indent=2) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def promote_version(client: DirectusClient, id: str, mainHash: str | None = None) -> str: """Promote version to main.""" try: result = await client.promote_version(id, mainHash) return json.dumps( { "success": True, "message": f"Version {id} promoted to main", "result": result.get("data") if result else None, }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def list_comments( client: DirectusClient, filter: dict | None = None, sort: list[str] | None = None, limit: int = 100, ) -> str: """List comments.""" try: # Parse JSON string parameters parsed_filter = _parse_json_param(filter, "filter") parsed_sort = _parse_json_param(sort, "sort") result = await client.list_comments(filter=parsed_filter, sort=parsed_sort, limit=limit) comments = result.get("data", []) return json.dumps( {"success": True, "total": len(comments), "comments": comments}, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def create_comment(client: DirectusClient, collection: str, item: str, comment: str) -> str: """Create a comment.""" try: result = await client.create_comment(collection, item, comment) return json.dumps( {"success": True, "message": "Comment created", "comment": result.get("data")}, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2)