diff --git a/apps/models/app.py b/apps/models/app.py index b774a5ee0610317d404c8c530dbe2c01a9e57824..0ba6b08eecbc635334ccd88d42521732d4898555 100644 --- a/apps/models/app.py +++ b/apps/models/app.py @@ -16,13 +16,13 @@ class App(Base): """应用""" __tablename__ = "framework_app" - name: Mapped[str] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False) """应用名称""" - description: Mapped[str] = mapped_column(String(2000)) + description: Mapped[str] = mapped_column(String(2000), nullable=False) """应用描述""" - author: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) + author: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) """应用作者""" - type: Mapped[AppType] = mapped_column(Enum(AppType)) + type: Mapped[AppType] = mapped_column(Enum(AppType), nullable=False) """应用类型""" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4) """应用ID""" @@ -31,13 +31,16 @@ class App(Base): default_factory=lambda: datetime.now(tz=UTC), onupdate=lambda: datetime.now(tz=UTC), index=True, + nullable=False, ) """应用更新时间""" - iconPath: Mapped[str] = mapped_column(String(255), default="") # noqa: N815 + iconPath: Mapped[str] = mapped_column(String(255), default="", nullable=False) # noqa: N815 """应用图标路径""" - isPublished: Mapped[bool] = mapped_column(Boolean, default=False) # noqa: N815 + isPublished: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # noqa: N815 """是否发布""" - permission: Mapped[PermissionType] = mapped_column(Enum(PermissionType), default=PermissionType.PUBLIC) + permission: Mapped[PermissionType] = mapped_column( + Enum(PermissionType), default=PermissionType.PUBLIC, nullable=False, + ) """权限类型""" __table_args__ = ( Index("idx_published_updated_at", "isPublished", "updatedAt"), @@ -49,11 +52,11 @@ class AppACL(Base): """应用权限""" __tablename__ = "framework_app_acl" - appId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_app.id")) # noqa: N815 + appId: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("framework_app.id"), primary_key=True) # noqa: N815 """关联的应用ID""" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False, index=True) # noqa: N815 """用户名""" - action: Mapped[str] = mapped_column(String(255), default="") + action: Mapped[str] = mapped_column(String(255), default="", index=True, nullable=False) """操作类型(读/写)""" @@ -63,9 +66,9 @@ class AppHashes(Base): __tablename__ = "framework_app_hashes" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - appId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_app.id")) # noqa: N815 + appId: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("framework_app.id"), nullable=False) # noqa: N815 """关联的应用ID""" - filePath: Mapped[str] = mapped_column(String(255)) # noqa: N815 + filePath: Mapped[str] = mapped_column(String(255), nullable=False) # noqa: N815 """文件路径""" - hash: Mapped[str] = mapped_column(String(255)) + hash: Mapped[str] = mapped_column(String(255), nullable=False) """哈希值""" diff --git a/apps/models/blacklist.py b/apps/models/blacklist.py index c5358062ebec4bdd0b813e74d2e87d71cabbe507..9acf1fc1f31fde7add8aec5d2275247692a5906a 100644 --- a/apps/models/blacklist.py +++ b/apps/models/blacklist.py @@ -3,7 +3,8 @@ import uuid from datetime import UTC, datetime -from sqlalchemy import BigInteger, Boolean, DateTime, ForeignKey, String +from sqlalchemy import BigInteger, Boolean, DateTime, ForeignKey, String, Text +from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from .base import Base @@ -15,21 +16,24 @@ class Blacklist(Base): __tablename__ = "framework_blacklist" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - recordId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_record.id")) # noqa: N815 + recordId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_record.id"), nullable=False, index=True, + ) """关联的问答对ID""" - question: Mapped[str] = mapped_column(String(65535)) + question: Mapped[str] = mapped_column(Text, nullable=False) """黑名单问题""" - answer: Mapped[str | None] = mapped_column(String(65535), default=None) + answer: Mapped[str | None] = mapped_column(Text, default=None, nullable=False) """应做出的固定回答""" - isAudited: Mapped[bool] = mapped_column(Boolean, default=False) # noqa: N815 + isAudited: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # noqa: N815 """黑名单是否生效""" - reasonType: Mapped[str] = mapped_column(String(255), default="") # noqa: N815 + reasonType: Mapped[str] = mapped_column(String(255), default="", nullable=False) # noqa: N815 """举报类型""" - reason: Mapped[str] = mapped_column(String(65535), default="") + reason: Mapped[str] = mapped_column(Text, default="", nullable=False) """举报原因""" updatedAt: Mapped[DateTime] = mapped_column( # noqa: N815 DateTime, default_factory=lambda: datetime.now(tz=UTC), init=False, + nullable=False, ) """更新时间""" diff --git a/apps/models/comment.py b/apps/models/comment.py index 85394ce80778b4e7c1ff687adfaf54369fbea84f..a0a1ad2257f062fa4061087fe5b11f9233f95826 100644 --- a/apps/models/comment.py +++ b/apps/models/comment.py @@ -4,6 +4,7 @@ import uuid from datetime import UTC, datetime from sqlalchemy import ARRAY, BigInteger, DateTime, Enum, ForeignKey, String +from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from apps.schemas.enum_var import CommentType @@ -17,19 +18,22 @@ class Comment(Base): __tablename__ = "framework_comment" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - recordId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_record.id")) # noqa: N815 + recordId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_record.id"), nullable=False, index=True, + ) """问答对ID""" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户名""" - commentType: Mapped[CommentType] = mapped_column(Enum(CommentType)) # noqa: N815 + commentType: Mapped[CommentType] = mapped_column(Enum(CommentType), nullable=False) # noqa: N815 """点赞点踩""" - feedbackType: Mapped[list[str]] = mapped_column(ARRAY(String(100))) # noqa: N815 + feedbackType: Mapped[list[str]] = mapped_column(ARRAY(String(100)), nullable=False) # noqa: N815 """投诉类别""" - feedbackLink: Mapped[str] = mapped_column(String(1000)) # noqa: N815 + feedbackLink: Mapped[str] = mapped_column(String(1000), nullable=False) # noqa: N815 """投诉链接""" - feedbackContent: Mapped[str] = mapped_column(String(1000)) # noqa: N815 + feedbackContent: Mapped[str] = mapped_column(String(1000), nullable=False) # noqa: N815 """投诉内容""" createdAt: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), + nullable=False, ) """评论创建时间""" diff --git a/apps/models/conversation.py b/apps/models/conversation.py index d3522c8341374c564c38a6c83593eec4104f2119..5b411ba25659add122013c050332985740009590 100644 --- a/apps/models/conversation.py +++ b/apps/models/conversation.py @@ -17,11 +17,13 @@ class Conversation(Base): """对话""" __tablename__ = "framework_conversation" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户名""" - appId: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("framework_app.id"), nullable=True) # noqa: N815 + appId: Mapped[uuid.UUID | None] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_app.id"), nullable=True, + ) """对话使用的App的ID""" - title: Mapped[str] = mapped_column(String(255), default=NEW_CHAT) + title: Mapped[str] = mapped_column(String(255), default=NEW_CHAT, nullable=False) """对话标题""" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default_factory=lambda: uuid.uuid4(), @@ -29,9 +31,10 @@ class Conversation(Base): """对话ID""" createdAt: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), + nullable=False, index=True, ) """对话创建时间""" - isTemporary: Mapped[bool] = mapped_column(Boolean, default=False) # noqa: N815 + isTemporary: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) # noqa: N815 """是否为临时对话""" @@ -48,11 +51,15 @@ class ConversationDocument(Base): __tablename__ = "framework_conversation_document" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - conversationId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_conversation.id")) # noqa: N815 + conversationId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_conversation.id"), nullable=False, index=True, + ) """对话ID""" - documentId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_document.id")) # noqa: N815 + documentId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_document.id"), nullable=False, index=True, + ) """文件ID""" - isUnused: Mapped[bool] = mapped_column(Boolean, default=True) # noqa: N815 + isUnused: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) # noqa: N815 """是否未使用""" associated: Mapped[ConvDocAssociated | None] = mapped_column( Enum(ConvDocAssociated), nullable=True, default=None, diff --git a/apps/models/document.py b/apps/models/document.py index 5f1419569ca794fe8563f1fa8e2902c6e66bbc06..6fe501f8b71ec1c3cdf64590ba7911158f61a0e8 100644 --- a/apps/models/document.py +++ b/apps/models/document.py @@ -14,15 +14,17 @@ class Document(Base): """文件""" __tablename__ = "framework_document" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户ID""" - name: Mapped[str] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False) """文件名称""" - extension: Mapped[str] = mapped_column(String(100)) + extension: Mapped[str] = mapped_column(String(100), nullable=False) """文件类型""" - size: Mapped[float] = mapped_column(Float) + size: Mapped[float] = mapped_column(Float, nullable=False) """文件大小""" - conversationId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_conversation.id")) # noqa: N815 + conversationId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_conversation.id"), nullable=False, + ) """所属对话的ID""" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4, @@ -31,6 +33,7 @@ class Document(Base): createdAt: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), + nullable=False, ) """文件的创建时间""" __table_args__ = ( diff --git a/apps/models/flow.py b/apps/models/flow.py index 188ce2c546da35b7f555170bb371a1387f76dff5..60be2e1efbd36757bcfb061ea7bdc6981b8fd801 100644 --- a/apps/models/flow.py +++ b/apps/models/flow.py @@ -3,7 +3,7 @@ import uuid from datetime import UTC, datetime -from sqlalchemy import Boolean, DateTime, ForeignKey, Index, String +from sqlalchemy import Boolean, DateTime, ForeignKey, Index, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column @@ -14,17 +14,22 @@ class Flow(Base): """Flow""" __tablename__ = "framework_flow" - appId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_app.id")) # noqa: N815 + appId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), + ForeignKey("framework_app.id"), + nullable=False, + index=True, + ) """所属App的ID""" - name: Mapped[str] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False) """Flow的名称""" - description: Mapped[str] = mapped_column(String(2000)) + description: Mapped[str] = mapped_column(Text, nullable=False) """Flow的描述""" - path: Mapped[str] = mapped_column(String(255)) + path: Mapped[str] = mapped_column(String(255), nullable=False) """Flow的路径""" - debug: Mapped[bool] = mapped_column(Boolean, default=False) + debug: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) """是否经过调试""" - enabled: Mapped[bool] = mapped_column(Boolean, default=True) + enabled: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False) """是否启用""" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4, @@ -34,23 +39,10 @@ class Flow(Base): DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), onupdate=lambda: datetime.now(tz=UTC), + nullable=False, ) """Flow的更新时间""" __table_args__ = ( Index("idx_app_id_id", "appId", "id"), Index("idx_app_id_name", "appId", "name"), ) - - -class FlowContext(Base): - """Flow上下文""" - - __tablename__ = "framework_flow_context" - flowId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_flow.id"), index=True) # noqa: N815 - """所属Flow的ID""" - context: Mapped[str] = mapped_column(String(2000)) - """上下文""" - id: Mapped[uuid.UUID] = mapped_column( - UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4, - ) - """Flow上下文的ID""" diff --git a/apps/models/llm.py b/apps/models/llm.py index dc0216c6b952074083f5e31fc8f324e008191374..0c44797dbae3b3270312b6a0bedd51cdb3b82c74 100644 --- a/apps/models/llm.py +++ b/apps/models/llm.py @@ -17,21 +17,22 @@ class LLMData(Base): __tablename__ = "framework_llm" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub"), index=True) # noqa: N815 + userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub"), index=True, nullable=False) # noqa: N815 """添加LLM所属的用户""" - icon: Mapped[str] = mapped_column(String(1000), default=llm_provider_dict["ollama"]["icon"]) + icon: Mapped[str] = mapped_column(String(1000), default=llm_provider_dict["ollama"]["icon"], nullable=False) """LLM图标路径""" - openaiBaseUrl: Mapped[str] = mapped_column(String(300), default=config.llm.endpoint) # noqa: N815 + openaiBaseUrl: Mapped[str] = mapped_column(String(300), default=config.llm.endpoint, nullable=False) # noqa: N815 """LLM URL地址""" - openaiAPIKey: Mapped[str] = mapped_column(String(300), default=config.llm.key) # noqa: N815 + openaiAPIKey: Mapped[str] = mapped_column(String(300), default=config.llm.key, nullable=False) # noqa: N815 """LLM API Key""" - modelName: Mapped[str] = mapped_column(String(300), default=config.llm.model) # noqa: N815 + modelName: Mapped[str] = mapped_column(String(300), default=config.llm.model, nullable=False) # noqa: N815 """LLM模型名""" - maxToken: Mapped[int] = mapped_column(Integer, default=config.llm.max_tokens) # noqa: N815 + maxToken: Mapped[int] = mapped_column(Integer, default=config.llm.max_tokens, nullable=False) # noqa: N815 """LLM最大Token数量""" createdAt: Mapped[DateTime] = mapped_column( # noqa: N815 DateTime, default_factory=lambda: datetime.now(tz=UTC), init=False, + nullable=False, ) """添加LLM的时间""" diff --git a/apps/models/mcp.py b/apps/models/mcp.py index 83d3d8f7634298463c17afe42a5210117ccfc8f2..984cd0496550b80f0e098f1fb2ee31bc4356db56 100644 --- a/apps/models/mcp.py +++ b/apps/models/mcp.py @@ -6,7 +6,7 @@ from enum import Enum as PyEnum from hashlib import shake_128 from typing import Any -from sqlalchemy import BigInteger, DateTime, Enum, ForeignKey, String +from sqlalchemy import BigInteger, DateTime, Enum, ForeignKey, String, Text from sqlalchemy.dialects.postgresql import JSONB from sqlalchemy.orm import Mapped, mapped_column @@ -33,27 +33,31 @@ class MCPInfo(Base): """MCP""" __tablename__ = "framework_mcp" - name: Mapped[str] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False) """MCP 名称""" - overview: Mapped[str] = mapped_column(String(2000)) + overview: Mapped[str] = mapped_column(String(2000), nullable=False) """MCP 概述""" - description: Mapped[str] = mapped_column(String(65535)) + description: Mapped[str] = mapped_column(Text, nullable=False) """MCP 描述""" - author: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub")) + author: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) """MCP 创建者""" - config: Mapped[dict[str, Any]] = mapped_column(JSONB) - """MCP 配置""" id: Mapped[str] = mapped_column(String(100), primary_key=True) """MCP ID""" updatedAt: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), onupdate=lambda: datetime.now(tz=UTC), + nullable=False, + index=True, ) """MCP 更新时间""" - status: Mapped[MCPInstallStatus] = mapped_column(Enum(MCPInstallStatus), default=MCPInstallStatus.INSTALLING) + status: Mapped[MCPInstallStatus] = mapped_column( + Enum(MCPInstallStatus), default=MCPInstallStatus.INSTALLING, nullable=False, + ) """MCP 状态""" - mcpType: Mapped[MCPType] = mapped_column(Enum(MCPType), default=MCPType.STDIO) # noqa: N815 + mcpType: Mapped[MCPType] = mapped_column( # noqa: N815 + Enum(MCPType), default=MCPType.STDIO, nullable=False, + ) """MCP 类型""" @@ -62,10 +66,10 @@ class MCPActivated(Base): __tablename__ = "framework_mcp_activated" mcpId: Mapped[str] = mapped_column( # noqa: N815 - String(100), ForeignKey("framework_mcp.id"), index=True, unique=True, + String(100), ForeignKey("framework_mcp.id"), index=True, nullable=False, ) """MCP ID""" - userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户ID""" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" @@ -76,16 +80,16 @@ class MCPTools(Base): __tablename__ = "framework_mcp_tools" mcpId: Mapped[str] = mapped_column( # noqa: N815 - String(100), ForeignKey("framework_mcp.id"), index=True, + String(100), ForeignKey("framework_mcp.id"), index=True, nullable=False, ) """MCP ID""" - toolName: Mapped[str] = mapped_column(String(255)) # noqa: N815 + toolName: Mapped[str] = mapped_column(String(255), nullable=False) # noqa: N815 """MCP 工具名称""" - description: Mapped[str] = mapped_column(String(65535)) + description: Mapped[str] = mapped_column(Text, nullable=False) """MCP 工具描述""" - inputSchema: Mapped[dict[str, Any]] = mapped_column(JSONB) # noqa: N815 + inputSchema: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) # noqa: N815 """MCP 工具输入参数""" - outputSchema: Mapped[dict[str, Any]] = mapped_column(JSONB) # noqa: N815 + outputSchema: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) # noqa: N815 """MCP 工具输出参数""" id: Mapped[str] = mapped_column( String(32), diff --git a/apps/models/node.py b/apps/models/node.py index fe4e607fdbcc7ee4546ee3058867e9cf11354217..f89f6b1acca859b299c2cb53910792758b31cdac 100644 --- a/apps/models/node.py +++ b/apps/models/node.py @@ -15,32 +15,28 @@ class NodeInfo(Base): """节点""" __tablename__ = "framework_node" - name: Mapped[str] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False) """节点名称""" - description: Mapped[str] = mapped_column(String(2000)) + description: Mapped[str] = mapped_column(String(2000), nullable=False) """节点描述""" - serviceId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_service.id")) # noqa: N815 + serviceId: Mapped[uuid.UUID | None] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_service.id"), nullable=True, + ) """所属服务ID""" - callId: Mapped[str] = mapped_column(ForeignKey("framework_call.id")) # noqa: N815 + callId: Mapped[str] = mapped_column(String(50), nullable=False) # noqa: N815 """所属CallID""" - knownParams: Mapped[dict[str, Any]] = mapped_column(JSONB) # noqa: N815 + knownParams: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) # noqa: N815 """已知的用于Call部分的参数,独立于输入和输出之外""" - overrideInput: Mapped[dict[str, Any]] = mapped_column(JSONB) # noqa: N815 + overrideInput: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) # noqa: N815 """Node的输入Schema;用于描述Call的参数中特定的字段""" - overrideOutput: Mapped[dict[str, Any]] = mapped_column(JSONB) # noqa: N815 + overrideOutput: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) # noqa: N815 """Node的输出Schema;用于描述Call的输出中特定的字段""" - id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4) + id: Mapped[str] = mapped_column(String(50), primary_key=True, default_factory=lambda: str(uuid.uuid4())) """节点ID""" updatedAt: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), onupdate=lambda: datetime.now(tz=UTC), + nullable=False, ) """节点更新时间""" - - -class CallInfo(Base): - """工具信息""" - - __tablename__ = "framework_call" - diff --git a/apps/models/record.py b/apps/models/record.py index ee2a352a6d5dabec08be7b28d86d9fc5392d30c9..008678f955b932d30cb503cf4725aaa601256367 100644 --- a/apps/models/record.py +++ b/apps/models/record.py @@ -2,9 +2,10 @@ import uuid from datetime import UTC, datetime +from enum import Enum as PyEnum from typing import Any -from sqlalchemy import VARCHAR, BigInteger, DateTime, Float, ForeignKey, Integer, String +from sqlalchemy import BigInteger, DateTime, Enum, Float, ForeignKey, Integer, String, Text from sqlalchemy.dialects.postgresql import JSONB, UUID from sqlalchemy.orm import Mapped, mapped_column @@ -15,22 +16,26 @@ class Record(Base): """问答对""" __tablename__ = "framework_record" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户名""" - conversationId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_conversation.id")) # noqa: N815 + conversationId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_conversation.id"), nullable=False, + ) """对话ID""" - taskId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_task.id")) # noqa: N815 + taskId: Mapped[uuid.UUID] = mapped_column( # noqa: N815 + UUID(as_uuid=True), ForeignKey("framework_task.id"), nullable=False, + ) """任务ID""" - content: Mapped[str] = mapped_column(VARCHAR) + content: Mapped[str] = mapped_column(Text, nullable=False) """问答对数据""" - key: Mapped[dict[str, Any]] = mapped_column(JSONB) + key: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False) """问答对密钥""" id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, default_factory=lambda: uuid.uuid4(), ) """问答对ID""" createdAt: Mapped[datetime] = mapped_column( # noqa: N815 - DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), + DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), nullable=False, ) """问答对创建时间""" @@ -39,33 +44,43 @@ class RecordMetadata(Base): """问答对元数据""" __tablename__ = "framework_record_metadata" - id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) - """主键ID""" - record_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_record.id"), unique=True) + record_id: Mapped[uuid.UUID] = mapped_column( + UUID(as_uuid=True), ForeignKey("framework_record.id"), primary_key=True, + ) """问答对ID""" - timeCost: Mapped[float] = mapped_column(Float, default=0) # noqa: N815 + timeCost: Mapped[float] = mapped_column(Float, default=0, nullable=False) # noqa: N815 """问答对耗时""" - inputTokens: Mapped[int] = mapped_column(Integer, default=0) # noqa: N815 + inputTokens: Mapped[int] = mapped_column(Integer, default=0, nullable=False) # noqa: N815 """问答对输入token数""" - outputTokens: Mapped[int] = mapped_column(Integer, default=0) # noqa: N815 + outputTokens: Mapped[int] = mapped_column(Integer, default=0, nullable=False) # noqa: N815 """问答对输出token数""" - featureSwitch: Mapped[dict[str, Any]] = mapped_column(JSONB, default={}) # noqa: N815 + featureSwitch: Mapped[dict[str, Any]] = mapped_column(JSONB, default={}, nullable=False) # noqa: N815 """问答对功能开关""" +class FootNoteType(str, PyEnum): + """脚注类型""" + + RAG = "rag" + FRAMEWORK = "framework" + WEB = "web" + + class RecordFootNote(Base): """问答对脚注""" __tablename__ = "framework_record_foot_note" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - record_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_record.id")) + record_id: Mapped[uuid.UUID] = mapped_column( + UUID(as_uuid=True), ForeignKey("framework_record.id"), nullable=False, + ) """问答对ID""" - releatedId: Mapped[str] = mapped_column(String, default="") # noqa: N815 + releatedId: Mapped[str] = mapped_column(String(64), default="", nullable=False) # noqa: N815 """脚注数字""" - insertPosition: Mapped[int] = mapped_column(Integer, default=0) # noqa: N815 + insertPosition: Mapped[int] = mapped_column(Integer, default=0, nullable=False) # noqa: N815 """插入位置""" - footSource: Mapped[str] = mapped_column(String, default="") # noqa: N815 + footSource: Mapped[str] = mapped_column(String(4096), default="", nullable=False) # noqa: N815 """脚注来源""" - footType: Mapped[str] = mapped_column(String, default="") # noqa: N815 + footType: Mapped[FootNoteType] = mapped_column(Enum(FootNoteType), default=FootNoteType.RAG, nullable=False) # noqa: N815 """脚注类型""" diff --git a/apps/models/service.py b/apps/models/service.py index 8f51f86659e63b009147a2bd658c162ffd617a3a..390f93553fda02b0a4c977a4cd0b3629886109f9 100644 --- a/apps/models/service.py +++ b/apps/models/service.py @@ -16,23 +16,26 @@ class Service(Base): """插件""" __tablename__ = "framework_service" - name: Mapped[str] = mapped_column(String(255)) + name: Mapped[str] = mapped_column(String(255), nullable=False) """插件名称""" - description: Mapped[str] = mapped_column(String(2000)) + description: Mapped[str] = mapped_column(String(2000), nullable=False) """插件描述""" - author: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) + author: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) """插件作者""" updatedAt: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), default_factory=lambda: datetime.now(tz=UTC), onupdate=lambda: datetime.now(tz=UTC), + nullable=False, ) """插件更新时间""" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default_factory=uuid.uuid4) """插件ID""" - iconPath: Mapped[str] = mapped_column(String(255), default="") # noqa: N815 + iconPath: Mapped[str] = mapped_column(String(255), default="", nullable=False) # noqa: N815 """插件图标路径""" - permission: Mapped[PermissionType] = mapped_column(Enum(PermissionType), default=PermissionType.PUBLIC) + permission: Mapped[PermissionType] = mapped_column( + Enum(PermissionType), default=PermissionType.PUBLIC, nullable=False, + ) """权限类型""" @@ -40,12 +43,14 @@ class ServiceACL(Base): """插件权限""" __tablename__ = "framework_service_acl" - serviceId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_service.id")) # noqa: N815 + serviceId: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("framework_service.id"), nullable=False) # noqa: N815 """关联的插件ID""" - userSub: Mapped[str] = mapped_column(ForeignKey("framework_user.userSub")) # noqa: N815 + userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户名""" - action: Mapped[str] = mapped_column(String(255), default="") + action: Mapped[str] = mapped_column(String(255), default="", nullable=False) """操作类型(读/写)""" + id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) + """主键ID""" class ServiceHashes(Base): @@ -54,9 +59,9 @@ class ServiceHashes(Base): __tablename__ = "framework_service_hashes" id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, init=False) """主键ID""" - serviceId: Mapped[uuid.UUID] = mapped_column(ForeignKey("framework_service.id")) # noqa: N815 + serviceId: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("framework_service.id"), nullable=False) # noqa: N815 """关联的插件ID""" - filePath: Mapped[str] = mapped_column(String(255)) # noqa: N815 + filePath: Mapped[str] = mapped_column(String(255), nullable=False) # noqa: N815 """文件路径""" - hash: Mapped[str] = mapped_column(String(255)) + hash: Mapped[str] = mapped_column(String(255), nullable=False) """哈希值""" diff --git a/apps/models/session.py b/apps/models/session.py index b08149e33445ae2867556fe2a67b2a9d4f25a58a..d17585fa50c9d4a06adbc8529e2bb6370230475e 100644 --- a/apps/models/session.py +++ b/apps/models/session.py @@ -25,13 +25,11 @@ class Session(Base): __tablename__ = "framework_session" userSub: Mapped[str] = mapped_column(String(50), ForeignKey("framework_user.userSub"), nullable=False) # noqa: N815 """用户名""" - ip: Mapped[str] = mapped_column(String(255), nullable=False) + ip: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None) """IP地址""" - nonce: Mapped[str] = mapped_column(String(255), nullable=False) - """随机值""" - pluginId: Mapped[str] = mapped_column(String(255), nullable=False) # noqa: N815 + pluginId: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None) # noqa: N815 """(AccessToken) 插件ID""" - token: Mapped[str] = mapped_column(String(2000), nullable=False) + token: Mapped[str | None] = mapped_column(String(2000), nullable=True, default=None) """(AccessToken) Token信息""" validUntil: Mapped[datetime] = mapped_column( # noqa: N815 DateTime(timezone=True), diff --git a/apps/routers/mcp_service.py b/apps/routers/mcp_service.py index 159e0f9877272e0d0c2f13247b0de9b452aaabec..ab01d52c59523b59849c1fb6fbc0873f9744d6c7 100644 --- a/apps/routers/mcp_service.py +++ b/apps/routers/mcp_service.py @@ -5,7 +5,7 @@ import json import logging from typing import Annotated -from fastapi import APIRouter, Depends, File, HTTPException, Path, Query, Request, UploadFile, status +from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request, UploadFile, status from fastapi.responses import JSONResponse from apps.dependency.user import verify_admin, verify_personal_token, verify_session @@ -50,17 +50,16 @@ admin_router = APIRouter( @router.get("", response_model=GetMCPServiceListRsp | ResponseData) async def get_mcpservice_list( - user_sub: Annotated[str, Depends(get_user)], - search_type: Annotated[ - SearchType, Query(..., alias="searchType", description="搜索类型"), - ] = SearchType.ALL, - keyword: Annotated[str | None, Query(..., alias="keyword", description="搜索关键字")] = None, - page: Annotated[int, Query(..., alias="page", ge=1, description="页码")] = 1, + request: Request, + searchType: SearchType = SearchType.ALL, # noqa: N803 + keyword: str | None = None, + page: Annotated[int, Query(ge=1)] = 1, ) -> JSONResponse: """获取服务列表""" + user_sub = request.state.user_sub try: service_cards = await MCPServiceManager.fetch_mcp_services( - search_type, + searchType, user_sub, keyword, page, @@ -132,7 +131,7 @@ async def create_or_update_mcpservice( ).model_dump(exclude_none=True, by_alias=True)) -@router.get("/{serviceId}", response_model=GetMCPServiceDetailRsp) +@admin_router.get("/{serviceId}", response_model=GetMCPServiceDetailRsp) async def get_service_detail( request: Request, service_id: Annotated[str, Path(..., alias="serviceId", description="服务ID")], @@ -140,10 +139,6 @@ async def get_service_detail( edit: Annotated[bool, Query(..., description="是否为编辑模式")] = False, ) -> JSONResponse: """获取MCP服务详情""" - # 检查用户权限 - if edit: - await _check_user_admin(user_sub) - # 获取MCP服务详情 try: data = await MCPServiceManager.get_mcp_service(service_id) @@ -277,18 +272,18 @@ async def update_mcp_icon( ) -@router.post("/{serviceId}", response_model=ActiveMCPServiceRsp) +@router.post("/{mcpId}", response_model=ActiveMCPServiceRsp) async def active_or_deactivate_mcp_service( request: Request, - serviceId: Annotated[str, Path()], # noqa: N803 + mcpId: Annotated[str, Path()], # noqa: N803 data: ActiveMCPServiceRequest, ) -> JSONResponse: """激活/取消激活mcp""" try: if data.active: - await MCPServiceManager.active_mcpservice(request.state.user_sub, serviceId) + await MCPServiceManager.active_mcpservice(request.state.user_sub, mcpId) else: - await MCPServiceManager.deactive_mcpservice(request.state.user_sub, serviceId) + await MCPServiceManager.deactive_mcpservice(request.state.user_sub, mcpId) except Exception as e: err = f"[MCPService] 激活mcp服务失败: {e!s}" if data.active else f"[MCPService] 取消激活mcp服务失败: {e!s}" logger.exception(err) @@ -305,6 +300,6 @@ async def active_or_deactivate_mcp_service( content=ActiveMCPServiceRsp( code=status.HTTP_200_OK, message="OK", - result=BaseMCPServiceOperationMsg(serviceId=serviceId), + result=BaseMCPServiceOperationMsg(serviceId=mcpId), ).model_dump(exclude_none=True, by_alias=True), ) diff --git a/apps/routers/record.py b/apps/routers/record.py index 2a2fd591a58c771ddb4a91e59f7145b964e81e85..9ed98825e0bfed977dc269958fbb723f373eeb1b 100644 --- a/apps/routers/record.py +++ b/apps/routers/record.py @@ -9,7 +9,7 @@ from fastapi import APIRouter, Depends, Path, Request, status from fastapi.responses import JSONResponse from apps.common.security import Security -from apps.dependency import verify_admin, verify_personal_token, verify_session +from apps.dependency import verify_personal_token, verify_session from apps.schemas.record import ( RecordContent, RecordData, diff --git a/apps/routers/service.py b/apps/routers/service.py index ba90cee7ea5f3a500c1a2280b0a20f1d5118ad98..77144eaf96eea3dd38434a1fb01901ebede55cc1 100644 --- a/apps/routers/service.py +++ b/apps/routers/service.py @@ -10,7 +10,7 @@ from fastapi.responses import JSONResponse from apps.dependency.user import verify_personal_token, verify_session from apps.exceptions import InstancePermissionError, ServiceIDError from apps.schemas.enum_var import SearchType -from apps.schemas.request_data import ModFavServiceRequest, UpdateServiceRequest +from apps.schemas.request_data import ChangeFavouriteServiceRequest, UpdateServiceRequest from apps.schemas.response_data import ( BaseServiceOperationMsg, DeleteServiceRsp, @@ -18,8 +18,8 @@ from apps.schemas.response_data import ( GetServiceDetailRsp, GetServiceListMsg, GetServiceListRsp, - ModFavServiceMsg, - ModFavServiceRsp, + ChangeFavouriteServiceMsg, + ChangeFavouriteServiceRsp, ResponseData, UpdateServiceMsg, UpdateServiceRsp, @@ -283,11 +283,11 @@ async def delete_service(request: Request, serviceId: Annotated[str, Path()]) -> return JSONResponse(status_code=status.HTTP_200_OK, content=rsp.model_dump(exclude_none=True, by_alias=True)) -@router.put("/{serviceId}", response_model=ModFavServiceRsp) +@router.put("/{serviceId}", response_model=ChangeFavouriteServiceRsp) async def modify_favorite_service( request: Request, serviceId: Annotated[str, Path()], # noqa: N803 - data: ModFavServiceRequest, + data: ChangeFavouriteServiceRequest, ) -> JSONResponse: """修改服务收藏状态""" try: @@ -324,6 +324,6 @@ async def modify_favorite_service( result={}, ).model_dump(exclude_none=True, by_alias=True), ) - msg = ModFavServiceMsg(serviceId=serviceId, favorited=data.favorited) - rsp = ModFavServiceRsp(code=status.HTTP_200_OK, message="OK", result=msg) + msg = ChangeFavouriteServiceMsg(serviceId=serviceId, favorited=data.favorited) + rsp = ChangeFavouriteServiceRsp(code=status.HTTP_200_OK, message="OK", result=msg) return JSONResponse(status_code=status.HTTP_200_OK, content=rsp.model_dump(exclude_none=True, by_alias=True)) diff --git a/apps/scheduler/pool/loader/call.py b/apps/scheduler/pool/loader/call.py index 7452ae6e48625952b3a4dc96ff352195e59d7ef1..68281b7378f2b13b428082acfa493eaac30966b6 100644 --- a/apps/scheduler/pool/loader/call.py +++ b/apps/scheduler/pool/loader/call.py @@ -58,7 +58,7 @@ class CallLoader(metaclass=SingletonMeta): )) call_descriptions.append(call.description) - # 进行向量化,更新LanceDB + # 进行向量化 call_vecs = await Embedding.get_embedding(call_descriptions) vector_data = [] for call_id, vec in zip(call_metadata.keys(), call_vecs, strict=True): diff --git a/apps/scheduler/pool/mcp/default.py b/apps/scheduler/pool/mcp/default.py index f16b964bff3722aff73bee08a1f2c067231c670f..bf9b7d941cd89e2216073f60b1dfae390de5eee1 100644 --- a/apps/scheduler/pool/mcp/default.py +++ b/apps/scheduler/pool/mcp/default.py @@ -15,7 +15,7 @@ logger = logging.getLogger(__name__) DEFAULT_STDIO = MCPServerConfig( name="MCP服务_" + uuid.uuid4().hex[:6], description="MCP服务描述", - mcp_type=MCPType.STDIO, + mcpType=MCPType.STDIO, config=MCPServerStdioConfig( command="uvx", args=[ @@ -31,7 +31,7 @@ DEFAULT_STDIO = MCPServerConfig( DEFAULT_SSE = MCPServerConfig( name="MCP服务_" + uuid.uuid4().hex[:6], description="MCP服务描述", - mcp_type=MCPType.SSE, + mcpType=MCPType.SSE, config=MCPServerSSEConfig( url="http://test.domain/sse", env={ diff --git a/apps/scheduler/pool/mcp/install.py b/apps/scheduler/pool/mcp/install.py index 1b6c3edeb3a042b7716d0d7748e9c3e50b01af74..a320714c27534f5e8ec58528cc77af4be71215b4 100644 --- a/apps/scheduler/pool/mcp/install.py +++ b/apps/scheduler/pool/mcp/install.py @@ -59,7 +59,7 @@ async def install_uvx(mcp_id: str, config: "MCPServerStdioConfig") -> "MCPServer config.command = "uv" config.args = ["run", *config.args] - config.auto_install = False + config.autoInstall = False return config @@ -86,7 +86,7 @@ async def install_uvx(mcp_id: str, config: "MCPServerStdioConfig") -> "MCPServer # 更新配置 config.command = "uv" config.args = ["run", *config.args] - config.auto_install = False + config.autoInstall = False return config @@ -139,6 +139,6 @@ async def install_npx(mcp_id: str, config: "MCPServerStdioConfig") -> "MCPServer # 更新配置 config.command = "npm" config.args = ["exec", *config.args] - config.auto_install = False + config.autoInstall = False return config diff --git a/apps/scheduler/pool/mcp/pool.py b/apps/scheduler/pool/mcp/pool.py index ec711ef961de208d5a28faa4972010e550a2da9c..9ff5d2e9642581bb4ffdf534a8d740c87f1d3d90 100644 --- a/apps/scheduler/pool/mcp/pool.py +++ b/apps/scheduler/pool/mcp/pool.py @@ -33,7 +33,7 @@ class MCPPool(metaclass=SingletonMeta): config = MCPServerConfig.model_validate_json(await config_path.read_text()) - if config.mcp_type in (MCPType.SSE, MCPType.STDIO): + if config.mcpType in (MCPType.SSE, MCPType.STDIO): client = MCPClient() else: logger.warning("[MCPPool] 用户 %s 的MCP %s 类型错误", user_sub, mcp_id) diff --git a/apps/services/rag.py b/apps/services/rag.py index dc1783de2c5b34a4abd46dad90b2eb3fba96d98b..a923317d62876109c0231a8679f329fab0df2d0f 100644 --- a/apps/services/rag.py +++ b/apps/services/rag.py @@ -13,7 +13,6 @@ from apps.common.config import config from apps.llm.patterns.rewrite import QuestionRewrite from apps.llm.reasoning import ReasoningLLM from apps.llm.token import TokenCalculator -from apps.schemas.collection import LLM from apps.schemas.config import LLMConfig from apps.schemas.enum_var import EventType from apps.schemas.rag_data import RAGQueryReq @@ -108,8 +107,8 @@ class RAG: if response.status_code == status.HTTP_200_OK: result = response.json() doc_chunk_list += result["result"]["docChunks"] - except Exception as e: - logger.error(f"[RAG] 获取文档分片失败: {e}") + except Exception: + logger.exception("[RAG] 获取文档分片失败") if data.kb_ids: try: async with httpx.AsyncClient(timeout=30) as client: @@ -119,12 +118,14 @@ class RAG: if response.status_code == status.HTTP_200_OK: result = response.json() doc_chunk_list += result["result"]["docChunks"] - except Exception as e: - logger.error(f"[RAG] 获取文档分片失败: {e}") + except Exception: + logger.exception("[RAG] 获取文档分片失败") return doc_chunk_list @staticmethod - async def assemble_doc_info(doc_chunk_list: list[dict[str, Any]], max_tokens: int) -> str: + async def assemble_doc_info( + doc_chunk_list: list[dict[str, Any]], max_tokens: int, + ) -> tuple[str, list[dict[str, Any]]]: """组装文档信息""" bac_info = "" doc_info_list = [] @@ -255,7 +256,7 @@ class RAG: ): if not await Activity.is_active(user_sub): return - chunk = buffer + chunk + current_chunk = buffer + chunk # 防止脚注被截断 if len(chunk) >= 2 and chunk[-2:] != "]]": index = len(chunk) - 1 @@ -263,12 +264,12 @@ class RAG: index -= 1 if index >= 0: buffer = chunk[index + 1:] - chunk = chunk[:index + 1] + current_chunk = chunk[:index + 1] else: buffer = "" output_tokens += TokenCalculator().calculate_token_length( messages=[ - {"role": "assistant", "content": chunk}, + {"role": "assistant", "content": current_chunk}, ], pure_text=True, ) @@ -277,7 +278,7 @@ class RAG: + json.dumps( { "event_type": EventType.TEXT_ADD.value, - "content": chunk, + "content": current_chunk, "input_tokens": input_tokens, "output_tokens": output_tokens, }, diff --git a/apps/services/service.py b/apps/services/service.py index 7d6869993a164c15e3f1871c469613bc352939d8..652e7b206a2c3ef6a02c21128f6bf7c82129322c 100644 --- a/apps/services/service.py +++ b/apps/services/service.py @@ -7,13 +7,13 @@ from typing import Any import yaml from anyio import Path -from sqlalchemy import and_, select +from sqlalchemy import and_, or_, select from apps.common.config import config from apps.common.postgres import postgres from apps.exceptions import InstancePermissionError, ServiceIDError from apps.models.node import NodeInfo -from apps.models.service import Service +from apps.models.service import Service, ServiceACL from apps.scheduler.openapi import ReducedOpenAPISpec from apps.scheduler.pool.loader.openapi import OpenAPILoader from apps.scheduler.pool.loader.service import ServiceLoader @@ -222,6 +222,7 @@ class ServiceCenterManager: ) return service_pool_store.name, api_list + @staticmethod async def get_service_data( user_sub: str, @@ -229,32 +230,49 @@ class ServiceCenterManager: ) -> tuple[str, dict[str, Any]]: """获取服务数据""" # 验证用户权限 - service_collection = MongoDB().get_collection("service") - match_conditions = [ - {"author": user_sub}, - {"permission.type": PermissionType.PUBLIC.value}, - { - "$and": [ - {"permission.type": PermissionType.PROTECTED.value}, - {"permission.users": user_sub}, - ], - }, - ] - query = {"$and": [{"_id": service_id}, {"$or": match_conditions}]} - db_service = await service_collection.find_one(query) - if not db_service: - msg = "Service not found" - raise ServiceIDError(msg) - service_pool_store = ServicePool.model_validate(db_service) - if service_pool_store.author != user_sub: - msg = "Permission denied" - raise InstancePermissionError(msg) + async with postgres.session() as session: + allowed_user = list((await session.scalars( + select(ServiceACL.userSub).where( + ServiceACL.serviceId == service_id, + ), + )).all()) + + if user_sub in allowed_user: + db_service = (await session.scalars( + select(Service).where( + and_( + Service.id == service_id, + Service.permission == PermissionType.PRIVATE, + ), + ), + )).one_or_none() + else: + db_service = (await session.scalars( + select(Service).where( + and_( + Service.id == service_id, + or_( + and_( + Service.author == user_sub, + Service.permission == PermissionType.PRIVATE, + ), + Service.permission == PermissionType.PUBLIC, + ), + ), + ), + )).one_or_none() + + if not db_service: + msg = "[ServiceCenterManager] Service not found or permission denied" + raise RuntimeError(msg) + service_path = ( Path(config.deploy.data_dir) / "semantics" / "service" / service_id / "openapi" / "api.yaml" ) async with await service_path.open() as f: service_data = yaml.safe_load(await f.read()) - return service_pool_store.name, service_data + return db_service.name, service_data + @staticmethod async def get_service_metadata( diff --git a/apps/services/task.py b/apps/services/task.py index a0fbb109c824f81d919824e9e4693ea26aae5a54..28ab72d54c121e786f7b782115acc83a27f9f6a7 100644 --- a/apps/services/task.py +++ b/apps/services/task.py @@ -6,7 +6,6 @@ import uuid from typing import Any from apps.common.postgres import postgres -from apps.schemas.record import RecordGroup from apps.schemas.request_data import RequestData from apps.schemas.task import ( Task, diff --git a/apps/services/token.py b/apps/services/token.py index 111257e68bcd51a782078f052fec74ef25eba132..61ce859514adb62002b398f430ef59327c44cdb8 100644 --- a/apps/services/token.py +++ b/apps/services/token.py @@ -51,7 +51,7 @@ class TokenManager: ) ).one_or_none() - if token_data: + if token_data and token_data.token: return token_data.token token = await TokenManager.generate_plugin_token( @@ -124,7 +124,7 @@ class TokenManager: ) ).one_or_none() - if not refresh_token: + if not refresh_token or not refresh_token.token: await SessionManager.delete_session(session_id) err = "Refresh token均过期,需要重新登录" raise RuntimeError(err)