Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ require (
github.com/PagerDuty/go-pagerduty v1.8.0
github.com/caarlos0/go-reddit/v3 v3.0.1
github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
github.com/mattn/go-mastodon v0.0.9
google.golang.org/api v0.215.0
)

Expand Down Expand Up @@ -88,6 +89,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/rs/zerolog v1.33.0 // indirect
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
go.mau.fi/util v0.8.4 // indirect
go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/contrib/detectors/gcp v1.32.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-mastodon v0.0.9 h1:zAlQF0LMumKPQLNR7dZL/YVCrvr4iP6ayyzxTR3vsSw=
github.com/mattn/go-mastodon v0.0.9/go.mod h1:8YkqetHoAVEktRkK15qeiv/aaIMfJ/Gc89etisPZtHU=
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=
Expand Down Expand Up @@ -353,6 +355,8 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y=
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0=
github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w=
github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4=
Expand Down
44 changes: 44 additions & 0 deletions service/mastodon/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
Package mastodon provides message notification integration for the Mastodon social network.

Usage:

package main

import (
"context"
"log"

"github.com/nikoksr/notify"
"github.com/nikoksr/notify/service/mastodon"
)

func main() {
cfg := &mastodon.Config{
ServerURL: "https://mastodon.social",
AccessToken: "your-access-token",
Visibility: mastodon.VisibilityPublic,
}

service, err := mastodon.New(cfg)
if err != nil {
log.Fatalf("mastodon.New() failed: %s", err.Error())
}

notifier := notify.New()
notifier.UseServices(service)

err = notifier.Send(context.Background(), "", "Hello from Mastodon!")
if err != nil {
log.Fatalf("notifier.Send() failed: %s", err.Error())
}
}

Visibility values:

- VisibilityPublic — visible to everyone
- VisibilityUnlisted — visible to everyone but not listed
- VisibilityPrivate — visible to followers only
- VisibilityDirect — visible only to mentioned users (direct message)
*/
package mastodon
74 changes: 74 additions & 0 deletions service/mastodon/mastodon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package mastodon

import (
"context"
"errors"

"github.com/mattn/go-mastodon"
)

var ErrInvalidConfParams = errors.New("server and accessToken params are required")

const (
VisibilityPublic = "public"
VisibilityUnlisted = "unlisted"
VisibilityPrivate = "private"
VisibilityDirect = "direct"
)

//go:generate mockery --name=mastodonClient --output=. --case=underscore --inpackage
type mastodonClient interface {
PostStatus(ctx context.Context, toot *mastodon.Toot) (*mastodon.Status, error)
}

type Mastodon struct {
accessToken string
visibility string
client mastodonClient
}

type Config struct {
Visibility string
ServerURL string
AccessToken string
}

// New creates a new Mastodon client using the provided configuration.
// It returns an error if either the ServerURL or AccessToken is missing.
func New(cfg *Config) (*Mastodon, error) {
if cfg.ServerURL == "" || cfg.AccessToken == "" {
return nil, ErrInvalidConfParams
}

clientCfg := &mastodon.Config{
Server: cfg.ServerURL,
AccessToken: cfg.AccessToken,
}

return &Mastodon{
accessToken: cfg.AccessToken,
visibility: cfg.Visibility,
client: mastodon.NewClient(clientCfg),
}, nil
}

// ChangeVisibility updates the default visibility setting for all future posts.
// Supported values include: public, unlisted, private (followers-only), and direct.
func (m *Mastodon) ChangeVisibility(visibility string) {
m.visibility = visibility
}

// Send posts a new status (toot) to the configured Mastodon server.
// It uses the current visibility setting and accepts the message content as input.
func (m *Mastodon) Send(ctx context.Context, _, message string) error {
status := &mastodon.Toot{
Visibility: m.visibility,
Status: message,
}

if _, err := m.client.PostStatus(ctx, status); err != nil {
return err
}

return nil
}
91 changes: 91 additions & 0 deletions service/mastodon/mastodon_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package mastodon

import (
"context"
"errors"
"testing"

"github.com/mattn/go-mastodon"
"github.com/stretchr/testify/assert"
)

var errSome = errors.New("some error")

func TestNew(t *testing.T) {
tests := []struct {
name string
cfg *Config
expectedError error
}{
{
name: "Success",
cfg: &Config{
ServerURL: "some-url",
AccessToken: "some-access-token",
},
expectedError: nil,
},
{
name: "Invalid configuration",
cfg: &Config{
ServerURL: "",
AccessToken: "",
},
expectedError: ErrInvalidConfParams,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
_, err := New(tc.cfg)
assert.Equal(t, tc.expectedError, err)
})
}
}

func TestSend(t *testing.T) {
tests := []struct {
name string
message string
setup func(*mockmastodonClient)
expectedError error
}{
{
name: "Success",
message: "Hello world!",
setup: func(mc *mockmastodonClient) {
mc.On("PostStatus", context.Background(), &mastodon.Toot{
Status: "Hello world!",
}).
Return(&mastodon.Status{}, nil)
},
expectedError: nil,
},
{
name: "Sending failed",
message: "Hello world!",
setup: func(mc *mockmastodonClient) {
mc.On("PostStatus", context.Background(), &mastodon.Toot{
Status: "Hello world!",
}).
Return(nil, errSome)
},
expectedError: nil,
},
}

client := new(mockmastodonClient)

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
tc.setup(client)

mastodon := Mastodon{
client: client,
}

err := mastodon.Send(context.Background(), tc.message, tc.message)
assert.Equal(t, tc.expectedError, err)
})
}
}
96 changes: 96 additions & 0 deletions service/mastodon/mock_mastodon_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion service/msteams/mock_teams_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion service/pagerduty/pager_duty.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import (
)

type Client interface {
CreateIncidentWithContext(ctx context.Context, from string, options *pagerduty.CreateIncidentOptions) (*pagerduty.Incident, error) //nolint:lll // acceptable in this case, alternative makes the interface even less readable
CreateIncidentWithContext(
ctx context.Context,
from string,
options *pagerduty.CreateIncidentOptions,
) (*pagerduty.Incident, error) //nolint:lll // acceptable in this case, alternative makes the interface even less readable
}

// Compile-time check to verify that the PagerDuty type implements the notifier.Notifier interface.
Expand Down