From 5d583809a05f29fcccb2634d3c1d98e6ca75c2ff Mon Sep 17 00:00:00 2001 From: CrazyMax <1951866+crazy-max@users.noreply.github.com> Date: Fri, 25 Jun 2021 23:24:02 +0200 Subject: [PATCH] Allow to customize notification message (#415) Co-authored-by: CrazyMax --- README.md | 12 ++-- docs/_overrides/main.html | 62 +++++++++---------- docs/contributing.md | 6 +- docs/donate.md | 2 +- docs/faq.md | 37 +++++++++++ docs/install/binary.md | 28 ++++----- docs/install/linux-service.md | 2 +- docs/notif/discord.md | 29 +++++++-- docs/notif/gotify.md | 33 +++++++--- docs/notif/mail.md | 53 ++++++++++++---- docs/notif/matrix.md | 28 ++++++--- docs/notif/pushover.md | 31 ++++++++-- docs/notif/rocketchat.md | 35 ++++++++--- docs/notif/slack.md | 16 ++++- docs/notif/teams.md | 16 ++++- docs/notif/telegram.md | 25 ++++++-- docs/reporting-issue.md | 4 +- internal/config/config_test.go | 65 ++++++++++++++------ internal/config/fixtures/config.docker.yml | 7 +++ internal/config/fixtures/config.test.yml | 7 +++ internal/config/fixtures/config.validate.yml | 7 +++ internal/model/notif.go | 6 ++ internal/model/notif_discord.go | 10 ++- internal/model/notif_gotify.go | 14 +++-- internal/model/notif_mail.go | 15 +++++ internal/model/notif_matrix.go | 2 + internal/model/notif_pushover.go | 9 ++- internal/model/notif_rocketchat.go | 19 ++++-- internal/model/notif_slack.go | 12 +++- internal/model/notif_teams.go | 12 +++- internal/model/notif_telegram.go | 18 ++++-- internal/msg/client.go | 65 ++++++++++---------- internal/notif/discord/client.go | 12 ++-- internal/notif/gotify/client.go | 18 +++--- internal/notif/mail/client.go | 34 ++++------ internal/notif/matrix/client.go | 5 +- internal/notif/mqtt/client.go | 8 +-- internal/notif/pushover/client.go | 12 ++-- internal/notif/rocketchat/client.go | 14 ++--- internal/notif/slack/client.go | 11 ++-- internal/notif/teams/client.go | 20 +++--- internal/notif/telegram/client.go | 15 ++--- mkdocs.yml | 13 +++- 43 files changed, 573 insertions(+), 276 deletions(-) diff --git a/README.md b/README.md index 4d4309e3..d7392c9f 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,14 @@ a Docker registry. Documentation can be found on https://crazymax.dev/diun/ -## How can I help? +## Contributing -All kinds of contributions are welcome :raised_hands:! The most basic way to show your support is to star :star2: the -project, or to raise issues :speech_balloon: You can also support this project by -[**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) :clap: or by making a -[Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely! :rocket: +Want to contribute? Awesome! The most basic way to show your support is to star :star2: the project, +or to raise issues :speech_balloon:. If you want to open a pull request, please read the +[contributing guidelines](.github/CONTRIBUTING.md). + +You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by +making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely! Thanks again for your support, it is much appreciated! :pray: diff --git a/docs/_overrides/main.html b/docs/_overrides/main.html index 9d90a811..ec3ec0eb 100644 --- a/docs/_overrides/main.html +++ b/docs/_overrides/main.html @@ -10,48 +10,48 @@ {% set assets = config.site_url ~ 'assets' %} {% block extrahead %} - - + + - + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + {% endblock %} diff --git a/docs/contributing.md b/docs/contributing.md index 1e088ee7..199ce887 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -3,18 +3,18 @@ Hi there! I'm thrilled that you'd like to contribute to this project. Your help is essential for keeping it great. Contributions to this project are [released](https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license) -to the public under the [project's open source license]({{ config.repo_url }}/blob/master/LICENSE). +to the public under the [project's open source license]([[ config.repo_url ]]/blob/master/LICENSE). ## Submitting a pull request -1. [Fork]({{ config.repo_url }}fork) and clone the repository +1. [Fork]([[ config.repo_url ]]fork) and clone the repository 2. Configure and install the dependencies: `go mod download` 3. Create a new branch: `git checkout -b my-branch-name` 4. Make your changes 5. Validate: `docker buildx bake validate` 6. Test your code: `docker buildx bake test` 7. Build the project: `docker buildx bake artifact-all image-all` -8. Push to your fork and [submit a pull request]({{ config.repo_url }}compare) +8. Push to your fork and [submit a pull request]([[ config.repo_url ]]compare) 9. Pat your self on the back and wait for your pull request to be reviewed and merged. Here are a few things you can do that will increase the likelihood of your pull request being accepted: diff --git a/docs/donate.md b/docs/donate.md index 5a1c3cfc..4ed9e964 100644 --- a/docs/donate.md +++ b/docs/donate.md @@ -1,7 +1,7 @@ **Diun** :bell: is free and open source and always will be. All kinds of contributions are welcome! The most basic way to show your support is to -[star the project]({{ config.repo_url }}), or to raise issues. +[star the project]([[ config.repo_url ]]), or to raise issues. You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely! diff --git a/docs/faq.md b/docs/faq.md index 8b9f8d96..ac3cf6e9 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -26,6 +26,43 @@ Or within a container: docker-compose exec diun diun notif test ``` +## Notification template + +The title and body of a notification message can be customized for each notifier through `templateTitle` and +`templateBody` fields except for those rendering _JSON_ or _Env_ like [Amqp](notif/amqp.md), +[MQTT](notif/mqtt.md), [Script](notif/script.md) and [Webhook](notif/webhook.md). + +Templating is supported with the following fields: + +| Key | Description | +|----------------------------------|-------------| +| `.Meta.ID` | App ID: `diun` | +| `.Meta.Name` | App Name: `Diun` | +| `.Meta.Desc` | App description: `Docker image update notifier` | +| `.Meta.URL` | App repo URL: `https://github.com/crazy-max/diun` | +| `.Meta.Logo` | App logo URL: `https://raw.githubusercontent.com/crazy-max/diun/master/.res/diun.png` | +| `.Meta.Author` | App author: `CrazyMax` | +| `.Meta.Version` | App version: `v4.19.0` | +| `.Meta.UserAgent` | App user-agent used to talk with registries: `diun/4.19.0 go/1.16 Linux` | +| `.Meta.Hostname` | Hostname | +| `.Entry.Status` | Entry status. Can be `new`, `update`, `unchange`, `skip` or `error` | +| `.Entry.Provider` | [Provider](config/providers.md) used | +| `.Entry.Image` | Docker image name. e.g. `docker.io/crazymax/diun:latest` | +| `.Entry.Image.Domain` | Docker image domain. e.g. `docker.io` | +| `.Entry.Image.Path` | Docker image path. e.g. `crazymax/diun` | +| `.Entry.Image.Tag` | Docker image tag. e.g. `latest` | +| `.Entry.Image.Digest` | Docker image digest | +| `.Entry.Image.HubLink` | Docker image hub link (if available). e.g. `https://hub.docker.com/r/crazymax/diun` | +| `.Entry.Manifest.Name` | Manifest name. e.g. `docker.io/crazymax/diun` | +| `.Entry.Manifest.Tag` | Manifest tag. e.g. `latest` | +| `.Entry.Manifest.MIMEType` | Manifest MIME type. e.g. `application/vnd.docker.distribution.manifest.list.v2+json` | +| `.Entry.Manifest.Digest` | Manifest digest | +| `.Entry.Manifest.Created` | Manifest created date. e.g. `2021-06-20T12:23:56Z` | +| `.Entry.Manifest.DockerVersion` | Version of Docker that was used to build the image. e.g. `20.10.7` | +| `.Entry.Manifest.Labels` | Image labels | +| `.Entry.Manifest.Layers` | Image layers | +| `.Entry.Manifest.Platform` | Platform that the image is runs on. e.g. `linux/amd64` | + ## Authentication against the registry You can authenticate against the registry through the [`regopts` settings](config/regopts.md) or you can mount diff --git a/docs/install/binary.md b/docs/install/binary.md index da26e169..27bff058 100644 --- a/docs/install/binary.md +++ b/docs/install/binary.md @@ -2,27 +2,27 @@ ## Download -Diun binaries are available on [releases]({{ config.repo_url }}releases) page. +Diun binaries are available on [releases]([[ config.repo_url ]]releases) page. Choose the archive matching the destination platform: -* [diun_{{ git.tag | trim('v') }}_darwin_arm64.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_darwin_arm64.tar.gz) -* [diun_{{ git.tag | trim('v') }}_darwin_x86_64.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_darwin_x86_64.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_arm64.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_arm64.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_armv5.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_armv5.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_armv6.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_armv6.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_armv7.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_armv7.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_i386.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_i386.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_ppc64le.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_ppc64le.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_s390x.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_s390x.tar.gz) -* [diun_{{ git.tag | trim('v') }}_linux_x86_64.tar.gz]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_x86_64.tar.gz) -* [diun_{{ git.tag | trim('v') }}_windows_i386.zip]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_windows_i386.zip) -* [diun_{{ git.tag | trim('v') }}_windows_x86_64.zip]({{ config.repo_url }}/releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_windows_x86_64.zip) +* [diun_[[ git.tag | trim('v') ]]_darwin_arm64.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_darwin_arm64.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_darwin_x86_64.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_darwin_x86_64.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_arm64.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_arm64.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_armv5.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_armv5.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_armv6.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_armv6.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_armv7.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_armv7.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_i386.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_i386.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_ppc64le.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_ppc64le.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_s390x.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_s390x.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_linux_x86_64.tar.gz]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_x86_64.tar.gz) +* [diun_[[ git.tag | trim('v') ]]_windows_i386.zip]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_windows_i386.zip) +* [diun_[[ git.tag | trim('v') ]]_windows_x86_64.zip]([[ config.repo_url ]]/releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_windows_x86_64.zip) And extract diun: ```shell -wget -qO- {{ config.repo_url }}releases/download/v{{ git.tag | trim('v') }}/diun_{{ git.tag | trim('v') }}_linux_x86_64.tar.gz | tar -zxvf - diun +wget -qO- [[ config.repo_url ]]releases/download/v[[ git.tag | trim('v') ]]/diun_[[ git.tag | trim('v') ]]_linux_x86_64.tar.gz | tar -zxvf - diun ``` After getting the binary, it can be tested with [`./diun --help`](../usage/command-line.md#global-options) command diff --git a/docs/install/linux-service.md b/docs/install/linux-service.md index 0a2cb250..51e0c09f 100644 --- a/docs/install/linux-service.md +++ b/docs/install/linux-service.md @@ -10,7 +10,7 @@ To create a new service, paste this content in `/etc/systemd/system/diun.service ``` [Unit] Description=Diun -Documentation={{ config.site_url }} +Documentation=[[ config.site_url ]] After=syslog.target After=network.target diff --git a/docs/notif/discord.md b/docs/notif/discord.md index 5085383b..e08629a1 100644 --- a/docs/notif/discord.md +++ b/docs/notif/discord.md @@ -16,18 +16,37 @@ Allow to send notifications to your Discord channel. - "<@125>" - "<@&200>" timeout: 10s + templateTitle: "{{ .Entry.Image }} released" + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| 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 | +| 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 | +| `templateTitle`[^1] | See [below](#default-templatetitle) | [Notification template](../faq.md#notification-template) for message title | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_DISCORD_WEBHOOKURL` * `DIUN_NOTIF_DISCORD_MENTIONS` (comma separated) * `DIUN_NOTIF_DISCORD_TIMEOUT` + * `DIUN_NOTIF_DISCORD_TEMPLATETITLE` + * `DIUN_NOTIF_DISCORD_TEMPLATEBODY` + +### Default `templateTitle` + +``` +[[ config.extra.template.defaultTitle ]] +``` + +### Default `templateBody` + +``` +[[ config.extra.template.defaultBody ]] +``` ## Sample diff --git a/docs/notif/gotify.md b/docs/notif/gotify.md index 47af8ae6..b2fe0ea1 100644 --- a/docs/notif/gotify.md +++ b/docs/notif/gotify.md @@ -12,15 +12,20 @@ Notifications can be sent using a [Gotify](https://gotify.net/) instance. token: Token123456 priority: 1 timeout: 10s + templateTitle: "{{ .Entry.Image }} released" + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| Name | Default | Description | -|--------------------|---------------|---------------| -| `endpoint`[^1] | | Gotify base URL | -| `token` | | Application token | -| `tokenFile` | | Use content of secret file as application token if `token` not defined | -| `priority` | `1` | The priority of the message | -| `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +| Name | Default | Description | +|---------------------|---------------------------------------|---------------| +| `endpoint`[^1] | | Gotify base URL | +| `token` | | Application token | +| `tokenFile` | | Use content of secret file as application token if `token` not defined | +| `priority` | `1` | The priority of the message | +| `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +| `templateTitle`[^1] | See [below](#default-templatetitle) | [Notification template](../faq.md#notification-template) for message title | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_GOTIFY_ENDPOINT` @@ -28,6 +33,20 @@ Notifications can be sent using a [Gotify](https://gotify.net/) instance. * `DIUN_NOTIF_GOTIFY_TOKENFILE` * `DIUN_NOTIF_GOTIFY_PRIORITY` * `DIUN_NOTIF_GOTIFY_TIMEOUT` + * `DIUN_NOTIF_GOTIFY_TEMPLATETITLE` + * `DIUN_NOTIF_GOTIFY_TEMPLATEBODY` + +### Default `templateTitle` + +``` +[[ config.extra.template.defaultTitle ]] +``` + +### Default `templateBody` + +``` +[[ config.extra.template.defaultBody ]] +``` ## Sample diff --git a/docs/notif/mail.md b/docs/notif/mail.md index 539be533..dd4733b8 100644 --- a/docs/notif/mail.md +++ b/docs/notif/mail.md @@ -14,21 +14,26 @@ Notifications can be sent through SMTP. insecureSkipVerify: false from: diun@example.com to: webmaster@example.com + templateTitle: "{{ .Entry.Image }} released" + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| Name | Default | Description | -|-----------------------|---------------|---------------| -| `host`[^1] | `localhost` | SMTP server host | -| `port`[^1] | `25` | SMTP server port | -| `ssl` | `false` | SSL defines whether an SSL connection is used. Should be false in most cases since the auth mechanism should use STARTTLS | -| `insecureSkipVerify` | `false` | Controls whether a client verifies the server's certificate chain and hostname | -| `localName` | `localhost` | Hostname sent to the SMTP server with the HELO command | -| `username` | | SMTP username | -| `usernameFile` | | Use content of secret file as SMTP username if `username` not defined | -| `password` | | SMTP password | -| `passwordFile` | | Use content of secret file as SMTP password if `password` not defined | -| `from`[^1] | | Sender email address | -| `to`[^1] | | Recipient email address | +| Name | Default | Description | +|-----------------------|--------------------------------------------|---------------| +| `host`[^1] | `localhost` | SMTP server host | +| `port`[^1] | `25` | SMTP server port | +| `ssl` | `false` | SSL defines whether an SSL connection is used. Should be false in most cases since the auth mechanism should use STARTTLS | +| `insecureSkipVerify` | `false` | Controls whether a client verifies the server's certificate chain and hostname | +| `localName` | `localhost` | Hostname sent to the SMTP server with the HELO command | +| `username` | | SMTP username | +| `usernameFile` | | Use content of secret file as SMTP username if `username` not defined | +| `password` | | SMTP password | +| `passwordFile` | | Use content of secret file as SMTP password if `password` not defined | +| `from`[^1] | | Sender email address | +| `to`[^1] | | Recipient email address | +| `templateTitle`[^1] | See [below](#default-templatetitle) | [Notification template](../faq.md#notification-template) for message title | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_MAIL_HOST` @@ -42,6 +47,28 @@ Notifications can be sent through SMTP. * `DIUN_NOTIF_MAIL_PASSWORDFILE` * `DIUN_NOTIF_MAIL_FROM` * `DIUN_NOTIF_MAIL_TO` + * `DIUN_NOTIF_MAIL_TEMPLATETITLE` + * `DIUN_NOTIF_MAIL_TEMPLATEBODY` + +### Default `templateTitle` + +``` +[[ config.extra.template.defaultTitle ]] +``` + +### Default `templateBody` + +``` +Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} +which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} +on {{ .Meta.Hostname }}. + +This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at +{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} +for {{ .Entry.Manifest.Platform }} platform. + +Need help, or have questions? Go to {{ .Meta.URL }} and leave an issue. +``` ## Sample diff --git a/docs/notif/matrix.md b/docs/notif/matrix.md index bdda9525..26488784 100644 --- a/docs/notif/matrix.md +++ b/docs/notif/matrix.md @@ -13,17 +13,20 @@ Allow to send notifications to your Matrix server. password: bar roomID: "!abcdefGHIjklmno:matrix.org" msgType: notice + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| Name | Default | Description | -|-----------------------|------------------------|-------------------| -| `homeserverURL` | `https://matrix.org` | Matrix server URL | -| `user` | | Username for authentication | -| `userFile` | | Use content of secret file as username authentication if `username` not defined | -| `password` | | Password for authentication | -| `passwordFile` | | Use content of secret file as password authentication if `password` not defined | -| `roomID` | | Room ID to send messages | -| `msgType` | `notice` | Type of message being sent. Can be `notice` or `text` | +| Name | Default | Description | +|-----------------------|--------------------------------------------|-------------------| +| `homeserverURL` | `https://matrix.org` | Matrix server URL | +| `user` | | Username for authentication | +| `userFile` | | Use content of secret file as username authentication if `username` not defined | +| `password` | | Password for authentication | +| `passwordFile` | | Use content of secret file as password authentication if `password` not defined | +| `roomID` | | Room ID to send messages | +| `msgType` | `notice` | Type of message being sent. Can be `notice` or `text` | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_MATRIX_HOMESERVERURL` @@ -33,6 +36,13 @@ Allow to send notifications to your Matrix server. * `DIUN_NOTIF_MATRIX_PASSWORDFILE` * `DIUN_NOTIF_MATRIX_ROOMID` * `DIUN_NOTIF_MATRIX_MSGTYPE` + * `DIUN_NOTIF_MATRIX_TEMPLATEBODY` + +### Default `templateBody` + +``` +[[ config.extra.template.defaultBody ]] +``` ## Sample diff --git a/docs/notif/pushover.md b/docs/notif/pushover.md index 0a7f2e6f..56d57752 100644 --- a/docs/notif/pushover.md +++ b/docs/notif/pushover.md @@ -10,20 +10,39 @@ You can send notifications using [Pushover](https://pushover.net/). pushover: token: uQiRzpo4DXghDmr9QzzfQu27cmVRsG recipient: gznej3rKEVAvPUxu9vvNnqpmZpokzF + templateTitle: "{{ .Entry.Image }} released" + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| 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 | +| 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 | +| `templateTitle`[^1] | See [below](#default-templatetitle) | [Notification template](../faq.md#notification-template) for message title | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_PUSHOVER_TOKEN` * `DIUN_NOTIF_PUSHOVER_TOKENFILE` * `DIUN_NOTIF_PUSHOVER_RECIPIENT` * `DIUN_NOTIF_PUSHOVER_RECIPIENTFILE` + * `DIUN_NOTIF_PUSHOVER_TEMPLATETITLE` + * `DIUN_NOTIF_PUSHOVER_TEMPLATEBODY` + +### Default `templateTitle` + +``` +[[ config.extra.template.defaultTitle ]] +``` + +### Default `templateBody` + +``` +[[ config.extra.template.defaultBody ]] +``` ## Sample diff --git a/docs/notif/rocketchat.md b/docs/notif/rocketchat.md index 5fd44baf..591d3908 100644 --- a/docs/notif/rocketchat.md +++ b/docs/notif/rocketchat.md @@ -13,16 +13,21 @@ Allow to send notifications to your Rocket.Chat channel. userID: abcdEFGH012345678 token: Token123456 timeout: 10s + templateTitle: "{{ .Entry.Image }} released" + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| Name | Default | Description | -|--------------------|---------------|---------------| -| `endpoint`[^1] | | Rocket.Chat base URL | -| `channel`[^1] | | Channel name with the prefix in front of it | -| `userID`[^1] | | User ID | -| `token` | | Authentication token | -| `tokenFile` | | Use content of secret file as authentication token if `token` not defined | -| `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +| Name | Default | Description | +|---------------------|--------------------------------------------|---------------| +| `endpoint`[^1] | | Rocket.Chat base URL | +| `channel`[^1] | | Channel name with the prefix in front of it | +| `userID`[^1] | | User ID | +| `token` | | Authentication token | +| `tokenFile` | | Use content of secret file as authentication token if `token` not defined | +| `timeout` | `10s` | Timeout specifies a time limit for the request to be made | +| `templateTitle`[^1] | See [below](#default-templatetitle) | [Notification template](../faq.md#notification-template) for message title | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! warning You must first create a _Personal Access Token_ through your account settings on your Rocket.Chat instance. @@ -34,6 +39,20 @@ Allow to send notifications to your Rocket.Chat channel. * `DIUN_NOTIF_ROCKETCHAT_TOKEN` * `DIUN_NOTIF_ROCKETCHAT_TOKENFILE` * `DIUN_NOTIF_ROCKETCHAT_TIMEOUT` + * `DIUN_NOTIF_ROCKETCHAT_TEMPLATETITLE` + * `DIUN_NOTIF_ROCKETCHAT_TEMPLATEBODY` + +### Default `templateTitle` + +``` +[[ config.extra.template.defaultTitle ]] +``` + +### Default `templateBody` + +``` +Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} on {{ .Meta.Hostname }}. +``` ## Sample diff --git a/docs/notif/slack.md b/docs/notif/slack.md index c8513c59..f76fdabc 100644 --- a/docs/notif/slack.md +++ b/docs/notif/slack.md @@ -12,14 +12,24 @@ You can send notifications to your Slack channel using an [incoming webhook URL] notif: slack: webhookURL: https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| Name | Default | Description | -|--------------------|---------------|---------------| -| `webhookURL`[^1] | | Slack [incoming webhook URL](https://api.slack.com/messaging/webhooks) | +| Name | Default | Description | +|--------------------|--------------------------------------------|---------------| +| `webhookURL`[^1] | | Slack [incoming webhook URL](https://api.slack.com/messaging/webhooks) | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_SLACK_WEBHOOKURL` + * `DIUN_NOTIF_SLACK_TEMPLATEBODY` + +### Default `templateBody` + +``` + Docker tag `{{ .Entry.Image }}` {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. +``` ## Sample diff --git a/docs/notif/teams.md b/docs/notif/teams.md index 9c418e76..089c473c 100644 --- a/docs/notif/teams.md +++ b/docs/notif/teams.md @@ -9,14 +9,24 @@ You can send notifications to your Teams team-channel using an [incoming webhook notif: teams: webhookURL: https://outlook.office.com/webhook/ABCD12EFG/HIJK34LMN/01234567890abcdefghij + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| 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) | +| 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) | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_TEAMS_WEBHOOKURL` + * `DIUN_NOTIF_TEAMS_TEMPLATEBODY` + +### Default `templateBody` + +``` +Docker tag {{ if .Entry.Image.HubLink }}[`{{ .Entry.Image }}`]({{ .Entry.Image.HubLink }}){{ else }}`{{ .Entry.Image }}`{{ end }}{{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. +``` ## Sample diff --git a/docs/notif/telegram.md b/docs/notif/telegram.md index 46f49e56..c68cbda9 100644 --- a/docs/notif/telegram.md +++ b/docs/notif/telegram.md @@ -17,24 +17,37 @@ Multiple chat IDs can be provided in order to deliver notifications to multiple chatIDs: - 123456789 - 987654321 + templateBody: | + Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been released. ``` -| Name | Default | Description | -|--------------------|---------------|---------------| -| `token` | | Telegram bot token | -| `tokenFile` | | Use content of secret file as Telegram bot token if `token` not defined | -| `chatIDs` | | List of chat IDs to send notifications to | -| `chatIDsFile` | | Use content of secret file as chat IDs if `chatIDs` not defined | +| Name | Default | Description | +|--------------------|--------------------------------------------|---------------| +| `token` | | Telegram bot token | +| `tokenFile` | | Use content of secret file as Telegram bot token if `token` not defined | +| `chatIDs` | | List of chat IDs to send notifications to | +| `chatIDsFile` | | Use content of secret file as chat IDs if `chatIDs` not defined | +| `templateBody`[^1] | See [below](#default-templatebody) | [Notification template](../faq.md#notification-template) for message body | !!! abstract "Environment variables" * `DIUN_NOTIF_TELEGRAM_TOKEN` * `DIUN_NOTIF_TELEGRAM_TOKENFILE` * `DIUN_NOTIF_TELEGRAM_CHATIDS` (comma separated) * `DIUN_NOTIF_TELEGRAM_CHATIDSFILE` + * `DIUN_NOTIF_TELEGRAM_TEMPLATEBODY` !!! example "chat IDs secret file" Chat IDs secret file must be a valid JSON array like: `[123456789,987654321]` +### Default `templateBody` + +``` +Docker tag {{ if .Entry.Image.HubLink }}[{{ .Entry.Image }}]({{ .Entry.Image.HubLink }}){{ else }}{{ .Entry.Image }}{{ end }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} on {{ escapeMarkdown .Meta.Hostname }}. +``` + +!!! note + `escapeMarkdown` is a special function to deal with a [makrdown strict parsing issue](https://github.com/crazy-max/diun/issues/162#issuecomment-683095898) on Telegram server. + ## Sample ![](../assets/notif/telegram.png) diff --git a/docs/reporting-issue.md b/docs/reporting-issue.md index 3764fdce..4265a2a8 100644 --- a/docs/reporting-issue.md +++ b/docs/reporting-issue.md @@ -4,7 +4,7 @@ First, [be a good guy](https://github.com/kossnocorp/etiquette/blob/master/README.md). -Please do a search in [open issues]({{ config.repo_url }}issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed and read the [FAQ](faq.md) page first. +Please do a search in [open issues]([[ config.repo_url ]]issues?utf8=%E2%9C%93&q=) to see if the issue or feature request has already been filed and read the [FAQ](faq.md) page first. If you find your issue already exists, make relevant comments and add your [reaction](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments). Use a reaction in place of a "+1" comment. @@ -23,7 +23,7 @@ File a single issue per problem and feature request. The more information you can provide, the more likely someone will be successful reproducing the issue and finding a fix. -You are now ready to [create a new issue]({{ config.repo_url }}issues/new/choose)! +You are now ready to [create a new issue]([[ config.repo_url ]]issues/new/choose)! ## Closure policy diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 3314ea29..66a9b371 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -76,13 +76,17 @@ func TestLoadFile(t *testing.T) { "<@125>", "<@&200>", }, - Timeout: utl.NewDuration(10 * time.Second), + Timeout: utl.NewDuration(10 * time.Second), + TemplateTitle: model.NotifDefaultTemplateTitle, + TemplateBody: model.NotifDefaultTemplateBody, }, Gotify: &model.NotifGotify{ - Endpoint: "http://gotify.foo.com", - Token: "Token123456", - Priority: 1, - Timeout: utl.NewDuration(10 * time.Second), + Endpoint: "http://gotify.foo.com", + Token: "Token123456", + Priority: 1, + Timeout: utl.NewDuration(10 * time.Second), + TemplateTitle: model.NotifDefaultTemplateTitle, + TemplateBody: model.NotifDefaultTemplateBody, }, Mail: &model.NotifMail{ Host: "localhost", @@ -92,6 +96,14 @@ func TestLoadFile(t *testing.T) { LocalName: "localhost", From: "diun@example.com", To: "webmaster@example.com", + TemplateTitle: model.NotifDefaultTemplateTitle, + TemplateBody: `Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} +which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. + +This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at +{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} +for {{ .Entry.Manifest.Platform }} platform. +`, }, Matrix: &model.NotifMatrix{ HomeserverURL: "https://matrix.org", @@ -99,6 +111,7 @@ func TestLoadFile(t *testing.T) { Password: "bar", RoomID: "!abcdefGHIjklmno:matrix.org", MsgType: model.NotifMatrixMsgTypeNotice, + TemplateBody: model.NotifDefaultTemplateBody, }, Mqtt: &model.NotifMqtt{ Scheme: "mqtt", @@ -111,15 +124,19 @@ func TestLoadFile(t *testing.T) { QoS: 0, }, Pushover: &model.NotifPushover{ - Token: "uQiRzpo4DXghDmr9QzzfQu27cmVRsG", - Recipient: "gznej3rKEVAvPUxu9vvNnqpmZpokzF", + Token: "uQiRzpo4DXghDmr9QzzfQu27cmVRsG", + Recipient: "gznej3rKEVAvPUxu9vvNnqpmZpokzF", + TemplateTitle: model.NotifDefaultTemplateTitle, + TemplateBody: model.NotifDefaultTemplateBody, }, RocketChat: &model.NotifRocketChat{ - Endpoint: "http://rocket.foo.com:3000", - Channel: "#general", - UserID: "abcdEFGH012345678", - Token: "Token123456", - Timeout: utl.NewDuration(10 * time.Second), + Endpoint: "http://rocket.foo.com:3000", + Channel: "#general", + UserID: "abcdEFGH012345678", + Token: "Token123456", + Timeout: utl.NewDuration(10 * time.Second), + TemplateTitle: model.NotifDefaultTemplateTitle, + TemplateBody: model.NotifRocketChatDefaultTemplateBody, }, Script: &model.NotifScript{ Cmd: "uname", @@ -128,14 +145,17 @@ func TestLoadFile(t *testing.T) { }, }, Slack: &model.NotifSlack{ - WebhookURL: "https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij", + WebhookURL: "https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij", + TemplateBody: model.NotifSlackDefaultTemplateBody, }, Teams: &model.NotifTeams{ - WebhookURL: "https://outlook.office.com/webhook/ABCD12EFG/HIJK34LMN/01234567890abcdefghij", + WebhookURL: "https://outlook.office.com/webhook/ABCD12EFG/HIJK34LMN/01234567890abcdefghij", + TemplateBody: model.NotifTeamsDefaultTemplateBody, }, Telegram: &model.NotifTelegram{ - Token: "abcdef123456", - ChatIDs: []int64{8547439, 1234567}, + Token: "abcdef123456", + ChatIDs: []int64{8547439, 1234567}, + TemplateBody: model.NotifTelegramDefaultTemplateBody, }, Webhook: &model.NotifWebhook{ Endpoint: "http://webhook.foo.com/sd54qad89azd5a", @@ -291,8 +311,9 @@ func TestLoadEnv(t *testing.T) { Watch: (&model.Watch{}).GetDefaults(), Notif: &model.Notif{ Telegram: &model.NotifTelegram{ - Token: "abcdef123456", - ChatIDs: []int64{8547439, 1234567}, + Token: "abcdef123456", + ChatIDs: []int64{8547439, 1234567}, + TemplateBody: model.NotifTelegramDefaultTemplateBody, }, }, Providers: &model.Providers{ @@ -398,6 +419,14 @@ func TestLoadMixed(t *testing.T) { LocalName: "foo.com", From: "diun@foo.com", To: "webmaster@foo.com", + TemplateTitle: model.NotifDefaultTemplateTitle, + TemplateBody: `Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} +which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. + +This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at +{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} +for {{ .Entry.Manifest.Platform }} platform. +`, }, }, RegOpts: nil, diff --git a/internal/config/fixtures/config.docker.yml b/internal/config/fixtures/config.docker.yml index 6922649a..633f2947 100644 --- a/internal/config/fixtures/config.docker.yml +++ b/internal/config/fixtures/config.docker.yml @@ -6,6 +6,13 @@ notif: insecureSkipVerify: false from: diun@example.com to: webmaster@example.com + templateBody: | + Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} + which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. + + This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at + {{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} + for {{ .Entry.Manifest.Platform }} platform. providers: docker: {} diff --git a/internal/config/fixtures/config.test.yml b/internal/config/fixtures/config.test.yml index 17fb777b..092a6848 100644 --- a/internal/config/fixtures/config.test.yml +++ b/internal/config/fixtures/config.test.yml @@ -38,6 +38,13 @@ notif: insecureSkipVerify: false from: diun@example.com to: webmaster@example.com + templateBody: | + Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} + which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. + + This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at + {{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} + for {{ .Entry.Manifest.Platform }} platform. matrix: homeserverURL: https://matrix.org user: "@foo:matrix.org" diff --git a/internal/config/fixtures/config.validate.yml b/internal/config/fixtures/config.validate.yml index c631d0b9..f7bbe2b5 100644 --- a/internal/config/fixtures/config.validate.yml +++ b/internal/config/fixtures/config.validate.yml @@ -38,6 +38,13 @@ notif: insecureSkipVerify: false from: diun@example.com to: webmaster@example.com + templateBody: | + Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} + which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}. + + This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at + {{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} + for {{ .Entry.Manifest.Platform }} platform. matrix: homeserverURL: https://matrix.org user: "@foo:matrix.org" diff --git a/internal/model/notif.go b/internal/model/notif.go index d8c7a705..f2ec4dfd 100644 --- a/internal/model/notif.go +++ b/internal/model/notif.go @@ -4,6 +4,12 @@ import ( "github.com/crazy-max/diun/v4/pkg/registry" ) +// Defaults used for notification template +const ( + NotifDefaultTemplateTitle = `{{ if (eq .Entry.Status "new") }}New image {{ .Entry.Image }} has been added{{ else }}Image update for {{ .Entry.Image }}{{ end }}` + NotifDefaultTemplateBody = `Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} on {{ .Meta.Hostname }}.` +) + // NotifEntries represents a list of notification entries type NotifEntries struct { Entries []NotifEntry diff --git a/internal/model/notif_discord.go b/internal/model/notif_discord.go index f3a395d7..b2e18dfd 100644 --- a/internal/model/notif_discord.go +++ b/internal/model/notif_discord.go @@ -8,9 +8,11 @@ import ( // NotifDiscord holds Discord notification configuration details type NotifDiscord struct { - WebhookURL string `yaml:"webhookURL,omitempty" json:"webhookURL,omitempty" validate:"required"` - Mentions []string `yaml:"mentions,omitempty" json:"mentions,omitempty"` - Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"` + WebhookURL string `yaml:"webhookURL,omitempty" json:"webhookURL,omitempty" validate:"required"` + Mentions []string `yaml:"mentions,omitempty" json:"mentions,omitempty"` + Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"` + TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values @@ -23,4 +25,6 @@ func (s *NotifDiscord) GetDefaults() *NotifDiscord { // SetDefaults sets the default values func (s *NotifDiscord) SetDefaults() { s.Timeout = utl.NewDuration(10 * time.Second) + s.TemplateTitle = NotifDefaultTemplateTitle + s.TemplateBody = NotifDefaultTemplateBody } diff --git a/internal/model/notif_gotify.go b/internal/model/notif_gotify.go index cb28ddaf..19bc7481 100644 --- a/internal/model/notif_gotify.go +++ b/internal/model/notif_gotify.go @@ -8,11 +8,13 @@ import ( // NotifGotify holds gotify notification configuration details type NotifGotify struct { - Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty" validate:"required"` - Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` - TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` - Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=0"` - Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"` + Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty" validate:"required"` + Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` + TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` + Priority int `yaml:"priority,omitempty" json:"priority,omitempty" validate:"omitempty,min=0"` + Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"` + TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values @@ -26,4 +28,6 @@ func (s *NotifGotify) GetDefaults() *NotifGotify { func (s *NotifGotify) SetDefaults() { s.Priority = 1 s.Timeout = utl.NewDuration(10 * time.Second) + s.TemplateTitle = NotifDefaultTemplateTitle + s.TemplateBody = NotifDefaultTemplateBody } diff --git a/internal/model/notif_mail.go b/internal/model/notif_mail.go index 72e61803..4447afaf 100644 --- a/internal/model/notif_mail.go +++ b/internal/model/notif_mail.go @@ -4,6 +4,17 @@ import ( "github.com/crazy-max/diun/v4/pkg/utl" ) +// NotifMailDefaultTemplateBody ... +const NotifMailDefaultTemplateBody = `Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} +which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} +on {{ .Meta.Hostname }}. + +This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at +{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} +for {{ .Entry.Manifest.Platform }} platform. + +Need help, or have questions? Go to {{ .Meta.URL }} and leave an issue.` + // NotifMail holds mail notification configuration details type NotifMail struct { Host string `yaml:"host,omitempty" json:"host,omitempty" validate:"required"` @@ -17,6 +28,8 @@ type NotifMail struct { PasswordFile string `yaml:"passwordFile,omitempty" json:"passwordFile,omitempty" validate:"omitempty,file"` From string `yaml:"from,omitempty" json:"from,omitempty" validate:"required,email"` To string `yaml:"to,omitempty" json:"to,omitempty" validate:"required,email"` + TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values @@ -33,4 +46,6 @@ func (s *NotifMail) SetDefaults() { s.SSL = utl.NewFalse() s.InsecureSkipVerify = utl.NewFalse() s.LocalName = "localhost" + s.TemplateTitle = NotifDefaultTemplateTitle + s.TemplateBody = NotifMailDefaultTemplateBody } diff --git a/internal/model/notif_matrix.go b/internal/model/notif_matrix.go index 5357aa63..9fe935a1 100644 --- a/internal/model/notif_matrix.go +++ b/internal/model/notif_matrix.go @@ -9,6 +9,7 @@ type NotifMatrix struct { PasswordFile string `yaml:"passwordFile,omitempty" json:"passwordFile,omitempty" validate:"omitempty,file"` RoomID string `yaml:"roomID,omitempty" json:"roomID,omitempty" validate:"required"` MsgType NotifMatrixMsgType `yaml:"msgType,omitempty" json:"msgType,omitempty" validate:"required,oneof=notice text"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // NotifMatrix message type constants @@ -31,4 +32,5 @@ func (s *NotifMatrix) GetDefaults() *NotifMatrix { func (s *NotifMatrix) SetDefaults() { s.HomeserverURL = "https://matrix.org" s.MsgType = NotifMatrixMsgTypeNotice + s.TemplateBody = NotifDefaultTemplateBody } diff --git a/internal/model/notif_pushover.go b/internal/model/notif_pushover.go index 5b496966..df709fba 100644 --- a/internal/model/notif_pushover.go +++ b/internal/model/notif_pushover.go @@ -7,14 +7,19 @@ type NotifPushover struct { 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"` + TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values func (s *NotifPushover) GetDefaults() *NotifPushover { - return nil + n := &NotifPushover{} + n.SetDefaults() + return n } // SetDefaults sets the default values func (s *NotifPushover) SetDefaults() { - // noop + s.TemplateTitle = NotifDefaultTemplateTitle + s.TemplateBody = NotifDefaultTemplateBody } diff --git a/internal/model/notif_rocketchat.go b/internal/model/notif_rocketchat.go index 71e7ee3c..36c7dc41 100644 --- a/internal/model/notif_rocketchat.go +++ b/internal/model/notif_rocketchat.go @@ -6,14 +6,19 @@ import ( "github.com/crazy-max/diun/v4/pkg/utl" ) +// NotifRocketChatDefaultTemplateBody ... +const NotifRocketChatDefaultTemplateBody = `Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} on {{ .Meta.Hostname }}.` + // NotifRocketChat holds Rocket.Chat notification configuration details type NotifRocketChat struct { - Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty" validate:"required"` - Channel string `yaml:"channel,omitempty" json:"channel,omitempty" validate:"required"` - UserID string `yaml:"userID,omitempty" json:"userID,omitempty" validate:"required"` - Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` - TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` - Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"` + Endpoint string `yaml:"endpoint,omitempty" json:"endpoint,omitempty" validate:"required"` + Channel string `yaml:"channel,omitempty" json:"channel,omitempty" validate:"required"` + UserID string `yaml:"userID,omitempty" json:"userID,omitempty" validate:"required"` + Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` + TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` + Timeout *time.Duration `yaml:"timeout,omitempty" json:"timeout,omitempty" validate:"required"` + TemplateTitle string `yaml:"templateTitle,omitempty" json:"templateTitle,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values @@ -26,4 +31,6 @@ func (s *NotifRocketChat) GetDefaults() *NotifRocketChat { // SetDefaults sets the default values func (s *NotifRocketChat) SetDefaults() { s.Timeout = utl.NewDuration(10 * time.Second) + s.TemplateTitle = NotifDefaultTemplateTitle + s.TemplateBody = NotifRocketChatDefaultTemplateBody } diff --git a/internal/model/notif_slack.go b/internal/model/notif_slack.go index 4d2dd68a..fa998684 100644 --- a/internal/model/notif_slack.go +++ b/internal/model/notif_slack.go @@ -1,16 +1,22 @@ package model +// NotifSlackDefaultTemplateBody ... +const NotifSlackDefaultTemplateBody = " Docker tag `{{ .Entry.Image }}` {{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }}." + // NotifSlack holds slack notification configuration details type NotifSlack struct { - WebhookURL string `yaml:"webhookURL,omitempty" json:"webhookURL,omitempty" validate:"required"` + WebhookURL string `yaml:"webhookURL,omitempty" json:"webhookURL,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values func (s *NotifSlack) GetDefaults() *NotifSlack { - return nil + n := &NotifSlack{} + n.SetDefaults() + return n } // SetDefaults sets the default values func (s *NotifSlack) SetDefaults() { - // noop + s.TemplateBody = NotifSlackDefaultTemplateBody } diff --git a/internal/model/notif_teams.go b/internal/model/notif_teams.go index e2245308..81d93577 100644 --- a/internal/model/notif_teams.go +++ b/internal/model/notif_teams.go @@ -1,16 +1,22 @@ package model +// NotifTeamsDefaultTemplateBody ... +const NotifTeamsDefaultTemplateBody = "Docker tag {{ if .Entry.Image.HubLink }}[`{{ .Entry.Image }}`]({{ .Entry.Image.HubLink }}){{ else }}`{{ .Entry.Image }}`{{ end }}{{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }}." + // NotifTeams holds Teams notification configuration details type NotifTeams struct { - WebhookURL string `yaml:"webhookURL,omitempty" json:"webhookURL,omitempty" validate:"required"` + WebhookURL string `yaml:"webhookURL,omitempty" json:"webhookURL,omitempty" validate:"required"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values func (s *NotifTeams) GetDefaults() *NotifTeams { - return nil + n := &NotifTeams{} + n.SetDefaults() + return n } // SetDefaults sets the default values func (s *NotifTeams) SetDefaults() { - // noop + s.TemplateBody = NotifTeamsDefaultTemplateBody } diff --git a/internal/model/notif_telegram.go b/internal/model/notif_telegram.go index 42fc7bf4..8ddf1a08 100644 --- a/internal/model/notif_telegram.go +++ b/internal/model/notif_telegram.go @@ -1,19 +1,25 @@ package model +// NotifTelegramDefaultTemplateBody ... +const NotifTelegramDefaultTemplateBody = `Docker tag {{ if .Entry.Image.HubLink }}[{{ .Entry.Image }}]({{ .Entry.Image.HubLink }}){{ else }}{{ .Entry.Image }}{{ end }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} on {{ escapeMarkdown .Meta.Hostname }}.` + // NotifTelegram holds Telegram notification configuration details type NotifTelegram struct { - Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` - TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` - ChatIDs []int64 `yaml:"chatIDs,omitempty" json:"chatIDs,omitempty" validate:"omitempty"` - ChatIDsFile string `yaml:"chatIDsFile,omitempty" json:"chatIDsFile,omitempty" validate:"omitempty,file"` + Token string `yaml:"token,omitempty" json:"token,omitempty" validate:"omitempty"` + TokenFile string `yaml:"tokenFile,omitempty" json:"tokenFile,omitempty" validate:"omitempty,file"` + ChatIDs []int64 `yaml:"chatIDs,omitempty" json:"chatIDs,omitempty" validate:"omitempty"` + ChatIDsFile string `yaml:"chatIDsFile,omitempty" json:"chatIDsFile,omitempty" validate:"omitempty,file"` + TemplateBody string `yaml:"templateBody,omitempty" json:"templateBody,omitempty" validate:"required"` } // GetDefaults gets the default values func (s *NotifTelegram) GetDefaults() *NotifTelegram { - return nil + n := &NotifTelegram{} + n.SetDefaults() + return n } // SetDefaults sets the default values func (s *NotifTelegram) SetDefaults() { - // noop + s.TemplateBody = NotifTelegramDefaultTemplateBody } diff --git a/internal/msg/client.go b/internal/msg/client.go index af6e353b..76e33249 100644 --- a/internal/msg/client.go +++ b/internal/msg/client.go @@ -11,6 +11,7 @@ import ( "github.com/crazy-max/diun/v4/internal/model" "github.com/microcosm-cc/bluemonday" "github.com/opencontainers/go-digest" + "github.com/pkg/errors" "github.com/russross/blackfriday/v2" ) @@ -21,15 +22,13 @@ type Client struct { // Options holds msg client object options type Options struct { - Meta model.Meta - Entry model.NotifEntry - TplFuncs template.FuncMap + Meta model.Meta + Entry model.NotifEntry + TemplateTitle string + TemplateBody string + TemplateFuncs template.FuncMap } -const defaultTpl = `Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} -which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} -on {{ .Meta.Hostname }}.` - // New initializes a new msg client func New(opts Options) (*Client, error) { return &Client{ @@ -38,47 +37,49 @@ func New(opts Options) (*Client, error) { } // RenderMarkdown returns a notification message as markdown -func (c *Client) RenderMarkdown() (title string, text []byte, err error) { - return c.RenderMarkdownTemplate(strings.ReplaceAll(defaultTpl, "\n", " ")) -} - -// RenderMarkdownTemplate returns a notification message as markdown with a custom template -func (c *Client) RenderMarkdownTemplate(tpl string) (title string, text []byte, err error) { - title = fmt.Sprintf("Image update for %s", c.opts.Entry.Image.String()) - if c.opts.Entry.Status == model.ImageStatusNew { - title = fmt.Sprintf("New image %s has been added", c.opts.Entry.Image.String()) - } - - var msgBuf bytes.Buffer - msgTpl := template.Must(template.New("notif").Funcs(c.opts.TplFuncs).Parse(tpl)) - err = msgTpl.Execute(&msgBuf, struct { +func (c *Client) RenderMarkdown() (title []byte, body []byte, err error) { + var titleBuf bytes.Buffer + titleTpl := template.Must(template.New("title").Funcs(c.opts.TemplateFuncs).Parse(strings.TrimSuffix(strings.TrimSpace(c.opts.TemplateTitle), "\n"))) + err = titleTpl.Execute(&titleBuf, struct { Meta model.Meta Entry model.NotifEntry }{ Meta: c.opts.Meta, Entry: c.opts.Entry, }) + if err != nil { + return title, body, errors.Wrap(err, "Cannot render notif title") + } + title = titleBuf.Bytes() + + var bodyBuf bytes.Buffer + bodyTpl := template.Must(template.New("body").Funcs(c.opts.TemplateFuncs).Parse(strings.TrimSuffix(strings.TrimSpace(c.opts.TemplateBody), "\n"))) + err = bodyTpl.Execute(&bodyBuf, struct { + Meta model.Meta + Entry model.NotifEntry + }{ + Meta: c.opts.Meta, + Entry: c.opts.Entry, + }) + if err != nil { + return title, body, errors.Wrap(err, "Cannot render notif body") + } + body = bodyBuf.Bytes() - text = msgBuf.Bytes() return } // RenderHTML returns a notification message as html -func (c *Client) RenderHTML() (title string, text []byte, err error) { - return c.RenderHTMLTemplate(strings.ReplaceAll(defaultTpl, "\n", " ")) -} - -// RenderHTMLTemplate returns a notification message as html with a custom template -func (c *Client) RenderHTMLTemplate(tpl string) (title string, text []byte, err error) { - title, text, err = c.RenderMarkdownTemplate(tpl) +func (c *Client) RenderHTML() (title []byte, body []byte, err error) { + title, body, err = c.RenderMarkdown() if err != nil { - return + return title, body, err } - text = []byte(bluemonday.UGCPolicy().Sanitize( + body = []byte(bluemonday.UGCPolicy().Sanitize( // Dirty way to remove wrapped

and newline // https://github.com/russross/blackfriday/issues/237 - strings.TrimRight(strings.TrimLeft(strings.TrimSpace(string(blackfriday.Run(text))), "

"), "

"), + strings.TrimRight(strings.TrimLeft(strings.TrimSpace(string(blackfriday.Run(body))), "

"), "

"), )) return } diff --git a/internal/notif/discord/client.go b/internal/notif/discord/client.go index b7bb4fa0..0e777d77 100644 --- a/internal/notif/discord/client.go +++ b/internal/notif/discord/client.go @@ -45,14 +45,16 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateTitle: c.cfg.TemplateTitle, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - title, text, err := message.RenderMarkdown() + title, body, err := message.RenderMarkdown() if err != nil { return err } @@ -62,7 +64,7 @@ func (c *Client) Send(entry model.NotifEntry) error { content.WriteString(fmt.Sprintf("%s ", mention)) } } - content.WriteString(title) + content.WriteString(string(title)) fields := []EmbedField{ { @@ -100,7 +102,7 @@ func (c *Client) Send(entry model.NotifEntry) error { AvatarURL: c.meta.Logo, Embeds: []Embed{ { - Description: string(text), + Description: string(body), Footer: EmbedFooter{ Text: fmt.Sprintf("%s © %d %s %s", c.meta.Author, time.Now().Year(), c.meta.Name, c.meta.Version), IconURL: c.meta.Logo, diff --git a/internal/notif/gotify/client.go b/internal/notif/gotify/client.go index 71717c11..46114123 100644 --- a/internal/notif/gotify/client.go +++ b/internal/notif/gotify/client.go @@ -50,26 +50,28 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateTitle: c.cfg.TemplateTitle, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - title, text, err := message.RenderMarkdown() + title, body, err := message.RenderMarkdown() if err != nil { return err } - body, err := json.Marshal(struct { + jsonBody, err := json.Marshal(struct { Message string `json:"message"` Title string `json:"title"` Priority int `json:"priority"` Extras map[string]interface{} `json:"extras"` }{ - Message: string(text), - Title: title, + Message: string(body), + Title: string(title), Priority: c.cfg.Priority, Extras: map[string]interface{}{ "client::display": map[string]string{ @@ -91,13 +93,13 @@ func (c *Client) Send(entry model.NotifEntry) error { q.Set("token", token) u.RawQuery = q.Encode() - req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(body)) + req, err := http.NewRequest("POST", u.String(), bytes.NewBuffer(jsonBody)) if err != nil { return err } req.Header.Set("Content-Type", "application/json") - req.Header.Add("Content-Length", strconv.Itoa(len(string(body)))) + req.Header.Add("Content-Length", strconv.Itoa(len(string(jsonBody)))) req.Header.Set("User-Agent", c.meta.UserAgent) resp, err := hc.Do(req) diff --git a/internal/notif/mail/client.go b/internal/notif/mail/client.go index 506d8b49..332acd38 100644 --- a/internal/notif/mail/client.go +++ b/internal/notif/mail/client.go @@ -21,16 +21,6 @@ type Client struct { meta model.Meta } -const customTpl = `Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} -which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} -on {{ .Meta.Hostname }}. - -This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at -{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Entry.Manifest.Digest }} -for {{ .Entry.Manifest.Platform }} platform. - -Need help, or have questions? Go to {{ .Meta.URL }} and leave an issue.` - // New creates a new mail notification instance func New(config *model.NotifMail, meta model.Meta) notifier.Notifier { return notifier.Notifier{ @@ -63,14 +53,16 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateTitle: c.cfg.TemplateTitle, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - title, text, err := message.RenderMarkdownTemplate(customTpl) + title, body, err := message.RenderMarkdown() if err != nil { return err } @@ -78,7 +70,7 @@ func (c *Client) Send(entry model.NotifEntry) error { email := hermes.Email{ Body: hermes.Body{ Title: fmt.Sprintf("%s 🔔 notification", c.meta.Name), - FreeMarkdown: hermes.Markdown(text), + FreeMarkdown: hermes.Markdown(body), Signature: "Thanks for your support!", }, } @@ -95,12 +87,12 @@ func (c *Client) Send(entry model.NotifEntry) error { return fmt.Errorf("hermes: %v", err) } - msg := gomail.NewMessage() - msg.SetHeader("From", fmt.Sprintf("%s <%s>", c.meta.Name, c.cfg.From)) - msg.SetHeader("To", c.cfg.To) - msg.SetHeader("Subject", title) - msg.SetBody("text/plain", textpart) - msg.AddAlternative("text/html", htmlpart) + mailMessage := gomail.NewMessage() + mailMessage.SetHeader("From", fmt.Sprintf("%s <%s>", c.meta.Name, c.cfg.From)) + mailMessage.SetHeader("To", c.cfg.To) + mailMessage.SetHeader("Subject", string(title)) + mailMessage.SetBody("text/plain", textpart) + mailMessage.AddAlternative("text/html", htmlpart) var tlsConfig *tls.Config if *c.cfg.InsecureSkipVerify { @@ -128,5 +120,5 @@ func (c *Client) Send(entry model.NotifEntry) error { LocalName: c.cfg.LocalName, } - return dialer.DialAndSend(msg) + return dialer.DialAndSend(mailMessage) } diff --git a/internal/notif/matrix/client.go b/internal/notif/matrix/client.go index b11c54e0..9f121de1 100644 --- a/internal/notif/matrix/client.go +++ b/internal/notif/matrix/client.go @@ -72,8 +72,9 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err diff --git a/internal/notif/mqtt/client.go b/internal/notif/mqtt/client.go index 1257f346..d3b55a76 100644 --- a/internal/notif/mqtt/client.go +++ b/internal/notif/mqtt/client.go @@ -8,8 +8,6 @@ import ( "github.com/crazy-max/diun/v4/internal/notif/notifier" "github.com/crazy-max/diun/v4/pkg/utl" MQTT "github.com/eclipse/paho.mqtt.golang" - "github.com/rs/zerolog" - "github.com/rs/zerolog/log" ) // Client represents an active mqtt notification object @@ -17,7 +15,6 @@ type Client struct { *notifier.Notifier cfg *model.NotifMqtt meta model.Meta - logger zerolog.Logger mqttClient MQTT.Client } @@ -25,9 +22,8 @@ type Client struct { func New(config *model.NotifMqtt, meta model.Meta) notifier.Notifier { return notifier.Notifier{ Handler: &Client{ - cfg: config, - meta: meta, - logger: log.With().Str("notif", "mqtt").Logger(), + cfg: config, + meta: meta, }, } } diff --git a/internal/notif/pushover/client.go b/internal/notif/pushover/client.go index 16f55285..dd871bcf 100644 --- a/internal/notif/pushover/client.go +++ b/internal/notif/pushover/client.go @@ -46,21 +46,23 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateTitle: c.cfg.TemplateTitle, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - title, text, err := message.RenderHTML() + title, body, err := message.RenderHTML() if err != nil { return err } _, err = pushover.New(token).SendMessage(&pushover.Message{ - Message: string(text), - Title: title, + Title: string(title), + Message: string(body), Priority: c.cfg.Priority, URL: c.meta.URL, URLTitle: c.meta.Name, diff --git a/internal/notif/rocketchat/client.go b/internal/notif/rocketchat/client.go index 8b3f852c..d7beb63a 100644 --- a/internal/notif/rocketchat/client.go +++ b/internal/notif/rocketchat/client.go @@ -24,8 +24,6 @@ type Client struct { meta model.Meta } -const customTpl = `Docker tag {{ .Entry.Image }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} on {{ .Meta.Hostname }}.` - // New creates a new rocketchat notification instance func New(config *model.NotifRocketChat, meta model.Meta) notifier.Notifier { return notifier.Notifier{ @@ -54,14 +52,16 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateTitle: c.cfg.TemplateTitle, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - title, text, err := message.RenderMarkdownTemplate(customTpl) + title, body, err := message.RenderMarkdown() if err != nil { return err } @@ -106,10 +106,10 @@ func (c *Client) Send(entry model.NotifEntry) error { Alias: c.meta.Name, Avatar: c.meta.Logo, Channel: c.cfg.Channel, - Text: title, + Text: string(title), Attachments: []Attachment{ { - Text: string(text), + Text: string(body), Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), Fields: fields, }, diff --git a/internal/notif/slack/client.go b/internal/notif/slack/client.go index ac1e076c..7fcd1a17 100644 --- a/internal/notif/slack/client.go +++ b/internal/notif/slack/client.go @@ -19,8 +19,6 @@ type Client struct { meta model.Meta } -const customTpl = " Docker tag `{{ .Entry.Image }}` {{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }}." - // New creates a new slack notification instance func New(config *model.NotifSlack, meta model.Meta) notifier.Notifier { return notifier.Notifier{ @@ -39,14 +37,15 @@ func (c *Client) Name() string { // Send creates and sends a slack notification with an entry func (c *Client) Send(entry model.NotifEntry) error { message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - _, text, err := message.RenderMarkdownTemplate(customTpl) + _, body, err := message.RenderMarkdown() if err != nil { return err } @@ -99,7 +98,7 @@ func (c *Client) Send(entry model.NotifEntry) error { AuthorSubname: "github.com/crazy-max/diun", AuthorLink: c.meta.URL, AuthorIcon: c.meta.Logo, - Text: string(text), + Text: string(body), Footer: fmt.Sprintf("%s © %d %s %s", c.meta.Author, time.Now().Year(), c.meta.Name, c.meta.Version), Fields: fields, Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)), diff --git a/internal/notif/teams/client.go b/internal/notif/teams/client.go index 379438dd..a25fb53b 100644 --- a/internal/notif/teams/client.go +++ b/internal/notif/teams/client.go @@ -18,9 +18,6 @@ type Client struct { meta model.Meta } -const customTpl = "Docker tag {{ if .Entry.Image.HubLink }}[`{{ .Entry.Image }}`]({{ .Entry.Image.HubLink }}){{ else }}`{{ .Entry.Image }}`{{ end }}" + - "{{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }}." - // New creates a new webhook notification instance func New(config *model.NotifTeams, meta model.Meta) notifier.Notifier { return notifier.Notifier{ @@ -56,14 +53,15 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, + Meta: c.meta, + Entry: entry, + TemplateBody: c.cfg.TemplateBody, }) if err != nil { return err } - _, text, err := message.RenderMarkdownTemplate(customTpl) + _, body, err := message.RenderMarkdown() if err != nil { return err } @@ -73,7 +71,7 @@ func (c *Client) Send(entry model.NotifEntry) error { themeColor = "0076D7" } - body, err := json.Marshal(struct { + jsonBody, err := json.Marshal(struct { Type string `json:"@type"` Context string `json:"@context"` ThemeColor string `json:"themeColor"` @@ -81,11 +79,11 @@ func (c *Client) Send(entry model.NotifEntry) error { Sections []Sections `json:"sections"` }{ Type: "MessageCard", - Context: "http://schema.org/extensions", + Context: "https://schema.org/extensions", ThemeColor: themeColor, - Summary: string(text), + Summary: string(body), Sections: []Sections{{ - ActivityTitle: string(text), + ActivityTitle: string(body), ActivitySubtitle: "Provider: " + entry.Provider, Facts: []Fact{ {"Hostname", c.meta.Hostname}, @@ -99,7 +97,7 @@ func (c *Client) Send(entry model.NotifEntry) error { return err } - req, err := http.NewRequest("POST", c.cfg.WebhookURL, bytes.NewBuffer(body)) + req, err := http.NewRequest("POST", c.cfg.WebhookURL, bytes.NewBuffer(jsonBody)) if err != nil { return err } diff --git a/internal/notif/telegram/client.go b/internal/notif/telegram/client.go index f342cad0..6f43a120 100644 --- a/internal/notif/telegram/client.go +++ b/internal/notif/telegram/client.go @@ -20,10 +20,6 @@ type Client struct { meta model.Meta } -const customTpl = `Docker tag {{ if .Entry.Image.HubLink }}[{{ .Entry.Image }}]({{ .Entry.Image.HubLink }}){{ else }}{{ .Entry.Image }}{{ end }} -which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} -on {{ escapeMarkdown .Meta.Hostname }}.` - // New creates a new Telegram notification instance func New(config *model.NotifTelegram, meta model.Meta) notifier.Notifier { return notifier.Notifier{ @@ -63,9 +59,10 @@ func (c *Client) Send(entry model.NotifEntry) error { } message, err := msg.New(msg.Options{ - Meta: c.meta, - Entry: entry, - TplFuncs: template.FuncMap{ + Meta: c.meta, + Entry: entry, + TemplateBody: c.cfg.TemplateBody, + TemplateFuncs: template.FuncMap{ "escapeMarkdown": func(text string) string { text = strings.ReplaceAll(text, "_", "\\_") text = strings.ReplaceAll(text, "*", "\\*") @@ -79,7 +76,7 @@ func (c *Client) Send(entry model.NotifEntry) error { return err } - _, text, err := message.RenderMarkdownTemplate(strings.ReplaceAll(customTpl, "\n", " ")) + _, body, err := message.RenderMarkdown() if err != nil { return err } @@ -89,7 +86,7 @@ func (c *Client) Send(entry model.NotifEntry) error { BaseChat: tgbotapi.BaseChat{ ChatID: chatID, }, - Text: string(text), + Text: string(body), ParseMode: "markdown", DisableWebPagePreview: true, }) diff --git a/mkdocs.yml b/mkdocs.yml index 8a36c60b..9e2ad73b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -22,6 +22,13 @@ extra: plausible: server: plausible.re4per.com domain: crazymax.dev/diun + template: + defaultTitle: | + {{ if (eq .Entry.Status "new") }}New image {{ .Entry.Image }} has been added{{ else }}Image update for {{ .Entry.Image }}{{ end }} + defaultBody: | + Docker tag {{ if .Entry.Image.HubLink }}[**{{ .Entry.Image }}**]({{ .Entry.Image.HubLink }}){{ else }}**{{ .Entry.Image }}**{{ end }} + which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }} + on {{ .Meta.Hostname }}. theme: name: material @@ -76,7 +83,11 @@ plugins: - git-revision-date-localized: type: iso_datetime enable_creation_date: true - - macros + - macros: + j2_block_start_string: '[[%' + j2_block_end_string: '%]]' + j2_variable_start_string: '[[' + j2_variable_end_string: ']]' - search: prebuild_index: python lang: