```
feat: 添加飞书用户模块和订阅功能支持 - 新增feishu_users模块用于处理飞书用户身份验证和权限管理 - 新增subscriptions模块用于处理订阅相关功能 - 新增personalization模块用于个性化服务 - 在alembic迁移配置中注册新的模型模块 - 在API路由器中添加feishu_users和subscriptions路由 - 实现事件调度服务的改进,包括错误处理和状态更新优化 - 添加飞书命令处理的权限检查机制 - 实现飞书应用票据事件处理 - 改进审计日志记录功能 ```
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
from hashlib import sha256
|
||||
from secrets import compare_digest
|
||||
from typing import Any
|
||||
|
||||
@@ -22,10 +23,18 @@ from app.modules.feishu.constants import (
|
||||
class FeishuService:
|
||||
"""Send Feishu messages and record audit entries for outbound actions."""
|
||||
|
||||
def __init__(self, db: Session):
|
||||
def __init__(self, db: Session, tenant_key: str | None = None):
|
||||
self.db = db
|
||||
self.audit = AuditService(db)
|
||||
self.client = FeishuClient()
|
||||
self.client = FeishuClient(db)
|
||||
self.tenant_key = _optional_text(tenant_key) or _optional_text(
|
||||
get_settings().feishu_default_tenant_key
|
||||
)
|
||||
|
||||
def set_tenant_key(self, tenant_key: str | None) -> None:
|
||||
"""Set the default tenant used by subsequent outbound operations."""
|
||||
|
||||
self.tenant_key = _optional_text(tenant_key)
|
||||
|
||||
def verify_event(self, payload: dict[str, Any]) -> None:
|
||||
settings = get_settings()
|
||||
@@ -49,21 +58,32 @@ class FeishuService:
|
||||
receive_id: str | None = None,
|
||||
receive_id_type: str = FeishuReceiveIdType.CHAT_ID,
|
||||
actor: str = ActorValue.SYSTEM,
|
||||
uuid: str | None = None,
|
||||
tenant_key: str | None = None,
|
||||
record_audit: bool = True,
|
||||
) -> dict[str, Any]:
|
||||
result = self.client.send_text(text, receive_id, receive_id_type)
|
||||
self.audit.log(
|
||||
AuditLogCreate(
|
||||
actor=actor,
|
||||
source=AuditSource.FEISHU,
|
||||
action=AuditAction.FEISHU_SEND_TEXT,
|
||||
request_payload={
|
||||
FeishuPayloadKey.RECEIVE_ID: receive_id,
|
||||
FeishuPayloadKey.RECEIVE_ID_TYPE: receive_id_type,
|
||||
FeishuPayloadKey.TEXT: text,
|
||||
},
|
||||
response_payload=result,
|
||||
)
|
||||
result = self.client.send_text(
|
||||
text,
|
||||
receive_id,
|
||||
receive_id_type,
|
||||
uuid,
|
||||
tenant_key=self._resolve_tenant_key(tenant_key),
|
||||
)
|
||||
if record_audit:
|
||||
self.audit.log(
|
||||
AuditLogCreate(
|
||||
actor=actor,
|
||||
source=AuditSource.FEISHU,
|
||||
action=AuditAction.FEISHU_SEND_TEXT,
|
||||
request_payload={
|
||||
"receive_target_hash": _target_fingerprint(receive_id),
|
||||
FeishuPayloadKey.RECEIVE_ID_TYPE: receive_id_type,
|
||||
"content_length": len(text),
|
||||
FeishuPayloadKey.UUID: uuid,
|
||||
},
|
||||
response_payload=result,
|
||||
)
|
||||
)
|
||||
return result
|
||||
|
||||
def send_card(
|
||||
@@ -72,17 +92,26 @@ class FeishuService:
|
||||
receive_id: str | None = None,
|
||||
receive_id_type: str = FeishuReceiveIdType.CHAT_ID,
|
||||
actor: str = ActorValue.SYSTEM,
|
||||
uuid: str | None = None,
|
||||
tenant_key: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
result = self.client.send_card(card, receive_id, receive_id_type)
|
||||
result = self.client.send_card(
|
||||
card,
|
||||
receive_id,
|
||||
receive_id_type,
|
||||
uuid,
|
||||
tenant_key=self._resolve_tenant_key(tenant_key),
|
||||
)
|
||||
self.audit.log(
|
||||
AuditLogCreate(
|
||||
actor=actor,
|
||||
source=AuditSource.FEISHU,
|
||||
action=AuditAction.FEISHU_SEND_CARD,
|
||||
request_payload={
|
||||
FeishuPayloadKey.RECEIVE_ID: receive_id,
|
||||
"receive_target_hash": _target_fingerprint(receive_id),
|
||||
FeishuPayloadKey.RECEIVE_ID_TYPE: receive_id_type,
|
||||
FeishuPayloadKey.CARD: card,
|
||||
"card_element_count": len(card.get(FeishuPayloadKey.ELEMENTS) or []),
|
||||
FeishuPayloadKey.UUID: uuid,
|
||||
},
|
||||
response_payload=result,
|
||||
)
|
||||
@@ -93,8 +122,12 @@ class FeishuService:
|
||||
self,
|
||||
image: bytes,
|
||||
actor: str = ActorValue.SYSTEM,
|
||||
tenant_key: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
result = self.client.upload_image(image)
|
||||
result = self.client.upload_image(
|
||||
image,
|
||||
tenant_key=self._resolve_tenant_key(tenant_key),
|
||||
)
|
||||
self.audit.log(
|
||||
AuditLogCreate(
|
||||
actor=actor,
|
||||
@@ -106,6 +139,9 @@ class FeishuService:
|
||||
)
|
||||
return result
|
||||
|
||||
def _resolve_tenant_key(self, tenant_key: str | None) -> str | None:
|
||||
return _optional_text(tenant_key) or self.tenant_key
|
||||
|
||||
@staticmethod
|
||||
def build_basic_card(
|
||||
title: str,
|
||||
@@ -144,3 +180,14 @@ class FeishuService:
|
||||
},
|
||||
FeishuPayloadKey.ELEMENTS: elements,
|
||||
}
|
||||
|
||||
|
||||
def _target_fingerprint(receive_id: str | None) -> str | None:
|
||||
if not receive_id:
|
||||
return None
|
||||
return sha256(receive_id.encode("utf-8")).hexdigest()[:16]
|
||||
|
||||
|
||||
def _optional_text(value: str | None) -> str | None:
|
||||
text = str(value or "").strip()
|
||||
return text or None
|
||||
|
||||
Reference in New Issue
Block a user