feat: embed the vikunja logo as inline attachment
This commit is contained in:
parent
30e0e98f77
commit
f4f8450d16
8 changed files with 22 additions and 7 deletions
2
go.mod
2
go.mod
|
@ -87,4 +87,4 @@ replace (
|
||||||
gopkg.in/fsnotify.v1 => github.com/kolaente/fsnotify v1.4.10-0.20200411160148-1bc3c8ff4048 // See https://github.com/fsnotify/fsnotify/issues/328 and https://github.com/golang/go/issues/26904
|
gopkg.in/fsnotify.v1 => github.com/kolaente/fsnotify v1.4.10-0.20200411160148-1bc3c8ff4048 // See https://github.com/fsnotify/fsnotify/issues/328 and https://github.com/golang/go/issues/26904
|
||||||
)
|
)
|
||||||
|
|
||||||
go 1.15
|
go 1.16
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
"code.vikunja.io/api/pkg/log"
|
"code.vikunja.io/api/pkg/log"
|
||||||
"code.vikunja.io/api/pkg/version"
|
"code.vikunja.io/api/pkg/version"
|
||||||
|
"io"
|
||||||
|
|
||||||
"github.com/wneessen/go-mail"
|
"github.com/wneessen/go-mail"
|
||||||
)
|
)
|
||||||
|
@ -34,6 +35,7 @@ type Opts struct {
|
||||||
ContentType ContentType
|
ContentType ContentType
|
||||||
Boundary string
|
Boundary string
|
||||||
Headers []*header
|
Headers []*header
|
||||||
|
Embeds map[string]io.Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContentType represents mail content types
|
// ContentType represents mail content types
|
||||||
|
@ -78,10 +80,15 @@ func getMessage(opts *Opts) *mail.Msg {
|
||||||
_ = m.From(opts.From)
|
_ = m.From(opts.From)
|
||||||
_ = m.To(opts.To)
|
_ = m.To(opts.To)
|
||||||
m.Subject(opts.Subject)
|
m.Subject(opts.Subject)
|
||||||
|
|
||||||
for _, h := range opts.Headers {
|
for _, h := range opts.Headers {
|
||||||
m.SetHeader(h.Field, h.Content)
|
m.SetHeader(h.Field, h.Content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name, content := range opts.Embeds {
|
||||||
|
m.EmbedReader(name, content)
|
||||||
|
}
|
||||||
|
|
||||||
switch opts.ContentType {
|
switch opts.ContentType {
|
||||||
case ContentTypePlain:
|
case ContentTypePlain:
|
||||||
m.SetBodyString("text/plain", opts.Message)
|
m.SetBodyString("text/plain", opts.Message)
|
||||||
|
|
|
@ -242,12 +242,12 @@ func convertTrelloDataToVikunja(trelloData []*trello.Board, token string) (fullV
|
||||||
log.Debugf("[Trello Migration] Converted label %s from card %s", label.ID, card.ID)
|
log.Debugf("[Trello Migration] Converted label %s from card %s", label.ID, card.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachments
|
// Embeds
|
||||||
if len(card.Attachments) > 0 {
|
if len(card.Attachments) > 0 {
|
||||||
log.Debugf("[Trello Migration] Downloading %d card attachments from card %s", len(card.Attachments), card.ID)
|
log.Debugf("[Trello Migration] Downloading %d card attachments from card %s", len(card.Attachments), card.ID)
|
||||||
}
|
}
|
||||||
for _, attachment := range card.Attachments {
|
for _, attachment := range card.Attachments {
|
||||||
if attachment.MimeType == "" { // Attachments can also be not downloadable - the mime type is empty in that case.
|
if attachment.MimeType == "" { // Embeds can also be not downloadable - the mime type is empty in that case.
|
||||||
log.Debugf("[Trello Migration] Attachment %s does not have a mime type, not downloading", attachment.ID)
|
log.Debugf("[Trello Migration] Attachment %s does not have a mime type, not downloading", attachment.ID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,7 @@ func convertListForFolder(listID int, list *list, content *wunderlistContents) (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachments
|
// Embeds
|
||||||
for _, f := range content.files {
|
for _, f := range content.files {
|
||||||
if f.TaskID == t.ID {
|
if f.TaskID == t.ID {
|
||||||
// Download the attachment and put it in the file
|
// Download the attachment and put it in the file
|
||||||
|
|
BIN
pkg/notifications/logo.png
Normal file
BIN
pkg/notifications/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
|
@ -18,7 +18,9 @@ package notifications
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
templatehtml "html/template"
|
templatehtml "html/template"
|
||||||
|
"io"
|
||||||
templatetext "text/template"
|
templatetext "text/template"
|
||||||
|
|
||||||
"code.vikunja.io/api/pkg/config"
|
"code.vikunja.io/api/pkg/config"
|
||||||
|
@ -49,7 +51,7 @@ const mailTemplateHTML = `
|
||||||
<div style="width: 100%; font-family: 'Open Sans', sans-serif; text-rendering: optimizeLegibility">
|
<div style="width: 100%; font-family: 'Open Sans', sans-serif; text-rendering: optimizeLegibility">
|
||||||
<div style="width: 600px; margin: 0 auto; text-align: justify;">
|
<div style="width: 600px; margin: 0 auto; text-align: justify;">
|
||||||
<h1 style="font-size: 30px; text-align: center;">
|
<h1 style="font-size: 30px; text-align: center;">
|
||||||
<img src="{{.FrontendURL}}images/logo-full.svg" style="height: 75px;" alt="Vikunja"/>
|
<img src="cid:logo.png" style="height: 75px;" alt="Vikunja"/>
|
||||||
</h1>
|
</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;">
|
<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>
|
<p>
|
||||||
|
@ -84,6 +86,9 @@ const mailTemplateHTML = `
|
||||||
</html>
|
</html>
|
||||||
`
|
`
|
||||||
|
|
||||||
|
//go:embed logo.png
|
||||||
|
var logo []byte
|
||||||
|
|
||||||
// RenderMail takes a precomposed mail message and renders it into a ready to send mail.Opts object
|
// 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) {
|
func RenderMail(m *Mail) (mailOpts *mail.Opts, err error) {
|
||||||
|
|
||||||
|
@ -155,6 +160,9 @@ func RenderMail(m *Mail) (mailOpts *mail.Opts, err error) {
|
||||||
Message: plainContent.String(),
|
Message: plainContent.String(),
|
||||||
HTMLMessage: htmlContent.String(),
|
HTMLMessage: htmlContent.String(),
|
||||||
Boundary: boundary,
|
Boundary: boundary,
|
||||||
|
Embeds: map[string]io.Reader{
|
||||||
|
"logo.png": bytes.NewBuffer(logo),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return mailOpts, nil
|
return mailOpts, nil
|
||||||
|
|
|
@ -36,7 +36,7 @@ import (
|
||||||
// @Param id path int true "Task ID"
|
// @Param id path int true "Task ID"
|
||||||
// @Param files formData string true "The file, as multipart form file. You can pass multiple."
|
// @Param files formData string true "The file, as multipart form file. You can pass multiple."
|
||||||
// @Security JWTKeyAuth
|
// @Security JWTKeyAuth
|
||||||
// @Success 200 {object} models.Message "Attachments were uploaded successfully."
|
// @Success 200 {object} models.Message "Embeds were uploaded successfully."
|
||||||
// @Failure 403 {object} models.Message "No access to the task."
|
// @Failure 403 {object} models.Message "No access to the task."
|
||||||
// @Failure 404 {object} models.Message "The task does not exist."
|
// @Failure 404 {object} models.Message "The task does not exist."
|
||||||
// @Failure 500 {object} models.Message "Internal error"
|
// @Failure 500 {object} models.Message "Internal error"
|
||||||
|
|
|
@ -4791,7 +4791,7 @@ const docTemplate = `{
|
||||||
],
|
],
|
||||||
"responses": {
|
"responses": {
|
||||||
"200": {
|
"200": {
|
||||||
"description": "Attachments were uploaded successfully.",
|
"description": "Embeds were uploaded successfully.",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/models.Message"
|
"$ref": "#/definitions/models.Message"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue