Implement per-app open_id storage via user_feishu_open_ids table with union_id-based cross-app user identification. WS handlers now auto-capture open_id+union_id and resolve/associate user accounts. Schedule notifications route through the correct bot's open_id instead of always falling back to 苹果. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
33 lines
1.6 KiB
Python
33 lines
1.6 KiB
Python
"""用户飞书多应用 open_id 映射表 — 每个飞书应用给同一用户分配不同的 open_id"""
|
||
from __future__ import annotations
|
||
|
||
from sqlalchemy import Column, String, DateTime, func, UniqueConstraint, Index
|
||
from sqlalchemy.dialects.mysql import CHAR
|
||
from app.core.database import Base
|
||
import uuid
|
||
|
||
|
||
class UserFeishuOpenId(Base):
|
||
"""用户在各飞书应用下的 open_id 映射。
|
||
|
||
飞书的 open_id 按应用隔离:同一个用户在苹果/灵犀/橙子/苏瑶/甜甜
|
||
各自拥有不同的 open_id。union_id 在同一租户下跨应用相同,用于跨应用识别用户。
|
||
"""
|
||
__tablename__ = "user_feishu_open_ids"
|
||
|
||
id = Column(CHAR(36), primary_key=True, default=lambda: str(uuid.uuid4()), comment="主键")
|
||
user_id = Column(CHAR(36), nullable=True, index=True, comment="平台用户 ID(首次捕获时可能为空)")
|
||
app_id = Column(String(64), nullable=False, index=True, comment="飞书应用 app_id")
|
||
open_id = Column(String(64), nullable=False, comment="该应用下的用户 open_id")
|
||
union_id = Column(String(64), nullable=True, index=True, comment="飞书 union_id,跨应用唯一,用于关联同一用户")
|
||
created_at = Column(DateTime, default=func.now(), comment="创建时间")
|
||
updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
|
||
|
||
__table_args__ = (
|
||
UniqueConstraint("app_id", "open_id", name="uq_app_open_id"),
|
||
Index("ix_user_app", "user_id", "app_id"),
|
||
)
|
||
|
||
def __repr__(self):
|
||
return f"<UserFeishuOpenId(user={self.user_id}, app={self.app_id})>"
|