feat(sms): 迁移 PineSound 阿里云短信+Redis缓存+真实随机数;强制MySQL禁用SQLite;连接池取消请求shield修复
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""短信生态配置写入脚本(迁移自 PineSoundServer .env)。
|
||||
|
||||
把阿里云凭据/签名/区域与 PineSound 短信模板(仅本项目需要的 T1 登录)写入
|
||||
system_configs 表:
|
||||
|
||||
- sms.provider -> aliyun
|
||||
- sms.aliyun -> 凭据/签名/区域(与 PineSoundServer .env 完全一致:
|
||||
ACCESS_KEY_ID / ACCESS_KEY_SECRET / REGION_ID=cn-qingdao /
|
||||
SIGN_NAME=派音人工智能)
|
||||
- sms.template.login -> SMS_510980133(PineSound T1 登录验证码,变量 code)
|
||||
- sms.template.register -> SMS_510980133(本项目注册=手机号登录一体,复用 T1)
|
||||
|
||||
PineSound 其余模板(修改密码/绑定手机/找回密码/注销/充值/内测)本项目当前业务
|
||||
未使用,不迁移;notification / order_status / appointment 场景 PineSound 无匹配
|
||||
模板,保持留空(stub 打印,不阻断业务)。
|
||||
|
||||
用法:
|
||||
python scripts/db/set_sms_config.py # 实际执行
|
||||
python scripts/db/set_sms_config.py --dry-run # 只预览不写库
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv(Path(__file__).resolve().parent.parent.parent / ".env")
|
||||
|
||||
from sqlalchemy import text # noqa: E402
|
||||
|
||||
from app.infrastructure.db import AsyncSessionLocal # noqa: E402
|
||||
from app.infrastructure.repositories import utcnow_iso # noqa: E402
|
||||
|
||||
# 与 PineSoundServer .env 完全一致的阿里云短信配置
|
||||
ALIYUN_CONFIG = {
|
||||
"access_key_id": "LTAI5t6ZU2Nf8qbGpEpn7bzN",
|
||||
"access_key_secret": "lnNkxiXvNVsCPdc7hVZSXz6goOz8YJ",
|
||||
"sign_name": "派音人工智能",
|
||||
"region_id": "cn-qingdao",
|
||||
"endpoint": "dysmsapi.aliyuncs.com",
|
||||
}
|
||||
|
||||
# key -> (value, description);幂等覆盖:已存在的键也更新为 PineSound 配置。
|
||||
SMS_CONFIGS: list[tuple[str, str, str]] = [
|
||||
("sms.provider", "aliyun", "短信 provider(stub|aliyun)"),
|
||||
("sms.aliyun",
|
||||
__import__("json").dumps(ALIYUN_CONFIG, ensure_ascii=False),
|
||||
"阿里云短信总配置(与 PineSoundServer .env 一致)"),
|
||||
("sms.template.login",
|
||||
'{"template_id":"SMS_510980133","variables":["code"]}',
|
||||
"登录验证码模板(PineSound T1:验证码 code,5分钟有效,请勿泄露)"),
|
||||
("sms.template.register",
|
||||
'{"template_id":"SMS_510980133","variables":["code"]}',
|
||||
"注册验证码模板(本项目注册=手机号登录一体,复用 T1)"),
|
||||
("sms.template.notification",
|
||||
'{"template_id":"","variables":[]}',
|
||||
"通知提醒模板(PineSound 无匹配模板,暂留空)"),
|
||||
("sms.template.order_status",
|
||||
'{"template_id":"","variables":["order_no","status"]}',
|
||||
"订单状态变动模板(PineSound 无匹配模板,暂留空)"),
|
||||
("sms.template.appointment",
|
||||
'{"template_id":"","variables":["service_name","schedule_at","contact"]}',
|
||||
"服务预约模板(PineSound 无匹配模板,暂留空)"),
|
||||
]
|
||||
|
||||
|
||||
async def main(dry_run: bool) -> int:
|
||||
now = utcnow_iso()
|
||||
async with AsyncSessionLocal() as session:
|
||||
for key, value, description in SMS_CONFIGS:
|
||||
exists = (
|
||||
await session.execute(
|
||||
text("SELECT `key` FROM system_configs WHERE `key` = :k"),
|
||||
{"k": key},
|
||||
)
|
||||
).scalar_one_or_none()
|
||||
if exists:
|
||||
sql = text(
|
||||
"UPDATE system_configs SET `value` = :v, description = :d, "
|
||||
"updated_at = :now WHERE `key` = :k"
|
||||
)
|
||||
else:
|
||||
sql = text(
|
||||
"INSERT INTO system_configs (`key`, `value`, `description`, "
|
||||
"updated_at) VALUES (:k, :v, :d, :now)"
|
||||
)
|
||||
if dry_run:
|
||||
print(f"[dry-run] {'UPDATE' if exists else 'INSERT'} {key} = {value}")
|
||||
continue
|
||||
await session.execute(sql, {"k": key, "v": value, "d": description, "now": now})
|
||||
if not dry_run:
|
||||
await session.commit()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="写入短信生态配置(PineSound 迁移)")
|
||||
parser.add_argument("--dry-run", action="store_true", help="只预览不写库")
|
||||
args = parser.parse_args()
|
||||
raise SystemExit(asyncio.run(main(args.dry_run)))
|
||||
Reference in New Issue
Block a user