mirror of
https://github.com/nikoksr/notify.git
synced 2024-11-28 08:39:13 +02:00
feat(service): Add Plivo service
Added support for Plivo as a backend service with unit tests and documentation. Signed-off-by: Prashanth Pai <mail@ppai.me>
This commit is contained in:
parent
77cea7b546
commit
67b2d011b8
@ -64,10 +64,11 @@ _ = notifier.Send(
|
|||||||
- *Discord*
|
- *Discord*
|
||||||
- *Email*
|
- *Email*
|
||||||
- *Microsoft Teams*
|
- *Microsoft Teams*
|
||||||
- *Slack*
|
- *Plivo*
|
||||||
- *Twitter*
|
|
||||||
- *Telegram*
|
|
||||||
- *Pushbullet*
|
- *Pushbullet*
|
||||||
|
- *Slack*
|
||||||
|
- *Telegram*
|
||||||
|
- *Twitter*
|
||||||
|
|
||||||
## Roadmap <a id="roadmap"></a>
|
## Roadmap <a id="roadmap"></a>
|
||||||
|
|
||||||
|
4
go.mod
4
go.mod
@ -9,9 +9,13 @@ require (
|
|||||||
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d
|
github.com/dghubble/go-twitter v0.0.0-20201011215211-4b180d0cc78d
|
||||||
github.com/dghubble/oauth1 v0.7.0
|
github.com/dghubble/oauth1 v0.7.0
|
||||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
|
||||||
|
github.com/google/go-querystring v1.0.0 // indirect
|
||||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/plivo/plivo-go v5.5.1+incompatible
|
||||||
|
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||||
github.com/slack-go/slack v0.8.0
|
github.com/slack-go/slack v0.8.0
|
||||||
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||||
|
5
go.sum
5
go.sum
@ -29,10 +29,15 @@ github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
|
|||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/plivo/plivo-go v5.5.1+incompatible h1:LtZaUNHjSrNzBCHAe/IdDBnLGlyZB+WX18Dr+dnlVzE=
|
||||||
|
github.com/plivo/plivo-go v5.5.1+incompatible/go.mod h1:OhnI9crdl6O+D94Lp1lvuwJoA3KUH39J6IM+j3HwCBE=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||||
|
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/slack-go/slack v0.8.0 h1:ANyLY5KHLV+MxLJDQum2IuHTLwbCbDtaWY405X1EU9U=
|
github.com/slack-go/slack v0.8.0 h1:ANyLY5KHLV+MxLJDQum2IuHTLwbCbDtaWY405X1EU9U=
|
||||||
github.com/slack-go/slack v0.8.0/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM=
|
github.com/slack-go/slack v0.8.0/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM=
|
||||||
|
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
49
service/plivo/README.md
Normal file
49
service/plivo/README.md
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# Plivo
|
||||||
|
|
||||||
|
[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat)](https://pkg.go.dev/github.com/nikoksr/notify/service/plivo)
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
You will need to have a [Plivo](https://www.plivo.com/) account and the
|
||||||
|
following things:
|
||||||
|
|
||||||
|
1. `Auth ID` and `Auth Token` from Plivo [console](https://console.plivo.com/dashboard/).
|
||||||
|
1. An active rented Plivo [phone number](https://console.plivo.com/active-phone-numbers/).
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/nikoksr/notify"
|
||||||
|
"github.com/nikoksr/notify/service/plivo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
plivoSvc, err := plivo.New(
|
||||||
|
&plivo.ClientOptions{
|
||||||
|
AuthID: "<Your-Plivo-Auth-Id>",
|
||||||
|
AuthToken: "<Your-Plivo-Auth-Token>",
|
||||||
|
}, &plivo.MessageOptions{
|
||||||
|
Source: "<Your-Plivo-Source-Number>",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("plivo.New() failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
plivoSvc.AddReceivers("Destination1")
|
||||||
|
|
||||||
|
notifier := notify.New()
|
||||||
|
notifier.UseServices(plivoSvc)
|
||||||
|
|
||||||
|
err = notifier.Send("subject", "message")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("notification sent")
|
||||||
|
}
|
||||||
|
```
|
41
service/plivo/doc.go
Normal file
41
service/plivo/doc.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Package plivo provides message notification integration for Plivo.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/nikoksr/notify"
|
||||||
|
"github.com/nikoksr/notify/service/plivo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
plivoSvc, err := plivo.New(
|
||||||
|
&plivo.ClientOptions{
|
||||||
|
AuthID: "<Your-Plivo-Auth-Id>",
|
||||||
|
AuthToken: "<Your-Plivo-Auth-Token>",
|
||||||
|
}, &plivo.MessageOptions{
|
||||||
|
Source: "<Your-Plivo-Source-Number>",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("plivo.New() failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
plivoSvc.AddReceivers("Destination1")
|
||||||
|
|
||||||
|
notifier := notify.New()
|
||||||
|
notifier.UseServices(plivoSvc)
|
||||||
|
|
||||||
|
err = notifier.Send("subject", "message")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("notification sent")
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
package plivo
|
36
service/plivo/mock_plivoMsgClient.go
Normal file
36
service/plivo/mock_plivoMsgClient.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Code generated by mockery v0.0.0-dev. DO NOT EDIT.
|
||||||
|
|
||||||
|
package plivo
|
||||||
|
|
||||||
|
import (
|
||||||
|
plivo "github.com/plivo/plivo-go"
|
||||||
|
mock "github.com/stretchr/testify/mock"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mockPlivoMsgClient is an autogenerated mock type for the plivoMsgClient type
|
||||||
|
type mockPlivoMsgClient struct {
|
||||||
|
mock.Mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create provides a mock function with given fields: _a0
|
||||||
|
func (_m *mockPlivoMsgClient) Create(_a0 plivo.MessageCreateParams) (*plivo.MessageCreateResponseBody, error) {
|
||||||
|
ret := _m.Called(_a0)
|
||||||
|
|
||||||
|
var r0 *plivo.MessageCreateResponseBody
|
||||||
|
if rf, ok := ret.Get(0).(func(plivo.MessageCreateParams) *plivo.MessageCreateResponseBody); ok {
|
||||||
|
r0 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(*plivo.MessageCreateResponseBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(plivo.MessageCreateParams) error); ok {
|
||||||
|
r1 = rf(_a0)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
102
service/plivo/plivo.go
Normal file
102
service/plivo/plivo.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package plivo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
plivo "github.com/plivo/plivo-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientOptions allow you to configure a Plivo SDK client.
|
||||||
|
type ClientOptions struct {
|
||||||
|
AuthID string // If empty, env variable PLIVO_AUTH_ID will be used
|
||||||
|
AuthToken string // If empty, env variable PLIVO_AUTH_TOKEN will be used
|
||||||
|
|
||||||
|
// Optional
|
||||||
|
HTTPClient *http.Client // Bring Your Own Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageOptions allow you to configure options for sending a message.
|
||||||
|
type MessageOptions struct {
|
||||||
|
Source string // a Plivo source phone number or a Plivo Powerpack UUID
|
||||||
|
|
||||||
|
// Optional
|
||||||
|
CallbackURL string // URL to which status update callbacks for the message should be sent
|
||||||
|
CallbackMethod string // The HTTP method to be used when calling CallbackURL - GET or POST(default)
|
||||||
|
}
|
||||||
|
|
||||||
|
// plivoMsgClient abstracts Plivo SDK for writing unit tests
|
||||||
|
type plivoMsgClient interface {
|
||||||
|
Create(plivo.MessageCreateParams) (*plivo.MessageCreateResponseBody, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service is a Plivo client
|
||||||
|
type Service struct {
|
||||||
|
client plivoMsgClient
|
||||||
|
mopts MessageOptions
|
||||||
|
destinations []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new instance of plivo service.
|
||||||
|
func New(cOpts *ClientOptions, mOpts *MessageOptions) (*Service, error) {
|
||||||
|
if cOpts == nil {
|
||||||
|
return nil, fmt.Errorf("client-options cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if mOpts == nil {
|
||||||
|
return nil, fmt.Errorf("message-options cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if mOpts.Source == "" {
|
||||||
|
return nil, fmt.Errorf("source cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
client, err := plivo.NewClient(
|
||||||
|
cOpts.AuthID,
|
||||||
|
cOpts.AuthToken,
|
||||||
|
&plivo.ClientOptions{
|
||||||
|
HttpClient: cOpts.HTTPClient,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("plivo.NewClient() failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Service{
|
||||||
|
client: client.Messages,
|
||||||
|
mopts: *mOpts,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddReceivers adds the given destination phone numbers to the notifier.
|
||||||
|
func (s *Service) AddReceivers(phoneNumbers ...string) {
|
||||||
|
s.destinations = append(s.destinations, phoneNumbers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send sends a SMS via Plivo to all previously added receivers.
|
||||||
|
func (s *Service) Send(subject, message string) error {
|
||||||
|
text := subject + "\n" + message
|
||||||
|
|
||||||
|
var dst string
|
||||||
|
switch len(s.destinations) {
|
||||||
|
case 0:
|
||||||
|
return fmt.Errorf("no receivers added")
|
||||||
|
case 1:
|
||||||
|
dst = s.destinations[0]
|
||||||
|
default:
|
||||||
|
// multiple destinations, use bulk message syntax
|
||||||
|
// see: https://www.plivo.com/docs/sms/api/message#bulk-messaging
|
||||||
|
dst = strings.Join(s.destinations, "<")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := s.client.Create(plivo.MessageCreateParams{
|
||||||
|
Dst: dst,
|
||||||
|
Text: text,
|
||||||
|
Src: s.mopts.Source,
|
||||||
|
URL: s.mopts.CallbackURL,
|
||||||
|
Method: s.mopts.CallbackMethod,
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
78
service/plivo/plivo_test.go
Normal file
78
service/plivo/plivo_test.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package plivo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
plivo "github.com/plivo/plivo-go"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
// nil ClientOptions
|
||||||
|
svc, err := New(nil, &MessageOptions{})
|
||||||
|
assert.NotNil(err)
|
||||||
|
assert.Nil(svc)
|
||||||
|
|
||||||
|
// nil MessageOptions
|
||||||
|
svc, err = New(&ClientOptions{}, nil)
|
||||||
|
assert.NotNil(err)
|
||||||
|
assert.Nil(svc)
|
||||||
|
|
||||||
|
// empty source
|
||||||
|
svc, err = New(&ClientOptions{}, &MessageOptions{})
|
||||||
|
assert.NotNil(err)
|
||||||
|
assert.Nil(svc)
|
||||||
|
|
||||||
|
// success
|
||||||
|
svc, err = New(&ClientOptions{}, &MessageOptions{Source: "12345"})
|
||||||
|
assert.Nil(err)
|
||||||
|
assert.NotNil(svc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddReceivers(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
svc, err := New(&ClientOptions{}, &MessageOptions{Source: "12345"})
|
||||||
|
assert.Nil(err)
|
||||||
|
assert.NotNil(svc)
|
||||||
|
|
||||||
|
nums := []string{"1", "2", "3", "4", "5"}
|
||||||
|
svc.AddReceivers(nums...)
|
||||||
|
|
||||||
|
assert.Equal(svc.destinations, nums)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSend(t *testing.T) {
|
||||||
|
assert := require.New(t)
|
||||||
|
|
||||||
|
svc, err := New(&ClientOptions{}, &MessageOptions{Source: "12345"})
|
||||||
|
assert.Nil(err)
|
||||||
|
assert.NotNil(svc)
|
||||||
|
|
||||||
|
// no receivers added
|
||||||
|
err = svc.Send("message", "test")
|
||||||
|
assert.NotNil(err)
|
||||||
|
|
||||||
|
// test plivo client returning error
|
||||||
|
mockClient := new(mockPlivoMsgClient)
|
||||||
|
mockClient.On("Create", plivo.MessageCreateParams{Src: "12345", Dst: "67890", Text: "message\ntest"}).
|
||||||
|
Return(nil, errors.New("some error"))
|
||||||
|
svc.client = mockClient
|
||||||
|
svc.AddReceivers("67890")
|
||||||
|
err = svc.Send("message", "test")
|
||||||
|
assert.NotNil(err)
|
||||||
|
mockClient.AssertExpectations(t)
|
||||||
|
|
||||||
|
// test success and multiple receivers
|
||||||
|
mockClient = new(mockPlivoMsgClient)
|
||||||
|
mockClient.On("Create", plivo.MessageCreateParams{Src: "12345", Dst: "67890<09876", Text: "message\ntest"}).
|
||||||
|
Return(nil, nil)
|
||||||
|
svc.client = mockClient
|
||||||
|
svc.AddReceivers("09876")
|
||||||
|
err = svc.Send("message", "test")
|
||||||
|
assert.Nil(err)
|
||||||
|
mockClient.AssertExpectations(t)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user