"""Profiles Handler - OpenPanel user profile management (8 tools)""" import json from typing import Any from plugins.openpanel.client import OpenPanelClient def get_tool_specifications() -> list[dict[str, Any]]: """Return tool specifications for ToolGenerator (8 tools)""" return [ { "name": "list_profiles", "method_name": "list_profiles", "description": "List user profiles with optional filtering and pagination.", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "limit": { "type": "integer", "description": "Number of profiles to return", "default": 50, "maximum": 100, }, "offset": { "type": "integer", "description": "Offset for pagination", "default": 0, }, "sort_by": { "type": "string", "enum": ["last_seen", "first_seen", "event_count"], "description": "Sort order", "default": "last_seen", }, }, "required": ["project_id"], }, "scope": "read", }, { "name": "get_profile", "method_name": "get_profile", "description": "Get detailed information about a specific user profile.", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "profile_id": {"type": "string", "description": "User profile ID"}, }, "required": ["project_id", "profile_id"], }, "scope": "read", }, { "name": "search_profiles", "method_name": "search_profiles", "description": "Search user profiles by property value.", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "property": { "type": "string", "description": "Property to search (e.g., 'email', 'name', 'plan')", }, "value": {"type": "string", "description": "Value to search for"}, "operator": { "type": "string", "enum": ["is", "contains", "startsWith", "endsWith"], "description": "Search operator", "default": "contains", }, "limit": {"type": "integer", "description": "Maximum results", "default": 50}, }, "required": ["project_id", "property", "value"], }, "scope": "read", }, { "name": "get_profile_events", "method_name": "get_profile_events", "description": "Get events for a specific user profile.", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "profile_id": {"type": "string", "description": "User profile ID"}, "event": { "anyOf": [{"type": "string"}, {"type": "null"}], "description": "Filter by event name", }, "limit": { "type": "integer", "description": "Number of events", "default": 50, "maximum": 200, }, }, "required": ["project_id", "profile_id"], }, "scope": "read", }, { "name": "get_profile_sessions", "method_name": "get_profile_sessions", "description": "Get sessions for a specific user profile.", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "profile_id": {"type": "string", "description": "User profile ID"}, "limit": { "type": "integer", "description": "Number of sessions", "default": 20, "maximum": 50, }, }, "required": ["project_id", "profile_id"], }, "scope": "read", }, { "name": "delete_profile", "method_name": "delete_profile", "description": "Delete a user profile and all associated data (GDPR compliance).", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "profile_id": {"type": "string", "description": "User profile ID to delete"}, "confirm": { "type": "boolean", "description": "Confirm deletion (required)", "default": False, }, }, "required": ["project_id", "profile_id", "confirm"], }, "scope": "admin", }, { "name": "merge_profiles", "method_name": "merge_profiles", "description": "Merge two user profiles into one (for duplicate resolution).", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "primary_profile_id": { "type": "string", "description": "Primary profile ID to keep", }, "secondary_profile_id": { "type": "string", "description": "Secondary profile ID to merge and delete", }, }, "required": ["project_id", "primary_profile_id", "secondary_profile_id"], }, "scope": "admin", }, { "name": "export_profile_data", "method_name": "export_profile_data", "description": "Export all data for a user profile (GDPR data portability).", "schema": { "type": "object", "properties": { "project_id": {"type": "string", "description": "Project ID"}, "profile_id": {"type": "string", "description": "User profile ID"}, "format": { "type": "string", "enum": ["json", "csv"], "description": "Export format", "default": "json", }, }, "required": ["project_id", "profile_id"], }, "scope": "read", }, ] # ===================== # Profile Functions (8) # ===================== async def list_profiles( client: OpenPanelClient, project_id: str, limit: int = 50, offset: int = 0, sort_by: str = "last_seen", ) -> str: """List user profiles""" try: return json.dumps( { "success": True, "project_id": project_id, "pagination": {"limit": limit, "offset": offset, "sort_by": sort_by}, "note": "Profile listing requires dashboard tRPC API. Use OpenPanel dashboard to view profiles.", "message": "Profile list request processed", }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def get_profile(client: OpenPanelClient, project_id: str, profile_id: str) -> str: """Get profile details""" try: # Try to get events for this profile via export API try: result = await client.export_events( project_id=project_id, profile_id=profile_id, limit=1, includes=["profile"] ) if isinstance(result, dict) and result.get("data"): return json.dumps( { "success": True, "project_id": project_id, "profile_id": profile_id, "has_events": True, "note": "Full profile details require dashboard tRPC API.", "message": "Profile found with associated events", }, indent=2, ensure_ascii=False, ) except: pass return json.dumps( { "success": True, "project_id": project_id, "profile_id": profile_id, "note": "Profile details require dashboard tRPC API. Use OpenPanel dashboard for full profile view.", "message": "Profile request processed", }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def search_profiles( client: OpenPanelClient, project_id: str, property: str, value: str, operator: str = "contains", limit: int = 50, ) -> str: """Search profiles by property""" try: return json.dumps( { "success": True, "project_id": project_id, "search": { "property": property, "value": value, "operator": operator, "limit": limit, }, "note": "Profile search requires dashboard tRPC API. Use OpenPanel dashboard for profile search.", "message": "Profile search request processed", }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def get_profile_events( client: OpenPanelClient, project_id: str, profile_id: str, event: str | None = None, limit: int = 50, ) -> str: """Get events for a profile""" try: result = await client.export_events( project_id=project_id, profile_id=profile_id, event=event, limit=limit ) events_count = len(result.get("data", [])) if isinstance(result, dict) else 0 return json.dumps( { "success": True, "project_id": project_id, "profile_id": profile_id, "event_filter": event, "count": events_count, "data": result, }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def get_profile_sessions( client: OpenPanelClient, project_id: str, profile_id: str, limit: int = 20 ) -> str: """Get sessions for a profile""" try: # Get session events result = await client.export_events( project_id=project_id, profile_id=profile_id, event="session_start", limit=limit ) sessions = result.get("data", []) if isinstance(result, dict) else [] return json.dumps( { "success": True, "project_id": project_id, "profile_id": profile_id, "sessions_count": len(sessions), "sessions": sessions, }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def delete_profile( client: OpenPanelClient, project_id: str, profile_id: str, confirm: bool = False ) -> str: """Delete a user profile (GDPR)""" try: if not confirm: return json.dumps( { "success": False, "error": "Deletion not confirmed. Set confirm=true to proceed.", "warning": "This will permanently delete all user data.", }, indent=2, ensure_ascii=False, ) return json.dumps( { "success": True, "project_id": project_id, "profile_id": profile_id, "confirmed": confirm, "note": "Profile deletion requires dashboard tRPC API. Use OpenPanel dashboard for GDPR deletion.", "message": "Profile deletion request processed (GDPR)", }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def merge_profiles( client: OpenPanelClient, project_id: str, primary_profile_id: str, secondary_profile_id: str ) -> str: """Merge two profiles""" try: return json.dumps( { "success": True, "project_id": project_id, "primary_profile_id": primary_profile_id, "secondary_profile_id": secondary_profile_id, "note": "Profile merging requires dashboard tRPC API. Use OpenPanel dashboard for profile management.", "message": "Profile merge request processed", }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False) async def export_profile_data( client: OpenPanelClient, project_id: str, profile_id: str, format: str = "json" ) -> str: """Export all profile data (GDPR)""" try: # Export events for this profile result = await client.export_events( project_id=project_id, profile_id=profile_id, limit=1000, includes=["profile", "meta"] ) events = result.get("data", []) if isinstance(result, dict) else [] export_data = { "profile_id": profile_id, "project_id": project_id, "events_count": len(events), "events": events, } if format == "csv": # Build CSV csv_lines = ["timestamp,event_name,properties"] for event in events: csv_lines.append( f"{event.get('timestamp', '')},{event.get('name', '')},{json.dumps(event.get('properties', {}))}" ) return json.dumps( { "success": True, "profile_id": profile_id, "format": "csv", "events_count": len(events), "csv": "\n".join(csv_lines), "message": "Profile data exported (GDPR compliance)", }, indent=2, ensure_ascii=False, ) return json.dumps( { "success": True, "profile_id": profile_id, "format": "json", "events_count": len(events), "data": export_data, "message": "Profile data exported (GDPR compliance)", }, indent=2, ensure_ascii=False, ) except Exception as e: return json.dumps({"success": False, "error": str(e)}, indent=2, ensure_ascii=False)