Add notifications package for easy sending of notifications (#779)
Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/779 Co-authored-by: konrad <konrad@kola-entertainments.de> Co-committed-by: konrad <konrad@kola-entertainments.de>
This commit is contained in:
93
pkg/notifications/mail.go
Normal file
93
pkg/notifications/mail.go
Normal file
@ -0,0 +1,93 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package notifications
|
||||
|
||||
import "code.vikunja.io/api/pkg/mail"
|
||||
|
||||
// Mail is a mail message
|
||||
type Mail struct {
|
||||
from string
|
||||
to string
|
||||
subject string
|
||||
actionText string
|
||||
actionURL string
|
||||
greeting string
|
||||
introLines []string
|
||||
outroLines []string
|
||||
}
|
||||
|
||||
// NewMail creates a new mail object with a default greeting
|
||||
func NewMail() *Mail {
|
||||
return &Mail{
|
||||
greeting: "Hi,",
|
||||
}
|
||||
}
|
||||
|
||||
// From sets the from name and email address
|
||||
func (m *Mail) From(from string) *Mail {
|
||||
m.from = from
|
||||
return m
|
||||
}
|
||||
|
||||
// To sets the recipient of the mail message
|
||||
func (m *Mail) To(to string) *Mail {
|
||||
m.to = to
|
||||
return m
|
||||
}
|
||||
|
||||
// Subject sets the subject of the mail message
|
||||
func (m *Mail) Subject(subject string) *Mail {
|
||||
m.subject = subject
|
||||
return m
|
||||
}
|
||||
|
||||
// Greeting sets the greeting of the mail message
|
||||
func (m *Mail) Greeting(greeting string) *Mail {
|
||||
m.greeting = greeting
|
||||
return m
|
||||
}
|
||||
|
||||
// Action sets any action a mail might have
|
||||
func (m *Mail) Action(text, url string) *Mail {
|
||||
m.actionText = text
|
||||
m.actionURL = url
|
||||
return m
|
||||
}
|
||||
|
||||
// Line adds a line of text to the mail
|
||||
func (m *Mail) Line(line string) *Mail {
|
||||
if m.actionURL == "" {
|
||||
m.introLines = append(m.introLines, line)
|
||||
return m
|
||||
}
|
||||
|
||||
m.outroLines = append(m.outroLines, line)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// SendMail passes the notification to the mailing queue for sending
|
||||
func SendMail(m *Mail) error {
|
||||
opts, err := RenderMail(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mail.SendMail(opts)
|
||||
|
||||
return nil
|
||||
}
|
137
pkg/notifications/mail_render.go
Normal file
137
pkg/notifications/mail_render.go
Normal file
@ -0,0 +1,137 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
templatehtml "html/template"
|
||||
templatetext "text/template"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
"code.vikunja.io/api/pkg/mail"
|
||||
"code.vikunja.io/api/pkg/utils"
|
||||
)
|
||||
|
||||
const mailTemplatePlain = `
|
||||
{{ .Greeting }}
|
||||
{{ range $line := .IntroLines}}
|
||||
{{ $line }}
|
||||
{{ end }}
|
||||
{{ if .ActionURL }}{{ .ActionText }}:
|
||||
{{ .ActionURL }}{{end}}
|
||||
{{ range $line := .OutroLines}}
|
||||
{{ $line }}
|
||||
{{ end }}`
|
||||
|
||||
const mailTemplateHTML = `
|
||||
<!doctype html>
|
||||
<html style="width: 100%; height: 100%; padding: 0; margin: 0;">
|
||||
<head>
|
||||
<meta name="viewport" content="width: display-width;">
|
||||
</head>
|
||||
<body style="width: 100%; padding: 0; margin: 0; background: #f3f4f6">
|
||||
<div style="width: 100%; font-family: 'Open Sans', sans-serif; text-rendering: optimizeLegibility">
|
||||
<div style="width: 600px; margin: 0 auto; text-align: justify;">
|
||||
<h1 style="font-size: 30px; text-align: center;">
|
||||
<img src="{{.FrontendURL}}images/logo-full.svg" style="height: 75px;" alt="Vikunja"/>
|
||||
</h1>
|
||||
<div style="border: 1px solid #dbdbdb; -webkit-box-shadow: 0.3em 0.3em 0.8em #e6e6e6; box-shadow: 0.3em 0.3em 0.8em #e6e6e6; color: #4a4a4a; padding: 5px 25px; border-radius: 3px; background: #fff;">
|
||||
<p>
|
||||
{{ .Greeting }}
|
||||
</p>
|
||||
|
||||
{{ range $line := .IntroLines}}
|
||||
<p>
|
||||
{{ $line }}
|
||||
</p>
|
||||
{{ end }}
|
||||
|
||||
{{ if .ActionURL }}
|
||||
<a href="{{ .ActionURL }}" title="{{ .ActionText }}"
|
||||
style="position: relative;text-decoration:none;display: block;border-radius: 4px;cursor: pointer;padding-bottom: 8px;padding-left: 14px;padding-right: 14px;padding-top: 8px;width:280px;margin:10px auto;text-align: center;white-space: nowrap;border: 0;text-transform: uppercase;font-size: 14px;font-weight: 700;-webkit-box-shadow: 0 3px 6px rgba(107,114,128,.12),0 2px 4px rgba(107,114,128,.1);box-shadow: 0 3px 6px rgba(107,114,128,.12),0 2px 4px rgba(107,114,128,.1);background-color: #1973ff;border-color: transparent;color: #fff;">
|
||||
{{ .ActionText }}
|
||||
</a>
|
||||
{{end}}
|
||||
|
||||
{{ range $line := .OutroLines}}
|
||||
<p>
|
||||
{{ $line }}
|
||||
</p>
|
||||
{{ end }}
|
||||
|
||||
{{ if .ActionURL }}
|
||||
<p style="color: #9CA3AF;font-size:12px;border-top: 1px solid #dbdbdb;margin-top:20px;padding-top:20px;">
|
||||
If the button above doesn't work, copy the url below and paste it in your browsers address bar:<br/>
|
||||
{{ .ActionURL }}
|
||||
</p>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
// RenderMail takes a precomposed mail message and renders it into a ready to send mail.Opts object
|
||||
func RenderMail(m *Mail) (mailOpts *mail.Opts, err error) {
|
||||
|
||||
var htmlContent bytes.Buffer
|
||||
var plainContent bytes.Buffer
|
||||
|
||||
plain, err := templatetext.New("mail-plain").Parse(mailTemplatePlain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
html, err := templatehtml.New("mail-plain").Parse(mailTemplateHTML)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boundary := "np" + utils.MakeRandomString(13)
|
||||
|
||||
data := make(map[string]interface{})
|
||||
|
||||
data["Greeting"] = m.greeting
|
||||
data["IntroLines"] = m.introLines
|
||||
data["OutroLines"] = m.outroLines
|
||||
data["ActionText"] = m.actionText
|
||||
data["ActionURL"] = m.actionURL
|
||||
data["Boundary"] = boundary
|
||||
data["FrontendURL"] = config.ServiceFrontendurl.GetString()
|
||||
|
||||
err = plain.Execute(&plainContent, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = html.Execute(&htmlContent, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mailOpts = &mail.Opts{
|
||||
From: m.from,
|
||||
To: m.to,
|
||||
Subject: m.subject,
|
||||
ContentType: mail.ContentTypeMultipart,
|
||||
Message: plainContent.String(),
|
||||
HTMLMessage: htmlContent.String(),
|
||||
Boundary: boundary,
|
||||
}
|
||||
|
||||
return mailOpts, nil
|
||||
}
|
173
pkg/notifications/mail_test.go
Normal file
173
pkg/notifications/mail_test.go
Normal file
@ -0,0 +1,173 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewMail(t *testing.T) {
|
||||
t.Run("Full mail", func(t *testing.T) {
|
||||
mail := NewMail().
|
||||
From("test@example.com").
|
||||
To("test@otherdomain.com").
|
||||
Subject("Testmail").
|
||||
Greeting("Hi there,").
|
||||
Line("This is a line").
|
||||
Line("And another one").
|
||||
Action("the actiopn", "https://example.com").
|
||||
Line("This should be an outro line").
|
||||
Line("And one more, because why not?")
|
||||
|
||||
assert.Equal(t, "test@example.com", mail.from)
|
||||
assert.Equal(t, "test@otherdomain.com", mail.to)
|
||||
assert.Equal(t, "Testmail", mail.subject)
|
||||
assert.Equal(t, "Hi there,", mail.greeting)
|
||||
assert.Len(t, mail.introLines, 2)
|
||||
assert.Equal(t, "This is a line", mail.introLines[0])
|
||||
assert.Equal(t, "And another one", mail.introLines[1])
|
||||
assert.Len(t, mail.outroLines, 2)
|
||||
assert.Equal(t, "This should be an outro line", mail.outroLines[0])
|
||||
assert.Equal(t, "And one more, because why not?", mail.outroLines[1])
|
||||
})
|
||||
t.Run("No greeting", func(t *testing.T) {
|
||||
mail := NewMail().
|
||||
From("test@example.com").
|
||||
To("test@otherdomain.com").
|
||||
Subject("Testmail").
|
||||
Line("This is a line").
|
||||
Line("And another one")
|
||||
|
||||
assert.Equal(t, "test@example.com", mail.from)
|
||||
assert.Equal(t, "test@otherdomain.com", mail.to)
|
||||
assert.Equal(t, "Testmail", mail.subject)
|
||||
assert.Equal(t, "Hi,", mail.greeting) // Default greeting
|
||||
assert.Len(t, mail.introLines, 2)
|
||||
assert.Equal(t, "This is a line", mail.introLines[0])
|
||||
assert.Equal(t, "And another one", mail.introLines[1])
|
||||
})
|
||||
t.Run("No action", func(t *testing.T) {
|
||||
mail := NewMail().
|
||||
From("test@example.com").
|
||||
To("test@otherdomain.com").
|
||||
Subject("Testmail").
|
||||
Line("This is a line").
|
||||
Line("And another one").
|
||||
Line("This should be an outro line").
|
||||
Line("And one more, because why not?")
|
||||
|
||||
assert.Equal(t, "test@example.com", mail.from)
|
||||
assert.Equal(t, "test@otherdomain.com", mail.to)
|
||||
assert.Equal(t, "Testmail", mail.subject)
|
||||
assert.Len(t, mail.introLines, 4)
|
||||
assert.Equal(t, "This is a line", mail.introLines[0])
|
||||
assert.Equal(t, "And another one", mail.introLines[1])
|
||||
assert.Equal(t, "This should be an outro line", mail.introLines[2])
|
||||
assert.Equal(t, "And one more, because why not?", mail.introLines[3])
|
||||
})
|
||||
}
|
||||
|
||||
func TestRenderMail(t *testing.T) {
|
||||
mail := NewMail().
|
||||
From("test@example.com").
|
||||
To("test@otherdomain.com").
|
||||
Subject("Testmail").
|
||||
Greeting("Hi there,").
|
||||
Line("This is a line").
|
||||
Line("And another one").
|
||||
Action("The action", "https://example.com").
|
||||
Line("This should be an outro line").
|
||||
Line("And one more, because why not?")
|
||||
|
||||
mailopts, err := RenderMail(mail)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, mail.from, mailopts.From)
|
||||
assert.Equal(t, mail.to, mailopts.To)
|
||||
|
||||
assert.Equal(t, `
|
||||
Hi there,
|
||||
|
||||
This is a line
|
||||
|
||||
And another one
|
||||
|
||||
The action:
|
||||
https://example.com
|
||||
|
||||
This should be an outro line
|
||||
|
||||
And one more, because why not?
|
||||
`, mailopts.Message)
|
||||
assert.Equal(t, `
|
||||
<!doctype html>
|
||||
<html style="width: 100%; height: 100%; padding: 0; margin: 0;">
|
||||
<head>
|
||||
<meta name="viewport" content="width: display-width;">
|
||||
</head>
|
||||
<body style="width: 100%; padding: 0; margin: 0; background: #f3f4f6">
|
||||
<div style="width: 100%; font-family: 'Open Sans', sans-serif; text-rendering: optimizeLegibility">
|
||||
<div style="width: 600px; margin: 0 auto; text-align: justify;">
|
||||
<h1 style="font-size: 30px; text-align: center;">
|
||||
<img src="images/logo-full.svg" style="height: 75px;" alt="Vikunja"/>
|
||||
</h1>
|
||||
<div style="border: 1px solid #dbdbdb; -webkit-box-shadow: 0.3em 0.3em 0.8em #e6e6e6; box-shadow: 0.3em 0.3em 0.8em #e6e6e6; color: #4a4a4a; padding: 5px 25px; border-radius: 3px; background: #fff;">
|
||||
<p>
|
||||
Hi there,
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
This is a line
|
||||
</p>
|
||||
|
||||
<p>
|
||||
And another one
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<a href="https://example.com" title="The action"
|
||||
style="position: relative;text-decoration:none;display: block;border-radius: 4px;cursor: pointer;padding-bottom: 8px;padding-left: 14px;padding-right: 14px;padding-top: 8px;width:280px;margin:10px auto;text-align: center;white-space: nowrap;border: 0;text-transform: uppercase;font-size: 14px;font-weight: 700;-webkit-box-shadow: 0 3px 6px rgba(107,114,128,.12),0 2px 4px rgba(107,114,128,.1);box-shadow: 0 3px 6px rgba(107,114,128,.12),0 2px 4px rgba(107,114,128,.1);background-color: #1973ff;border-color: transparent;color: #fff;">
|
||||
The action
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<p>
|
||||
This should be an outro line
|
||||
</p>
|
||||
|
||||
<p>
|
||||
And one more, because why not?
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<p style="color: #9CA3AF;font-size:12px;border-top: 1px solid #dbdbdb;margin-top:20px;padding-top:20px;">
|
||||
If the button above doesn't work, copy the url below and paste it in your browsers address bar:<br/>
|
||||
https://example.com
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`, mailopts.HTMLMessage)
|
||||
}
|
55
pkg/notifications/main_test.go
Normal file
55
pkg/notifications/main_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"code.vikunja.io/api/pkg/log"
|
||||
"code.vikunja.io/api/pkg/mail"
|
||||
|
||||
"code.vikunja.io/api/pkg/config"
|
||||
)
|
||||
|
||||
// SetupTests initializes all db tests
|
||||
func SetupTests() {
|
||||
var err error
|
||||
x, err := db.CreateTestEngine()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = x.Sync2(&DatabaseNotification{})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMain is the main test function used to bootstrap the test env
|
||||
func TestMain(m *testing.M) {
|
||||
// Set default config
|
||||
config.InitDefaultConfig()
|
||||
// We need to set the root path even if we're not using the config, otherwise fixtures are not loaded correctly
|
||||
config.ServiceRootpath.Set(os.Getenv("VIKUNJA_SERVICE_ROOTPATH"))
|
||||
|
||||
SetupTests()
|
||||
|
||||
mail.Fake()
|
||||
os.Exit(m.Run())
|
||||
}
|
106
pkg/notifications/notification.go
Normal file
106
pkg/notifications/notification.go
Normal file
@ -0,0 +1,106 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
)
|
||||
|
||||
// Notification is a notification which can be sent via mail or db.
|
||||
type Notification interface {
|
||||
ToMail() *Mail
|
||||
ToDB() interface{}
|
||||
}
|
||||
|
||||
// Notifiable is an entity which can be notified. Usually a user.
|
||||
type Notifiable interface {
|
||||
// Should return the email address this notifiable has.
|
||||
RouteForMail() string
|
||||
// Should return the id of the notifiable entity
|
||||
RouteForDB() int64
|
||||
}
|
||||
|
||||
// DatabaseNotification represents a notification that was saved to the database
|
||||
type DatabaseNotification struct {
|
||||
// The unique, numeric id of this notification.
|
||||
ID int64 `xorm:"bigint autoincr not null unique pk" json:"id"`
|
||||
|
||||
// The ID of the notifiable this notification is associated with.
|
||||
NotifiableID int64 `xorm:"bigint not null" json:"-"`
|
||||
// The actual content of the notification.
|
||||
Notification interface{} `xorm:"json not null" json:"notification"`
|
||||
|
||||
// A timestamp when this notification was created. You cannot change this value.
|
||||
Created time.Time `xorm:"created not null" json:"created"`
|
||||
}
|
||||
|
||||
// TableName resolves to a better table name for notifications
|
||||
func (d *DatabaseNotification) TableName() string {
|
||||
return "notifications"
|
||||
}
|
||||
|
||||
// Notify notifies a notifiable of a notification
|
||||
func Notify(notifiable Notifiable, notification Notification) (err error) {
|
||||
|
||||
err = notifyMail(notifiable, notification)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return notifyDB(notifiable, notification)
|
||||
}
|
||||
|
||||
func notifyMail(notifiable Notifiable, notification Notification) error {
|
||||
mail := notification.ToMail()
|
||||
if mail == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
mail.To(notifiable.RouteForMail())
|
||||
|
||||
return SendMail(mail)
|
||||
}
|
||||
|
||||
func notifyDB(notifiable Notifiable, notification Notification) (err error) {
|
||||
|
||||
dbContent := notification.ToDB()
|
||||
if dbContent == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
content, err := json.Marshal(dbContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s := db.NewSession()
|
||||
dbNotification := &DatabaseNotification{
|
||||
NotifiableID: notifiable.RouteForDB(),
|
||||
Notification: content,
|
||||
}
|
||||
|
||||
_, err = s.Insert(dbNotification)
|
||||
if err != nil {
|
||||
_ = s.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return s.Commit()
|
||||
}
|
86
pkg/notifications/notification_test.go
Normal file
86
pkg/notifications/notification_test.go
Normal file
@ -0,0 +1,86 @@
|
||||
// Vikunja is a to-do list application to facilitate your life.
|
||||
// Copyright 2018-2021 Vikunja and contributors. All rights reserved.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public Licensee as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public Licensee for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public Licensee
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.vikunja.io/api/pkg/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type testNotification struct {
|
||||
Test string
|
||||
OtherValue int64
|
||||
}
|
||||
|
||||
// ToMail returns the mail notification for testNotification
|
||||
func (n *testNotification) ToMail() *Mail {
|
||||
return NewMail().
|
||||
Subject("Test Notification").
|
||||
Line(n.Test)
|
||||
}
|
||||
|
||||
// ToDB returns the testNotification notification in a format which can be saved in the db
|
||||
func (n *testNotification) ToDB() interface{} {
|
||||
data := make(map[string]interface{}, 2)
|
||||
data["test"] = n.Test
|
||||
data["other_value"] = n.OtherValue
|
||||
return data
|
||||
}
|
||||
|
||||
type testNotifiable struct {
|
||||
}
|
||||
|
||||
// RouteForMail routes a test notification for mail
|
||||
func (t *testNotifiable) RouteForMail() string {
|
||||
return "some@email.com"
|
||||
}
|
||||
|
||||
// RouteForDB routes a test notification for db
|
||||
func (t *testNotifiable) RouteForDB() int64 {
|
||||
return 42
|
||||
}
|
||||
|
||||
func TestNotify(t *testing.T) {
|
||||
tn := &testNotification{
|
||||
Test: "somethingsomething",
|
||||
OtherValue: 42,
|
||||
}
|
||||
tnf := &testNotifiable{}
|
||||
|
||||
err := Notify(tnf, tn)
|
||||
|
||||
assert.NoError(t, err)
|
||||
vals := map[string]interface{}{
|
||||
"notifiable_id": 42,
|
||||
"notification": "'{\"other_value\":42,\"test\":\"somethingsomething\"}'",
|
||||
}
|
||||
|
||||
if db.Type() == schemas.POSTGRES {
|
||||
vals["notification::jsonb"] = vals["notification"].(string) + "::jsonb"
|
||||
delete(vals, "notification")
|
||||
}
|
||||
|
||||
if db.Type() == schemas.SQLITE {
|
||||
vals["CAST(notification AS BLOB)"] = "CAST(" + vals["notification"].(string) + " AS BLOB)"
|
||||
delete(vals, "notification")
|
||||
}
|
||||
|
||||
db.AssertExists(t, "notifications", vals, true)
|
||||
}
|
Reference in New Issue
Block a user