sync: 同步 sql-platform-pro 最新代码 — 权限体系安全修复 v0.8.1
- P0: 实例访问控制全线接入权限组 (829测试) - P1: permissions字段激活 + 操作级权限检查 (843测试) - 前端: 删除数据权限页面, 权限组合并为唯一入口 - 新增: CodeMirror编辑器 + 查询模板 + 慢查询分析 - 新增: MongoDB管理页面 + Dashboard增强 - 修复: Pydantic V2迁移 + 前端TS错误修复
This commit is contained in:
1 parent
6fcd9465cf
commit
4c9427e546
105 files changed
+23680
-471
No files matched your search
@@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class AnnouncementCreate(BaseModel):
|
||||
@@ -23,5 +23,4 @@ class AnnouncementResponse(BaseModel):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional, Literal
|
||||
|
||||
|
||||
@@ -41,5 +41,4 @@ class AuditRuleResponse(BaseModel):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -1,5 +1,5 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
@@ -20,5 +20,4 @@ class UserBrief(BaseModel):
|
||||
role: str
|
||||
email: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -1,7 +1,7 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class BackupCreate(BaseModel):
|
||||
@@ -24,5 +24,4 @@ class BackupResponse(BaseModel):
|
||||
completed_at: Optional[datetime] = None
|
||||
remark: Optional[str] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -0,0 +1,101 @@
|
||||
"""执行相关 Schema — 工单执行报告和数据验证模型。"""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class ExecutionReportResponse(BaseModel):
|
||||
"""工单执行报告响应模型。
|
||||
|
||||
包含工单执行后的完整结果信息,用于 API 返回。
|
||||
|
||||
Attributes:
|
||||
status: 执行状态(success / failed / partial)
|
||||
affected_rows: 影响行数(SQL)或成功命令数(Redis)或修改文档数(MongoDB)
|
||||
duration_ms: 执行耗时(毫秒)
|
||||
validation_passed: 验证是否通过
|
||||
warnings: 警告信息列表
|
||||
errors: 错误信息列表
|
||||
raw_output: 原始执行输出
|
||||
before_snapshot_summary: 执行前快照摘要
|
||||
after_snapshot_summary: 执行后快照摘要
|
||||
"""
|
||||
|
||||
status: str = Field(..., description="执行状态: success / failed / partial")
|
||||
affected_rows: int = Field(0, ge=0, description="影响行数")
|
||||
duration_ms: int = Field(0, ge=0, description="执行耗时(毫秒)")
|
||||
validation_passed: bool = Field(True, description="验证是否通过")
|
||||
warnings: List[str] = Field(default_factory=list, description="警告信息")
|
||||
errors: List[str] = Field(default_factory=list, description="错误信息")
|
||||
raw_output: Optional[str] = Field(None, description="原始执行输出")
|
||||
before_snapshot_summary: Optional[str] = Field(None, description="执行前快照摘要")
|
||||
after_snapshot_summary: Optional[str] = Field(None, description="执行后快照摘要")
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"status": "success",
|
||||
"affected_rows": 3,
|
||||
"duration_ms": 145,
|
||||
"validation_passed": True,
|
||||
"warnings": [],
|
||||
"errors": [],
|
||||
"raw_output": "[UPDATE users SET status='active' WHERE ...] 影响 3 行",
|
||||
"before_snapshot_summary": "UPDATE 表 `users`: 将有 3 行被更新 (WHERE: status='inactive')",
|
||||
"after_snapshot_summary": "表 `users`: 当前 150 行",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class RedisCommandRequest(BaseModel):
|
||||
"""Redis 命令请求模型。"""
|
||||
|
||||
command: str = Field(..., min_length=1, description="Redis 命令")
|
||||
db: int = Field(0, ge=0, le=15, description="数据库编号")
|
||||
|
||||
|
||||
class RedisTicketContent(BaseModel):
|
||||
"""Redis 工单内容模型(JSON 格式)。"""
|
||||
|
||||
commands: List[RedisCommandRequest] = Field(
|
||||
..., min_length=1, description="命令列表"
|
||||
)
|
||||
|
||||
|
||||
class MongoOperationRequest(BaseModel):
|
||||
"""MongoDB 操作请求模型。
|
||||
|
||||
支持的操作类型:
|
||||
- insertOne / insertMany: 插入文档
|
||||
- updateOne / updateMany: 更新文档
|
||||
- deleteOne / deleteMany: 删除文档
|
||||
- replaceOne: 替换文档
|
||||
"""
|
||||
|
||||
collection: str = Field(..., min_length=1, description="集合名称")
|
||||
operation: str = Field(
|
||||
...,
|
||||
pattern=r"^(insertOne|insertMany|updateOne|updateMany|deleteOne|deleteMany|replaceOne)$",
|
||||
description="操作类型",
|
||||
)
|
||||
filter: Optional[dict] = Field(None, description="查询条件")
|
||||
update: Optional[dict] = Field(None, description="更新内容")
|
||||
document: Optional[dict] = Field(None, description="插入/替换的文档")
|
||||
documents: Optional[List[dict]] = Field(None, description="批量插入的文档列表")
|
||||
options: Optional[dict] = Field(None, description="额外选项")
|
||||
|
||||
|
||||
class TicketExecuteResponse(BaseModel):
|
||||
"""工单执行响应模型(API 返回)。"""
|
||||
|
||||
id: int = Field(..., description="工单ID")
|
||||
title: str = Field(..., description="工单标题")
|
||||
status: str = Field(..., description="工单状态")
|
||||
db_type: str = Field(..., description="数据库类型")
|
||||
execute_result: Optional[str] = Field(None, description="执行结果摘要")
|
||||
execute_time: Optional[str] = Field(None, description="执行时间")
|
||||
execution_report: Optional[ExecutionReportResponse] = Field(
|
||||
None, description="详细执行报告"
|
||||
)
|
||||
message: Optional[str] = Field(None, description="提示消息")
|
||||
@@ -0,0 +1,21 @@
|
||||
"""影响分析 Pydantic Schemas。"""
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class ImpactAnalysisRequest(BaseModel):
|
||||
instance_id: int
|
||||
database: str
|
||||
sql_content: str
|
||||
|
||||
|
||||
class ImpactAnalysisResponse(BaseModel):
|
||||
sql_type: str
|
||||
estimated_rows: int
|
||||
estimated_duration_ms: int
|
||||
table_size_mb: float
|
||||
table_row_count: int
|
||||
index_usage: List[str]
|
||||
has_full_scan: bool
|
||||
risk_level: str # low / medium / high / critical
|
||||
warnings: List[str]
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional, Literal, List, Any
|
||||
|
||||
|
||||
@@ -64,8 +64,7 @@ class InstanceResponse(BaseModel):
|
||||
mask_fields: Optional[List[dict]] = None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class ConnectionTestResult(BaseModel):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, List
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class InstanceGroupCreate(BaseModel):
|
||||
@@ -31,8 +31,7 @@ class InstanceGroupResponse(BaseModel):
|
||||
instance_count: int = 0
|
||||
user_count: int = 0
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class InstanceGroupDetailResponse(InstanceGroupResponse):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, Any
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class LdapConfigCreate(BaseModel):
|
||||
@@ -38,8 +38,7 @@ class LdapConfigResponse(BaseModel):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class LdapTestRequest(BaseModel):
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
"""数据脱敏规则 Pydantic Schemas — 用于 MaskingRule CRUD 操作。"""
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, Any, List
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class MaskingRuleBase(BaseModel):
|
||||
"""脱敏规则基础 Schema。"""
|
||||
database: str = Field(..., min_length=1, max_length=100, description="数据库名称")
|
||||
table_name: str = Field(..., min_length=1, max_length=100, description="表名,* 表示所有表")
|
||||
column_name: str = Field(..., min_length=1, max_length=100, description="列名,* 表示所有列")
|
||||
mask_type: str = Field(..., pattern=r"^(full|partial|hash|truncate|regex)$")
|
||||
mask_config: Optional[Dict[str, Any]] = Field(default=None, description="脱敏配置(JSON)")
|
||||
is_enabled: bool = Field(default=True, description="是否启用")
|
||||
|
||||
|
||||
class MaskingRuleCreate(MaskingRuleBase):
|
||||
"""创建脱敏规则请求 Schema。"""
|
||||
pass
|
||||
|
||||
|
||||
class MaskingRuleUpdate(BaseModel):
|
||||
"""更新脱敏规则请求 Schema。"""
|
||||
database: Optional[str] = Field(default=None, max_length=100)
|
||||
table_name: Optional[str] = Field(default=None, max_length=100)
|
||||
column_name: Optional[str] = Field(default=None, max_length=100)
|
||||
mask_type: Optional[str] = Field(default=None, pattern=r"^(full|partial|hash|truncate|regex)$")
|
||||
mask_config: Optional[Dict[str, Any]] = Field(default=None, description="脱敏配置(JSON)")
|
||||
is_enabled: Optional[bool] = Field(default=None, description="是否启用")
|
||||
|
||||
|
||||
class MaskingRuleResponse(MaskingRuleBase):
|
||||
"""脱敏规则响应 Schema。"""
|
||||
id: int
|
||||
instance_id: int
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class MaskingRuleBatchCreate(BaseModel):
|
||||
"""批量创建脱敏规则请求 Schema。"""
|
||||
rules: List[MaskingRuleCreate] = Field(..., min_length=1, max_length=100)
|
||||
|
||||
|
||||
class MaskingRuleListResponse(BaseModel):
|
||||
"""脱敏规则列表响应 Schema。"""
|
||||
total: int
|
||||
items: List[MaskingRuleResponse]
|
||||
|
||||
|
||||
class MaskingRuleQueryParams(BaseModel):
|
||||
"""脱敏规则查询参数 Schema。"""
|
||||
database: Optional[str] = None
|
||||
table_name: Optional[str] = None
|
||||
keyword: Optional[str] = None
|
||||
page: int = Field(default=1, ge=1)
|
||||
page_size: int = Field(default=20, ge=1, le=100)
|
||||
@@ -1,6 +1,6 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, Any
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class NotificationChannelCreate(BaseModel):
|
||||
@@ -26,5 +26,4 @@ class NotificationChannelResponse(BaseModel):
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
@@ -1,16 +1,49 @@
|
||||
from typing import Optional, List, Dict, Any
|
||||
from typing import Any, Dict, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class QueryRequest(BaseModel):
|
||||
"""统一查询请求模型。
|
||||
|
||||
支持 MySQL、PostgreSQL、Redis、MongoDB 四种数据库的查询请求。
|
||||
|
||||
Attributes:
|
||||
instance_id: 数据源实例ID
|
||||
database: 目标数据库名/Redis DB号/MongoDB database
|
||||
sql: 查询语句(SQL/Redis命令/MongoDB查询JSON)
|
||||
options: 额外查询选项
|
||||
"""
|
||||
instance_id: int
|
||||
database: Optional[str] = None
|
||||
sql: str = Field(..., min_length=1)
|
||||
sql: str = Field(..., min_length=1, description="查询语句(SQL/Redis命令/MongoDB查询JSON)")
|
||||
options: Optional[Dict[str, Any]] = Field(default=None, description="额外选项(如 limit, offset 等)")
|
||||
|
||||
|
||||
class QueryResult(BaseModel):
|
||||
columns: List[str]
|
||||
rows: List[Dict[str, Any]]
|
||||
total: int
|
||||
elapsed_ms: int
|
||||
truncated: bool = False
|
||||
class UnifiedQueryResult(BaseModel):
|
||||
"""统一查询结果模型。
|
||||
|
||||
兼容 MySQL、PostgreSQL、Redis、MongoDB 四种数据库的返回格式。
|
||||
SQL 数据库返回标准表格格式,Redis/MongoDB 同时返回格式化表格和原始结果。
|
||||
|
||||
Attributes:
|
||||
columns: SQL表格列名列表
|
||||
rows: SQL表格行数据列表(字典格式)
|
||||
raw_result: Redis/MongoDB原始结果
|
||||
total: 总行数/总文档数
|
||||
elapsed_ms: 执行耗时(毫秒)
|
||||
truncated: 是否因超过行数限制而截断
|
||||
db_type: 数据库类型(mysql/postgres/redis/mongo)
|
||||
query_type: 查询类型(SELECT/GET/find等)
|
||||
"""
|
||||
columns: List[str] = Field(default=[], description="SQL表格列名")
|
||||
rows: List[Dict[str, Any]] = Field(default=[], description="SQL表格行数据")
|
||||
raw_result: Any = Field(default=None, description="Redis/MongoDB原始结果")
|
||||
total: int = Field(default=0, description="总行数")
|
||||
elapsed_ms: int = Field(default=0, description="执行耗时(毫秒)")
|
||||
truncated: bool = Field(default=False, description="是否截断")
|
||||
db_type: str = Field(default="", description="数据库类型")
|
||||
query_type: str = Field(default="", description="查询类型")
|
||||
|
||||
|
||||
# 保留旧名兼容
|
||||
QueryResult = UnifiedQueryResult
|
||||
@@ -0,0 +1,33 @@
|
||||
"""回滚操作 Pydantic Schemas — 用于回滚 SQL 生成和预览。"""
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class RollbackPreviewRequest(BaseModel):
|
||||
"""预览回滚 SQL 请求 Schema。"""
|
||||
instance_id: int = Field(..., description="数据源实例ID")
|
||||
database: str = Field(..., min_length=1, max_length=100, description="数据库名称")
|
||||
sql: str = Field(..., min_length=1, description="原始 DML 语句")
|
||||
|
||||
|
||||
class RollbackPreviewResponse(BaseModel):
|
||||
"""预览回滚 SQL 响应 Schema。"""
|
||||
original_sql: str = Field(..., description="原始 SQL")
|
||||
rollback_sql: str = Field(..., description="生成的回滚 SQL")
|
||||
sql_type: Optional[str] = Field(default=None, description="SQL 类型 (INSERT/UPDATE/DELETE)")
|
||||
warning: Optional[str] = Field(default=None, description="警告信息")
|
||||
|
||||
|
||||
class RollbackGenerateRequest(BaseModel):
|
||||
"""为工单生成回滚 SQL 请求 Schema。"""
|
||||
auto_save: bool = Field(default=True, description="是否自动保存到工单")
|
||||
|
||||
|
||||
class RollbackGenerateResponse(BaseModel):
|
||||
"""生成回滚 SQL 响应 Schema。"""
|
||||
ticket_id: int = Field(..., description="工单ID")
|
||||
original_sql: str = Field(..., description="原始 SQL")
|
||||
rollback_sql: str = Field(..., description="生成的回滚 SQL")
|
||||
sql_type: Optional[str] = Field(default=None, description="SQL 类型")
|
||||
saved: bool = Field(default=False, description="是否已保存到工单")
|
||||
warning: Optional[str] = Field(default=None, description="警告信息")
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional, Literal
|
||||
|
||||
|
||||
@@ -40,8 +40,7 @@ class TicketResponse(BaseModel):
|
||||
review_time: Optional[datetime] = None
|
||||
execute_time: Optional[datetime] = None
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class TicketListParams(BaseModel):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@@ -31,8 +31,7 @@ class UserResponse(BaseModel):
|
||||
last_login: Optional[datetime] = None
|
||||
created_at: datetime
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class PasswordChange(BaseModel):
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
"""审批流程 Pydantic Schemas。"""
|
||||
from typing import List, Optional
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class WorkflowStepCreate(BaseModel):
|
||||
step_number: int
|
||||
name: str
|
||||
step_type: str = "serial" # serial / parallel / any_one
|
||||
approver_role: Optional[str] = None
|
||||
approver_ids: Optional[str] = None # JSON list
|
||||
is_required: bool = True
|
||||
timeout_hours: int = 24
|
||||
auto_approve_on_timeout: bool = False
|
||||
|
||||
|
||||
class WorkflowStepResponse(WorkflowStepCreate):
|
||||
id: int
|
||||
workflow_id: int
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class WorkflowCreate(BaseModel):
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
is_default: bool = False
|
||||
steps: List[WorkflowStepCreate]
|
||||
|
||||
|
||||
class WorkflowUpdate(BaseModel):
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
|
||||
class WorkflowResponse(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
description: Optional[str]
|
||||
is_default: bool
|
||||
is_active: bool
|
||||
created_at: Optional[datetime]
|
||||
steps: List[WorkflowStepResponse]
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class TicketApprovalResponse(BaseModel):
|
||||
id: int
|
||||
ticket_id: int
|
||||
step_number: int
|
||||
step_name: Optional[str]
|
||||
approver_id: Optional[int]
|
||||
approver_role: Optional[str]
|
||||
approver_name: Optional[str] = None
|
||||
action: str
|
||||
comment: Optional[str]
|
||||
created_at: Optional[datetime]
|
||||
updated_at: Optional[datetime]
|
||||
|
||||
|
||||
class ApprovalProgressResponse(BaseModel):
|
||||
ticket_id: int
|
||||
current_step: int
|
||||
total_steps: int
|
||||
status: str
|
||||
steps: List[dict]
|
||||
|
||||
|
||||
class ApprovalActionRequest(BaseModel):
|
||||
comment: Optional[str] = ""
|
||||
|
||||
|
||||
class TransferRequest(BaseModel):
|
||||
to_user_id: int
|
||||
comment: Optional[str] = ""
|
||||
Reference in new issue
Block a user