feat(sms): 新增节点短信提醒(审核未通过/被租用需辅助/上架未成交)
This commit is contained in:
@@ -57,18 +57,45 @@ func NewAliyunProvider(cfg AliyunConfig, log *zap.Logger) (*AliyunProvider, erro
|
||||
}
|
||||
|
||||
func (p *AliyunProvider) SendLoginCode(ctx context.Context, phone string, code string) error {
|
||||
params, err := json.Marshal(map[string]string{"code": code})
|
||||
if err != nil {
|
||||
return err
|
||||
return p.SendTemplate(ctx, TemplateRequest{
|
||||
Phone: phone,
|
||||
TemplateCode: p.loginTemplateCode,
|
||||
Params: map[string]string{"code": code},
|
||||
})
|
||||
}
|
||||
|
||||
// SendTemplate 发送已报备的模板短信。req.SignName 为空时回退到 Provider 默认签名。
|
||||
// 模板无变量时按阿里云要求传空 JSON,避免拼接文案导致模板不匹配。
|
||||
func (p *AliyunProvider) SendTemplate(ctx context.Context, req TemplateRequest) error {
|
||||
phone := strings.TrimSpace(req.Phone)
|
||||
if phone == "" {
|
||||
return ErrProviderConfigInvalid
|
||||
}
|
||||
signName := strings.TrimSpace(req.SignName)
|
||||
if signName == "" {
|
||||
signName = p.signName
|
||||
}
|
||||
templateCode := strings.TrimSpace(req.TemplateCode)
|
||||
if templateCode == "" {
|
||||
return ErrProviderConfigInvalid
|
||||
}
|
||||
|
||||
req := &dysms.SendSmsRequest{}
|
||||
req.SetPhoneNumbers(phone)
|
||||
req.SetSignName(p.signName)
|
||||
req.SetTemplateCode(p.loginTemplateCode)
|
||||
req.SetTemplateParam(string(params))
|
||||
params := "{}"
|
||||
if len(req.Params) > 0 {
|
||||
raw, err := json.Marshal(req.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params = string(raw)
|
||||
}
|
||||
|
||||
resp, err := p.client.SendSmsWithContext(ctx, req, &dara.RuntimeOptions{})
|
||||
apiReq := &dysms.SendSmsRequest{}
|
||||
apiReq.SetPhoneNumbers(phone)
|
||||
apiReq.SetSignName(signName)
|
||||
apiReq.SetTemplateCode(templateCode)
|
||||
apiReq.SetTemplateParam(params)
|
||||
|
||||
resp, err := p.client.SendSmsWithContext(ctx, apiReq, &dara.RuntimeOptions{})
|
||||
if err != nil {
|
||||
return fmt.Errorf("aliyun sms send failed: %w", err)
|
||||
}
|
||||
@@ -90,6 +117,7 @@ func (p *AliyunProvider) SendLoginCode(ctx context.Context, phone string, code s
|
||||
p.log.Debug(
|
||||
"短信发送成功",
|
||||
zap.String("phone", maskPhone(phone)),
|
||||
zap.String("template_code", templateCode),
|
||||
zap.String("provider_request_id", dara.StringValue(resp.Body.RequestId)),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -23,3 +23,17 @@ func (p *MockProvider) SendLoginCode(ctx context.Context, phone string, code str
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *MockProvider) SendTemplate(ctx context.Context, req TemplateRequest) error {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
if p.log != nil {
|
||||
p.log.Info("本地模板短信(未真实发送)",
|
||||
zap.String("phone", maskPhone(req.Phone)),
|
||||
zap.String("template_code", req.TemplateCode),
|
||||
zap.Any("params", req.Params),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -11,8 +11,19 @@ var (
|
||||
ErrProviderRateLimited = errors.New("sms provider rate limited")
|
||||
)
|
||||
|
||||
// TemplateRequest 描述一条模板短信。SignName 留空时使用 Provider 自身配置的默认签名。
|
||||
type TemplateRequest struct {
|
||||
Phone string
|
||||
SignName string
|
||||
TemplateCode string
|
||||
Params map[string]string
|
||||
}
|
||||
|
||||
type Provider interface {
|
||||
SendLoginCode(ctx context.Context, phone string, code string) error
|
||||
// SendTemplate 发送模板短信,用于登录验证码以外的业务节点触达。
|
||||
// 阿里云要求模板必须提前报备审核,因此调用方只传模板 CODE 与变量,不拼接文案。
|
||||
SendTemplate(ctx context.Context, req TemplateRequest) error
|
||||
}
|
||||
|
||||
type ProviderError struct {
|
||||
|
||||
@@ -19,3 +19,7 @@ func (p *UnavailableProvider) SendLoginCode(ctx context.Context, phone string, c
|
||||
}
|
||||
return ErrProviderConfigInvalid
|
||||
}
|
||||
|
||||
func (p *UnavailableProvider) SendTemplate(ctx context.Context, req TemplateRequest) error {
|
||||
return p.SendLoginCode(ctx, req.Phone, "")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user