Add message client for notifiers (#273)

Co-authored-by: CrazyMax <crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax
2021-02-14 18:34:42 +01:00
committed by GitHub
parent 63c231d981
commit c971e06d9f
15 changed files with 308 additions and 361 deletions

127
internal/msg/client.go Normal file
View File

@@ -0,0 +1,127 @@
package msg
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/microcosm-cc/bluemonday"
"github.com/opencontainers/go-digest"
"github.com/russross/blackfriday/v2"
)
// Client represents an active msg object
type Client struct {
opts Options
}
// Options holds msg client object options
type Options struct {
Meta model.Meta
Entry model.NotifEntry
TplFuncs 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{
opts,
}, nil
}
// RenderMarkdown returns a notification message as markdown
func (c *Client) RenderMarkdown() (title string, text []byte, err error) {
return c.RenderHTMLTemplate(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 {
Meta model.Meta
Entry model.NotifEntry
}{
Meta: c.opts.Meta,
Entry: c.opts.Entry,
})
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)
if err != nil {
return
}
text = []byte(bluemonday.UGCPolicy().Sanitize(
// Dirty way to remove wrapped <p></p> and newline
// https://github.com/russross/blackfriday/issues/237
strings.TrimRight(strings.TrimLeft(strings.TrimSpace(string(blackfriday.Run(text))), "<p>"), "</p>"),
))
return
}
// RenderJSON returns a notification message as JSON
func (c *Client) RenderJSON() ([]byte, error) {
return json.Marshal(struct {
Version string `json:"diun_version"`
Hostname string `json:"hostname"`
Status string `json:"status"`
Provider string `json:"provider"`
Image string `json:"image"`
HubLink string `json:"hub_link"`
MIMEType string `json:"mime_type"`
Digest digest.Digest `json:"digest"`
Created *time.Time `json:"created"`
Platform string `json:"platform"`
}{
Version: c.opts.Meta.Version,
Hostname: c.opts.Meta.Hostname,
Status: string(c.opts.Entry.Status),
Provider: c.opts.Entry.Provider,
Image: c.opts.Entry.Image.String(),
HubLink: c.opts.Entry.Image.HubLink,
MIMEType: c.opts.Entry.Manifest.MIMEType,
Digest: c.opts.Entry.Manifest.Digest,
Created: c.opts.Entry.Manifest.Created,
Platform: c.opts.Entry.Manifest.Platform,
})
}
// RenderEnv returns a notification message as environment variables
func (c *Client) RenderEnv() []string {
return []string{
fmt.Sprintf("DIUN_VERSION=%s", c.opts.Meta.Version),
fmt.Sprintf("DIUN_HOSTNAME=%s", c.opts.Meta.Hostname),
fmt.Sprintf("DIUN_ENTRY_STATUS=%s", string(c.opts.Entry.Status)),
fmt.Sprintf("DIUN_ENTRY_PROVIDER=%s", c.opts.Entry.Provider),
fmt.Sprintf("DIUN_ENTRY_IMAGE=%s", c.opts.Entry.Image.String()),
fmt.Sprintf("DIUN_ENTRY_HUBLINK=%s", c.opts.Entry.Image.HubLink),
fmt.Sprintf("DIUN_ENTRY_MIMETYPE=%s", c.opts.Entry.Manifest.MIMEType),
fmt.Sprintf("DIUN_ENTRY_DIGEST=%s", c.opts.Entry.Manifest.Digest),
fmt.Sprintf("DIUN_ENTRY_CREATED=%s", c.opts.Entry.Manifest.Created),
fmt.Sprintf("DIUN_ENTRY_PLATFORM=%s", c.opts.Entry.Manifest.Platform),
}
}

View File

@@ -1,14 +1,12 @@
package amqp
import (
"encoding/json"
"fmt"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/crazy-max/diun/v4/pkg/utl"
"github.com/opencontainers/go-digest"
"github.com/streadway/amqp"
)
@@ -70,33 +68,19 @@ func (c *Client) Send(entry model.NotifEntry) error {
return err
}
body, err := json.Marshal(struct {
Version string `json:"diun_version"`
Hostname string `json:"hostname"`
Status string `json:"status"`
Provider string `json:"provider"`
Image string `json:"image"`
HubLink string `json:"hub_link"`
MIMEType string `json:"mime_type"`
Digest digest.Digest `json:"digest"`
Created *time.Time `json:"created"`
Platform string `json:"platform"`
}{
Version: c.meta.Version,
Hostname: c.meta.Hostname,
Status: string(entry.Status),
Provider: entry.Provider,
Image: entry.Image.String(),
HubLink: entry.Image.HubLink,
MIMEType: entry.Manifest.MIMEType,
Digest: entry.Manifest.Digest,
Created: entry.Manifest.Created,
Platform: entry.Manifest.Platform,
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
})
if err != nil {
return err
}
body, err := message.RenderJSON()
if err != nil {
return err
}
return ch.Publish(
c.cfg.Exchange,
q.Name,

View File

@@ -6,10 +6,10 @@ import (
"fmt"
"net/http"
"net/url"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
)
@@ -44,33 +44,25 @@ func (c *Client) Send(entry model.NotifEntry) error {
Timeout: *c.cfg.Timeout,
}
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
})
if err != nil {
return err
}
title, text, err := message.RenderMarkdown()
if err != nil {
return err
}
if len(c.cfg.Mentions) > 0 {
for _, mention := range c.cfg.Mentions {
content.WriteString(fmt.Sprintf("%s ", mention))
}
}
if entry.Status == model.ImageStatusNew {
content.WriteString(fmt.Sprintf("New image %s has been added", entry.Image.String()))
} else {
content.WriteString(fmt.Sprintf("Image update for %s", 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 }}**]({{ .Entry.Image.HubLink }})"
}
var textBuf bytes.Buffer
textTpl := template.Must(template.New("discord").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 **{{ .Meta.Hostname }}**.`, tagTpl)))
if err := textTpl.Execute(&textBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
Meta: c.meta,
Entry: entry,
}); err != nil {
return err
}
content.WriteString(title)
fields := []EmbedField{
{
@@ -108,7 +100,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
AvatarURL: c.meta.Logo,
Embeds: []Embed{
{
Description: textBuf.String(),
Description: string(text),
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,

View File

@@ -8,9 +8,9 @@ import (
"net/url"
"path"
"strconv"
"text/template"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
)
@@ -42,35 +42,26 @@ func (c *Client) Send(entry model.NotifEntry) error {
Timeout: *c.cfg.Timeout,
}
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 }}`]({{ .Entry.Image.HubLink }})"
}
var msgBuf bytes.Buffer
msgTpl := template.Must(template.New("gotify").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 {{ .Meta.Hostname }}.", tagTpl)))
if err := msgTpl.Execute(&msgBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
}); err != nil {
})
if err != nil {
return err
}
var body, err = json.Marshal(struct {
title, text, err := message.RenderMarkdown()
if err != nil {
return err
}
body, err := json.Marshal(struct {
Message string `json:"message"`
Title string `json:"title"`
Priority int `json:"priority"`
Extras map[string]interface{} `json:"extras"`
}{
Message: msgBuf.String(),
Message: string(text),
Title: title,
Priority: c.cfg.Priority,
Extras: map[string]interface{}{

View File

@@ -1,13 +1,12 @@
package mail
import (
"bytes"
"crypto/tls"
"fmt"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/crazy-max/diun/v4/pkg/utl"
"github.com/go-gomail/gomail"
@@ -22,6 +21,16 @@ 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
<code>{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }}</code> with digest <code>{{ .Entry.Manifest.Digest }}</code>
for <code>{{ .Entry.Manifest.Platform }}</code> 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{
@@ -53,43 +62,24 @@ func (c *Client) Send(entry model.NotifEntry) error {
},
}
// Subject
subject := fmt.Sprintf("Image update for %s", entry.Image.String())
if entry.Status == model.ImageStatusNew {
subject = 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 }}**]({{ .Entry.Image.HubLink }})"
}
// Body
var emailBuf bytes.Buffer
emailTpl := 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 **{{ .Meta.Hostname }}**.
This image has been {{ if (eq .Entry.Status "new") }}created{{ else }}updated{{ end }} at <code>{{ .Entry.Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }}</code>
with digest <code>{{ .Entry.Manifest.Digest }}</code> for <code>{{ .Entry.Manifest.Platform }}</code> platform.
Need help, or have questions? Go to https://github.com/crazy-max/diun and leave an issue.
`, tagTpl)))
if err := emailTpl.Execute(&emailBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
}); err != nil {
})
if err != nil {
return err
}
title, text, err := message.RenderMarkdownTemplate(customTpl)
if err != nil {
return err
}
email := hermes.Email{
Body: hermes.Body{
Title: fmt.Sprintf("%s 🔔 notification", c.meta.Name),
FreeMarkdown: hermes.Markdown(emailBuf.String()),
Signature: "Thanks for your support",
FreeMarkdown: hermes.Markdown(text),
Signature: "Thanks for your support!",
},
}
@@ -108,7 +98,7 @@ Need help, or have questions? Go to https://github.com/crazy-max/diun and leave
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", subject)
msg.SetHeader("Subject", title)
msg.SetBody("text/plain", textpart)
msg.AddAlternative("text/html", htmlpart)

View File

@@ -174,7 +174,7 @@ func (t *Theme) HTMLTemplate() string {
}
cite {
display: block;
font-size: 0.925rem;
font-size: 0.925rem;
}
cite:before {
content: "\2014 \0020";
@@ -304,92 +304,8 @@ func (t *Theme) HTMLTemplate() string {
{{ end }}
{{ if (ne .Email.Body.FreeMarkdown "") }}
{{ .Email.Body.FreeMarkdown.ToHTML }}
{{ else }}
{{ with .Email.Body.Dictionary }}
{{ if gt (len .) 0 }}
<dl class="body-dictionary">
{{ range $entry := . }}
<dt>{{ $entry.Key }}:</dt>
<dd>{{ $entry.Value }}</dd>
{{ end }}
</dl>
{{ end }}
{{ end }}
<!-- Table -->
{{ with .Email.Body.Table }}
{{ $data := .Data }}
{{ $columns := .Columns }}
{{ if gt (len $data) 0 }}
<table class="data-wrapper" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2">
<table class="data-table" width="100%" cellpadding="0" cellspacing="0">
<tr>
{{ $col := index $data 0 }}
{{ range $entry := $col }}
<th
{{ with $columns }}
{{ $width := index .CustomWidth $entry.Key }}
{{ with $width }}
width="{{ . }}"
{{ end }}
{{ $align := index .CustomAlignment $entry.Key }}
{{ with $align }}
style="text-align:{{ . }}"
{{ end }}
{{ end }}
>
<p>{{ $entry.Key }}</p>
</th>
{{ end }}
</tr>
{{ range $row := $data }}
<tr>
{{ range $cell := $row }}
<td
{{ with $columns }}
{{ $align := index .CustomAlignment $cell.Key }}
{{ with $align }}
style="text-align:{{ . }}"
{{ end }}
{{ end }}
>
{{ $cell.Value }}
</td>
{{ end }}
</tr>
{{ end }}
</table>
</td>
</tr>
</table>
{{ end }}
{{ end }}
<!-- Action -->
{{ with .Email.Body.Actions }}
{{ if gt (len .) 0 }}
{{ range $action := . }}
<p>{{ $action.Instructions }}</p>
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<div>
<a href="{{ $action.Button.Link }}" class="button" style="background-color: {{ $action.Button.Color }}; color: {{ $action.Button.TextColor }};" target="_blank">
{{ $action.Button.Text }}
</a>
</div>
</td>
</tr>
</table>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ with .Email.Body.Outros }}
{{ with .Email.Body.Outros }}
{{ if gt (len .) 0 }}
{{ range $line := . }}
<p>{{ $line }}</p>
@@ -398,13 +314,11 @@ func (t *Theme) HTMLTemplate() string {
{{ end }}
<p>
{{.Email.Body.Signature}},
<br />
{{.Hermes.Product.Name}}
{{.Email.Body.Signature}}
</p>
{{ if (eq .Email.Body.FreeMarkdown "") }}
{{ with .Email.Body.Actions }}
{{ with .Email.Body.Actions }}
<table class="body-sub">
<tbody>
{{ range $action := . }}
@@ -487,13 +401,13 @@ func (t *Theme) PlainTextTemplate() string {
</table>
{{ end }}
{{ end }}
{{ with .Email.Body.Actions }}
{{ with .Email.Body.Actions }}
{{ range $action := . }}
<p>{{ $action.Instructions }} {{ $action.Button.Link }}</p>
<p>{{ $action.Instructions }} {{ $action.Button.Link }}</p>
{{ end }}
{{ end }}
{{ end }}
{{ with .Email.Body.Outros }}
{{ with .Email.Body.Outros }}
{{ range $line := . }}
<p>{{ $line }}<p>
{{ end }}

View File

@@ -1,18 +1,15 @@
package matrix
import (
"bytes"
"fmt"
"text/template"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/crazy-max/diun/v4/pkg/utl"
"github.com/matrix-org/gomatrix"
"github.com/microcosm-cc/bluemonday"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
"github.com/russross/blackfriday/v2"
)
// Client represents an active rocketchat notification object
@@ -74,29 +71,26 @@ func (c *Client) Send(entry model.NotifEntry) error {
return errors.Wrap(err, "failed to join room")
}
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 }}**]({{ .Entry.Image.HubLink }})"
}
var msgBuf bytes.Buffer
msgTpl := template.Must(template.New("text").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 {{ .Meta.Hostname }}.", tagTpl)))
if err := msgTpl.Execute(&msgBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
}); err != nil {
})
if err != nil {
return err
}
msgHTML := bluemonday.UGCPolicy().SanitizeBytes(
blackfriday.Run(msgBuf.Bytes()),
)
_, msgText, err := message.RenderMarkdown()
if err != nil {
return err
}
_, msgHTML, err := message.RenderHTML()
if err != nil {
return err
}
if _, err := m.SendMessageEvent(joined.RoomID, "m.room.message", gomatrix.HTMLMessage{
Body: msgBuf.String(),
Body: string(msgText),
MsgType: fmt.Sprintf("m.%s", c.cfg.MsgType),
Format: "org.matrix.custom.html",
FormattedBody: string(msgHTML),

View File

@@ -1,11 +1,10 @@
package mqtt
import (
"encoding/json"
"fmt"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/crazy-max/diun/v4/pkg/utl"
MQTT "github.com/eclipse/paho.mqtt.golang"
@@ -64,32 +63,20 @@ func (c *Client) Send(entry model.NotifEntry) error {
}
}
message, err := json.Marshal(struct {
Version string `json:"diun_version"`
Hostname string `json:"hostname"`
Status string `json:"status"`
Provider string `json:"provider"`
Image string `json:"image"`
HubLink string `json:"hub_link"`
MIMEType string `json:"mime_type"`
Created *time.Time `json:"created"`
Platform string `json:"platform"`
}{
Version: c.meta.Version,
Hostname: c.meta.Hostname,
Status: string(entry.Status),
Provider: entry.Provider,
Image: entry.Image.String(),
HubLink: entry.Image.HubLink,
MIMEType: entry.Manifest.MIMEType,
Created: entry.Manifest.Created,
Platform: entry.Manifest.Platform,
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
})
if err != nil {
return err
}
token := c.mqttClient.Publish(c.cfg.Topic, byte(c.cfg.QoS), false, message)
body, err := message.RenderJSON()
if err != nil {
return err
}
token := c.mqttClient.Publish(c.cfg.Topic, byte(c.cfg.QoS), false, body)
token.Wait()
return token.Error()
}

View File

@@ -1,13 +1,11 @@
package pushover
import (
"bytes"
"errors"
"fmt"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/crazy-max/diun/v4/pkg/utl"
"github.com/gregdel/pushover"
@@ -50,25 +48,16 @@ func (c *Client) Send(entry model.NotifEntry) error {
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())
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
})
if err != nil {
return err
}
tagTpl := "{{ .Entry.Image.Domain }}/{{ .Entry.Image.Path }}:{{ .Entry.Image.Tag }}"
if len(entry.Image.HubLink) > 0 {
tagTpl = `<a href="{{ .Entry.Image.HubLink }}">{{ .Entry.Image.Domain }}/{{ .Entry.Image.Path }}:{{ .Entry.Image.Tag }}</a>`
}
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 {
title, text, err := message.RenderHTML()
if err != nil {
return err
}
@@ -78,7 +67,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
}
_, err = app.SendMessage(&pushover.Message{
Message: msgBuf.String(),
Message: string(text),
Title: title,
Priority: c.cfg.Priority,
URL: c.meta.URL,

View File

@@ -8,10 +8,10 @@ import (
"net/url"
"path"
"strconv"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
)
@@ -22,6 +22,8 @@ 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{
@@ -44,20 +46,16 @@ func (c *Client) Send(entry model.NotifEntry) error {
Timeout: *c.cfg.Timeout,
}
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())
}
var textBuf bytes.Buffer
textTpl := template.Must(template.New("rocketchat").Parse(`Docker tag {{ .Entry.Image.Domain }}/{{ .Entry.Image.Path }}:{{ .Entry.Image.Tag }} which you subscribed to through {{ .Entry.Provider }} provider has been {{ if (eq .Entry.Status "new") }}newly added{{ else }}updated{{ end }}.`))
if err := textTpl.Execute(&textBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
}); err != nil {
})
if err != nil {
return err
}
title, text, err := message.RenderMarkdownTemplate(customTpl)
if err != nil {
return err
}
@@ -104,7 +102,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
Text: title,
Attachments: []Attachment{
{
Text: textBuf.String(),
Text: string(text),
Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)),
Fields: fields,
},

View File

@@ -2,12 +2,12 @@ package script
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
@@ -50,19 +50,16 @@ func (c *Client) Send(entry model.NotifEntry) error {
cmd.Dir = c.cfg.Dir
}
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
})
if err != nil {
return err
}
// Set env vars
cmd.Env = append(os.Environ(), []string{
fmt.Sprintf("DIUN_VERSION=%s", c.meta.Version),
fmt.Sprintf("DIUN_HOSTNAME=%s", c.meta.Hostname),
fmt.Sprintf("DIUN_ENTRY_STATUS=%s", string(entry.Status)),
fmt.Sprintf("DIUN_ENTRY_PROVIDER=%s", entry.Provider),
fmt.Sprintf("DIUN_ENTRY_IMAGE=%s", entry.Image.String()),
fmt.Sprintf("DIUN_ENTRY_HUBLINK=%s", entry.Image.HubLink),
fmt.Sprintf("DIUN_ENTRY_MIMETYPE=%s", entry.Manifest.MIMEType),
fmt.Sprintf("DIUN_ENTRY_DIGEST=%s", entry.Manifest.Digest),
fmt.Sprintf("DIUN_ENTRY_CREATED=%s", entry.Manifest.Created),
fmt.Sprintf("DIUN_ENTRY_PLATFORM=%s", entry.Manifest.Platform),
}...)
cmd.Env = append(os.Environ(), message.RenderEnv()...)
// Run
if err := cmd.Run(); err != nil {

View File

@@ -1,14 +1,13 @@
package slack
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/nlopes/slack"
)
@@ -20,6 +19,8 @@ type Client struct {
meta model.Meta
}
const customTpl = "<!channel> 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{
@@ -37,15 +38,16 @@ func (c *Client) Name() string {
// Send creates and sends a slack notification with an entry
func (c *Client) Send(entry model.NotifEntry) error {
var textBuf bytes.Buffer
textTpl := template.Must(template.New("text").Parse("<!channel> Docker tag `{{ .Entry.Image.Domain }}/{{ .Entry.Image.Path }}:{{ .Entry.Image.Tag }}` {{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }}."))
if err := textTpl.Execute(&textBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
}); err != nil {
})
if err != nil {
return err
}
_, text, err := message.RenderMarkdownTemplate(customTpl)
if err != nil {
return err
}
@@ -97,7 +99,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
AuthorSubname: "github.com/crazy-max/diun",
AuthorLink: c.meta.URL,
AuthorIcon: c.meta.Logo,
Text: textBuf.String(),
Text: string(text),
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)),

View File

@@ -3,12 +3,11 @@ package teams
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"text/template"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
)
@@ -19,6 +18,9 @@ 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{
@@ -53,20 +55,16 @@ func (c *Client) Send(entry model.NotifEntry) error {
Timeout: time.Duration(10) * time.Second,
}
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 }}`]({{ .Entry.Image.HubLink }})"
}
var textBuf bytes.Buffer
textTpl := template.Must(template.New("text").Parse(fmt.Sprintf("Docker tag %s {{ if (eq .Entry.Status \"new\") }}newly added{{ else }}updated{{ end }}.", tagTpl)))
if err := textTpl.Execute(&textBuf, struct {
Meta model.Meta
Entry model.NotifEntry
}{
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
}); err != nil {
})
if err != nil {
return err
}
_, text, err := message.RenderMarkdownTemplate(customTpl)
if err != nil {
return err
}
@@ -75,7 +73,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
themeColor = "0076D7"
}
var body, err = json.Marshal(struct {
body, err := json.Marshal(struct {
Type string `json:"@type"`
Context string `json:"@context"`
ThemeColor string `json:"themeColor"`
@@ -85,9 +83,9 @@ func (c *Client) Send(entry model.NotifEntry) error {
Type: "MessageCard",
Context: "http://schema.org/extensions",
ThemeColor: themeColor,
Summary: textBuf.String(),
Summary: string(text),
Sections: []Sections{{
ActivityTitle: textBuf.String(),
ActivityTitle: string(text),
ActivitySubtitle: "Provider: " + entry.Provider,
Facts: []Fact{
{"Hostname", c.meta.Hostname},

View File

@@ -1,12 +1,11 @@
package telegram
import (
"bytes"
"fmt"
"strings"
"text/template"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api"
)
@@ -18,6 +17,10 @@ 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{
@@ -40,20 +43,25 @@ func (c *Client) Send(entry model.NotifEntry) error {
return err
}
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 }}]({{ .Entry.Image.HubLink }})"
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
TplFuncs: template.FuncMap{
"escapeMarkdown": func(text string) string {
text = strings.ReplaceAll(text, "_", "\\_")
text = strings.ReplaceAll(text, "*", "\\*")
text = strings.ReplaceAll(text, "[", "\\[")
text = strings.ReplaceAll(text, "`", "\\`")
return text
},
},
})
if err != nil {
return err
}
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: escapeMarkdown(c.meta.Hostname),
Entry: entry,
}); err != nil {
_, text, err := message.RenderMarkdownTemplate(strings.ReplaceAll(customTpl, "\n", " "))
if err != nil {
return err
}
@@ -62,7 +70,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
BaseChat: tgbotapi.BaseChat{
ChatID: chatID,
},
Text: msgBuf.String(),
Text: string(text),
ParseMode: "markdown",
DisableWebPagePreview: true,
})
@@ -73,11 +81,3 @@ func (c *Client) Send(entry model.NotifEntry) error {
return nil
}
func escapeMarkdown(txt string) string {
txt = strings.ReplaceAll(txt, "_", "\\_")
txt = strings.ReplaceAll(txt, "*", "\\*")
txt = strings.ReplaceAll(txt, "[", "\\[")
txt = strings.ReplaceAll(txt, "`", "\\`")
return txt
}

View File

@@ -2,13 +2,11 @@ package webhook
import (
"bytes"
"encoding/json"
"net/http"
"time"
"github.com/crazy-max/diun/v4/internal/model"
"github.com/crazy-max/diun/v4/internal/msg"
"github.com/crazy-max/diun/v4/internal/notif/notifier"
"github.com/opencontainers/go-digest"
)
// Client represents an active webhook notification object
@@ -39,33 +37,19 @@ func (c *Client) Send(entry model.NotifEntry) error {
Timeout: *c.cfg.Timeout,
}
body, err := json.Marshal(struct {
Version string `json:"diun_version"`
Hostname string `json:"hostname"`
Status string `json:"status"`
Provider string `json:"provider"`
Image string `json:"image"`
HubLink string `json:"hub_link"`
MIMEType string `json:"mime_type"`
Digest digest.Digest `json:"digest"`
Created *time.Time `json:"created"`
Platform string `json:"platform"`
}{
Version: c.meta.Version,
Hostname: c.meta.Hostname,
Status: string(entry.Status),
Provider: entry.Provider,
Image: entry.Image.String(),
HubLink: entry.Image.HubLink,
MIMEType: entry.Manifest.MIMEType,
Digest: entry.Manifest.Digest,
Created: entry.Manifest.Created,
Platform: entry.Manifest.Platform,
message, err := msg.New(msg.Options{
Meta: c.meta,
Entry: entry,
})
if err != nil {
return err
}
body, err := message.RenderJSON()
if err != nil {
return err
}
req, err := http.NewRequest(c.cfg.Method, c.cfg.Endpoint, bytes.NewBuffer(body))
if err != nil {
return err