105 lines
4.3 KiB
Python
105 lines
4.3 KiB
Python
|
|
#!/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)))
|