feat(distribution): 支持分站独立短信验证码通道
- 新增分销站点独立短信服务商配置(阿里云),登录验证码按 site_code/domain 解析专属通道,未启用或解析失败时回退主站默认通道 - 密钥经 crypto.Encryptor 加密落库,模型字段 json 序列化隔离,DTO 仅回传掩码 - provider 白名单校验,mock 仅在非生产环境放行;启用时强制校验必填凭据 - 配置读写/测试接口限管理员权限,测试发送增加 60s 频控(Redis,缺省进程内) - 解密失败记告警并优雅回退主站,避免把密文当明文密钥使用 - 两套前端新增短信配置入口、必填与手机号校验、发送冷却 - 新增迁移 000071 及加解密、白名单、频控、解析回退等单测
This commit is contained in:
@@ -82,6 +82,57 @@ func (h *Handler) UpdateSite(c *gin.Context) {
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) GetSiteSMSConfig(c *gin.Context) {
|
||||
id, ok := parseID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
adminID, _ := currentAdminID(c)
|
||||
item, err := h.service.GetSiteSMSConfig(c.Request.Context(), adminID, id)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateSiteSMSConfig(c *gin.Context) {
|
||||
id, ok := parseID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var req UpdateSiteSMSConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "短信配置参数不正确")
|
||||
return
|
||||
}
|
||||
adminID, _ := currentAdminID(c)
|
||||
item, err := h.service.UpdateSiteSMSConfig(c.Request.Context(), adminID, id, req)
|
||||
if err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, item)
|
||||
}
|
||||
|
||||
func (h *Handler) TestSiteSMSConfig(c *gin.Context) {
|
||||
id, ok := parseID(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var req TestSiteSMSConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "测试参数不正确,手机号必填")
|
||||
return
|
||||
}
|
||||
adminID, _ := currentAdminID(c)
|
||||
if err := h.service.TestSiteSMSConfig(c.Request.Context(), adminID, id, req); err != nil {
|
||||
writeError(c, err)
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"message": "测试短信发送成功"})
|
||||
}
|
||||
|
||||
func (h *Handler) ListRules(c *gin.Context) {
|
||||
var siteID *uint64
|
||||
if raw := strings.TrimSpace(c.Query("site_id")); raw != "" {
|
||||
@@ -828,6 +879,12 @@ func writeError(c *gin.Context, err error) {
|
||||
response.BadRequest(c, "请选择要加价的商品")
|
||||
case errors.Is(err, ErrInvalidListingStatus):
|
||||
response.BadRequest(c, "商品展示状态不正确")
|
||||
case errors.Is(err, ErrSMSConfigInvalid):
|
||||
response.BadRequest(c, "分销短信配置不完整,启用时必须配置 AccessKey、签名与模板")
|
||||
case errors.Is(err, ErrSMSTestRateLimited):
|
||||
response.Error(c, http.StatusTooManyRequests, "rate_limited", "测试短信发送过于频繁,请稍后再试")
|
||||
case errors.Is(err, ErrSMSSendFailed):
|
||||
response.Error(c, http.StatusBadGateway, "sms_send_failed", "短信测试发送失败,请检查配置与通道额度")
|
||||
case errors.Is(err, ErrSiteAccessDenied):
|
||||
response.Error(c, http.StatusForbidden, "forbidden", "无权访问该分销站点")
|
||||
case errors.Is(err, ErrDependencyUnavailable):
|
||||
|
||||
Reference in New Issue
Block a user