migrate_special_users_init.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. """
  2. 特殊实验用户:加字段 + 预置 A/B 组 60 个账号
  3. 运行(在 backend 目录): python migrations/migrate_special_users_init.py
  4. """
  5. import asyncio
  6. import sys
  7. from pathlib import Path
  8. from typing import Any
  9. # 允许从 backend 目录直接运行
  10. sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
  11. import aiomysql
  12. from config import settings
  13. MIGRATIONS_DIR = Path(__file__).resolve().parent
  14. async def column_exists(cursor: Any, column_name: str) -> bool:
  15. await cursor.execute(
  16. """
  17. SELECT COUNT(*) FROM information_schema.columns
  18. WHERE table_schema = %s AND table_name = 'users' AND column_name = %s
  19. """,
  20. (settings.MYSQL_DATABASE, column_name),
  21. )
  22. row = await cursor.fetchone()
  23. return bool(row and row[0] > 0)
  24. async def run_sql_file(cursor: Any, conn: Any, path: Path) -> None:
  25. sql = path.read_text(encoding="utf-8")
  26. statements = [s.strip() for s in sql.split(";") if s.strip()]
  27. for stmt in statements:
  28. if stmt.upper().startswith("SET NAMES"):
  29. continue
  30. await cursor.execute(stmt)
  31. await conn.commit()
  32. async def count_special_users(cursor: Any) -> list[tuple[str, int]]:
  33. await cursor.execute(
  34. """
  35. SELECT special_group, COUNT(*) AS cnt
  36. FROM users
  37. WHERE is_special_user = 1
  38. AND email LIKE '%@lyrria.com'
  39. AND (email LIKE 'A%@lyrria.com' OR email LIKE 'B%@lyrria.com')
  40. GROUP BY special_group
  41. ORDER BY special_group
  42. """
  43. )
  44. return await cursor.fetchall()
  45. async def migrate() -> bool:
  46. try:
  47. conn: aiomysql.Connection = await aiomysql.connect(
  48. host=settings.MYSQL_HOST,
  49. port=settings.MYSQL_PORT,
  50. user=settings.MYSQL_USER,
  51. password=settings.MYSQL_PASSWORD,
  52. db=settings.MYSQL_DATABASE,
  53. charset="utf8mb4",
  54. )
  55. async with conn.cursor() as cursor:
  56. if not await column_exists(cursor, "is_special_user"):
  57. print("🔄 添加 is_special_user / special_group 字段...")
  58. alter_sql = (MIGRATIONS_DIR / "add_special_user_fields.sql").read_text(encoding="utf-8")
  59. for stmt in [s.strip() for s in alter_sql.split(";") if s.strip()]:
  60. if stmt.upper().startswith("SET NAMES"):
  61. continue
  62. await cursor.execute(stmt)
  63. await conn.commit()
  64. print("✅ 字段添加完成")
  65. else:
  66. print("✅ is_special_user 字段已存在,跳过 ALTER")
  67. print("🔄 预置 A/B 组 60 个账号...")
  68. seed_path = MIGRATIONS_DIR / "seed_special_users_ab_groups.sql"
  69. seed_sql = seed_path.read_text(encoding="utf-8")
  70. for stmt in [s.strip() for s in seed_sql.split(";") if s.strip()]:
  71. upper = stmt.upper()
  72. if upper.startswith("SET NAMES") or upper.startswith("SELECT"):
  73. if upper.startswith("SELECT"):
  74. await cursor.execute(stmt)
  75. rows = await cursor.fetchall()
  76. print("📊 校验结果:", rows)
  77. continue
  78. await cursor.execute(stmt)
  79. await conn.commit()
  80. print("✅ 账号预置完成")
  81. rows = await count_special_users(cursor)
  82. print("📊 当前特殊用户数量:", dict(rows) if rows else "无")
  83. conn.close()
  84. return True
  85. except Exception:
  86. import traceback
  87. traceback.print_exc()
  88. return False
  89. if __name__ == "__main__":
  90. ok = asyncio.run(migrate())
  91. sys.exit(0 if ok else 1)