Files
company-ai-platform/app/modules/feishu_users/principal.py
JiuContinent d7db84571d ```
feat: 添加飞书用户模块和订阅功能支持

- 新增feishu_users模块用于处理飞书用户身份验证和权限管理
- 新增subscriptions模块用于处理订阅相关功能
- 新增personalization模块用于个性化服务
- 在alembic迁移配置中注册新的模型模块
- 在API路由器中添加feishu_users和subscriptions路由
- 实现事件调度服务的改进,包括错误处理和状态更新优化
- 添加飞书命令处理的权限检查机制
- 实现飞书应用票据事件处理
- 改进审计日志记录功能
```
2026-07-27 08:02:17 +08:00

103 lines
2.9 KiB
Python

from dataclasses import dataclass
from datetime import time
from fastapi import HTTPException, status
from app.modules.feishu_users.constants import (
FeishuCapability,
FeishuUserRole,
FeishuUserStatus,
capabilities_for_role,
)
from app.modules.feishu_users.models import FeishuUser
@dataclass(frozen=True, slots=True)
class FeishuMention:
"""Structured mention identity supplied by a verified Feishu event."""
key: str | None = None
name: str | None = None
tenant_key: str | None = None
open_id: str | None = None
union_id: str | None = None
user_id: str | None = None
@dataclass(frozen=True, slots=True)
class FeishuPrincipal:
"""Authenticated Feishu user plus the current chat context."""
owner_id: int
user_code: str
tenant_key: str
open_id: str
union_id: str | None
feishu_user_id: str | None
role: str
status: str
timezone: str
quiet_hours_start: time | None
quiet_hours_end: time | None
chat_id: str | None = None
chat_type: str | None = None
mentions: tuple[FeishuMention, ...] = ()
@property
def is_active(self) -> bool:
return self.status == FeishuUserStatus.ACTIVE
@property
def is_admin(self) -> bool:
return self.role == FeishuUserRole.ADMIN
def has_capability(self, capability: str | FeishuCapability) -> bool:
if not self.is_active:
return False
try:
required = FeishuCapability(capability)
return required in capabilities_for_role(self.role)
except ValueError:
return False
def require_active(self) -> None:
if not self.is_active:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Feishu user is disabled",
)
def require_capability(self, capability: str | FeishuCapability) -> None:
self.require_active()
if not self.has_capability(capability):
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Feishu user is not authorized for this capability",
)
@classmethod
def from_user(
cls,
user: FeishuUser,
*,
chat_id: str | None = None,
chat_type: str | None = None,
mentions: tuple[FeishuMention, ...] = (),
) -> "FeishuPrincipal":
return cls(
owner_id=user.id,
user_code=user.code,
tenant_key=user.tenant_key,
open_id=user.open_id,
union_id=user.union_id,
feishu_user_id=user.user_id,
role=user.role,
status=user.status,
timezone=user.timezone,
quiet_hours_start=user.quiet_hours_start,
quiet_hours_end=user.quiet_hours_end,
chat_id=chat_id,
chat_type=chat_type,
mentions=mentions,
)