增加短信渠道
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package dto
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type SMSSendRequest struct {
|
||||
Phone string `json:"phone"`
|
||||
Params json.RawMessage `json:"params"`
|
||||
}
|
||||
|
||||
type SMSSendResponse struct {
|
||||
RequestID string `json:"requestId"`
|
||||
MessageID string `json:"messageId"`
|
||||
}
|
||||
@@ -3,4 +3,4 @@ package integration
|
||||
import "github.com/google/wire"
|
||||
|
||||
// ProviderSet wires integration transport services.
|
||||
var ProviderSet = wire.NewSet(NewIntegrationConfigService)
|
||||
var ProviderSet = wire.NewSet(NewIntegrationConfigService, NewSMSService)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
biz "kra/internal/biz/integration"
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
|
||||
type smsUsecase interface {
|
||||
Send(context.Context, *biz.SMSMessage) (*biz.SMSResult, error)
|
||||
}
|
||||
|
||||
type SMSService struct{ uc smsUsecase }
|
||||
|
||||
func NewSMSService(uc *biz.SMSUsecase) *SMSService { return &SMSService{uc: uc} }
|
||||
|
||||
func (s *SMSService) Send(ctx context.Context, provider string, req *dto.SMSSendRequest) (*dto.SMSSendResponse, error) {
|
||||
if req == nil || len(req.Params) > 12000 {
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
m := &biz.SMSMessage{Provider: provider, Phone: strings.TrimSpace(req.Phone)}
|
||||
params := bytes.TrimSpace(req.Params)
|
||||
var values any
|
||||
if json.Unmarshal(params, &values) != nil {
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
switch provider {
|
||||
case "aliyun":
|
||||
object, ok := values.(map[string]any)
|
||||
if !ok {
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
m.NamedParams = make(map[string]string, len(object))
|
||||
for key, value := range object {
|
||||
text, ok := value.(string)
|
||||
if !ok {
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
m.NamedParams[key] = text
|
||||
}
|
||||
case "tencent":
|
||||
array, ok := values.([]any)
|
||||
if !ok {
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
m.Params = make([]string, 0, len(array))
|
||||
for _, value := range array {
|
||||
text, ok := value.(string)
|
||||
if !ok {
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
m.Params = append(m.Params, text)
|
||||
}
|
||||
default:
|
||||
return nil, biz.ErrSMSInvalid
|
||||
}
|
||||
if err := biz.ValidateSMSMessage(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result, err := s.uc.Send(ctx, m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &dto.SMSSendResponse{RequestID: result.RequestID, MessageID: result.MessageID}, nil
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
biz "kra/internal/biz/integration"
|
||||
"kra/internal/service/dto"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type smsSenderFake struct{ calls int }
|
||||
|
||||
func (f *smsSenderFake) Send(context.Context, *biz.SMSMessage) (*biz.SMSResult, error) {
|
||||
f.calls++
|
||||
return &biz.SMSResult{MessageID: "test"}, nil
|
||||
}
|
||||
|
||||
func TestSMSRejectsInvalidInputBeforeDelivery(t *testing.T) {
|
||||
fake := &smsSenderFake{}
|
||||
s := &SMSService{uc: fake}
|
||||
for _, tt := range []struct{ provider, phone, params string }{
|
||||
{"aliyun", "+8613800138000", `[]`}, {"tencent", "+8613800138000", `{}`},
|
||||
{"tencent", "+8613800138000", `null`}, {"tencent", "+8613800138000", `[123]`},
|
||||
{"tencent", "+8613800138000", `[null]`}, {"aliyun", "+8613800138000", `{"code":null}`},
|
||||
{"aliyun", "13800138000", `{}`}, {"aliyun", "+12025550123", `{}`},
|
||||
{"aliyun", "+8613800138000,+8613800138001", `{}`}, {"other", "+8613800138000", `{}`},
|
||||
} {
|
||||
if _, err := s.Send(context.Background(), tt.provider, &dto.SMSSendRequest{Phone: tt.phone, Params: json.RawMessage(tt.params)}); err == nil {
|
||||
t.Fatalf("accepted invalid input: %+v", tt)
|
||||
}
|
||||
}
|
||||
if fake.calls != 0 {
|
||||
t.Fatal("invalid input reached sender")
|
||||
}
|
||||
for _, provider := range []string{"aliyun", "tencent"} {
|
||||
params := `{}`
|
||||
if provider == "tencent" {
|
||||
params = `[]`
|
||||
}
|
||||
if _, err := s.Send(context.Background(), provider, &dto.SMSSendRequest{Phone: "+8613800138000", Params: json.RawMessage(params)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user