mirror of
https://github.com/nikoksr/notify.git
synced 2025-04-11 11:41:58 +02:00
Merge pull request #300 from immanuelhume/feat/lark
This commit is contained in:
commit
2a4c07843e
@ -85,7 +85,8 @@ Yes, please! Contributions of all kinds are very welcome! Feel free to check our
|
||||
| [DingTalk](https://www.dingtalk.com) | [service/dinding](service/dingding) | [blinkbean/dingtalk](https://github.com/blinkbean/dingtalk) |
|
||||
| [Discord](https://discord.com) | [service/discord](service/discord) | [bwmarrin/discordgo](https://github.com/bwmarrin/discordgo) |
|
||||
| [Email](https://wikipedia.org/wiki/Email) | [service/mail](service/mail) | [jordan-wright/email](https://github.com/jordan-wright/email) |
|
||||
| [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) | [service/fcm](service/fcm) | [appleboy/go-fcm](https://github.com/appleboy/go-fcm) |
|
||||
| [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging) | [service/fcm](service/fcm) | [appleboy/go-fcm](https://github.com/appleboy/go-fcm) |
|
||||
| [Lark](https://www.larksuite.com/) | [service/lark](service/lark) | [go-lark/lark](https://github.com/go-lark/lark) |
|
||||
| [Line](https://line.me) | [service/line](service/line) | [line/line-bot-sdk-go](https://github.com/line/line-bot-sdk-go) |
|
||||
| [Line Notify](https://notify-bot.line.me) | [service/line](service/line) | [utahta/go-linenotify](https://github.com/utahta/go-linenotify) |
|
||||
| [Mailgun](https://www.mailgun.com) | [service/mailgun](service/mailgun) | [mailgun/mailgun-go](https://github.com/mailgun/mailgun-go) |
|
||||
|
1
go.mod
1
go.mod
@ -35,6 +35,7 @@ require (
|
||||
|
||||
require (
|
||||
github.com/appleboy/go-fcm v0.1.5
|
||||
github.com/go-lark/lark v1.7.2
|
||||
github.com/google/go-cmp v0.5.8
|
||||
github.com/kevinburke/twilio-go v0.0.0-20220615032439-b0fe9b151b0e
|
||||
)
|
||||
|
5
go.sum
5
go.sum
@ -83,6 +83,8 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-lark/lark v1.7.2 h1:F2LlwbRrZVuHPs8lz1D7owDevUndPy88Hbw6ZXaho/A=
|
||||
github.com/go-lark/lark v1.7.2/go.mod h1:6ltbSztPZRT6IaO9ZIQyVaY5pVp/KeMizDYtfZkU+vM=
|
||||
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc h1:jZY+lpZB92nvBo2f31oPC/ivGll6NcsnEOORm8Fkr4M=
|
||||
github.com/go-redis/redis/v8 v8.11.6-0.20220405070650-99c79f7041fc/go.mod h1:25mL1NKxbJhB63ihiK8MnNeTRd+xAizd6bOdydrTLUQ=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
@ -136,6 +138,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
|
||||
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
|
||||
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@ -334,5 +338,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
99
service/lark/README.md
Normal file
99
service/lark/README.md
Normal file
@ -0,0 +1,99 @@
|
||||
# Lark
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Depending on your requirements, you'll need either a custom app or a Lark group
|
||||
chat webhook. The latter is easier to set up, but can only send messages to the
|
||||
group it is in. You may refer to the doc
|
||||
[here](https://open.larksuite.com/document/uAjLw4CM/ukTMukTMuhttps://open.larksuite.com/document/home/develop-a-bot-in-5-minutes/create-an-appkTM/bot-v3/use-custom-bots-in-a-group)
|
||||
to set up a webhook bot, and the doc
|
||||
[here](https://open.larksuite.com/document/home/develop-a-bot-in-5-minutes/create-an-app)
|
||||
to set up a custom app.
|
||||
|
||||
## Usage
|
||||
|
||||
### Webhook
|
||||
|
||||
For webhook bots, we only need the webhook URL, which might look something like
|
||||
`https://open.feishu.cn/open-apis/bot/v2/hook/xxx`. Note that there is no
|
||||
method to configure receivers, because the webhook bot can only send messages
|
||||
to the group in which it was created.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/lark"
|
||||
)
|
||||
|
||||
// Replace this with your own webhook URL.
|
||||
const webHookURL = "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
|
||||
|
||||
func main() {
|
||||
larkWebhookSvc := lark.NewWebhookService(webHookURL)
|
||||
|
||||
notifier := notify.New()
|
||||
notifier.UseServices(larkWebhookSvc)
|
||||
|
||||
if err := notifier.Send(context.Background(), "subject", "message"); err != nil {
|
||||
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Println("notification sent")
|
||||
}
|
||||
```
|
||||
|
||||
### Custom App
|
||||
|
||||
For custom apps, we need to pass in the App ID and App Secret when creating a
|
||||
new notification service. When adding receivers, the type of the receiver ID
|
||||
must be specified, as shown in the example below. You may refer to the section
|
||||
entitled "Query parameters" in the doc
|
||||
[here](https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/create)
|
||||
for more information about the different ID types.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/lark"
|
||||
)
|
||||
|
||||
// Replace these with the credentials from your custom app.
|
||||
const (
|
||||
appId = "xxx"
|
||||
appSecret = "xxx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
larkCustomAppService := lark.NewCustomAppService(appId, appSecret)
|
||||
|
||||
// Lark implements five types of receiver IDs. You'll need to specify the
|
||||
// type using the respective helper functions when adding them as receivers.
|
||||
larkCustomAppService.AddReceivers(
|
||||
lark.OpenID("xxx"),
|
||||
lark.UserID("xxx"),
|
||||
lark.UnionID("xxx"),
|
||||
lark.Email("xyz@example.com"),
|
||||
lark.ChatID("xxx"),
|
||||
)
|
||||
|
||||
notifier := notify.New()
|
||||
notifier.UseServices(larkCustomAppService)
|
||||
|
||||
if err := notifier.Send(context.Background(), "subject", "message"); err != nil {
|
||||
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Println("notification sent")
|
||||
}
|
||||
```
|
||||
|
58
service/lark/common.go
Normal file
58
service/lark/common.go
Normal file
@ -0,0 +1,58 @@
|
||||
package lark
|
||||
|
||||
// sender is an interface for sending a message to an already defined receiver.
|
||||
type sender interface {
|
||||
Send(subject, message string) error
|
||||
}
|
||||
|
||||
// sender is an interface for sending a message to a specific receiver ID.
|
||||
type sendToer interface {
|
||||
SendTo(subject, message, id, idType string) error
|
||||
}
|
||||
|
||||
// receiverID encapsulates a receiver ID and its type in Lark.
|
||||
type receiverID struct {
|
||||
id string
|
||||
typ receiverIDType
|
||||
}
|
||||
|
||||
// OpenID specifies an ID as a Lark Open ID.
|
||||
func OpenID(s string) *receiverID {
|
||||
return &receiverID{s, openID}
|
||||
}
|
||||
|
||||
// UserID specifies an ID as a Lark User ID.
|
||||
func UserID(s string) *receiverID {
|
||||
return &receiverID{s, userID}
|
||||
}
|
||||
|
||||
// UnionID specifies an ID as a Lark Union ID.
|
||||
func UnionID(s string) *receiverID {
|
||||
return &receiverID{s, unionID}
|
||||
}
|
||||
|
||||
// Email specifies a receiver ID as an email.
|
||||
func Email(s string) *receiverID {
|
||||
return &receiverID{s, email}
|
||||
}
|
||||
|
||||
// ChatID specifies an ID as a Lark Chat ID.
|
||||
func ChatID(s string) *receiverID {
|
||||
return &receiverID{s, chatID}
|
||||
}
|
||||
|
||||
// receiverIDType represents the different ID types implemented by Lark. This
|
||||
// information is required when sending a message. More information about the
|
||||
// different ID types can be found in the "Query parameters" section of
|
||||
// the https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/message/create,
|
||||
// or on
|
||||
// https://open.larksuite.com/document/home/user-identity-introduction/introduction.
|
||||
type receiverIDType string
|
||||
|
||||
const (
|
||||
openID receiverIDType = "open_id"
|
||||
userID receiverIDType = "user_id"
|
||||
unionID receiverIDType = "union_id"
|
||||
email receiverIDType = "email"
|
||||
chatID receiverIDType = "chat_id"
|
||||
)
|
111
service/lark/custom_app.go
Normal file
111
service/lark/custom_app.go
Normal file
@ -0,0 +1,111 @@
|
||||
package lark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-lark/lark"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
)
|
||||
|
||||
type customAppService struct {
|
||||
receiveIDs []*receiverID
|
||||
cli sendToer
|
||||
}
|
||||
|
||||
// Compile time check that larkCustomAppService implements notify.Notifer.
|
||||
var _ notify.Notifier = &customAppService{}
|
||||
|
||||
// NewCustomAppService returns a new instance of a Lark notify service using a
|
||||
// Lark custom app.
|
||||
func NewCustomAppService(appID, appSecret string) *customAppService {
|
||||
bot := lark.NewChatBot(appID, appSecret)
|
||||
|
||||
// We need to set the bot to use Lark's open.larksuite.com domain instead of
|
||||
// the default open.feishu.cn domain.
|
||||
bot.SetDomain(lark.DomainLark)
|
||||
|
||||
// Let the bot use a HTTP client with a longer timeout than the default 5
|
||||
// seconds.
|
||||
bot.SetClient(&http.Client{
|
||||
Timeout: 8 * time.Second,
|
||||
})
|
||||
|
||||
_ = bot.StartHeartbeat()
|
||||
|
||||
return &customAppService{
|
||||
receiveIDs: make([]*receiverID, 0),
|
||||
cli: &larkClientGoLarkChatBot{
|
||||
bot: bot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// AddReceivers adds recipients to future notifications. There are five different
|
||||
// types of receiver IDs available in Lark and they must be specified here. For
|
||||
// example:
|
||||
//
|
||||
// larkService.AddReceivers(
|
||||
// lark.OpenID("ou_c99c5f35d542efc7ee492afe11af19ef"),
|
||||
// lark.UserID("8335aga2"),
|
||||
// lark.UnionID("on_cad4860e7af114fb4ff6c5d496d1dd76"),
|
||||
// lark.Email("xyz@example.com"),
|
||||
// lark.ChatID("oc_a0553eda9014c201e6969b478895c230"),
|
||||
// )
|
||||
func (c *customAppService) AddReceivers(ids ...*receiverID) {
|
||||
c.receiveIDs = append(c.receiveIDs, ids...)
|
||||
}
|
||||
|
||||
// Send takes a message subject and a message body and sends them to all
|
||||
// previously registered recipient IDs.
|
||||
func (c *customAppService) Send(ctx context.Context, subject, message string) error {
|
||||
for _, id := range c.receiveIDs {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
if err := c.cli.SendTo(subject, message, id.id, string(id.typ)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// larkClientGoLarkChatBot is a wrapper around go-lark/lark's Bot, to be used
|
||||
// for sending messages with custom apps.
|
||||
type larkClientGoLarkChatBot struct {
|
||||
bot *lark.Bot
|
||||
}
|
||||
|
||||
// SendTo implements the sendToer interface using a go-lark/lark chat bot.
|
||||
func (l *larkClientGoLarkChatBot) SendTo(subject, message, receiverID, idType string) error {
|
||||
content := lark.NewPostBuilder().
|
||||
Title(subject).
|
||||
TextTag(message, 1, false).
|
||||
Render()
|
||||
msg := lark.NewMsgBuffer(lark.MsgPost).Post(content)
|
||||
switch receiverIDType(idType) {
|
||||
case openID:
|
||||
msg.BindOpenID(receiverID)
|
||||
case userID:
|
||||
msg.BindUserID(receiverID)
|
||||
case unionID:
|
||||
msg.BindUnionID(receiverID)
|
||||
case email:
|
||||
msg.BindEmail(receiverID)
|
||||
case chatID:
|
||||
msg.BindChatID(receiverID)
|
||||
}
|
||||
res, err := l.bot.PostMessage(msg.Build())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to send message: %w", err)
|
||||
}
|
||||
if res.Code != 0 {
|
||||
return fmt.Errorf("send failed with error code %d, please see https://open.larksuite.com/document/ukTMukTMukTM/ugjM14COyUjL4ITN for details", res.Code)
|
||||
}
|
||||
return nil
|
||||
}
|
80
service/lark/custom_app_test.go
Normal file
80
service/lark/custom_app_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
package lark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAddReceivers(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
xs := []*receiverID{
|
||||
OpenID("ou_c99c5f35d542efc7ee492afe11af19ef"),
|
||||
UserID("8335aga2"),
|
||||
}
|
||||
svc := NewCustomAppService("", "")
|
||||
svc.AddReceivers(xs...)
|
||||
|
||||
assert.ElementsMatch(t, svc.receiveIDs, xs)
|
||||
|
||||
// Test if adding more receivers afterwards works.
|
||||
ys := []*receiverID{
|
||||
UnionID("on_cad4860e7af114fb4ff6c5d496d1dd76"),
|
||||
Email("xyz@example.com"),
|
||||
ChatID("oc_a0553eda9014c201e6969b478895c230"),
|
||||
}
|
||||
svc.AddReceivers(ys...)
|
||||
|
||||
assert.ElementsMatch(t, svc.receiveIDs, append(xs, ys...))
|
||||
}
|
||||
|
||||
func TestSendCustomApp(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := context.Background()
|
||||
assert := assert.New(t)
|
||||
|
||||
tests := []*receiverID{
|
||||
OpenID("ou_c99c5f35d542efc7ee492afe11af19ef"),
|
||||
UserID("8335aga2"),
|
||||
UnionID("on_cad4860e7af114fb4ff6c5d496d1dd76"),
|
||||
Email("xyz@example.com"),
|
||||
ChatID("oc_a0553eda9014c201e6969b478895c230"),
|
||||
}
|
||||
|
||||
// First, test for when the sender returns an error.
|
||||
for _, tt := range tests {
|
||||
mockSendToer := NewSendToer(t)
|
||||
mockSendToer.
|
||||
On("SendTo", "subject", "message", tt.id, string(tt.typ)).
|
||||
Return(errors.New(""))
|
||||
|
||||
svc := NewCustomAppService("", "")
|
||||
svc.cli = mockSendToer
|
||||
|
||||
svc.AddReceivers(tt)
|
||||
err := svc.Send(ctx, "subject", "message")
|
||||
assert.NotNil(err)
|
||||
|
||||
mockSendToer.AssertExpectations(t)
|
||||
}
|
||||
|
||||
// Then test for when the sender does not return an error.
|
||||
for _, tt := range tests {
|
||||
mockSendToer := NewSendToer(t)
|
||||
mockSendToer.
|
||||
On("SendTo", "subject", "message", tt.id, string(tt.typ)).
|
||||
Return(nil)
|
||||
|
||||
svc := NewCustomAppService("", "")
|
||||
svc.cli = mockSendToer
|
||||
|
||||
svc.AddReceivers(tt)
|
||||
err := svc.Send(ctx, "subject", "message")
|
||||
assert.Nil(err)
|
||||
|
||||
mockSendToer.AssertExpectations(t)
|
||||
}
|
||||
}
|
53
service/lark/doc.go
Normal file
53
service/lark/doc.go
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
Package lark provides message notification integration for Lark. Two kinds of
|
||||
bots on Lark are supported -- webhooks and custom apps. For information on
|
||||
webhook bots, see
|
||||
https://open.larksuite.com/document/uAjLw4CM/ukTMukTMukTM/bot-v3/use-custom-bots-in-a-group,
|
||||
and for info on custom apps, see
|
||||
https://open.larksuite.com/document/home/develop-a-bot-in-5-minutes/create-an-app.
|
||||
|
||||
Usage:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
"github.com/nikoksr/notify/service/lark"
|
||||
)
|
||||
|
||||
const (
|
||||
webhookURL = "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
|
||||
appId = "xxx"
|
||||
appSecret = "xxx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Two types of services are available depending on your requirements.
|
||||
larkWebhookService := lark.NewWebhookService(webhookURL)
|
||||
larkCustomAppService := lark.NewCustomAppService(appId, appSecret)
|
||||
|
||||
// Lark implements five types of receiver IDs. You'll need to specify the
|
||||
// type using the respective helper functions when adding them as receivers
|
||||
// for the custom app service.
|
||||
larkCustomAppService.AddReceivers(
|
||||
lark.OpenID("xxx"),
|
||||
lark.UserID("xxx"),
|
||||
lark.UnionID("xxx"),
|
||||
lark.Email("xyz@example.com"),
|
||||
lark.ChatID("xxx"),
|
||||
)
|
||||
|
||||
notifier := notify.New()
|
||||
notifier.UseServices(larkWebhookService, larkCustomAppService)
|
||||
|
||||
if err := notifier.Send(context.Background(), "subject", "message"); err != nil {
|
||||
log.Fatalf("notifier.Send() failed: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Println("notification sent")
|
||||
}
|
||||
*/
|
||||
package lark
|
39
service/lark/mock_sendToer.go
Normal file
39
service/lark/mock_sendToer.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Code generated by mockery v2.12.3. DO NOT EDIT.
|
||||
|
||||
package lark
|
||||
|
||||
import "github.com/stretchr/testify/mock"
|
||||
|
||||
// SendToer is an autogenerated mock type for the sendToer type
|
||||
type SendToer struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// SendTo provides a mock function with given fields: subject, message, id, idType
|
||||
func (_m *SendToer) SendTo(subject string, message string, id string, idType string) error {
|
||||
ret := _m.Called(subject, message, id, idType)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
|
||||
r0 = rf(subject, message, id, idType)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type NewSendToerT interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewSendToer creates a new instance of SendToer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewSendToer(t NewSendToerT) *SendToer {
|
||||
mock := &SendToer{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
39
service/lark/mock_sender.go
Normal file
39
service/lark/mock_sender.go
Normal file
@ -0,0 +1,39 @@
|
||||
// Code generated by mockery v2.12.3. DO NOT EDIT.
|
||||
|
||||
package lark
|
||||
|
||||
import "github.com/stretchr/testify/mock"
|
||||
|
||||
// Sender is an autogenerated mock type for the sender type
|
||||
type Sender struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Send provides a mock function with given fields: subject, message
|
||||
func (_m *Sender) Send(subject string, message string) error {
|
||||
ret := _m.Called(subject, message)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(string, string) error); ok {
|
||||
r0 = rf(subject, message)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
type NewSenderT interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}
|
||||
|
||||
// NewSender creates a new instance of Sender. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewSender(t NewSenderT) *Sender {
|
||||
mock := &Sender{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
58
service/lark/webhook.go
Normal file
58
service/lark/webhook.go
Normal file
@ -0,0 +1,58 @@
|
||||
package lark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-lark/lark"
|
||||
|
||||
"github.com/nikoksr/notify"
|
||||
)
|
||||
|
||||
type webhookService struct {
|
||||
cli sender
|
||||
}
|
||||
|
||||
// Compile time check that larkCustomAppService implements notify.Notifer.
|
||||
var _ notify.Notifier = &webhookService{}
|
||||
|
||||
// NewWebhookService returns a new instance of a Lark notify service using a
|
||||
// Lark group chat webhook. Note that this service does not take any
|
||||
// notification receivers because it can only push messages to the group chat
|
||||
// it belongs to.
|
||||
func NewWebhookService(webhookURL string) *webhookService {
|
||||
bot := lark.NewNotificationBot(webhookURL)
|
||||
return &webhookService{
|
||||
cli: &larkClientGoLarkNotificationBot{
|
||||
bot: bot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Send sends the message subject and body to the group chat.
|
||||
func (w *webhookService) Send(ctx context.Context, subject, message string) error {
|
||||
return w.cli.Send(subject, message)
|
||||
}
|
||||
|
||||
// larkClientGoLarkNotificationBot is a wrapper around go-lark/lark's Bot, to
|
||||
// be used for notifications via webhooks only.
|
||||
type larkClientGoLarkNotificationBot struct {
|
||||
bot *lark.Bot
|
||||
}
|
||||
|
||||
// Send implements the sender interface using a go-lark/lark notification bot.
|
||||
func (w *larkClientGoLarkNotificationBot) Send(subject, message string) error {
|
||||
content := lark.NewPostBuilder().
|
||||
Title(subject).
|
||||
TextTag(message, 1, false).
|
||||
Render()
|
||||
msg := lark.NewMsgBuffer(lark.MsgPost).Post(content)
|
||||
res, err := w.bot.PostNotificationV2(msg.Build())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to post webhook message: %w", err)
|
||||
}
|
||||
if res.Code != 0 {
|
||||
return fmt.Errorf("send failed with error code %d, please see https://open.larksuite.com/document/ukTMukTMukTM/ugjM14COyUjL4ITN for details", res.Code)
|
||||
}
|
||||
return nil
|
||||
}
|
44
service/lark/webhook_test.go
Normal file
44
service/lark/webhook_test.go
Normal file
@ -0,0 +1,44 @@
|
||||
package lark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSendWebhook(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := assert.New(t)
|
||||
ctx := context.Background()
|
||||
|
||||
// First, test for when the sender returns an error.
|
||||
{
|
||||
mockSender := NewSender(t)
|
||||
mockSender.
|
||||
On("Send", "subject", "message").
|
||||
Return(errors.New(""))
|
||||
|
||||
svc := NewWebhookService("")
|
||||
svc.cli = mockSender
|
||||
err := svc.Send(ctx, "subject", "message")
|
||||
assert.NotNil(err)
|
||||
mockSender.AssertExpectations(t)
|
||||
}
|
||||
|
||||
// Then test for when the sender does not return an error.
|
||||
{
|
||||
mockSender := NewSender(t)
|
||||
mockSender.
|
||||
On("Send", "subject", "message").
|
||||
Return(nil)
|
||||
|
||||
svc := NewWebhookService("")
|
||||
svc.cli = mockSender
|
||||
err := svc.Send(ctx, "subject", "message")
|
||||
assert.Nil(err)
|
||||
mockSender.AssertExpectations(t)
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user