2021-02-07 22:05:09 +01:00
|
|
|
// 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"
|
2022-06-19 16:21:11 +02:00
|
|
|
_ "embed"
|
2021-02-07 22:05:09 +01:00
|
|
|
templatehtml "html/template"
|
2022-06-19 16:21:11 +02:00
|
|
|
"io"
|
2021-02-07 22:05:09 +01:00
|
|
|
templatetext "text/template"
|
|
|
|
|
|
|
|
"code.vikunja.io/api/pkg/config"
|
|
|
|
"code.vikunja.io/api/pkg/mail"
|
|
|
|
"code.vikunja.io/api/pkg/utils"
|
2021-04-18 15:32:02 +02:00
|
|
|
|
|
|
|
"github.com/yuin/goldmark"
|
2021-02-07 22:05:09 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
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;">
|
2022-06-19 16:21:11 +02:00
|
|
|
<img src="cid:logo.png" style="height: 75px;" alt="Vikunja"/>
|
2021-02-07 22:05:09 +01:00
|
|
|
</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>
|
|
|
|
|
2021-04-18 15:32:02 +02:00
|
|
|
{{ range $line := .IntroLinesHTML}}
|
|
|
|
{{ $line }}
|
2021-02-07 22:05:09 +01:00
|
|
|
{{ 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}}
|
|
|
|
|
2021-04-18 15:32:02 +02:00
|
|
|
{{ range $line := .OutroLinesHTML}}
|
|
|
|
{{ $line }}
|
2021-02-07 22:05:09 +01:00
|
|
|
{{ 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>
|
|
|
|
`
|
|
|
|
|
2022-06-19 16:21:11 +02:00
|
|
|
//go:embed logo.png
|
|
|
|
var logo []byte
|
|
|
|
|
2021-02-07 22:05:09 +01:00
|
|
|
// 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()
|
|
|
|
|
2021-04-18 15:32:02 +02:00
|
|
|
var introLinesHTML []templatehtml.HTML
|
|
|
|
for _, line := range m.introLines {
|
|
|
|
md := []byte(templatehtml.HTMLEscapeString(line))
|
|
|
|
var buf bytes.Buffer
|
|
|
|
err = goldmark.Convert(md, &buf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
//#nosec - the html is escaped few lines before
|
|
|
|
introLinesHTML = append(introLinesHTML, templatehtml.HTML(buf.String()))
|
|
|
|
}
|
|
|
|
data["IntroLinesHTML"] = introLinesHTML
|
|
|
|
|
|
|
|
var outroLinesHTML []templatehtml.HTML
|
|
|
|
for _, line := range m.outroLines {
|
|
|
|
md := []byte(templatehtml.HTMLEscapeString(line))
|
|
|
|
var buf bytes.Buffer
|
|
|
|
err = goldmark.Convert(md, &buf)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
//#nosec - the html is escaped few lines before
|
|
|
|
outroLinesHTML = append(outroLinesHTML, templatehtml.HTML(buf.String()))
|
|
|
|
}
|
|
|
|
data["OutroLinesHTML"] = outroLinesHTML
|
|
|
|
|
2021-02-07 22:05:09 +01:00
|
|
|
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,
|
2022-06-19 16:21:11 +02:00
|
|
|
Embeds: map[string]io.Reader{
|
|
|
|
"logo.png": bytes.NewBuffer(logo),
|
|
|
|
},
|
2021-02-07 22:05:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return mailOpts, nil
|
|
|
|
}
|