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>
174 lines
5.6 KiB
Python
174 lines
5.6 KiB
Python
"""
|
|
Database Operations Schemas
|
|
|
|
Pydantic models for WordPress database operations including:
|
|
- Database export/import
|
|
- Backup/restore
|
|
- Optimization and repair
|
|
- Search and query operations
|
|
"""
|
|
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
class DatabaseExportParams(BaseModel):
|
|
"""Parameters for database export"""
|
|
|
|
tables: list[str] | None = Field(
|
|
default=None, description="Specific tables to export (default: all tables)"
|
|
)
|
|
exclude_tables: list[str] | None = Field(
|
|
default=None, description="Tables to exclude from export"
|
|
)
|
|
add_drop_table: bool = Field(default=True, description="Include DROP TABLE statements")
|
|
|
|
@classmethod
|
|
@field_validator("tables", "exclude_tables")
|
|
def validate_table_names(cls, v):
|
|
"""Validate table names - no special characters"""
|
|
if v:
|
|
for table in v:
|
|
if not table.replace("_", "").isalnum():
|
|
raise ValueError(f"Invalid table name: {table}")
|
|
return v
|
|
|
|
class DatabaseImportParams(BaseModel):
|
|
"""Parameters for database import"""
|
|
|
|
file_path: str | None = Field(default=None, description="Path to SQL file on server")
|
|
url: str | None = Field(default=None, description="URL to download SQL file from")
|
|
skip_optimization: bool = Field(
|
|
default=False, description="Skip database optimization after import"
|
|
)
|
|
|
|
@classmethod
|
|
@field_validator("url")
|
|
def validate_url(cls, v):
|
|
"""Validate URL format"""
|
|
if v and not v.startswith(("http://", "https://")):
|
|
raise ValueError("URL must start with http:// or https://")
|
|
return v
|
|
|
|
class DatabaseBackupParams(BaseModel):
|
|
"""Parameters for creating database backup"""
|
|
|
|
description: str | None = Field(
|
|
default=None, max_length=255, description="Optional description for this backup"
|
|
)
|
|
compress: bool = Field(default=True, description="Compress backup with gzip")
|
|
include_uploads: bool = Field(
|
|
default=False, description="Also backup wp-content/uploads directory"
|
|
)
|
|
|
|
class DatabaseRestoreParams(BaseModel):
|
|
"""Parameters for restoring database"""
|
|
|
|
backup_id: str | None = Field(default=None, description="Backup ID to restore")
|
|
timestamp: str | None = Field(
|
|
default=None, description="Backup timestamp (alternative to backup_id)"
|
|
)
|
|
confirm: bool = Field(default=False, description="Confirmation required (safety check)")
|
|
|
|
@classmethod
|
|
@field_validator("confirm")
|
|
def validate_confirmation(cls, v):
|
|
"""Require explicit confirmation for restore"""
|
|
if not v:
|
|
raise ValueError("Confirmation required: set confirm=true")
|
|
return v
|
|
|
|
class DatabaseSearchParams(BaseModel):
|
|
"""Parameters for searching database"""
|
|
|
|
search_string: str = Field(
|
|
..., min_length=1, max_length=255, description="String to search for in database"
|
|
)
|
|
tables: list[str] | None = Field(
|
|
default=None, description="Specific tables to search (default: all tables)"
|
|
)
|
|
regex: bool = Field(default=False, description="Use regex pattern matching")
|
|
case_sensitive: bool = Field(default=False, description="Case-sensitive search")
|
|
max_results: int = Field(default=100, ge=1, le=1000, description="Maximum results to return")
|
|
|
|
class DatabaseQueryParams(BaseModel):
|
|
"""Parameters for executing SQL query"""
|
|
|
|
query: str = Field(
|
|
..., min_length=1, max_length=10000, description="SQL query to execute (SELECT only)"
|
|
)
|
|
max_rows: int = Field(default=1000, ge=1, le=10000, description="Maximum rows to return")
|
|
|
|
@classmethod
|
|
@field_validator("query")
|
|
def validate_query(cls, v):
|
|
"""
|
|
Validate query is safe (read-only SELECT)
|
|
|
|
Security: Only allow SELECT, SHOW, DESCRIBE statements
|
|
Prevent: INSERT, UPDATE, DELETE, DROP, ALTER, CREATE, etc.
|
|
"""
|
|
query_upper = v.strip().upper()
|
|
|
|
# Allowed statement types
|
|
allowed_starts = ("SELECT", "SHOW", "DESCRIBE", "DESC", "EXPLAIN")
|
|
|
|
if not any(query_upper.startswith(cmd) for cmd in allowed_starts):
|
|
raise ValueError("Only SELECT, SHOW, DESCRIBE, and EXPLAIN queries allowed")
|
|
|
|
# Forbidden keywords (prevent nested destructive queries)
|
|
forbidden = [
|
|
"INSERT",
|
|
"UPDATE",
|
|
"DELETE",
|
|
"DROP",
|
|
"ALTER",
|
|
"CREATE",
|
|
"TRUNCATE",
|
|
"REPLACE",
|
|
"GRANT",
|
|
"REVOKE",
|
|
]
|
|
|
|
for keyword in forbidden:
|
|
if keyword in query_upper:
|
|
raise ValueError(f"Forbidden keyword in query: {keyword}")
|
|
|
|
return v
|
|
|
|
class DatabaseSizeResponse(BaseModel):
|
|
"""Response model for database size information"""
|
|
|
|
total_size_mb: float = Field(description="Total database size in MB")
|
|
tables: list[dict[str, Any]] = Field(description="List of tables with size information")
|
|
row_count: int = Field(description="Total row count across all tables")
|
|
|
|
class DatabaseTableInfo(BaseModel):
|
|
"""Information about a database table"""
|
|
|
|
name: str
|
|
engine: str
|
|
rows: int
|
|
data_size_mb: float
|
|
index_size_mb: float
|
|
total_size_mb: float
|
|
collation: str
|
|
|
|
class DatabaseRepairResult(BaseModel):
|
|
"""Result of database repair operation"""
|
|
|
|
table: str
|
|
status: str # 'OK', 'Repaired', 'Failed'
|
|
message: str | None = None
|
|
|
|
class DatabaseBackupInfo(BaseModel):
|
|
"""Information about a database backup"""
|
|
|
|
backup_id: str
|
|
timestamp: str
|
|
size_mb: float
|
|
compressed: bool
|
|
description: str | None = None
|
|
location: str
|
|
tables_count: int
|