```
feat: 添加飞书用户模块和订阅功能支持 - 新增feishu_users模块用于处理飞书用户身份验证和权限管理 - 新增subscriptions模块用于处理订阅相关功能 - 新增personalization模块用于个性化服务 - 在alembic迁移配置中注册新的模型模块 - 在API路由器中添加feishu_users和subscriptions路由 - 实现事件调度服务的改进,包括错误处理和状态更新优化 - 添加飞书命令处理的权限检查机制 - 实现飞书应用票据事件处理 - 改进审计日志记录功能 ```
This commit is contained in:
157
tests/test_feishu_tenant_routing.py
Normal file
157
tests/test_feishu_tenant_routing.py
Normal file
@@ -0,0 +1,157 @@
|
||||
from collections.abc import Iterator
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.application.feishu.commands import FeishuCommandService
|
||||
from app.core.config import get_settings
|
||||
from app.core.database import Base
|
||||
from app.modules.audit.models import AuditLog
|
||||
from app.modules.feishu.service import FeishuService
|
||||
from app.modules.feishu_users.constants import FeishuUserRole, FeishuUserStatus
|
||||
from app.modules.feishu_users.principal import FeishuPrincipal
|
||||
|
||||
|
||||
class RecordingFeishuClient:
|
||||
def __init__(self) -> None:
|
||||
self.calls: list[dict[str, Any]] = []
|
||||
|
||||
def send_text(
|
||||
self,
|
||||
text: str,
|
||||
receive_id: str | None,
|
||||
receive_id_type: str,
|
||||
uuid: str | None,
|
||||
tenant_key: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
self.calls.append(
|
||||
{
|
||||
"operation": "text",
|
||||
"receive_id": receive_id,
|
||||
"tenant_key": tenant_key,
|
||||
"uuid": uuid,
|
||||
}
|
||||
)
|
||||
return {"code": 0, "data": {"message_id": "om-text"}}
|
||||
|
||||
def send_card(
|
||||
self,
|
||||
card: dict[str, Any],
|
||||
receive_id: str | None,
|
||||
receive_id_type: str,
|
||||
uuid: str | None,
|
||||
tenant_key: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
self.calls.append(
|
||||
{
|
||||
"operation": "card",
|
||||
"receive_id": receive_id,
|
||||
"tenant_key": tenant_key,
|
||||
"uuid": uuid,
|
||||
}
|
||||
)
|
||||
return {"code": 0, "data": {"message_id": "om-card"}}
|
||||
|
||||
def upload_image(
|
||||
self,
|
||||
image: bytes,
|
||||
filename: str = "lifecycle-report.png",
|
||||
tenant_key: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
self.calls.append(
|
||||
{
|
||||
"operation": "image",
|
||||
"filename": filename,
|
||||
"tenant_key": tenant_key,
|
||||
}
|
||||
)
|
||||
return {"code": 0, "data": {"image_key": "img-key"}}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def database(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> Iterator[Session]:
|
||||
monkeypatch.setenv("FEISHU_APP_ID", "cli-routing")
|
||||
monkeypatch.setenv("FEISHU_APP_SECRET", "routing-secret")
|
||||
monkeypatch.setenv("FEISHU_DEFAULT_TENANT_KEY", "tenant-default")
|
||||
monkeypatch.setenv("FEISHU_USER_FEATURES_ENABLED", "true")
|
||||
get_settings.cache_clear()
|
||||
engine = create_engine("sqlite://")
|
||||
Base.metadata.create_all(engine, tables=[AuditLog.__table__])
|
||||
try:
|
||||
with Session(engine) as db:
|
||||
yield db
|
||||
finally:
|
||||
engine.dispose()
|
||||
get_settings.cache_clear()
|
||||
|
||||
|
||||
def test_service_routes_text_card_and_image_through_selected_tenant(
|
||||
database: Session,
|
||||
) -> None:
|
||||
service = FeishuService(database)
|
||||
client = RecordingFeishuClient()
|
||||
service.client = client
|
||||
|
||||
service.send_text("默认消息", receive_id="oc-default")
|
||||
service.set_tenant_key("tenant-a")
|
||||
service.send_card({"elements": []}, receive_id="oc-a")
|
||||
service.upload_image(b"png")
|
||||
service.send_text(
|
||||
"显式覆盖",
|
||||
receive_id="oc-b",
|
||||
tenant_key="tenant-b",
|
||||
)
|
||||
|
||||
assert [
|
||||
(item["operation"], item["tenant_key"])
|
||||
for item in client.calls
|
||||
] == [
|
||||
("text", "tenant-default"),
|
||||
("card", "tenant-a"),
|
||||
("image", "tenant-a"),
|
||||
("text", "tenant-b"),
|
||||
]
|
||||
|
||||
|
||||
def test_command_reply_uses_verified_principal_tenant(
|
||||
database: Session,
|
||||
) -> None:
|
||||
commands = FeishuCommandService(database)
|
||||
client = RecordingFeishuClient()
|
||||
commands.feishu.client = client
|
||||
principal = FeishuPrincipal(
|
||||
owner_id=1,
|
||||
user_code="FSU-routing",
|
||||
tenant_key="tenant-principal",
|
||||
open_id="ou-routing",
|
||||
union_id=None,
|
||||
feishu_user_id=None,
|
||||
role=FeishuUserRole.USER,
|
||||
status=FeishuUserStatus.ACTIVE,
|
||||
timezone="Asia/Shanghai",
|
||||
quiet_hours_start=None,
|
||||
quiet_hours_end=None,
|
||||
chat_id="oc-routing",
|
||||
chat_type="p2p",
|
||||
)
|
||||
|
||||
result = commands.handle_text(
|
||||
"帮助",
|
||||
auto_reply=True,
|
||||
principal=principal,
|
||||
)
|
||||
|
||||
assert result["command"] == "help"
|
||||
assert commands.feishu.tenant_key == "tenant-principal"
|
||||
assert client.calls == [
|
||||
{
|
||||
"operation": "text",
|
||||
"receive_id": "oc-routing",
|
||||
"tenant_key": "tenant-principal",
|
||||
"uuid": None,
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user