#!/usr/bin/env python3 """ 创建用户 CLI 工具 ================ 绕过短信验证码,直接操作数据库创建用户。 用法: cd python-api python -m scripts.create_user --mobile 13800138000 --nickname 测试用户 python -m scripts.create_user --mobile 13800138001 --nickname 用户2 --device-id dev-001 环境变量: DATABASE_URL 数据库连接(默认从 .env 读取) SECRET_KEY JWT 密钥(默认从 .env 读取) """ import argparse import asyncio import os import sys import uuid # 将项目根目录加入路径 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from sqlalchemy import select from app.db.session import AsyncSessionLocal, close_db from app.models.user import User from app.models.user_device import UserDevice from app.models.user_point import UserPoint async def create_user( mobile: str, nickname: str | None = None, device_id: str | None = None, device_name: str | None = None, source: str = "cli", ) -> User: """创建用户并返回 User 实例。""" async with AsyncSessionLocal() as session: # 检查手机号是否已存在 stmt = select(User).where(User.mobile == mobile) result = await session.execute(stmt) existing = result.scalar_one_or_none() if existing is not None: print(f"⚠️ 手机号 {mobile} 已存在(id={existing.id}),跳过创建") return existing # 创建用户 user = User( id=uuid.uuid4(), mobile=mobile, nickname=nickname, source=source, ) session.add(user) # 需要先 flush 获取 user.id(虽然 uuid 已预生成,但 flush 确保数据库一致) await session.flush() # 创建积分汇总记录 user_point = UserPoint(user_id=user.id) session.add(user_point) # 可选:创建设备记录 if device_id: from datetime import UTC, datetime device = UserDevice( user_id=user.id, device_id=device_id, device_name=device_name, last_active_at=datetime.now(UTC), ) session.add(device) await session.commit() print(f"✅ 用户创建成功: id={user.id}, mobile={mobile}, nickname={nickname or '(未设置)'}") return user async def run(args: argparse.Namespace) -> None: """主执行逻辑。""" try: await create_user( mobile=args.mobile, nickname=args.nickname, device_id=args.device_id, device_name=args.device_name, source=args.source, ) finally: await close_db() def main() -> None: parser = argparse.ArgumentParser(description="直接操作数据库创建用户(绕过短信验证)") parser.add_argument("--mobile", required=True, help="手机号") parser.add_argument("--nickname", default=None, help="用户昵称") parser.add_argument("--device-id", default=None, help="设备标识(可选)") parser.add_argument("--device-name", default=None, help="设备名称(可选)") parser.add_argument("--source", default="cli", help="注册来源(默认: cli)") args = parser.parse_args() asyncio.run(run(args)) if __name__ == "__main__": main()