refactor: 权限组从一组一类型改为一组同时包含readonly+write实例
- 新增 instance_group_members 中间表关联权限组和实例 - InstanceGroup 模型移除旧的 instances relationship,改为通过中间表查询 - Instance 模型保留 group_id FK(兼容)但移除 group relationship - Schema 新增 readonly_instance_ids / write_instance_ids 字段 - InstanceGroupResponse 改为 readonly_instance_count + write_instance_count - InstanceGroupDetailResponse 返回 readonly_instances + write_instances - InstanceAssignRequest 新增 access_type 参数 - API create/update 支持同步写入 instance_group_members - role_permissions 服务更新为使用中间表查询 - 新增迁移 SQL 并应用到 sqlite3.db - 测试全部通过 (20/20)
This commit is contained in:
1 parent
40868c61bf
commit
39d9600e82
8 files changed
+418
-97
No files matched your search
@@ -1,3 +1,3 @@
|
||||
from app.models.instance_group import InstanceGroup, user_groups # noqa: F401
|
||||
from app.models.instance_group import InstanceGroup, user_groups, instance_group_members # noqa: F401
|
||||
from app.models.system_setting import SystemSetting # noqa: F401
|
||||
from app.models.query_history import QueryHistory, QuickQueryModel # noqa: F401
|
||||
@@ -26,12 +26,11 @@ class Instance(Base):
|
||||
excluded_databases = Column(Text, nullable=True) # JSON: ["sys", "information_schema", ...]
|
||||
mask_fields = Column(Text, nullable=True) # JSON: [{table, field, rule}]
|
||||
|
||||
# 权限组关联
|
||||
# 权限组关联 (legacy FK, kept for compat)
|
||||
group_id = Column(Integer, ForeignKey("instance_groups.id", ondelete="SET NULL"), nullable=True)
|
||||
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
# 关系
|
||||
group = relationship("InstanceGroup", back_populates="instances")
|
||||
# 关系 — legacy group relationship removed; use instance_group_members instead
|
||||
workflow_def = relationship("WorkflowDefinition")
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
import json
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey, Table, func
|
||||
from sqlalchemy import Column, Integer, String, Text, Boolean, DateTime, ForeignKey, Table, func, UniqueConstraint
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.core.database import Base
|
||||
@@ -17,6 +17,17 @@ user_groups = Table(
|
||||
Column("permissions", Text, nullable=True), # JSON: 覆盖组默认权限 (legacy, kept for compat)
|
||||
)
|
||||
|
||||
# 实例-权限组关联表(一个权限组可同时包含 readonly 和 write 实例)
|
||||
instance_group_members = Table(
|
||||
"instance_group_members",
|
||||
Base.metadata,
|
||||
Column("id", Integer, primary_key=True, autoincrement=True),
|
||||
Column("group_id", Integer, ForeignKey("instance_groups.id", ondelete="CASCADE"), nullable=False),
|
||||
Column("instance_id", Integer, ForeignKey("instances.id", ondelete="CASCADE"), nullable=False),
|
||||
Column("access_type", String(20), nullable=False, default="readonly"), # readonly / write
|
||||
UniqueConstraint("group_id", "instance_id", "access_type", name="uq_group_instance_access"),
|
||||
)
|
||||
|
||||
|
||||
class InstanceGroup(Base):
|
||||
__tablename__ = "instance_groups"
|
||||
@@ -26,14 +37,13 @@ class InstanceGroup(Base):
|
||||
description = Column(Text, nullable=True)
|
||||
db_type = Column(String(20), nullable=False, default="all") # mysql/redis/pg/mongo/all
|
||||
permissions = Column(Text, nullable=True) # JSON: ["query:select", ...] (legacy, kept for compat)
|
||||
access_type = Column(String(20), nullable=True, default="readonly") # readonly / write
|
||||
access_type = Column(String(20), nullable=True, default="readonly") # legacy, kept for compat
|
||||
allowed_databases = Column(Text, nullable=True) # JSON array of database names; empty = all databases
|
||||
is_active = Column(Boolean, default=True)
|
||||
created_at = Column(DateTime, server_default=func.now())
|
||||
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
|
||||
|
||||
# 关系
|
||||
instances = relationship("Instance", back_populates="group", lazy="selectin")
|
||||
# 关系 — users 保持不变
|
||||
users = relationship("User", secondary=user_groups, back_populates="groups", lazy="selectin")
|
||||
|
||||
# ---- Legacy helpers (kept for backward compatibility) ----
|
||||
|
||||
Reference in new issue
Block a user