```
feat: 添加飞书用户模块和订阅功能支持 - 新增feishu_users模块用于处理飞书用户身份验证和权限管理 - 新增subscriptions模块用于处理订阅相关功能 - 新增personalization模块用于个性化服务 - 在alembic迁移配置中注册新的模型模块 - 在API路由器中添加feishu_users和subscriptions路由 - 实现事件调度服务的改进,包括错误处理和状态更新优化 - 添加飞书命令处理的权限检查机制 - 实现飞书应用票据事件处理 - 改进审计日志记录功能 ```
This commit is contained in:
102
app/modules/feishu_users/principal.py
Normal file
102
app/modules/feishu_users/principal.py
Normal file
@@ -0,0 +1,102 @@
|
||||
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,
|
||||
)
|
||||
Reference in New Issue
Block a user