""" Users Handler - User management Phase J.2: 10 tools - list_users, get_user, get_current_user - create_user, update_user, delete_user, delete_users - invite_user, accept_invite, update_current_user """ import json from typing import Any from plugins.directus.client import DirectusClient def get_tool_specifications() -> list[dict[str, Any]]: """Return tool specifications for ToolGenerator (10 tools)""" return [ { "name": "list_users", "method_name": "list_users", "description": "List all users in Directus with filtering options.", "schema": { "type": "object", "properties": { "filter": { "anyOf": [{"type": "object"}, {"type": "null"}], "description": 'Filter object (e.g., {"status": {"_eq": "active"}})', }, "sort": { "anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "null"}], "description": "Sort fields (e.g., ['email'])", }, "limit": { "type": "integer", "description": "Maximum users to return", "default": 100, }, "offset": {"type": "integer", "description": "Users to skip", "default": 0}, "search": { "anyOf": [{"type": "string"}, {"type": "null"}], "description": "Search term", }, }, "required": [], }, "scope": "read", }, { "name": "get_user", "method_name": "get_user", "description": "Get user details by ID.", "schema": { "type": "object", "properties": {"id": {"type": "string", "description": "User UUID"}}, "required": ["id"], }, "scope": "read", }, { "name": "get_current_user", "method_name": "get_current_user", "description": "Get the currently authenticated user.", "schema": {"type": "object", "properties": {}, "required": []}, "scope": "read", }, { "name": "create_user", "method_name": "create_user", "description": "Create a new user.", "schema": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "User email address", }, "password": {"type": "string", "minLength": 8, "description": "User password"}, "role": {"type": "string", "description": "Role UUID"}, "first_name": { "anyOf": [{"type": "string"}, {"type": "null"}], "description": "First name", }, "last_name": { "anyOf": [{"type": "string"}, {"type": "null"}], "description": "Last name", }, "status": { "type": "string", "enum": ["draft", "invited", "active", "suspended", "archived"], "default": "active", "description": "User status", }, }, "required": ["email", "password", "role"], }, "scope": "admin", }, { "name": "update_user", "method_name": "update_user", "description": "Update user details.", "schema": { "type": "object", "properties": { "id": {"type": "string", "description": "User UUID"}, "data": { "type": "object", "description": "Fields to update (email, first_name, last_name, role, status, etc.)", }, }, "required": ["id", "data"], }, "scope": "admin", }, { "name": "delete_user", "method_name": "delete_user", "description": "Delete a user. This action is irreversible.", "schema": { "type": "object", "properties": {"id": {"type": "string", "description": "User UUID to delete"}}, "required": ["id"], }, "scope": "admin", }, { "name": "delete_users", "method_name": "delete_users", "description": "Delete multiple users. This action is irreversible.", "schema": { "type": "object", "properties": { "ids": { "type": "array", "items": {"type": "string"}, "description": "Array of user UUIDs to delete", } }, "required": ["ids"], }, "scope": "admin", }, { "name": "invite_user", "method_name": "invite_user", "description": "Invite a user by email.", "schema": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "Email to invite", }, "role": {"type": "string", "description": "Role UUID for the invited user"}, "invite_url": { "anyOf": [{"type": "string"}, {"type": "null"}], "description": "Custom invite URL", }, }, "required": ["email", "role"], }, "scope": "admin", }, { "name": "update_current_user", "method_name": "update_current_user", "description": "Update the currently authenticated user's profile.", "schema": { "type": "object", "properties": { "data": { "type": "object", "description": "Fields to update (first_name, last_name, language, theme, etc.)", } }, "required": ["data"], }, "scope": "write", }, { "name": "get_user_role", "method_name": "get_user_role", "description": "Get the role of a specific user.", "schema": { "type": "object", "properties": {"id": {"type": "string", "description": "User UUID"}}, "required": ["id"], }, "scope": "read", }, ] # ===================== # HANDLER FUNCTIONS # ===================== async def list_users( client: DirectusClient, filter: dict | None = None, sort: list[str] | None = None, limit: int = 100, offset: int = 0, search: str | None = None, ) -> str: """List users.""" try: result = await client.list_users( filter=filter, sort=sort, limit=limit, offset=offset, search=search ) users = result.get("data", []) return json.dumps( {"success": True, "total": len(users), "users": users}, indent=2, ensure_ascii=False ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def get_user(client: DirectusClient, id: str) -> str: """Get user by ID.""" try: result = await client.get_user(id) return json.dumps( {"success": True, "user": result.get("data")}, indent=2, ensure_ascii=False ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def get_current_user(client: DirectusClient) -> str: """Get current user.""" try: result = await client.get_current_user() return json.dumps( {"success": True, "user": 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_user( client: DirectusClient, email: str, password: str, role: str, first_name: str | None = None, last_name: str | None = None, status: str = "active", ) -> str: """Create a new user.""" try: result = await client.create_user( email=email, password=password, role=role, first_name=first_name, last_name=last_name, status=status, ) return json.dumps( {"success": True, "message": f"User {email} created", "user": 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_user(client: DirectusClient, id: str, data: dict[str, Any]) -> str: """Update user.""" try: result = await client.update_user(id, data) return json.dumps( {"success": True, "message": "User updated", "user": 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_user(client: DirectusClient, id: str) -> str: """Delete a user.""" try: await client.delete_user(id) return json.dumps({"success": True, "message": f"User {id} deleted"}, indent=2) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def delete_users(client: DirectusClient, ids: list[str]) -> str: """Delete multiple users.""" try: await client.delete_users(ids) return json.dumps({"success": True, "message": f"Deleted {len(ids)} users"}, indent=2) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def invite_user( client: DirectusClient, email: str, role: str, invite_url: str | None = None ) -> str: """Invite a user.""" try: result = await client.invite_user(email, role, invite_url) return json.dumps( { "success": True, "message": f"Invitation sent to {email}", "result": 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_current_user(client: DirectusClient, data: dict[str, Any]) -> str: """Update current user profile.""" try: # Get current user first to get ID current = await client.get_current_user() user_id = current.get("data", {}).get("id") if not user_id: return json.dumps( {"success": False, "error": "Cannot determine current user"}, indent=2 ) result = await client.update_user(user_id, data) return json.dumps( {"success": True, "message": "Profile updated", "user": result.get("data")}, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2) async def get_user_role(client: DirectusClient, id: str) -> str: """Get user's role.""" try: result = await client.get_user(id) user = result.get("data", {}) role_id = user.get("role") if role_id: role_result = await client.get_role(role_id) return json.dumps( {"success": True, "user_id": id, "role": role_result.get("data")}, indent=2, ensure_ascii=False, ) else: return json.dumps( { "success": True, "user_id": id, "role": None, "message": "User has no role assigned", }, indent=2, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2)