feat: 添加飞书集成和审计API密钥认证

- 在数据库配置中添加飞书模型导入
- 添加审计API密钥配置项和认证中间件
- 实现飞书事件重复处理防止机制
- 为审批路由添加API密钥认证
- 优化AI适配器错误处理并添加JSON解析异常捕获
- 更新测试用例以包含新的认证和事件处理逻辑
```
This commit is contained in:
2026-07-06 11:34:15 +08:00
parent 0dbe5c1c2d
commit 514b14d390
16 changed files with 353 additions and 16 deletions

View File

@@ -8,6 +8,7 @@ from app.core.db_base import Base
from app.modules.approvals import models as approval_models
from app.modules.audit import models as audit_models
from app.modules.business import models as business_models
from app.modules.feishu import models as feishu_models
config = context.config
@@ -18,7 +19,7 @@ target_metadata = Base.metadata
settings = get_settings()
# Keep imports referenced so SQLAlchemy model classes register with Base.metadata.
_REGISTERED_MODEL_MODULES = (approval_models, audit_models, business_models)
_REGISTERED_MODEL_MODULES = (approval_models, audit_models, business_models, feishu_models)
def run_migrations_offline() -> None:

View File

@@ -11,6 +11,7 @@ from app.core.db_base import Base
from app.modules.approvals import models as approval_models
from app.modules.audit import models as audit_models
from app.modules.business import models as business_models
from app.modules.feishu import models as feishu_models
revision = "202607060001"
down_revision = None
@@ -18,7 +19,7 @@ branch_labels = None
depends_on = None
# Keep imports referenced so SQLAlchemy model classes register with Base.metadata.
_REGISTERED_MODEL_MODULES = (approval_models, audit_models, business_models)
_REGISTERED_MODEL_MODULES = (approval_models, audit_models, business_models, feishu_models)
def upgrade() -> None:

View File

@@ -0,0 +1,91 @@
"""Add Feishu event receipts.
Revision ID: 202607060003
Revises: 202607060002
Create Date: 2026-07-06
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy import inspect
revision = "202607060003"
down_revision = "202607060002"
branch_labels = None
depends_on = None
FEISHU_EVENT_RECEIPTS_TABLE = "feishu_event_receipts"
def _table_exists() -> bool:
inspector = inspect(op.get_bind())
return FEISHU_EVENT_RECEIPTS_TABLE in inspector.get_table_names()
def upgrade() -> None:
if _table_exists():
return
op.create_table(
FEISHU_EVENT_RECEIPTS_TABLE,
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("event_key", sa.String(length=256), nullable=False),
sa.Column("source", sa.String(length=64), nullable=False),
sa.Column("event_id", sa.String(length=128), nullable=True),
sa.Column("message_id", sa.String(length=128), nullable=True),
sa.Column("received_at", sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint("id"),
)
op.create_index(
op.f("ix_feishu_event_receipts_event_id"),
FEISHU_EVENT_RECEIPTS_TABLE,
["event_id"],
unique=False,
)
op.create_index(
op.f("ix_feishu_event_receipts_event_key"),
FEISHU_EVENT_RECEIPTS_TABLE,
["event_key"],
unique=True,
)
op.create_index(
op.f("ix_feishu_event_receipts_message_id"),
FEISHU_EVENT_RECEIPTS_TABLE,
["message_id"],
unique=False,
)
op.create_index(
op.f("ix_feishu_event_receipts_received_at"),
FEISHU_EVENT_RECEIPTS_TABLE,
["received_at"],
unique=False,
)
op.create_index(
op.f("ix_feishu_event_receipts_source"),
FEISHU_EVENT_RECEIPTS_TABLE,
["source"],
unique=False,
)
def downgrade() -> None:
if not _table_exists():
return
op.drop_index(op.f("ix_feishu_event_receipts_source"), table_name=FEISHU_EVENT_RECEIPTS_TABLE)
op.drop_index(
op.f("ix_feishu_event_receipts_received_at"),
table_name=FEISHU_EVENT_RECEIPTS_TABLE,
)
op.drop_index(
op.f("ix_feishu_event_receipts_message_id"),
table_name=FEISHU_EVENT_RECEIPTS_TABLE,
)
op.drop_index(
op.f("ix_feishu_event_receipts_event_key"),
table_name=FEISHU_EVENT_RECEIPTS_TABLE,
)
op.drop_index(
op.f("ix_feishu_event_receipts_event_id"),
table_name=FEISHU_EVENT_RECEIPTS_TABLE,
)
op.drop_table(FEISHU_EVENT_RECEIPTS_TABLE)