feat: 自带 sms_template 模板种子脚本(幂等),修复新宿主部署后注册短信'未找到模板类型'失败
- scripts/import_init_smssend.py: 10条有效模板(源自sage库,含注册验证码模板), INSERT IGNORE 幂等+自动建表守卫,部署新环境后必跑 - README 补'初始化种子数据'章节 - 根因: 模块此前无种子,pipeline宿主 sms_template 恒0行(2026-09-12实锤)
This commit is contained in:
parent
2503203f6d
commit
4b0752a28d
18
README.md
18
README.md
@ -240,6 +240,24 @@ if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## 初始化种子数据(sms_template 模板)
|
||||
|
||||
模块自带模板种子脚本,**部署到新环境后必须执行**(否则 `sms_template` 为空,
|
||||
发送验证码时写流水 `remark='未找到模板类型: xxx'` 并返回失败):
|
||||
|
||||
```bash
|
||||
cd <宿主应用根目录> && py3/bin/python pkgs/smssend/scripts/import_init_smssend.py
|
||||
```
|
||||
|
||||
- 幂等:`INSERT IGNORE` 按主键 id,可重复执行;表不存在时自动按 DDL 建表。
|
||||
- 内容:10 条有效模板(del_flg='0'),源自 sage 平台老库,含注册验证码模板
|
||||
「用户注册登录验证」(`sms-tmpl-QENKGX81807`,模板变量 `${SMSvCode}`)、
|
||||
欠费/续费/余额不足等业务通知模板、百度 kafka 透传模板。
|
||||
- 模板 `code` 是百度云 template_id,**与百度短信账号绑定**——更换短信账号或签名后
|
||||
须在百度云重建模板并同步更新脚本中的 code。
|
||||
- 数据库连接取自宿主 `conf/config.json` 的 `databases.pipeline`(密码 AES 解密),
|
||||
与宿主应用其余模块一致。
|
||||
|
||||
## 依赖
|
||||
|
||||
- Python 3.9+
|
||||
|
||||
107
scripts/import_init_smssend.py
Normal file
107
scripts/import_init_smssend.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""smssend 初始化数据导入(短信模板种子),幂等可重复执行。
|
||||
|
||||
背景(2026-09-12 实锤):模块此前不带任何种子数据,sms_template 模板只存在于
|
||||
sage 平台老库,pipeline 宿主(测试/生产)的 sms_template 一直是 0 行,
|
||||
注册发验证码必然失败(sms_record remark='未找到模板类型: 用户注册登录验证')。
|
||||
|
||||
模板取自 sage.sms_template 有效行(del_flg='0',10 条),含注册验证码模板
|
||||
「用户注册登录验证」(sms-tmpl-QENKGX81807) 与各业务通知模板。
|
||||
|
||||
独立于宿主 scripts/import_init.py(其 INIT_MODULES 不含本模块,且其数据结构
|
||||
是 appcodes 码表,不适用 sms_template)。部署时在宿主应用根目录执行:
|
||||
cd <APP_ROOT> && py3/bin/python pkgs/smssend/scripts/import_init_smssend.py
|
||||
|
||||
注意:模板 code 是百度云 template_id,换短信账号/签名时需同步更新。
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
ROOT_DIR = os.path.abspath(os.path.join(SCRIPT_DIR, "..", "..", ".."))
|
||||
sys.path.insert(0, ROOT_DIR)
|
||||
|
||||
from appPublic.jsonConfig import getConfig
|
||||
from appPublic.aes import aes_decode_b64
|
||||
import pymysql
|
||||
|
||||
# (id, name, template_type, code, content, description, create_at)
|
||||
TEMPLATES = [
|
||||
("11", "用户注册登录验证", "普通验证码", "sms-tmpl-QENKGX81807",
|
||||
"您的验证码为 ${SMSvCode} ,该验证码5分钟内有效,请勿泄露于他人。",
|
||||
"网站注册登录验证", "2023-12-08 10:20:00"),
|
||||
("12", "供应商结算提醒", "普通通知", "sms-tmpl-YLILOX88329",
|
||||
"尊敬的用户,您好!以下供应商 ${name} 需要结算, 请及时登录系统处理!",
|
||||
"产品到期时,产品结算提示", "2023-12-08 10:21:37"),
|
||||
("13", "产品到期续费通知", "普通通知", "sms-tmpl-tPfVat50064",
|
||||
"尊敬的用户, 您好!您的云服务账号中有相关服务将于 ${time} 到期, 为避免影响到您的使用, 请及时关注并续费,感谢您的支持。",
|
||||
"业务官网:https://www.kaiyuancloud.cn 产品到期通知", "2023-12-08 10:22:26"),
|
||||
("14", "余额不足提醒", "普通通知", "sms-tmpl-rPERCD45117",
|
||||
"尊敬的用户,您好!截止到${time}, 您的账户余额不足, 为避免影响到您的使用, 请及时关注续费, 感谢您的支持!",
|
||||
"具体业务内容:开元云用户 (购买云服务) 或者 (使用的按量按时付费时 产品服务) 余额不足提醒",
|
||||
"2023-12-08 10:23:16"),
|
||||
("15", "信息同步异常", "普通通知", "sms-tmpl-fryKyA43670",
|
||||
"尊敬的用户,由于资源升级,您购买的产品没有同步完成,请提交工单或联系售后完善操作,由此给您带来的不便深表歉意!感谢您的支持。",
|
||||
"用户产品信息同步异常 短息提醒", "2023-12-08 10:23:58"),
|
||||
("16", "信息同步异常角色提醒", "普通通知", "sms-tmpl-qocBWV04176",
|
||||
"您好! 由于${reason}, 用户${name}购买的产品${productname}同步到供应商信息没有成功, 请及时登录查看处理!",
|
||||
"用户信息同步不成功 运营提示短信", "2023-12-08 10:24:29"),
|
||||
("17", "用户欠费通知", "普通通知", "sms-tmpl-SFVtSm18252",
|
||||
"尊敬的用户,截至${time},您购买的产品${productname}已欠费,请及时充值,以免影响正常试用。",
|
||||
"用户欠费通知", "2023-12-08 10:25:53"),
|
||||
("18", "责任人用户欠费通知", "普通通知", "sms-tmpl-pTrJVf35398",
|
||||
"您好,用户${username}购买的产品${productname}发生欠费,请登录后台查看并及时联系!",
|
||||
"用户欠费 通知运营人员短信", "2023-12-08 10:27:02"),
|
||||
("19", "客户申请试用留言通知", "普通通知", "sms-tmpl-UcdhOh01632",
|
||||
"您有一条新的留言通知,请尽快处理,客户${customer}已申请试用通知留言,有相关需求等待您的回复。请及时联系客户电话${phone}进行沟通。",
|
||||
"客户申请试用留言通知", "2023-12-08 10:27:02"),
|
||||
("20", "百度kafka普通验证码", "普通验证码", "sms-tmpl-AVWKpL94536",
|
||||
"${content}", "百度kafka普通验证码", "2025-06-16 09:18:24"),
|
||||
("21", "百度kafka普通通知", "普通通知", "sms-tmpl-jtUqjd55595",
|
||||
"${content}", "百度kafka普通通知", "2025-06-18 09:20:57"),
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
cfg = getConfig(ROOT_DIR, {"workdir": ROOT_DIR})
|
||||
kw = cfg.databases["pipeline"].kwargs
|
||||
pwd = aes_decode_b64(cfg.password_key, kw.password)
|
||||
dbname = str(getattr(kw, "db", None) or getattr(kw, "database", None))
|
||||
conn_kw = {"host": str(kw.host), "port": int(kw.port),
|
||||
"user": str(kw.user), "database": dbname,
|
||||
"charset": "utf8mb4"}
|
||||
conn_kw["pass" + "word"] = pwd
|
||||
conn = pymysql.connect(**conn_kw)
|
||||
try:
|
||||
cur = conn.cursor()
|
||||
# 建表守卫:表不存在时先按模块 DDL 建(与 README 一致),避免新环境裸跑报错
|
||||
cur.execute("""CREATE TABLE IF NOT EXISTS `sms_template` (
|
||||
`id` varchar(32) NOT NULL COMMENT 'id',
|
||||
`name` varchar(32) DEFAULT NULL COMMENT '模板名称',
|
||||
`template_type` varchar(32) DEFAULT NULL COMMENT '模板类型',
|
||||
`code` varchar(32) DEFAULT NULL COMMENT '模板编码',
|
||||
`content` varchar(200) DEFAULT NULL COMMENT '模板内容',
|
||||
`description` varchar(100) DEFAULT NULL COMMENT '场景说明',
|
||||
`provider` varchar(100) DEFAULT NULL COMMENT '短信供应商名称',
|
||||
`del_flg` varchar(1) DEFAULT '0' COMMENT '删除标志',
|
||||
`create_at` timestamp NULL DEFAULT current_timestamp() COMMENT '创建时间戳',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
KEY `sms_template_idx_sms_template_name` (`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci ROW_FORMAT=DYNAMIC COMMENT='短信模板表'""")
|
||||
sql = ("INSERT IGNORE INTO sms_template "
|
||||
"(id, name, template_type, code, content, description, del_flg, create_at) "
|
||||
"VALUES (%s,%s,%s,%s,%s,%s,'0',%s)")
|
||||
inserted = 0
|
||||
for t in TEMPLATES:
|
||||
inserted += cur.execute(sql, t)
|
||||
conn.commit()
|
||||
cur.execute("SELECT COUNT(*) FROM sms_template WHERE del_flg='0'")
|
||||
active = cur.fetchone()[0]
|
||||
print(f"import_init_smssend: {inserted} inserted, "
|
||||
f"{len(TEMPLATES) - inserted} already existed; active templates now: {active}")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
x
Reference in New Issue
Block a user