From f1cc0416c7bb0404e2c012b6b16a3502f34ef2f4 Mon Sep 17 00:00:00 2001 From: Josh Mills Date: Fri, 18 Nov 2022 16:34:19 +0800 Subject: [PATCH] feat(service): Add Pushover service (#467) Fixes #456 --- README.md | 3 +- go.mod | 1 + go.sum | 2 + service/pushover/doc.go | 38 ++++++++++++ service/pushover/mock_pushover_client.go | 51 ++++++++++++++++ service/pushover/pushover.go | 66 ++++++++++++++++++++ service/pushover/pushover_test.go | 76 ++++++++++++++++++++++++ service/pushover/usage.md | 47 +++++++++++++++ 8 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 service/pushover/doc.go create mode 100644 service/pushover/mock_pushover_client.go create mode 100644 service/pushover/pushover.go create mode 100644 service/pushover/pushover_test.go create mode 100644 service/pushover/usage.md diff --git a/README.md b/README.md index fa480efa..41575deb 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Yes, please! Contributions of all kinds are very welcome! Feel free to check our > Click [here](https://github.com/nikoksr/notify/issues/new?assignees=&labels=affects%2Fservices%2C+good+first+issue%2C+hacktoberfest%2C+help+wanted%2C+type%2Fenhancement%2C+up+for+grabs&template=service-request.md&title=feat%28service%29%3A+Add+%5BSERVICE+NAME%5D+service) to request a missing service. | Service | Path | Credits | Status | -|--------------------------------------------------------------------------------|------------------------------------------|-------------------------------------------------------------------------------------------------|:------------------:| +| ------------------------------------------------------------------------------ | ---------------------------------------- | ----------------------------------------------------------------------------------------------- | :----------------: | | [Amazon SES](https://aws.amazon.com/ses) | [service/amazonses](service/amazonses) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | :heavy_check_mark: | | [Amazon SNS](https://aws.amazon.com/sns) | [service/amazonsns](service/amazonsns) | [aws/aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2) | :heavy_check_mark: | | [Bark](https://apps.apple.com/us/app/bark-customed-notifications/id1403753865) | [service/bark](service/bark) | - | :heavy_check_mark: | @@ -93,6 +93,7 @@ Yes, please! Contributions of all kinds are very welcome! Feel free to check our | [Matrix](https://www.matrix.org) | [service/matrix](service/matrix) | [mautrix/go](https://github.com/mautrix/go) | :heavy_check_mark: | | [Microsoft Teams](https://www.microsoft.com/microsoft-teams) | [service/msteams](service/msteams) | [atc0005/go-teams-notify](https://github.com/atc0005/go-teams-notify) | :heavy_check_mark: | | [Plivo](https://www.plivo.com) | [service/plivo](service/plivo) | [plivo/plivo-go](https://github.com/plivo/plivo-go) | :heavy_check_mark: | +| [Pushover](https://pushover.net/) | [service/pushover](service/pushover) | [gregdel/pushover](https://github.com/gregdel/pushover) | :heavy_check_mark: | | [Pushbullet](https://www.pushbullet.com) | [service/pushbullet](service/pushbullet) | [cschomburg/go-pushbullet](https://github.com/cschomburg/go-pushbullet) | :heavy_check_mark: | | [RocketChat](https://rocket.chat) | [service/rocketchat](service/rocketchat) | [RocketChat/Rocket.Chat.Go.SDK](https://github.com/RocketChat/Rocket.Chat.Go.SDK) | :heavy_check_mark: | | [SendGrid](https://sendgrid.com) | [service/sendgrid](service/sendgrid) | [sendgrid/sendgrid-go](https://github.com/sendgrid/sendgrid-go) | :heavy_check_mark: | diff --git a/go.mod b/go.mod index e0ce077e..fceb8ed8 100644 --- a/go.mod +++ b/go.mod @@ -63,6 +63,7 @@ require ( github.com/google/uuid v1.3.0 // indirect github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/gregdel/pushover v1.1.0 github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/go-types v0.0.0-20210723172823-2deba1f80ba7 // indirect diff --git a/go.sum b/go.sum index 3366b373..d4254e90 100644 --- a/go.sum +++ b/go.sum @@ -122,6 +122,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregdel/pushover v1.1.0 h1:dwHyvrcpZCOS9V1fAnKPaGRRI5OC55cVaKhMybqNsKQ= +github.com/gregdel/pushover v1.1.0/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= diff --git a/service/pushover/doc.go b/service/pushover/doc.go new file mode 100644 index 00000000..5bfe2863 --- /dev/null +++ b/service/pushover/doc.go @@ -0,0 +1,38 @@ +/* +Package pushover implements a Pushover notifier, allowing messages to be sent to multiple recipients and supports +both users and groups. + +Usage: + + package main + + import ( + "context" + + "github.com/nikoksr/notify" + "github.com/nikoksr/notify/service/pushover" + ) + + func main() { + + notifier := notify.New() + + // Provide your Pushover App token + pushoverService := pushover.New("APP_TOKEN") + + // Pass user and/or group IDs for where to send the messages + pushoverService.AddReceivers("USER_ID", "GROUP_ID") + + // Tell our notifier to use the Pushover service. You can repeat the above process + // for as many services as you like and just tell the notifier to use them. + notifier.UseServices(pushoverService) + + // Send a message + _ = notifier.Send( + context.Background(), + "Hello!", + "I am a bot written in Go!", + ) + } +*/ +package pushover diff --git a/service/pushover/mock_pushover_client.go b/service/pushover/mock_pushover_client.go new file mode 100644 index 00000000..c60fa21f --- /dev/null +++ b/service/pushover/mock_pushover_client.go @@ -0,0 +1,51 @@ +// Code generated by mockery v2.15.0. DO NOT EDIT. + +package pushover + +import ( + gregdelpushover "github.com/gregdel/pushover" + mock "github.com/stretchr/testify/mock" +) + +// mockPushoverClient is an autogenerated mock type for the pushoverClient type +type mockPushoverClient struct { + mock.Mock +} + +// SendMessage provides a mock function with given fields: _a0, _a1 +func (_m *mockPushoverClient) SendMessage(_a0 *gregdelpushover.Message, _a1 *gregdelpushover.Recipient) (*gregdelpushover.Response, error) { + ret := _m.Called(_a0, _a1) + + var r0 *gregdelpushover.Response + if rf, ok := ret.Get(0).(func(*gregdelpushover.Message, *gregdelpushover.Recipient) *gregdelpushover.Response); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*gregdelpushover.Response) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gregdelpushover.Message, *gregdelpushover.Recipient) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +type mockConstructorTestingTnewMockPushoverClient interface { + mock.TestingT + Cleanup(func()) +} + +// newMockPushoverClient creates a new instance of mockPushoverClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func newMockPushoverClient(t mockConstructorTestingTnewMockPushoverClient) *mockPushoverClient { + mock := &mockPushoverClient{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/service/pushover/pushover.go b/service/pushover/pushover.go new file mode 100644 index 00000000..1a65f310 --- /dev/null +++ b/service/pushover/pushover.go @@ -0,0 +1,66 @@ +// Package pushover implements a Pushover notifier, allowing messages to be sent to multiple recipients and supports +// both users and groups. +package pushover + +import ( + "context" + + "github.com/gregdel/pushover" + "github.com/pkg/errors" +) + +//go:generate mockery --name=pushoverClient --output=. --case=underscore --inpackage +type pushoverClient interface { + SendMessage(*pushover.Message, *pushover.Recipient) (*pushover.Response, error) +} + +// Compile-time check to ensure that pushover.Pushover implements the pushoverClient interface. +var _ pushoverClient = new(pushover.Pushover) + +// Pushover struct holds necessary data to communicate with the Pushover API. +type Pushover struct { + client pushoverClient + recipients []pushover.Recipient +} + +// New returns a new instance of a Pushover notification service. +// For more information about Pushover app token: +// +// -> https://support.pushover.net/i175-how-do-i-get-an-api-or-application-token +func New(appToken string) *Pushover { + client := pushover.New(appToken) + + s := &Pushover{ + client: client, + recipients: []pushover.Recipient{}, + } + + return s +} + +// AddReceivers takes Pushover user/group IDs and adds them to the internal recipient list. The Send method will send +// a given message to all of those recipients. +func (p *Pushover) AddReceivers(recipientIDs ...string) { + for _, recipient := range recipientIDs { + p.recipients = append(p.recipients, *pushover.NewRecipient(recipient)) + } +} + +// Send takes a message subject and a message body and sends them to all previously set recipients. +func (p Pushover) Send(ctx context.Context, subject, message string) error { + for i := range p.recipients { + select { + case <-ctx.Done(): + return ctx.Err() + default: + _, err := p.client.SendMessage( + pushover.NewMessageWithTitle(message, subject), + &p.recipients[i], + ) + if err != nil { + return errors.Wrapf(err, "failed to send message to Pushover recipient '%s'", p.recipients[i]) + } + } + } + return nil +} diff --git a/service/pushover/pushover_test.go b/service/pushover/pushover_test.go new file mode 100644 index 00000000..0b89e4bf --- /dev/null +++ b/service/pushover/pushover_test.go @@ -0,0 +1,76 @@ +package pushover + +import ( + "context" + "testing" + + "github.com/gregdel/pushover" + "github.com/pkg/errors" + "github.com/stretchr/testify/require" +) + +func TestPushover_New(t *testing.T) { + t.Parallel() + + assert := require.New(t) + + service := New("") + assert.NotNil(service) +} + +func TestPushover_AddReceivers(t *testing.T) { + t.Parallel() + + assert := require.New(t) + + service := New("") + assert.NotNil(service) + + service.AddReceivers("") + assert.Len(service.recipients, 1) + + service.AddReceivers("", "") + assert.Len(service.recipients, 3) +} + +func TestPushover_Send(t *testing.T) { + t.Parallel() + + assert := require.New(t) + + service := New("") + assert.NotNil(service) + + // No receivers added + ctx := context.Background() + err := service.Send(ctx, "subject", "message") + assert.Nil(err) + + // Test error response + mockClient := newMockPushoverClient(t) + mockClient. + On("SendMessage", &pushover.Message{Title: "subject", Message: "message"}, pushover.NewRecipient("1234")). + Return(&pushover.Response{}, errors.New("some error")) + + service.client = mockClient + service.AddReceivers("1234") + err = service.Send(ctx, "subject", "message") + assert.NotNil(err) + mockClient.AssertExpectations(t) + + // Test success response + mockClient = newMockPushoverClient(t) + mockClient. + On("SendMessage", &pushover.Message{Title: "subject", Message: "message"}, pushover.NewRecipient("1234")). + Return(&pushover.Response{}, nil) + + mockClient. + On("SendMessage", &pushover.Message{Title: "subject", Message: "message"}, pushover.NewRecipient("5678")). + Return(&pushover.Response{}, nil) + + service.client = mockClient + service.AddReceivers("5678") + err = service.Send(ctx, "subject", "message") + assert.Nil(err) + mockClient.AssertExpectations(t) +} diff --git a/service/pushover/usage.md b/service/pushover/usage.md new file mode 100644 index 00000000..dc2e0312 --- /dev/null +++ b/service/pushover/usage.md @@ -0,0 +1,47 @@ +# Pushover Usage + +Ensure that you have already navigated to your GOPATH and installed the following packages: + +* `go get -u github.com/nikoksr/notify` + +## Steps for Pushover App + +These are general and very high level instructions + +1. Create a new Pushover App by visiting [here](https://pushover.net/apps/build) +2. Copy your *App token* for usage below +3. Copy the *User ID* or *Group ID* for where you'd like to send messages +4. Now you should be good to use the code below + +## Sample Code + +```go +package main + +import ( + "github.com/nikoksr/notify" + "github.com/nikoksr/notify/service/pushover" +) + +func main() { + + notifier := notify.New() + + // Provide your Pushover App token + pushoverService := pushover.New("APP_TOKEN") + + // Pass user and/or group IDs for where to send the messages + pushoverService.AddReceivers("USER_ID", "GROUP_ID") + + // Tell our notifier to use the Pushover service. You can repeat the above process + // for as many services as you like and just tell the notifier to use them. + notifier.UseServices(pushoverService) + + // Send a message + _ = notifier.Send( + context.Background(), + "Hello!", + "I am a bot written in Go!", + ) +} +```