feat(notifications): add Shoutrrr support (#1326)

This commit is contained in:
ze0s 2023-12-30 16:34:25 +01:00 committed by GitHub
parent 3dd1629a3f
commit 57a91bb99a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 149 additions and 31 deletions

4
go.mod
View file

@ -60,7 +60,9 @@ require (
github.com/anacrolix/missinggo/v2 v2.7.2 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect
github.com/containrrr/shoutrrr v0.8.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fatih/color v1.16.0 // indirect
github.com/gdm85/go-rencode v0.1.8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
@ -76,7 +78,7 @@ require (
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect

6
go.sum
View file

@ -121,6 +121,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/containrrr/shoutrrr v0.8.0 h1:mfG2ATzIS7NR2Ec6XL+xyoHzN97H8WPjir8aYzJUSec=
github.com/containrrr/shoutrrr v0.8.0/go.mod h1:ioyQAyu1LJY6sILuNyKaQaw+9Ttik5QePU8atnAdO2o=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cytec/releaseparser v0.0.0-20200706155913-2341b265c370 h1:g9q5BGfDdhcXn4EmVZD8UydPXrvhSvgz3FRBn7zAJNs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -145,6 +147,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/ergochat/irc-go v0.4.0 h1:0YibCKfAAtwxQdNjLQd9xpIEPisLcJ45f8FNsMHAuZc=
github.com/ergochat/irc-go v0.4.0/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
@ -309,6 +313,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
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-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=

View file

@ -82,6 +82,7 @@ const (
NotificationTypeGotify NotificationType = "GOTIFY"
NotificationTypeNtfy NotificationType = "NTFY"
NotificationTypeLunaSea NotificationType = "LUNASEA"
NotificationTypeShoutrrr NotificationType = "SHOUTRRR"
)
type NotificationEvent string

View file

@ -124,16 +124,20 @@ func (s *service) registerSenders() {
switch n.Type {
case domain.NotificationTypeDiscord:
s.senders = append(s.senders, NewDiscordSender(s.log, n))
case domain.NotificationTypeNotifiarr:
s.senders = append(s.senders, NewNotifiarrSender(s.log, n))
case domain.NotificationTypeTelegram:
s.senders = append(s.senders, NewTelegramSender(s.log, n))
case domain.NotificationTypePushover:
s.senders = append(s.senders, NewPushoverSender(s.log, n))
case domain.NotificationTypeGotify:
s.senders = append(s.senders, NewGotifySender(s.log, n))
case domain.NotificationTypeLunaSea:
s.senders = append(s.senders, NewLunaSeaSender(s.log, n))
case domain.NotificationTypeNotifiarr:
s.senders = append(s.senders, NewNotifiarrSender(s.log, n))
case domain.NotificationTypeNtfy:
s.senders = append(s.senders, NewNtfySender(s.log, n))
case domain.NotificationTypePushover:
s.senders = append(s.senders, NewPushoverSender(s.log, n))
case domain.NotificationTypeShoutrrr:
s.senders = append(s.senders, NewShoutrrrSender(s.log, n))
case domain.NotificationTypeTelegram:
s.senders = append(s.senders, NewTelegramSender(s.log, n))
}
}
}
@ -241,18 +245,20 @@ func (s *service) Test(ctx context.Context, notification domain.Notification) er
switch notification.Type {
case domain.NotificationTypeDiscord:
agent = NewDiscordSender(s.log, notification)
case domain.NotificationTypeNotifiarr:
agent = NewNotifiarrSender(s.log, notification)
case domain.NotificationTypeTelegram:
agent = NewTelegramSender(s.log, notification)
case domain.NotificationTypePushover:
agent = NewPushoverSender(s.log, notification)
case domain.NotificationTypeGotify:
agent = NewGotifySender(s.log, notification)
case domain.NotificationTypeNtfy:
agent = NewNtfySender(s.log, notification)
case domain.NotificationTypeLunaSea:
agent = NewLunaSeaSender(s.log, notification)
case domain.NotificationTypeNotifiarr:
agent = NewNotifiarrSender(s.log, notification)
case domain.NotificationTypeNtfy:
agent = NewNtfySender(s.log, notification)
case domain.NotificationTypePushover:
agent = NewPushoverSender(s.log, notification)
case domain.NotificationTypeShoutrrr:
agent = NewShoutrrrSender(s.log, notification)
case domain.NotificationTypeTelegram:
agent = NewTelegramSender(s.log, notification)
default:
s.log.Error().Msgf("unsupported notification type: %v", notification.Type)
return errors.New("unsupported notification type")

View file

@ -0,0 +1,69 @@
package notification
import (
"github.com/autobrr/autobrr/internal/domain"
"github.com/containrrr/shoutrrr"
"github.com/rs/zerolog"
)
type shoutrrrSender struct {
log zerolog.Logger
Settings domain.Notification
builder NotificationBuilderPlainText
}
func NewShoutrrrSender(log zerolog.Logger, settings domain.Notification) domain.NotificationSender {
return &shoutrrrSender{
log: log.With().Str("sender", "shoutrrr").Logger(),
Settings: settings,
builder: NotificationBuilderPlainText{},
}
}
func (s *shoutrrrSender) Send(event domain.NotificationEvent, payload domain.NotificationPayload) error {
message := s.builder.BuildBody(payload)
if err := shoutrrr.Send(s.Settings.Host, message); err != nil {
return err
}
s.log.Debug().Msg("notification successfully sent to via shoutrrr")
return nil
}
func (s *shoutrrrSender) CanSend(event domain.NotificationEvent) bool {
if s.isEnabled() && s.isEnabledEvent(event) {
return true
}
return false
}
func (s *shoutrrrSender) isEnabled() bool {
if s.Settings.Enabled {
if s.Settings.Host == "" {
s.log.Warn().Msg("shoutrrr missing host")
return false
}
if s.Settings.Token == "" {
s.log.Warn().Msg("shoutrrr missing application token")
return false
}
return true
}
return false
}
func (s *shoutrrrSender) isEnabledEvent(event domain.NotificationEvent) bool {
for _, e := range s.Settings.Events {
if e == string(event) {
return true
}
}
return false
}

View file

@ -390,30 +390,34 @@ export const NotificationTypeOptions: OptionBasicTyped<NotificationType>[] = [
label: "Discord",
value: "DISCORD"
},
{
label: "Notifiarr",
value: "NOTIFIARR"
},
{
label: "Telegram",
value: "TELEGRAM"
},
{
label: "Pushover",
value: "PUSHOVER"
},
{
label: "Gotify",
value: "GOTIFY"
},
{
label: "LunaSea",
value: "LUNASEA"
},
{
label: "Notifiarr",
value: "NOTIFIARR"
},
{
label: "Ntfy",
value: "NTFY"
},
{
label: "LunaSea",
value: "LUNASEA"
}
label: "Pushover",
value: "PUSHOVER"
},
{
label: "Shoutrrr",
value: "SHOUTRRR"
},
{
label: "Telegram",
value: "TELEGRAM"
},
];
export const IrcAuthMechanismTypeOptions: OptionBasicTyped<IrcAuthMechanism>[] = [

View file

@ -239,6 +239,34 @@ function FormFieldsNtfy() {
);
}
function FormFieldsShoutrrr() {
return (
<div className="border-t border-gray-200 dark:border-gray-700 py-4">
<div className="px-4 space-y-1">
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Settings</Dialog.Title>
</div>
<TextFieldWide
name="host"
label="URL"
help="URL"
tooltip={
<div><p>See full documentation </p>
<ExternalLink
href="https://containrrr.dev/shoutrrr/services/overview/"
className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400"
>
Services
</ExternalLink>
</div>
}
placeholder="smtp://username:password@host:port/?from=fromAddress&to=recipient1"
required={true}
/>
</div>
);
}
const componentMap: componentMapType = {
DISCORD: <FormFieldsDiscord />,
NOTIFIARR: <FormFieldsNotifiarr />,
@ -246,6 +274,7 @@ const componentMap: componentMapType = {
PUSHOVER: <FormFieldsPushover />,
GOTIFY: <FormFieldsGotify />,
NTFY: <FormFieldsNtfy />,
SHOUTRRR: <FormFieldsShoutrrr />,
LUNASEA: <FormFieldsLunaSea />
};

View file

@ -77,6 +77,7 @@ const iconComponentMap: componentMapType = {
PUSHOVER: <span className={iconStyle}><PushoverIcon /> Pushover</span>,
GOTIFY: <span className={iconStyle}><GotifyIcon /> Gotify</span>,
NTFY: <span className={iconStyle}><NtfyIcon /> ntfy</span>,
SHOUTRRR: <span className={iconStyle}><NtfyIcon /> Shoutrrr</span>,
LUNASEA: <span className={iconStyle}><LunaSeaIcon /> LunaSea</span>
};

View file

@ -3,7 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later
*/
type NotificationType = "DISCORD" | "NOTIFIARR" | "TELEGRAM" | "PUSHOVER" | "GOTIFY" | "NTFY" | "LUNASEA";
type NotificationType = "DISCORD" | "NOTIFIARR" | "TELEGRAM" | "PUSHOVER" | "GOTIFY" | "NTFY" | "LUNASEA" | "SHOUTRRR";
type NotificationEvent =
"PUSH_APPROVED"
| "PUSH_REJECTED"