""" Notion API simulator. Provides realistic mock responses for Notion API actions. """ from typing import Optional from .base import BaseSimulator from datetime import datetime import uuid class NotionSimulator(BaseSimulator): """Simulator for Notion API.""" def __init__(self): super().__init__('notion') def load_mock_responses(self): """Load Notion mock response templates.""" self.mock_responses = { 'create_page': self._create_page_template, 'read_database': self._read_database_template, 'update_page': self._update_page_template, 'get_page': self._get_page_template, 'query_database': self._query_database_template, 'create_database': self._create_database_template, } def get_required_permissions(self, action: str) -> set[str]: """Get required Notion permissions for an action.""" permissions_map = { 'create_page': {'pages:write'}, 'read_database': {'databases:read'}, 'update_page': {'pages:write'}, 'get_page': {'pages:read'}, 'query_database': {'databases:read'}, 'create_database': {'databases:write'}, } return permissions_map.get(action, set()) def validate_params(self, action: str, params: dict) -> tuple[bool, Optional[str]]: """Validate parameters for Notion actions.""" if action == 'create_page': required = {'parent'} missing = required - set(params.keys()) if missing: return False, f"Missing required parameters: {missing}" if 'database_id' not in params['parent'] and 'page_id' not in params['parent']: return False, "Parent must contain either database_id or page_id" elif action == 'read_database': required = {'database_id'} missing = required - set(params.keys()) if missing: return False, f"Missing required parameters: {missing}" elif action == 'update_page': required = {'page_id'} missing = required - set(params.keys()) if missing: return False, f"Missing required parameters: {missing}" elif action == 'get_page': required = {'page_id'} missing = required - set(params.keys()) if missing: return False, f"Missing required parameters: {missing}" elif action == 'query_database': required = {'database_id'} missing = required - set(params.keys()) if missing: return False, f"Missing required parameters: {missing}" elif action == 'create_database': required = {'parent', 'title', 'properties'} missing = required - set(params.keys()) if missing: return False, f"Missing required parameters: {missing}" else: return False, f"Unknown action: {action}" return True, None def generate_mock_response(self, action: str, params: dict) -> dict: """Generate realistic Notion API response.""" if action not in self.mock_responses: raise ValueError(f"Unknown action: {action}") template_func = self.mock_responses[action] return template_func(params) def _generate_id(self) -> str: """Generate a Notion-style UUID.""" return str(uuid.uuid4()) def _create_page_template(self, params: dict) -> dict: """Mock response for creating a page.""" page_id = self._generate_id() now = datetime.utcnow().isoformat() + "Z" return { "object": "page", "id": page_id, "created_time": now, "last_edited_time": now, "created_by": { "object": "user", "id": self._generate_id() }, "last_edited_by": { "object": "user", "id": self._generate_id() }, "cover": params.get('cover'), "icon": params.get('icon'), "parent": params['parent'], "archived": False, "properties": params.get('properties', { "title": { "id": "title", "type": "title", "title": [ { "type": "text", "text": { "content": "New Page", "link": None } } ] } }), "url": f"https://www.notion.so/{page_id.replace('-', '')}" } def _read_database_template(self, params: dict) -> dict: """Mock response for reading a database.""" database_id = params['database_id'] return { "object": "database", "id": database_id, "created_time": "2025-11-01T00:00:00.000Z", "last_edited_time": datetime.utcnow().isoformat() + "Z", "title": [ { "type": "text", "text": { "content": "Tasks Database" } } ], "properties": { "Name": { "id": "title", "name": "Name", "type": "title", "title": {} }, "Status": { "id": "status", "name": "Status", "type": "select", "select": { "options": [ {"name": "Not started", "color": "default"}, {"name": "In progress", "color": "blue"}, {"name": "Done", "color": "green"} ] } }, "Priority": { "id": "priority", "name": "Priority", "type": "select", "select": { "options": [ {"name": "High", "color": "red"}, {"name": "Medium", "color": "yellow"}, {"name": "Low", "color": "gray"} ] } }, "Due Date": { "id": "due", "name": "Due Date", "type": "date", "date": {} } }, "url": f"https://www.notion.so/{database_id.replace('-', '')}" } def _update_page_template(self, params: dict) -> dict: """Mock response for updating a page.""" page_id = params['page_id'] return { "object": "page", "id": page_id, "created_time": "2025-11-15T10:00:00.000Z", "last_edited_time": datetime.utcnow().isoformat() + "Z", "archived": params.get('archived', False), "properties": params.get('properties', {}), "url": f"https://www.notion.so/{page_id.replace('-', '')}" } def _get_page_template(self, params: dict) -> dict: """Mock response for getting a page.""" page_id = params['page_id'] return { "object": "page", "id": page_id, "created_time": "2025-11-15T10:00:00.000Z", "last_edited_time": "2025-11-25T14:30:00.000Z", "created_by": { "object": "user", "id": self._generate_id() }, "last_edited_by": { "object": "user", "id": self._generate_id() }, "cover": None, "icon": { "type": "emoji", "emoji": "📝" }, "parent": { "type": "database_id", "database_id": self._generate_id() }, "archived": False, "properties": { "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": { "content": "Sample Task" } } ] }, "Status": { "id": "status", "type": "select", "select": { "name": "In progress", "color": "blue" } }, "Priority": { "id": "priority", "type": "select", "select": { "name": "High", "color": "red" } } }, "url": f"https://www.notion.so/{page_id.replace('-', '')}" } def _query_database_template(self, params: dict) -> dict: """Mock response for querying a database.""" # Return a few sample pages pages = [] for i in range(3): page_id = self._generate_id() pages.append({ "object": "page", "id": page_id, "created_time": f"2025-11-{20+i}T10:00:00.000Z", "last_edited_time": datetime.utcnow().isoformat() + "Z", "properties": { "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": {"content": f"Task {i+1}"} } ] }, "Status": { "id": "status", "type": "select", "select": { "name": ["In progress", "Done", "Not started"][i], "color": ["blue", "green", "default"][i] } } }, "url": f"https://www.notion.so/{page_id.replace('-', '')}" }) return { "object": "list", "results": pages, "next_cursor": None, "has_more": False } def _create_database_template(self, params: dict) -> dict: """Mock response for creating a database.""" database_id = self._generate_id() now = datetime.utcnow().isoformat() + "Z" return { "object": "database", "id": database_id, "created_time": now, "last_edited_time": now, "title": params['title'], "properties": params['properties'], "parent": params['parent'], "url": f"https://www.notion.so/{database_id.replace('-', '')}" }