```
feat: 添加飞书用户模块和订阅功能支持 - 新增feishu_users模块用于处理飞书用户身份验证和权限管理 - 新增subscriptions模块用于处理订阅相关功能 - 新增personalization模块用于个性化服务 - 在alembic迁移配置中注册新的模型模块 - 在API路由器中添加feishu_users和subscriptions路由 - 实现事件调度服务的改进,包括错误处理和状态更新优化 - 添加飞书命令处理的权限检查机制 - 实现飞书应用票据事件处理 - 改进审计日志记录功能 ```
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import json
|
||||
import os
|
||||
from functools import lru_cache
|
||||
from typing import Annotated, Any
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
from pydantic import Field, field_validator, model_validator
|
||||
from pydantic_settings import BaseSettings, NoDecode, SettingsConfigDict
|
||||
@@ -12,11 +13,22 @@ from app.core.constants import (
|
||||
DEFAULT_OPENCLAW_ACTION_JSON,
|
||||
)
|
||||
|
||||
_DOTENV_DISABLED = os.getenv("COMPANY_AI_DISABLE_DOTENV", "").strip().lower() in {
|
||||
"1",
|
||||
"true",
|
||||
"yes",
|
||||
"on",
|
||||
}
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Runtime settings loaded from environment variables and `.env`."""
|
||||
|
||||
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8", extra="ignore")
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=None if _DOTENV_DISABLED else ".env",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
app_name: str = "Company AI Management Platform"
|
||||
app_env: str = "local"
|
||||
@@ -45,9 +57,14 @@ class Settings(BaseSettings):
|
||||
feishu_base_url: str = "https://open.feishu.cn/open-apis"
|
||||
feishu_app_id: str | None = None
|
||||
feishu_app_secret: str | None = None
|
||||
feishu_app_type: Literal["self", "store"] = "self"
|
||||
feishu_app_ticket: str | None = None
|
||||
feishu_verification_token: str | None = None
|
||||
feishu_encrypt_key: str | None = None
|
||||
feishu_default_chat_id: str | None = None
|
||||
feishu_default_tenant_key: str | None = None
|
||||
feishu_user_features_enabled: bool = False
|
||||
feishu_admin_identities: Annotated[list[str], NoDecode] = Field(default_factory=list)
|
||||
model_provider: str = DEFAULT_MODEL_PROVIDER
|
||||
openclaw_base_url: str = "http://127.0.0.1:2070"
|
||||
openclaw_http_url: str | None = None
|
||||
@@ -109,6 +126,7 @@ class Settings(BaseSettings):
|
||||
event_dispatch_lock_seconds: int = 300
|
||||
event_dispatch_cron_minute: str = "*/5"
|
||||
heartbeat_interval_seconds: int = 60
|
||||
heartbeat_retention_seconds: int = Field(default=86400, ge=1)
|
||||
ai_memory_enabled: bool = True
|
||||
ai_memory_auto_write_enabled: bool = True
|
||||
ai_memory_recall_limit: int = 5
|
||||
@@ -135,6 +153,8 @@ class Settings(BaseSettings):
|
||||
ai_memory_forbidden_keys: list[str] = Field(
|
||||
default_factory=lambda: [
|
||||
"authorization",
|
||||
"app_access_token",
|
||||
"app_ticket",
|
||||
"api_key",
|
||||
"apikey",
|
||||
"access_token",
|
||||
@@ -147,6 +167,7 @@ class Settings(BaseSettings):
|
||||
"direct_llm_api_key",
|
||||
"market_data_token",
|
||||
"feishu_app_secret",
|
||||
"feishu_app_ticket",
|
||||
"feishu_verification_token",
|
||||
]
|
||||
)
|
||||
@@ -166,11 +187,20 @@ class Settings(BaseSettings):
|
||||
return [str(item).strip() for item in data if str(item).strip()]
|
||||
return [item.strip() for item in text.split(",") if item.strip()]
|
||||
|
||||
@field_validator(
|
||||
"feishu_app_type",
|
||||
mode="before",
|
||||
)
|
||||
@classmethod
|
||||
def normalize_feishu_app_type(cls, value: Any) -> str:
|
||||
return str(value or "self").strip().lower()
|
||||
|
||||
@field_validator(
|
||||
"openclaw_allowed_tools",
|
||||
"openclaw_allowed_actions",
|
||||
"ai_memory_forbidden_keys",
|
||||
"ai_memory_blocked_content_terms",
|
||||
"feishu_admin_identities",
|
||||
mode="before",
|
||||
)
|
||||
@classmethod
|
||||
@@ -240,19 +270,49 @@ class Settings(BaseSettings):
|
||||
def validate_production_safety(self) -> "Settings":
|
||||
if self.app_env.lower() not in {"prod", "production"}:
|
||||
return self
|
||||
def _enabled_keys(
|
||||
legacy_key: str | None,
|
||||
configured_keys: list[dict[str, Any]],
|
||||
) -> set[str]:
|
||||
values: set[str] = set()
|
||||
if legacy_key and legacy_key.strip():
|
||||
values.add(legacy_key)
|
||||
for item in configured_keys:
|
||||
enabled = item.get("enabled", True)
|
||||
if not isinstance(enabled, bool):
|
||||
enabled = str(enabled).strip().lower() not in {
|
||||
"0", "false", "no", "off", "disabled"
|
||||
}
|
||||
key = item.get("key")
|
||||
if enabled and key is not None and str(key).strip():
|
||||
values.add(str(key))
|
||||
return values
|
||||
|
||||
errors: list[str] = []
|
||||
api_key_values = _enabled_keys(self.api_key, self.api_keys)
|
||||
audit_key_values = _enabled_keys(self.audit_api_key, self.audit_api_keys)
|
||||
if self.database_url.startswith("sqlite"):
|
||||
errors.append("DATABASE_URL must use PostgreSQL in production")
|
||||
if not self.api_key and not any(item.get("key") for item in self.api_keys):
|
||||
if not api_key_values:
|
||||
errors.append("API_KEY or API_KEYS is required in production")
|
||||
if not self.audit_api_key and not any(
|
||||
item.get("key") for item in self.audit_api_keys
|
||||
):
|
||||
if not audit_key_values:
|
||||
errors.append("AUDIT_API_KEY or AUDIT_API_KEYS is required in production")
|
||||
if api_key_values & audit_key_values:
|
||||
errors.append(
|
||||
"API_KEY/API_KEYS and AUDIT_API_KEY/AUDIT_API_KEYS cannot overlap in production"
|
||||
)
|
||||
if "*" in self.cors_origins:
|
||||
errors.append("CORS_ORIGINS cannot contain '*' in production")
|
||||
if self.debug:
|
||||
errors.append("DEBUG must be false in production")
|
||||
if not self.mask_sensitive_responses:
|
||||
errors.append("MASK_SENSITIVE_RESPONSES must be true in production")
|
||||
if not self.read_only_mode:
|
||||
errors.append("READ_ONLY_MODE must be true in production")
|
||||
if self.feishu_user_features_enabled and not self.feishu_admin_identities:
|
||||
errors.append(
|
||||
"FEISHU_ADMIN_IDENTITIES is required when Feishu user features are enabled"
|
||||
)
|
||||
if errors:
|
||||
raise ValueError("; ".join(errors))
|
||||
return self
|
||||
|
||||
Reference in New Issue
Block a user