增加短信渠道
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/go-kratos/kratos/v3/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrSMSInvalid = errors.BadRequest("SMS_INVALID", "短信参数无效")
|
||||
ErrSMSDisabled = errors.BadRequest("SMS_DISABLED", "短信渠道未配置或未启用")
|
||||
ErrSMSFailed = errors.BadRequest("SMS_SEND_FAILED", "短信提交失败,请检查服务商配置和账户状态")
|
||||
)
|
||||
|
||||
// SMSMessage carries one recipient and provider-specific template parameters.
|
||||
type SMSMessage struct {
|
||||
Provider string
|
||||
Phone string
|
||||
NamedParams map[string]string
|
||||
Params []string
|
||||
}
|
||||
|
||||
type SMSResult struct {
|
||||
RequestID string
|
||||
MessageID string
|
||||
}
|
||||
|
||||
type SMSSender interface {
|
||||
Send(context.Context, *SMSMessage) (*SMSResult, error)
|
||||
}
|
||||
|
||||
type SMSUsecase struct{ sender SMSSender }
|
||||
|
||||
func NewSMSUsecase(sender SMSSender) *SMSUsecase { return &SMSUsecase{sender: sender} }
|
||||
|
||||
var smsPhonePattern = regexp.MustCompile(`^\+[1-9][0-9]{6,14}$`)
|
||||
|
||||
func ValidateSMSMessage(m *SMSMessage) error {
|
||||
if m == nil || (m.Provider != "aliyun" && m.Provider != "tencent") || !smsPhonePattern.MatchString(m.Phone) {
|
||||
return ErrSMSInvalid
|
||||
}
|
||||
// The Aliyun adapter uses the mainland China SendSms API.
|
||||
if m.Provider == "aliyun" && (!strings.HasPrefix(m.Phone, "+861") || len(m.Phone) != 14 || len(m.Params) != 0) {
|
||||
return errors.BadRequest("SMS_INVALID", "阿里云短信请使用 +86 开头的中国大陆手机号及对象格式模板参数")
|
||||
}
|
||||
if m.Provider == "tencent" && len(m.NamedParams) != 0 {
|
||||
return errors.BadRequest("SMS_INVALID", "腾讯云短信模板参数必须是按模板顺序排列的字符串数组")
|
||||
}
|
||||
if len(m.NamedParams) > 20 || len(m.Params) > 20 {
|
||||
return ErrSMSInvalid
|
||||
}
|
||||
for key, value := range m.NamedParams {
|
||||
if strings.TrimSpace(key) == "" || len(key) > 64 || len(value) > 500 {
|
||||
return ErrSMSInvalid
|
||||
}
|
||||
}
|
||||
for _, value := range m.Params {
|
||||
if len(value) > 500 {
|
||||
return ErrSMSInvalid
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uc *SMSUsecase) Send(ctx context.Context, m *SMSMessage) (*SMSResult, error) {
|
||||
if err := ValidateSMSMessage(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uc.sender.Send(ctx, m)
|
||||
}
|
||||
|
||||
func validateSMSConfig(provider string, values map[string]any) error {
|
||||
definition, ok := IntegrationDefinition(IntegrationKindSMS, provider)
|
||||
if !ok {
|
||||
return errors.BadRequest("SMS_PROVIDER_INVALID", "不支持的短信服务商")
|
||||
}
|
||||
for _, field := range definition.Fields {
|
||||
value, ok := values[field.Key].(string)
|
||||
if !ok || len(value) > 512 || (field.Required && strings.TrimSpace(value) == "") {
|
||||
return errors.BadRequest("SMS_CONFIG_INVALID", "请填写有效的"+field.Label)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user