Community edition generated from private repo via sync pipeline. Includes 9 plugins (WordPress, WooCommerce, WP Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~587 tools. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
371 lines
13 KiB
Python
371 lines
13 KiB
Python
"""
|
|
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)
|