Merge branch 'feature/plugin' into develop
This commit is contained in:
@@ -310,7 +310,7 @@ async def get_file_url(
|
|||||||
try:
|
try:
|
||||||
if permanent:
|
if permanent:
|
||||||
# Generate permanent URL (no expiration check)
|
# Generate permanent URL (no expiration check)
|
||||||
server_url = f"http://{settings.SERVER_IP}:8000/api"
|
server_url = settings.FILE_LOCAL_SERVER_URL
|
||||||
url = f"{server_url}/storage/permanent/{file_id}"
|
url = f"{server_url}/storage/permanent/{file_id}"
|
||||||
return success(
|
return success(
|
||||||
data={
|
data={
|
||||||
|
|||||||
@@ -9,6 +9,25 @@ load_dotenv()
|
|||||||
|
|
||||||
|
|
||||||
class Settings:
|
class Settings:
|
||||||
|
# ========================================================================
|
||||||
|
# Deployment Mode Configuration
|
||||||
|
# ========================================================================
|
||||||
|
# community: 社区版(开源,功能受限)
|
||||||
|
# cloud: SaaS 云服务版(全功能,按量计费)
|
||||||
|
# enterprise: 企业私有化版(License 控制)
|
||||||
|
DEPLOYMENT_MODE: str = os.getenv("DEPLOYMENT_MODE", "community")
|
||||||
|
|
||||||
|
# License 配置(企业版)
|
||||||
|
LICENSE_FILE: str = os.getenv("LICENSE_FILE", "/etc/app/license.json")
|
||||||
|
LICENSE_SERVER_URL: str = os.getenv("LICENSE_SERVER_URL", "https://license.yourcompany.com")
|
||||||
|
|
||||||
|
# 计费服务配置(SaaS 版)
|
||||||
|
BILLING_SERVICE_URL: str = os.getenv("BILLING_SERVICE_URL", "")
|
||||||
|
|
||||||
|
# 基础 URL(用于 SSO 回调等)
|
||||||
|
BASE_URL: str = os.getenv("BASE_URL", "http://localhost:8000")
|
||||||
|
FRONTEND_URL: str = os.getenv("FRONTEND_URL", "http://localhost:3000")
|
||||||
|
|
||||||
ENABLE_SINGLE_WORKSPACE: bool = os.getenv("ENABLE_SINGLE_WORKSPACE", "true").lower() == "true"
|
ENABLE_SINGLE_WORKSPACE: bool = os.getenv("ENABLE_SINGLE_WORKSPACE", "true").lower() == "true"
|
||||||
# API Keys Configuration
|
# API Keys Configuration
|
||||||
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
|
OPENAI_API_KEY: str = os.getenv("OPENAI_API_KEY", "")
|
||||||
@@ -72,6 +91,10 @@ class Settings:
|
|||||||
|
|
||||||
# Single Sign-On configuration
|
# Single Sign-On configuration
|
||||||
ENABLE_SINGLE_SESSION: bool = os.getenv("ENABLE_SINGLE_SESSION", "false").lower() == "true"
|
ENABLE_SINGLE_SESSION: bool = os.getenv("ENABLE_SINGLE_SESSION", "false").lower() == "true"
|
||||||
|
|
||||||
|
# SSO 免登配置
|
||||||
|
SSO_TOKEN_EXPIRE_SECONDS: int = int(os.getenv("SSO_TOKEN_EXPIRE_SECONDS", "300"))
|
||||||
|
SSO_TRUSTED_SOURCES_CONFIG: str = os.getenv("SSO_TRUSTED_SOURCES_CONFIG", "{}")
|
||||||
|
|
||||||
# File Upload
|
# File Upload
|
||||||
MAX_FILE_SIZE: int = int(os.getenv("MAX_FILE_SIZE", "52428800"))
|
MAX_FILE_SIZE: int = int(os.getenv("MAX_FILE_SIZE", "52428800"))
|
||||||
@@ -107,6 +130,7 @@ class Settings:
|
|||||||
|
|
||||||
# Server Configuration
|
# Server Configuration
|
||||||
SERVER_IP: str = os.getenv("SERVER_IP", "127.0.0.1")
|
SERVER_IP: str = os.getenv("SERVER_IP", "127.0.0.1")
|
||||||
|
FILE_LOCAL_SERVER_URL : str = os.getenv("FILE_LOCAL_SERVER_URL", "http://localhost:8000/api")
|
||||||
|
|
||||||
# ========================================================================
|
# ========================================================================
|
||||||
# Internal Configuration (not in .env, used by application code)
|
# Internal Configuration (not in .env, used by application code)
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ def generate_signed_url(
|
|||||||
"""
|
"""
|
||||||
if base_url is None:
|
if base_url is None:
|
||||||
# Use SERVER_IP or default to localhost
|
# Use SERVER_IP or default to localhost
|
||||||
server_url = f"http://{settings.SERVER_IP}:8000/api"
|
server_url = settings.FILE_LOCAL_SERVER_URL
|
||||||
base_url = server_url
|
base_url = server_url
|
||||||
|
|
||||||
# Calculate expiration timestamp
|
# Calculate expiration timestamp
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ class Tenants(Base):
|
|||||||
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
||||||
is_active = Column(Boolean, default=True)
|
is_active = Column(Boolean, default=True)
|
||||||
|
|
||||||
|
# SSO 外部关联字段
|
||||||
|
external_id = Column(String(100), nullable=True, index=True) # 外部企业ID
|
||||||
|
external_source = Column(String(50), nullable=True) # 来源系统
|
||||||
|
|
||||||
# Relationship to users - one tenant has many users
|
# Relationship to users - one tenant has many users
|
||||||
users = relationship("User", back_populates="tenant")
|
users = relationship("User", back_populates="tenant")
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ class User(Base):
|
|||||||
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
||||||
last_login_at = Column(DateTime, nullable=True) # 最后登录时间,可为空
|
last_login_at = Column(DateTime, nullable=True) # 最后登录时间,可为空
|
||||||
|
|
||||||
|
# SSO 外部关联字段
|
||||||
|
external_id = Column(String(100), nullable=True) # 外部用户ID
|
||||||
|
external_source = Column(String(50), nullable=True) # 来源系统
|
||||||
|
|
||||||
current_workspace_id = Column(UUID(as_uuid=True), ForeignKey("workspaces.id"), nullable=True) # 当前工作空间ID,可为空
|
current_workspace_id = Column(UUID(as_uuid=True), ForeignKey("workspaces.id"), nullable=True) # 当前工作空间ID,可为空
|
||||||
|
|
||||||
# Foreign key to tenant - each user belongs to exactly one tenant
|
# Foreign key to tenant - each user belongs to exactly one tenant
|
||||||
|
|||||||
74
api/app/plugins/__init__.py
Normal file
74
api/app/plugins/__init__.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# app/plugins/__init__.py
|
||||||
|
"""
|
||||||
|
插件系统 - 支持开源核心 + 闭源增值模块
|
||||||
|
|
||||||
|
使用方式:
|
||||||
|
1. 开源版(community):基础功能
|
||||||
|
2. 商业版(enterprise):加载 premium 包中的高级实现
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
from app.core.logging_config import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
# 版本标识
|
||||||
|
EDITION = os.environ.get("EDITION", "community")
|
||||||
|
IS_ENTERPRISE = EDITION == "enterprise"
|
||||||
|
|
||||||
|
# 插件注册表
|
||||||
|
_plugins: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
# 路由注册表(用于动态注册闭源模块的路由)
|
||||||
|
_routers: list = []
|
||||||
|
|
||||||
|
|
||||||
|
def is_enterprise() -> bool:
|
||||||
|
"""是否为商业版"""
|
||||||
|
return IS_ENTERPRISE
|
||||||
|
|
||||||
|
|
||||||
|
def list_plugins() -> list:
|
||||||
|
"""列出所有已注册插件"""
|
||||||
|
return list(_plugins.keys())
|
||||||
|
|
||||||
|
|
||||||
|
def register_plugin(name: str, instance: Any):
|
||||||
|
"""注册插件"""
|
||||||
|
_plugins[name] = instance
|
||||||
|
logger.info(f"插件已注册: {name}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_plugin(name: str) -> Optional[Any]:
|
||||||
|
"""获取插件实例"""
|
||||||
|
return _plugins.get(name)
|
||||||
|
|
||||||
|
|
||||||
|
def register_router(router, prefix: str = "", tags: list = None):
|
||||||
|
"""注册路由(供闭源模块使用)"""
|
||||||
|
_routers.append({
|
||||||
|
"router": router,
|
||||||
|
"prefix": prefix,
|
||||||
|
"tags": tags or []
|
||||||
|
})
|
||||||
|
logger.info(f"路由已注册: {prefix}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_registered_routers() -> list:
|
||||||
|
"""获取所有注册的路由"""
|
||||||
|
return _routers
|
||||||
|
|
||||||
|
|
||||||
|
def register_premium_routers(app):
|
||||||
|
"""
|
||||||
|
注册 premium 模块的路由到 FastAPI app
|
||||||
|
|
||||||
|
在商业版 main.py 中调用
|
||||||
|
"""
|
||||||
|
for router_info in _routers:
|
||||||
|
app.include_router(
|
||||||
|
router_info["router"],
|
||||||
|
prefix=f"/api{router_info['prefix']}",
|
||||||
|
tags=router_info["tags"]
|
||||||
|
)
|
||||||
|
logger.info(f"Premium 路由已挂载: /api{router_info['prefix']}")
|
||||||
@@ -75,6 +75,7 @@ ENABLE_SINGLE_SESSION=
|
|||||||
MAX_FILE_SIZE=52428800 # 50MB:10 * 1024 * 1024
|
MAX_FILE_SIZE=52428800 # 50MB:10 * 1024 * 1024
|
||||||
FILE_PATH=/files
|
FILE_PATH=/files
|
||||||
|
|
||||||
|
FILE_LOCAL_SERVER_URL="http://localhost:8000/api"
|
||||||
# Storage Backend Configuration
|
# Storage Backend Configuration
|
||||||
# Supported values: local, oss, s3
|
# Supported values: local, oss, s3
|
||||||
# Default: local
|
# Default: local
|
||||||
|
|||||||
Reference in New Issue
Block a user