-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sms): Added SMS(with
mitake
provider) (#67)
* feat(sms): Added SMS Signed-off-by: Flc゛ <four_leaf_clover@foxmail.com> * feat(sms): fix lint Signed-off-by: Flc゛ <four_leaf_clover@foxmail.com> * feat(sms): fix lint Signed-off-by: Flc゛ <four_leaf_clover@foxmail.com> * test(sms): Increased unit test coverage. Signed-off-by: Flc゛ <four_leaf_clover@foxmail.com> * test(sms): Increased unit test coverage. Signed-off-by: Flc゛ <four_leaf_clover@foxmail.com> --------- Signed-off-by: Flc゛ <four_leaf_clover@foxmail.com>
- Loading branch information
Showing
8 changed files
with
270 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
// Package mitake is a sms provider for mitake. | ||
// See: https://sms.mitake.com.tw/ | ||
package mitake | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
"net/url" | ||
|
||
"golang.org/x/text/encoding/traditionalchinese" | ||
|
||
"github.com/go-kratos-ecosystem/components/v2/sms" | ||
) | ||
|
||
type provider struct { | ||
api string | ||
username string | ||
password string | ||
|
||
httpClient *http.Client | ||
} | ||
|
||
type Option func(t *provider) | ||
|
||
func WithAPI(api string) Option { | ||
return func(t *provider) { | ||
t.api = api | ||
} | ||
} | ||
|
||
func WithHTTPClient(httpClient *http.Client) Option { | ||
return func(t *provider) { | ||
t.httpClient = httpClient | ||
} | ||
} | ||
|
||
func New(username, password string, opts ...Option) sms.Provider { | ||
p := &provider{ | ||
api: "https://smsapi.mitake.com.tw", | ||
username: username, | ||
password: password, | ||
httpClient: http.DefaultClient, | ||
} | ||
|
||
for _, opt := range opts { | ||
opt(p) | ||
} | ||
|
||
return p | ||
} | ||
|
||
func (p *provider) Send(ctx context.Context, phone *sms.Phone, message *sms.Message) error { | ||
if err := p.verify(phone, message); err != nil { | ||
return err | ||
} | ||
|
||
// Convert to Big5 | ||
text, err := traditionalchinese.Big5.NewEncoder().String(message.Text) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Combine params | ||
params := url.Values{} | ||
params.Set("username", p.username) | ||
params.Set("password", p.password) | ||
params.Set("type", "now") | ||
params.Set("encoding", "big5") | ||
params.Set("dstaddr", phone.Number) | ||
params.Set("smbody", text) | ||
|
||
// new request | ||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, p.api+"?"+params.Encode(), nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// send request | ||
resp, err := p.httpClient.Do(req) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
// check response | ||
if resp.StatusCode != http.StatusOK { | ||
return fmt.Errorf("sms mitake: http status code: %d", resp.StatusCode) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (p *provider) verify(phone *sms.Phone, message *sms.Message) error { | ||
if phone.Number == "" { | ||
return sms.ErrInvalidPhone | ||
} | ||
|
||
if message.Text == "" { | ||
return sms.ErrInvalidMessage | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package mitake | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/go-kratos-ecosystem/components/v2/sms" | ||
) | ||
|
||
func TestProvider(t *testing.T) { | ||
var ( | ||
username = "test" | ||
password = "test" | ||
number = "123456789" | ||
text = "Hello, world" | ||
) | ||
|
||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
if r.Method != http.MethodGet { | ||
t.Fatal("method error") | ||
} | ||
|
||
if r.URL.Query().Get("username") != username { | ||
t.Fatal("username error") | ||
} | ||
|
||
if r.URL.Query().Get("password") != password { | ||
t.Fatal("password error") | ||
} | ||
|
||
if r.URL.Query().Get("dstaddr") != number { | ||
t.Fatal("dstaddr error") | ||
} | ||
|
||
if r.URL.Query().Get("smbody") != text { | ||
t.Fatal("smbody error") | ||
} | ||
|
||
w.Write([]byte("hello")) //nolint:errcheck | ||
})) | ||
defer srv.Close() | ||
|
||
p := New(username, password, | ||
WithAPI(srv.URL), | ||
WithHTTPClient(http.DefaultClient), | ||
) | ||
|
||
err := p.Send(context.Background(), &sms.Phone{ | ||
Number: number, | ||
}, &sms.Message{ | ||
Text: text, | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package sms | ||
|
||
import "context" | ||
|
||
type NullProvider struct{} | ||
|
||
func NewNullProvider() Provider { | ||
return &NullProvider{} | ||
} | ||
|
||
func (p *NullProvider) Send(_ context.Context, _ *Phone, _ *Message) error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package sms | ||
|
||
import "context" | ||
|
||
type Provider interface { | ||
Send(ctx context.Context, phone *Phone, message *Message) error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package sms | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"time" | ||
) | ||
|
||
var ( | ||
ErrInvalidPhone = errors.New("sms: invalid phone") | ||
ErrInvalidMessage = errors.New("sms: invalid message") | ||
) | ||
|
||
type Phone struct { | ||
IDDCode string | ||
Number string | ||
} | ||
|
||
type Message struct { | ||
Text string | ||
Template string | ||
Variables map[string]string | ||
Schedule time.Time | ||
} | ||
|
||
type Sms struct { | ||
gw Provider | ||
} | ||
|
||
func New(gw Provider) *Sms { | ||
return &Sms{ | ||
gw: gw, | ||
} | ||
} | ||
|
||
func (s *Sms) Send(ctx context.Context, phone *Phone, message *Message) error { | ||
return s.gw.Send(ctx, phone, message) | ||
} | ||
|
||
func (s *Sms) SendText(ctx context.Context, phone *Phone, text string) error { | ||
return s.Send(ctx, phone, &Message{ | ||
Text: text, | ||
}) | ||
} | ||
|
||
func (s *Sms) SendTemplate(ctx context.Context, phone *Phone, template string, variables map[string]string) error { | ||
return s.Send(ctx, phone, &Message{ | ||
Template: template, | ||
Variables: variables, | ||
}) | ||
} | ||
|
||
func (s *Sms) SendTextWithNumber(ctx context.Context, phoneNumber, text string) error { | ||
return s.SendText(ctx, &Phone{ | ||
Number: phoneNumber, | ||
}, text) | ||
} | ||
|
||
func (s *Sms) SendTemplateWithNumber(ctx context.Context, phoneNumber, template string, variables map[string]string) error { //nolint:lll | ||
return s.SendTemplate(ctx, &Phone{ | ||
Number: phoneNumber, | ||
}, template, variables) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package sms | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestSms(t *testing.T) { | ||
sms := New(NewNullProvider()) | ||
ctx := context.Background() | ||
|
||
assert.NoError(t, sms.Send(ctx, nil, nil)) | ||
assert.NoError(t, sms.SendText(ctx, nil, "")) | ||
assert.NoError(t, sms.SendTemplate(ctx, nil, "", nil)) | ||
assert.NoError(t, sms.SendTextWithNumber(ctx, "", "")) | ||
assert.NoError(t, sms.SendTemplateWithNumber(ctx, "", "", nil)) | ||
} |