mirror of
https://github.com/nikoksr/notify.git
synced 2025-03-19 21:08:48 +02:00
feat(service): Add Viber (#415)
This commit is contained in:
parent
7624ce31aa
commit
8aa5c9d2b6
@ -102,6 +102,7 @@ Yes, please! Contributions of all kinds are very welcome! Feel free to check our
|
||||
| [TextMagic](https://www.textmagic.com) | [service/textmagic](service/textmagic) | [textmagic/textmagic-rest-go-v2](https://github.com/textmagic/textmagic-rest-go-v2) | :heavy_check_mark: |
|
||||
| [Twilio](https://www.twilio.com/) | [service/twilio](service/twilio) | [kevinburke/twilio-go](https://github.com/kevinburke/twilio-go) | :heavy_check_mark: |
|
||||
| [Twitter](https://twitter.com) | [service/twitter](service/twitter) | [dghubble/go-twitter](https://github.com/dghubble/go-twitter) | :heavy_check_mark: |
|
||||
| [Viber](https://www.viber.com) | [service/viber](service/viber) | [mileusna/viber](https://github.com/mileusna/viber) | :heavy_check_mark: |
|
||||
| [WeChat](https://www.wechat.com) | [service/wechat](service/wechat) | [silenceper/wechat](https://github.com/silenceper/wechat) | :heavy_check_mark: |
|
||||
| [WhatsApp](https://www.whatsapp.com) | [service/whatsapp](service/whatsapp) | [Rhymen/go-whatsapp](https://github.com/Rhymen/go-whatsapp) | :x: |
|
||||
|
||||
|
3
go.mod
3
go.mod
@ -67,6 +67,9 @@ require (
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 // indirect
|
||||
github.com/kevinburke/rest v0.0.0-20210506044642-5611499aa33c // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mileusna/viber v1.0.1
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
|
8
go.sum
8
go.sum
@ -149,6 +149,14 @@ github.com/line/line-bot-sdk-go v7.8.0+incompatible h1:Uf9/OxV0zCVfqyvwZPH8CrdiH
|
||||
github.com/line/line-bot-sdk-go v7.8.0+incompatible/go.mod h1:0RjLjJEAU/3GIcHkC3av6O4jInAbt25nnZVmOFUgDBg=
|
||||
github.com/mailgun/mailgun-go/v4 v4.8.1 h1:1+MdKakJuXnW2JJDbyPdO1ngAANOyHyVPxQvFF8Sq6c=
|
||||
github.com/mailgun/mailgun-go/v4 v4.8.1/go.mod h1:FJlF9rI5cQT+mrwujtJjPMbIVy3Ebor9bKTVsJ0QU40=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mileusna/viber v1.0.1 h1:gWB6/lKoWYVxkH0Jb8jRnGIRZ/9DEM7RBZRJHRfdYWs=
|
||||
github.com/mileusna/viber v1.0.1/go.mod h1:Pxu/iPMnYjnHgu+bEp3SiKWHWmlf/kDp/yOX8XUdYrQ=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
@ -3,12 +3,10 @@
|
||||
package matrix
|
||||
|
||||
import (
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
mautrix "maunium.net/go/mautrix"
|
||||
event "maunium.net/go/mautrix/event"
|
||||
id "maunium.net/go/mautrix/id"
|
||||
|
||||
mautrix "maunium.net/go/mautrix"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// mockMatrixClient is an autogenerated mock type for the matrixClient type
|
||||
|
75
service/viber/README
Normal file
75
service/viber/README
Normal file
@ -0,0 +1,75 @@
|
||||
# Viber
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Create a Viber Bot
|
||||
|
||||
In order to use the Viber notification service, we'll need to create a new Viber bot [here](https://partners.viber.com/account/create-bot-account).
|
||||
|
||||
### Setting the webhook
|
||||
|
||||
After we have done with the bot setup, we'll need to have a webhook that will be used to receive callbacks from the Viber server otherwise we will not be able to send a message.
|
||||
|
||||
Please note that your webhook needs to be valid otherwise it will not work properly. You can read more details about the Viber webhook [here](https://developers.viber.com/docs/api/rest-bot-api/#webhooks) and about the callback [here](https://developers.viber.com/docs/api/rest-bot-api/#callbacks).
|
||||
|
||||
#### Tips: Easy setup for webhook
|
||||
|
||||
If you need to set up webhook easily like for example only for local testing, you can utilize [Google App Scripts](https://www.google.com/script/start/) and create a simple Web app from it. Here is the example script:
|
||||
|
||||
```javascript
|
||||
function doPost(e) {
|
||||
const contents = JSON.parse(e.postData.contents)
|
||||
Logger.log(JSON.stringify(contents))
|
||||
}
|
||||
```
|
||||
|
||||
_In short, it will just receive the POST request, and log the content_.
|
||||
|
||||
Don't forget to deploy the script as a web app and share the access with anyone.
|
||||
|
||||
You'll get a URL like https://script.google.com/macros/s/xxx/exec and this URL will be your webhook URL.
|
||||
|
||||
## Usage
|
||||
|
||||
Here is an example use case on how you can use Viber:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/viber"
|
||||
)
|
||||
|
||||
const appKey = "your-viber-token"
|
||||
const webhookURL = "https://webhook.com"
|
||||
const senderName = "vibersofyana"
|
||||
|
||||
func main() {
|
||||
viberSvc := viber.New(appKey, senderName, "")
|
||||
|
||||
err := viberSvc.SetWebhook(webhookURL) // this only needs to be called once
|
||||
if err != nil {
|
||||
log.Fatalf("set webhook to viber server failed: %v", err)
|
||||
}
|
||||
|
||||
viberSvc.AddReceivers("receiver-viber-user-id") // can add as many as required
|
||||
notifier := notify.New()
|
||||
|
||||
notifier.UseServices(viberSvc)
|
||||
if err := notifier.Send(context.Background(), "TEST", "Message using golang notifier library"); err != nil {
|
||||
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Println("Notification sent")
|
||||
}
|
||||
```
|
||||
|
||||
> ❗️**Viber is only allowing the bot to send the message to their subscriber**. Therefore, in order to send the notification, we need to make sure that the receiver already subscribed to the bot. Read more details here: https://developers.viber.com/docs/api/rest-bot-api/#send-message
|
||||
|
||||
## Attachment
|
||||
|
||||
- [Viber API Documentation](https://developers.viber.com/docs/)
|
39
service/viber/doc.go
Normal file
39
service/viber/doc.go
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
Package viber provides a service for sending messages to viber.
|
||||
|
||||
Usage:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/viber"
|
||||
)
|
||||
|
||||
const appKey = "your-viber-token"
|
||||
const webhookURL = "https://webhook.com"
|
||||
const senderName = "vibersofyana"
|
||||
|
||||
func main() {
|
||||
viberSvc := viber.New(appKey, senderName, "")
|
||||
|
||||
err := viberSvc.SetWebhook(webhookURL) // this only needs to be called once
|
||||
if err != nil {
|
||||
log.Fatalf("set webhook to viber server failed: %v", err)
|
||||
}
|
||||
|
||||
viberSvc.AddReceivers("receiver-viber-user-id") // can add as many as required
|
||||
notifier := notify.New()
|
||||
|
||||
notifier.UseServices(viberSvc)
|
||||
if err := notifier.Send(context.Background(), "TEST", "Message using golang notifier library"); err != nil {
|
||||
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Println("Notification sent")
|
||||
}
|
||||
*/
|
||||
package viber
|
70
service/viber/mock_viber_client.go
Normal file
70
service/viber/mock_viber_client.go
Normal file
@ -0,0 +1,70 @@
|
||||
// Code generated by mockery v2.14.0. DO NOT EDIT.
|
||||
|
||||
package viber
|
||||
|
||||
import (
|
||||
mileusnaviber "github.com/mileusna/viber"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// mockViberClient is an autogenerated mock type for the viberClient type
|
||||
type mockViberClient struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// SendTextMessage provides a mock function with given fields: receiver, msg
|
||||
func (_m *mockViberClient) SendTextMessage(receiver string, msg string) (uint64, error) {
|
||||
ret := _m.Called(receiver, msg)
|
||||
|
||||
var r0 uint64
|
||||
if rf, ok := ret.Get(0).(func(string, string) uint64); ok {
|
||||
r0 = rf(receiver, msg)
|
||||
} else {
|
||||
r0 = ret.Get(0).(uint64)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, string) error); ok {
|
||||
r1 = rf(receiver, msg)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SetWebhook provides a mock function with given fields: url, eventTypes
|
||||
func (_m *mockViberClient) SetWebhook(url string, eventTypes []string) (mileusnaviber.WebhookResp, error) {
|
||||
ret := _m.Called(url, eventTypes)
|
||||
|
||||
var r0 mileusnaviber.WebhookResp
|
||||
if rf, ok := ret.Get(0).(func(string, []string) mileusnaviber.WebhookResp); ok {
|
||||
r0 = rf(url, eventTypes)
|
||||
} else {
|
||||
r0 = ret.Get(0).(mileusnaviber.WebhookResp)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string, []string) error); ok {
|
||||
r1 = rf(url, eventTypes)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
type mockConstructorTestingTnewMockViberClient interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// newMockViberClient creates a new instance of mockViberClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func newMockViberClient(t mockConstructorTestingTnewMockViberClient) *mockViberClient {
|
||||
mock := &mockViberClient{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
61
service/viber/viber.go
Normal file
61
service/viber/viber.go
Normal file
@ -0,0 +1,61 @@
|
||||
package viber
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
vb "github.com/mileusna/viber"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
//go:generate mockery --name=viberClient --output=. --case=underscore --inpackage
|
||||
type viberClient interface {
|
||||
SetWebhook(url string, eventTypes []string) (vb.WebhookResp, error)
|
||||
SendTextMessage(receiver, msg string) (uint64, error)
|
||||
}
|
||||
|
||||
// Compile-time check to ensure that vb.Viber implements the viberClient interface.
|
||||
var _ viberClient = new(vb.Viber)
|
||||
|
||||
// Viber struct holds necessary fields to communicate with Viber API
|
||||
type Viber struct {
|
||||
Client viberClient
|
||||
SubscribedUserIDs []string
|
||||
}
|
||||
|
||||
// New returns a new instance of Viber notification service
|
||||
func New(appKey, senderName, senderAvatar string) *Viber {
|
||||
return &Viber{
|
||||
Client: vb.New(appKey, senderName, senderAvatar),
|
||||
SubscribedUserIDs: []string{},
|
||||
}
|
||||
}
|
||||
|
||||
// AddReceivers receives subscribed user IDs then add them to internal receivers list
|
||||
func (v *Viber) AddReceivers(subscribedUserIDs ...string) {
|
||||
v.SubscribedUserIDs = append(v.SubscribedUserIDs, subscribedUserIDs...)
|
||||
}
|
||||
|
||||
// SetWebhook receives a URL that will we used as a webhook URL for Viber
|
||||
func (v *Viber) SetWebhook(webhookURL string) error {
|
||||
_, err := v.Client.SetWebhook(webhookURL, []string{})
|
||||
return err
|
||||
}
|
||||
|
||||
// Send takes a message subject and a message body and sends them to all previously set userIds
|
||||
func (v *Viber) Send(ctx context.Context, subject, message string) error {
|
||||
fullMessage := subject + "\n" + message // Treating subject as message title
|
||||
|
||||
for _, subscribedUserID := range v.SubscribedUserIDs {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
_, err := v.Client.SendTextMessage(subscribedUserID, fullMessage)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to send message to User ID '%s'", subscribedUserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
103
service/viber/viber_test.go
Normal file
103
service/viber/viber_test.go
Normal file
@ -0,0 +1,103 @@
|
||||
package viber
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
vb "github.com/mileusna/viber"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestViber_New(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := require.New(t)
|
||||
|
||||
viber := New("appkey", "senderName", "senderAvatar")
|
||||
assert.NotNil(viber)
|
||||
}
|
||||
|
||||
func TestViber_AddReceivers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := require.New(t)
|
||||
|
||||
viber := New("appkey", "senderName", "senderAvatar")
|
||||
assert.Len(viber.SubscribedUserIDs, 0)
|
||||
|
||||
viber.AddReceivers("first-subscriber")
|
||||
assert.Len(viber.SubscribedUserIDs, 1)
|
||||
|
||||
viber.AddReceivers("second-subscriber", "third-subscriber")
|
||||
assert.Len(viber.SubscribedUserIDs, 3)
|
||||
}
|
||||
|
||||
func TestViber_SetWebhook(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := require.New(t)
|
||||
viber := New("appkey", "senderName", "senderAvatar")
|
||||
assert.NotNil(viber)
|
||||
|
||||
// Test error
|
||||
viberMock := newMockViberClient(t)
|
||||
webhookURLMock := "https://example-webhook.com"
|
||||
viberMock.
|
||||
On("SetWebhook", webhookURLMock, []string{}).
|
||||
Return(vb.WebhookResp{}, errors.New("set webhook error"))
|
||||
|
||||
viber.Client = viberMock
|
||||
err := viber.SetWebhook(webhookURLMock)
|
||||
assert.NotNil(err)
|
||||
viberMock.AssertExpectations(t)
|
||||
|
||||
// Test success
|
||||
viberMock = newMockViberClient(t)
|
||||
viberMock.
|
||||
On("SetWebhook", webhookURLMock, []string{}).
|
||||
Return(vb.WebhookResp{}, nil)
|
||||
|
||||
viber.Client = viberMock
|
||||
err = viber.SetWebhook(webhookURLMock)
|
||||
assert.Nil(err)
|
||||
viberMock.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func TestViber_Send(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert := require.New(t)
|
||||
viber := New("appkey", "senderName", "senderAvatar")
|
||||
assert.NotNil(viber)
|
||||
|
||||
// No receivers added
|
||||
ctx := context.Background()
|
||||
err := viber.Send(ctx, "subject", "message")
|
||||
assert.Nil(err)
|
||||
|
||||
// Test error response
|
||||
viberMock := newMockViberClient(t)
|
||||
viberMock.
|
||||
On("SendTextMessage", "receiver1", "subject\nmessage").
|
||||
Return(uint64(0), errors.New("error send text message"))
|
||||
|
||||
viber.Client = viberMock
|
||||
viber.AddReceivers("receiver1")
|
||||
err = viber.Send(ctx, "subject", "message")
|
||||
assert.NotNil(err)
|
||||
viberMock.AssertExpectations(t)
|
||||
|
||||
// Test success response
|
||||
viberMock = newMockViberClient(t)
|
||||
viberMock.
|
||||
On("SendTextMessage", "receiver1", "subject\nmessage").
|
||||
Return(uint64(0), nil)
|
||||
viberMock.
|
||||
On("SendTextMessage", "receiver2", "subject\nmessage").
|
||||
Return(uint64(0), nil)
|
||||
|
||||
viber.Client = viberMock
|
||||
viber.AddReceivers("receiver2")
|
||||
err = viber.Send(ctx, "subject", "message")
|
||||
assert.Nil(err)
|
||||
viberMock.AssertExpectations(t)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user