diff --git a/docs/assets/notif/pushover.png b/docs/assets/notif/pushover.png new file mode 100644 index 00000000..a2cc40f9 Binary files /dev/null and b/docs/assets/notif/pushover.png differ diff --git a/docs/config/index.md b/docs/config/index.md index 27108aa5..90efdb45 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -206,6 +206,7 @@ Can be transposed to: * [mail](../notif/mail.md) * [matrix](../notif/matrix.md) * [mqtt](../notif/mqtt.md) + * [pushover](../notif/pushover.md) * [rocketchat](../notif/rocketchat.md) * [script](../notif/script.md) * [slack](../notif/slack.md) diff --git a/docs/config/notif.md b/docs/config/notif.md index 33262947..083ff2d4 100644 --- a/docs/config/notif.md +++ b/docs/config/notif.md @@ -6,6 +6,7 @@ * [`mail`](../notif/mail.md) * [`matrix`](../notif/matrix.md) * [`mqtt`](../notif/mqtt.md) +* [`pushover`](../notif/pushover.md) * [`rocketchat`](../notif/rocketchat.md) * [`script`](../notif/script.md) * [`slack`](../notif/slack.md) diff --git a/docs/notif/amqp.md b/docs/notif/amqp.md index e058c351..e8b7fda0 100644 --- a/docs/notif/amqp.md +++ b/docs/notif/amqp.md @@ -15,16 +15,6 @@ You can send notifications to any amqp compatible server with the following sett queue: queue ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_AMQP_HOST` - * `DIUN_NOTIF_AMQP_PORT` - * `DIUN_NOTIF_AMQP_USERNAME` - * `DIUN_NOTIF_AMQP_USERNAMEFILE` - * `DIUN_NOTIF_AMQP_PASSWORD` - * `DIUN_NOTIF_AMQP_PASSWORDFILE` - * `DIUN_NOTIF_AMQP_EXCHANGE` - * `DIUN_NOTIF_AMQP_QUEUE` - | Name | Default | Description | |--------------------|---------------|---------------| | `host`[^1] | `localhost` | AMQP server host | @@ -36,6 +26,16 @@ You can send notifications to any amqp compatible server with the following sett | `exchange` | | Name of the exchange the message will be sent to | | `queue`[^1] | | Name of the queue the message will be sent to | +!!! abstract "Environment variables" + * `DIUN_NOTIF_AMQP_HOST` + * `DIUN_NOTIF_AMQP_PORT` + * `DIUN_NOTIF_AMQP_USERNAME` + * `DIUN_NOTIF_AMQP_USERNAMEFILE` + * `DIUN_NOTIF_AMQP_PASSWORD` + * `DIUN_NOTIF_AMQP_PASSWORDFILE` + * `DIUN_NOTIF_AMQP_EXCHANGE` + * `DIUN_NOTIF_AMQP_QUEUE` + ## Sample The JSON response will look like this: diff --git a/docs/notif/discord.md b/docs/notif/discord.md index 727670bd..6c5c84c7 100644 --- a/docs/notif/discord.md +++ b/docs/notif/discord.md @@ -18,17 +18,17 @@ Allow to send notifications to your Discord channel. timeout: 10s ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_DISCORD_WEBHOOKURL` - * `DIUN_NOTIF_DISCORD_MENTIONS` - * `DIUN_NOTIF_DISCORD_TIMEOUT` - | Name | Default | Description | |--------------------|---------------|---------------| | `webhookURL`[^1] | | Discord [incoming webhook URL](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) | | `mentions` | | List of users or roles to notify | | `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +!!! abstract "Environment variables" + * `DIUN_NOTIF_DISCORD_WEBHOOKURL` + * `DIUN_NOTIF_DISCORD_MENTIONS` + * `DIUN_NOTIF_DISCORD_TIMEOUT` + ## Sample ![](../assets/notif/discord-1.png) diff --git a/docs/notif/gotify.md b/docs/notif/gotify.md index 5a8bb7be..0b2ea849 100644 --- a/docs/notif/gotify.md +++ b/docs/notif/gotify.md @@ -14,12 +14,6 @@ Notifications can be sent using a [Gotify](https://gotify.net/) instance. timeout: 10s ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_GOTIFY_ENDPOINT` - * `DIUN_NOTIF_GOTIFY_TOKEN` - * `DIUN_NOTIF_GOTIFY_PRIORITY` - * `DIUN_NOTIF_GOTIFY_TIMEOUT` - | Name | Default | Description | |--------------------|---------------|---------------| | `endpoint`[^1] | | Gotify base URL | @@ -27,6 +21,12 @@ Notifications can be sent using a [Gotify](https://gotify.net/) instance. | `priority` | `1` | The priority of the message | | `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +!!! abstract "Environment variables" + * `DIUN_NOTIF_GOTIFY_ENDPOINT` + * `DIUN_NOTIF_GOTIFY_TOKEN` + * `DIUN_NOTIF_GOTIFY_PRIORITY` + * `DIUN_NOTIF_GOTIFY_TIMEOUT` + ## Sample ![](../assets/notif/gotify.png) diff --git a/docs/notif/mqtt.md b/docs/notif/mqtt.md index 24f6a74f..d4ae4ffc 100644 --- a/docs/notif/mqtt.md +++ b/docs/notif/mqtt.md @@ -29,6 +29,17 @@ You can send notifications to any MQTT compatible server with the following sett | `topic`[^1] | | Topic the message will be sent to | | `qos` | `0` | Ensured message delivery at specified Quality of Service (QoS) | +!!! abstract "Environment variables" + * `DIUN_NOTIF_MQTT_HOST` + * `DIUN_NOTIF_MQTT_PORT` + * `DIUN_NOTIF_MQTT_USERNAME` + * `DIUN_NOTIF_MQTT_USERNAMEFILE` + * `DIUN_NOTIF_MQTT_PASSWORD` + * `DIUN_NOTIF_MQTT_PASSWORDFILE` + * `DIUN_NOTIF_MQTT_CLIENT` + * `DIUN_NOTIF_MQTT_TOPIC` + * `DIUN_NOTIF_MQTT_QOS` + ## Sample The JSON response will look like this: diff --git a/docs/notif/pushover.md b/docs/notif/pushover.md new file mode 100644 index 00000000..0a7f2e6f --- /dev/null +++ b/docs/notif/pushover.md @@ -0,0 +1,30 @@ +# Pushover notifications + +You can send notifications using [Pushover](https://pushover.net/). + +## Configuration + +!!! example "File" + ```yaml + notif: + pushover: + token: uQiRzpo4DXghDmr9QzzfQu27cmVRsG + recipient: gznej3rKEVAvPUxu9vvNnqpmZpokzF + ``` + +| Name | Default | Description | +|--------------------|---------------|---------------| +| `token` | | Pushover [application/API token](https://pushover.net/api#registration) | +| `tokenFile` | | Use content of secret file as Pushover application/API token if `token` not defined | +| `recipient` | | User key to send notification to | +| `recipientFile` | | Use content of secret file as User key if `recipient` not defined | + +!!! abstract "Environment variables" + * `DIUN_NOTIF_PUSHOVER_TOKEN` + * `DIUN_NOTIF_PUSHOVER_TOKENFILE` + * `DIUN_NOTIF_PUSHOVER_RECIPIENT` + * `DIUN_NOTIF_PUSHOVER_RECIPIENTFILE` + +## Sample + +![](../assets/notif/pushover.png) diff --git a/docs/notif/rocketchat.md b/docs/notif/rocketchat.md index 30d6ccc0..d46f1064 100644 --- a/docs/notif/rocketchat.md +++ b/docs/notif/rocketchat.md @@ -15,13 +15,6 @@ Allow to send notifications to your Rocket.Chat channel. timeout: 10s ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_ROCKETCHAT_ENDPOINT` - * `DIUN_NOTIF_ROCKETCHAT_CHANNEL` - * `DIUN_NOTIF_ROCKETCHAT_USERID` - * `DIUN_NOTIF_ROCKETCHAT_TOKEN` - * `DIUN_NOTIF_ROCKETCHAT_TIMEOUT` - | Name | Default | Description | |--------------------|---------------|---------------| | `endpoint`[^1] | | Rocket.Chat base URL | @@ -33,6 +26,13 @@ Allow to send notifications to your Rocket.Chat channel. !!! warning You must first create a _Personal Access Token_ through your account settings on your Rocket.Chat instance. +!!! abstract "Environment variables" + * `DIUN_NOTIF_ROCKETCHAT_ENDPOINT` + * `DIUN_NOTIF_ROCKETCHAT_CHANNEL` + * `DIUN_NOTIF_ROCKETCHAT_USERID` + * `DIUN_NOTIF_ROCKETCHAT_TOKEN` + * `DIUN_NOTIF_ROCKETCHAT_TIMEOUT` + ## Sample ![](../assets/notif/rocketchat.png) diff --git a/docs/notif/slack.md b/docs/notif/slack.md index c2c85016..c8513c59 100644 --- a/docs/notif/slack.md +++ b/docs/notif/slack.md @@ -14,13 +14,13 @@ You can send notifications to your Slack channel using an [incoming webhook URL] webhookURL: https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_SLACK_WEBHOOKURL` - | Name | Default | Description | |--------------------|---------------|---------------| | `webhookURL`[^1] | | Slack [incoming webhook URL](https://api.slack.com/messaging/webhooks) | +!!! abstract "Environment variables" + * `DIUN_NOTIF_SLACK_WEBHOOKURL` + ## Sample ![](../assets/notif/slack.png) diff --git a/docs/notif/teams.md b/docs/notif/teams.md index c31bf5fc..9c418e76 100644 --- a/docs/notif/teams.md +++ b/docs/notif/teams.md @@ -11,13 +11,13 @@ You can send notifications to your Teams team-channel using an [incoming webhook webhookURL: https://outlook.office.com/webhook/ABCD12EFG/HIJK34LMN/01234567890abcdefghij ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_TEAMS_WEBHOOKURL` - | Name | Default | Description | |--------------------|---------------|---------------| | `webhookURL`[^1] | | Teams [incoming webhook URL](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/what-are-webhooks-and-connectors) | +!!! abstract "Environment variables" + * `DIUN_NOTIF_TEAMS_WEBHOOKURL` + ## Sample ![](../assets/notif/teams.png) diff --git a/docs/notif/telegram.md b/docs/notif/telegram.md index 041381c3..10218de9 100644 --- a/docs/notif/telegram.md +++ b/docs/notif/telegram.md @@ -19,15 +19,15 @@ Multiple chat IDs can be provided in order to deliver notifications to multiple - 987654321 ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_TELEGRAM_TOKEN` - * `DIUN_NOTIF_TELEGRAM_CHATIDS` (comma separated) - | Name | Default | Description | |--------------------|---------------|---------------| | `token`[^1] | | Telegram bot token | | `chatIDs`[^1] | | List of chat IDs to send notifications to | +!!! abstract "Environment variables" + * `DIUN_NOTIF_TELEGRAM_TOKEN` + * `DIUN_NOTIF_TELEGRAM_CHATIDS` (comma separated) + ## Sample ![](../assets/notif/telegram.png) diff --git a/docs/notif/webhook.md b/docs/notif/webhook.md index b5edea2c..9f06c1a9 100644 --- a/docs/notif/webhook.md +++ b/docs/notif/webhook.md @@ -16,12 +16,6 @@ You can send webhook notifications with the following settings. timeout: 10s ``` -!!! abstract "Environment variables" - * `DIUN_NOTIF_WEBHOOK_ENDPOINT` - * `DIUN_NOTIF_WEBHOOK_METHOD` - * `DIUN_NOTIF_WEBHOOK_HEADERS_` - * `DIUN_NOTIF_WEBHOOK_TIMEOUT` - | Name | Default | Description | |--------------------|---------------|---------------| | `endpoint`[^1] | | URL of the HTTP request | @@ -29,6 +23,12 @@ You can send webhook notifications with the following settings. | `headers` | | Map of additional headers to be sent (key is case insensitive) | | `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +!!! abstract "Environment variables" + * `DIUN_NOTIF_WEBHOOK_ENDPOINT` + * `DIUN_NOTIF_WEBHOOK_METHOD` + * `DIUN_NOTIF_WEBHOOK_HEADERS_` + * `DIUN_NOTIF_WEBHOOK_TIMEOUT` + ## Sample The JSON response will look like this: diff --git a/go.mod b/go.mod index 6455f167..6ba71ebd 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df github.com/go-playground/validator/v10 v10.4.1 github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible + github.com/gregdel/pushover v0.0.0-20201104094836-ddbe0c1d3a38 github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84 github.com/imdario/mergo v0.3.11 github.com/matcornic/hermes/v2 v2.1.0 diff --git a/go.sum b/go.sum index 09af4a3e..3b72ecca 100644 --- a/go.sum +++ b/go.sum @@ -202,6 +202,8 @@ github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregdel/pushover v0.0.0-20201104094836-ddbe0c1d3a38 h1:jb9bDQ07E8YdegHcvFJ6r0JAQhSxT6BQjDLn/xAMu64= +github.com/gregdel/pushover v0.0.0-20201104094836-ddbe0c1d3a38/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER1PthX7to= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84 h1:RvcDqcKLua4b/jtXez7ZVe9s6Iq5N6ujVevqY4FBQmM= github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE= diff --git a/internal/config/config_test.go b/internal/config/config_test.go index fa37412f..d9bf694c 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -131,6 +131,10 @@ func TestLoadFile(t *testing.T) { Topic: "docker/diun", QoS: 0, }, + Pushover: &model.NotifPushover{ + Token: "uQiRzpo4DXghDmr9QzzfQu27cmVRsG", + Recipient: "gznej3rKEVAvPUxu9vvNnqpmZpokzF", + }, RocketChat: &model.NotifRocketChat{ Endpoint: "http://rocket.foo.com:3000", Channel: "#general", diff --git a/internal/config/fixtures/config.test.yml b/internal/config/fixtures/config.test.yml index f2573899..6940ee69 100644 --- a/internal/config/fixtures/config.test.yml +++ b/internal/config/fixtures/config.test.yml @@ -51,6 +51,9 @@ notif: client: "diun" topic: "docker/diun" qos: 0 + pushover: + token: uQiRzpo4DXghDmr9QzzfQu27cmVRsG + recipient: gznej3rKEVAvPUxu9vvNnqpmZpokzF rocketchat: endpoint: http://rocket.foo.com:3000 channel: "#general" diff --git a/internal/config/fixtures/config.validate.yml b/internal/config/fixtures/config.validate.yml index 35e622d6..20e7ecca 100644 --- a/internal/config/fixtures/config.validate.yml +++ b/internal/config/fixtures/config.validate.yml @@ -51,6 +51,9 @@ notif: client: "diun" topic: "docker/diun" qos: 0 + pushover: + token: uQiRzpo4DXghDmr9QzzfQu27cmVRsG + recipient: gznej3rKEVAvPUxu9vvNnqpmZpokzF rocketchat: endpoint: http://rocket.foo.com:3000 channel: "#general" diff --git a/internal/model/notif.go b/internal/model/notif.go index e6c2e8b2..d8c7a705 100644 --- a/internal/model/notif.go +++ b/internal/model/notif.go @@ -31,6 +31,7 @@ type Notif struct { Mail *NotifMail `yaml:"mail,omitempty" json:"mail,omitempty"` Matrix *NotifMatrix `yaml:"matrix,omitempty" json:"matrix,omitempty"` Mqtt *NotifMqtt `yaml:"mqtt,omitempty" json:"mqtt,omitempty"` + Pushover *NotifPushover `yaml:"pushover,omitempty" json:"pushover,omitempty"` RocketChat *NotifRocketChat `yaml:"rocketchat,omitempty" json:"rocketchat,omitempty"` Script *NotifScript `yaml:"script,omitempty" json:"script,omitempty"` Slack *NotifSlack `yaml:"slack,omitempty" json:"slack,omitempty"` diff --git a/internal/model/notif_pushover.go b/internal/model/notif_pushover.go new file mode 100644 index 00000000..5b496966 --- /dev/null +++ b/internal/model/notif_pushover.go @@ -0,0 +1,20 @@ +package model + +// NotifPushover holds Pushover notification configuration details +type NotifPushover struct { + Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` + TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` + Recipient string `yaml:"recipient,omitempty" json:"recipient,omitempty" validate:"omitempty"` + RecipientFile string `yaml:"recipientFile,omitempty" json:"recipientFile,omitempty" validate:"omitempty,file"` + Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=-2,max=2"` +} + +// GetDefaults gets the default values +func (s *NotifPushover) GetDefaults() *NotifPushover { + return nil +} + +// SetDefaults sets the default values +func (s *NotifPushover) SetDefaults() { + // noop +} diff --git a/internal/notif/client.go b/internal/notif/client.go index db214e4a..8a3fb271 100644 --- a/internal/notif/client.go +++ b/internal/notif/client.go @@ -11,6 +11,7 @@ import ( "github.com/crazy-max/diun/v4/internal/notif/matrix" "github.com/crazy-max/diun/v4/internal/notif/mqtt" "github.com/crazy-max/diun/v4/internal/notif/notifier" + "github.com/crazy-max/diun/v4/internal/notif/pushover" "github.com/crazy-max/diun/v4/internal/notif/rocketchat" "github.com/crazy-max/diun/v4/internal/notif/script" "github.com/crazy-max/diun/v4/internal/notif/slack" @@ -59,6 +60,9 @@ func New(config *model.Notif, meta model.Meta) (*Client, error) { if config.Mqtt != nil { c.notifiers = append(c.notifiers, mqtt.New(config.Mqtt, meta)) } + if config.Pushover != nil { + c.notifiers = append(c.notifiers, pushover.New(config.Pushover, meta)) + } if config.RocketChat != nil { c.notifiers = append(c.notifiers, rocketchat.New(config.RocketChat, meta)) } diff --git a/internal/notif/pushover/pushover.go b/internal/notif/pushover/pushover.go new file mode 100644 index 00000000..b3d245a8 --- /dev/null +++ b/internal/notif/pushover/pushover.go @@ -0,0 +1,91 @@ +package pushover + +import ( + "bytes" + "errors" + "fmt" + "text/template" + "time" + + "github.com/crazy-max/diun/v4/internal/model" + "github.com/crazy-max/diun/v4/internal/notif/notifier" + "github.com/crazy-max/diun/v4/pkg/utl" + "github.com/gregdel/pushover" +) + +// Client represents an active Pushover notification object +type Client struct { + *notifier.Notifier + cfg *model.NotifPushover + meta model.Meta +} + +// New creates a new Pushover notification instance +func New(config *model.NotifPushover, meta model.Meta) notifier.Notifier { + return notifier.Notifier{ + Handler: &Client{ + cfg: config, + meta: meta, + }, + } +} + +// Name returns notifier's name +func (c *Client) Name() string { + return "pushover" +} + +// Send creates and sends a Pushover notification with an entry +func (c *Client) Send(entry model.NotifEntry) error { + token, err := utl.GetSecret(c.cfg.Token, c.cfg.TokenFile) + if err != nil { + return errors.New("Cannot retrieve token secret for Pushover notifier") + } + + recipient, err := utl.GetSecret(c.cfg.Recipient, c.cfg.RecipientFile) + if err != nil { + return errors.New("Cannot retrieve recipient secret for Pushover notifier") + } + + app := pushover.New(token) + user := pushover.NewRecipient(recipient) + + title := fmt.Sprintf("Image update for %s", entry.Image.String()) + if entry.Status == model.ImageStatusNew { + title = fmt.Sprintf("New image %s has been added", entry.Image.String()) + } + + tagTpl := "{{ .Entry.Image.Domain }}/{{ .Entry.Image.Path }}:{{ .Entry.Image.Tag }}" + if len(entry.Image.HubLink) > 0 { + tagTpl = `{{ .Entry.Image.Domain }}/{{ .Entry.Image.Path }}:{{ .Entry.Image.Tag }}` + } + + var msgBuf bytes.Buffer + msgTpl := template.Must(template.New("email").Parse(fmt.Sprintf("Docker tag %s which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }} on {{ .Hostname }}.", tagTpl))) + if err := msgTpl.Execute(&msgBuf, struct { + Hostname string + Entry model.NotifEntry + }{ + Hostname: c.meta.Hostname, + Entry: entry, + }); err != nil { + return err + } + + _, err = app.GetRecipientDetails(user) + if err != nil { + return err + } + + _, err = app.SendMessage(&pushover.Message{ + Message: msgBuf.String(), + Title: title, + Priority: c.cfg.Priority, + URL: c.meta.URL, + URLTitle: c.meta.Name, + Timestamp: time.Now().Unix(), + HTML: true, + }, user) + + return err +} diff --git a/mkdocs.yml b/mkdocs.yml index fb54cc53..95b0c473 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -94,6 +94,7 @@ nav: - Mail: notif/mail.md - Matrix: notif/matrix.md - MQTT: notif/mqtt.md + - Pushover: notif/pushover.md - Rocket.Chat: notif/rocketchat.md - Script: notif/script.md - Slack: notif/slack.md