Files
meijiaka-zy/python-api/app/models/user_device.py
T
小鱼开发 b597d715c8 fix: 认证流程修复 + alembic 迁移补全 + 前端僵尸代码清理
后端:
- 修复 get_current_user 未校验 is_active,被封禁用户仍可用旧 Token
- auth.py 捕获 ValueError 转 HTTPException(验证码错误、账号被封、Token 无效等不再返回 500)
- 修正 SMS 每日上限注释(3次 → 10次)
- 修复迁移脚本外键引用错误:users.id → mjk_users.id
- 新建积分系统 4 张表的迁移(mjk_user_points/batches/transactions/recharge_orders)
- pyproject.toml 补充 alembic + psycopg2-binary 依赖
- ruff 格式修复(import 排序等)

前端:
- 修复 doRefreshToken 成功后不持久化新 Token 的严重 bug
- 修复应用重启后 SSE 不自动重连(收不到踢人通知)
- 修复 App.tsx handleLogout 未 await
- client.ts 统一从 utils/env 导入 isTauri,默认 base URL 兜底 localhost:8000
- 清理 ~20 个未使用的 hooks/utils/api 模块/组件导出
- 修复所有 ESLint 警告(206 → 0)和 TSC 错误
- 测试通过(5/5)

其他:
- 更新 requirements.lock 和 uv.lock
2026-05-08 11:10:48 +08:00

67 lines
1.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
用户设备模型
============
单设备登录约束:一个用户同一时间只能在一个设备上登录。
user_id 字段带 UNIQUE 约束,强制 1:1 关系。
"""
import uuid
from datetime import UTC, datetime
from sqlalchemy import ForeignKey, String
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.models.base import BaseModelBigInt
class UserDevice(BaseModelBigInt):
"""用户设备表(单设备登录)"""
__tablename__ = "mjk_user_devices"
user_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("mjk_users.id", ondelete="CASCADE"),
nullable=False,
unique=True,
comment="用户 ID(唯一约束,强制单设备登录)",
)
device_id: Mapped[str] = mapped_column(
String(64),
nullable=False,
comment="设备唯一标识(前端生成)",
)
device_name: Mapped[str | None] = mapped_column(
String(128),
nullable=True,
comment="设备名称(如 'MacBook Pro'",
)
os_info: Mapped[str | None] = mapped_column(
String(128),
nullable=True,
comment="操作系统信息",
)
app_version: Mapped[str | None] = mapped_column(
String(32),
nullable=True,
comment="应用版本号",
)
refresh_token_hash: Mapped[str | None] = mapped_column(
String(64),
nullable=True,
comment="Refresh Token SHA256 哈希(用于校验和撤销)",
)
last_active_at: Mapped[datetime] = mapped_column(
default=lambda: datetime.now(UTC),
nullable=False,
comment="最后活跃时间",
)