1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

chore: use partial includes in mail templates to avoid code duplication

This commit is contained in:
Ferdinand Mütsch 2021-08-08 12:33:04 +02:00
parent 69f5d510dc
commit 87fadf46f7
12 changed files with 211 additions and 515 deletions

View File

@ -2,27 +2,24 @@ package routes
import ( import (
"fmt" "fmt"
"github.com/muety/wakapi/views"
"html/template" "html/template"
"io/fs"
"io/ioutil"
"net/http" "net/http"
"path"
"strings" "strings"
"github.com/muety/wakapi/config" "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models" "github.com/muety/wakapi/models"
"github.com/muety/wakapi/utils" "github.com/muety/wakapi/utils"
"github.com/muety/wakapi/views"
) )
func Init() {
loadTemplates()
}
type action func(w http.ResponseWriter, r *http.Request) (int, string, string) type action func(w http.ResponseWriter, r *http.Request) (int, string, string)
var templates map[string]*template.Template var templates map[string]*template.Template
func Init() {
loadTemplates()
}
func DefaultTemplateFuncs() template.FuncMap { func DefaultTemplateFuncs() template.FuncMap {
return template.FuncMap{ return template.FuncMap{
"json": utils.Json, "json": utils.Json,
@ -58,44 +55,6 @@ func DefaultTemplateFuncs() template.FuncMap {
} }
} }
func loadTemplates() {
tpls := template.New("").Funcs(DefaultTemplateFuncs())
templates = make(map[string]*template.Template)
// Use local file system when in 'dev' environment, go embed file system otherwise
templateFs := config.ChooseFS("views", views.TemplateFiles)
files, err := fs.ReadDir(templateFs, ".")
if err != nil {
panic(err)
}
for _, file := range files {
tplName := file.Name()
if file.IsDir() || path.Ext(tplName) != ".html" {
continue
}
templateFile, err := templateFs.Open(tplName)
if err != nil {
panic(err)
}
templateData, err := ioutil.ReadAll(templateFile)
if err != nil {
panic(err)
}
templateFile.Close()
tpl, err := tpls.New(tplName).Parse(string(templateData))
if err != nil {
panic(err)
}
templates[tplName] = tpl
}
}
func typeName(t uint8) string { func typeName(t uint8) string {
if t == models.SummaryProject { if t == models.SummaryProject {
return "project" return "project"
@ -118,6 +77,16 @@ func typeName(t uint8) string {
return "unknown" return "unknown"
} }
func loadTemplates() {
// Use local file system when in 'dev' environment, go embed file system otherwise
templateFs := config.ChooseFS("views", views.TemplateFiles)
if tpls, err := utils.LoadTemplates(templateFs, DefaultTemplateFuncs()); err == nil {
templates = tpls
} else {
panic(err)
}
}
func defaultErrorRedirectTarget() string { func defaultErrorRedirectTarget() string {
return fmt.Sprintf("%s/?error=unauthorized", config.Get().Server.BasePath) return fmt.Sprintf("%s/?error=unauthorized", config.Get().Server.BasePath)
} }

View File

@ -7,12 +7,10 @@ import (
"github.com/muety/wakapi/routes" "github.com/muety/wakapi/routes"
"github.com/muety/wakapi/services" "github.com/muety/wakapi/services"
"github.com/muety/wakapi/utils" "github.com/muety/wakapi/utils"
"html/template" "github.com/muety/wakapi/views/mail"
"io/ioutil"
"time" "time"
conf "github.com/muety/wakapi/config" conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/views"
) )
const ( const (
@ -33,6 +31,7 @@ type SendingService interface {
type MailService struct { type MailService struct {
config *conf.Config config *conf.Config
sendingService SendingService sendingService SendingService
templates utils.TemplateMap
} }
func NewMailService() services.IMailService { func NewMailService() services.IMailService {
@ -49,11 +48,18 @@ func NewMailService() services.IMailService {
} }
} }
return &MailService{sendingService: sendingService, config: config} // Use local file system when in 'dev' environment, go embed file system otherwise
templateFs := conf.ChooseFS("views/mail", mail.TemplateFiles)
templates, err := utils.LoadTemplates(templateFs, routes.DefaultTemplateFuncs())
if err != nil {
panic(err)
}
return &MailService{sendingService: sendingService, config: config, templates: templates}
} }
func (m *MailService) SendPasswordReset(recipient *models.User, resetLink string) error { func (m *MailService) SendPasswordReset(recipient *models.User, resetLink string) error {
tpl, err := getPasswordResetTemplate(PasswordResetTplData{ResetLink: resetLink}) tpl, err := m.getPasswordResetTemplate(PasswordResetTplData{ResetLink: resetLink})
if err != nil { if err != nil {
return err return err
} }
@ -67,7 +73,7 @@ func (m *MailService) SendPasswordReset(recipient *models.User, resetLink string
} }
func (m *MailService) SendWakatimeFailureNotification(recipient *models.User, numFailures int) error { func (m *MailService) SendWakatimeFailureNotification(recipient *models.User, numFailures int) error {
tpl, err := getWakatimeFailureNotificationTemplate(WakatimeFailureNotificationNotificationTplData{ tpl, err := m.getWakatimeFailureNotificationTemplate(WakatimeFailureNotificationNotificationTplData{
PublicUrl: m.config.Server.PublicUrl, PublicUrl: m.config.Server.PublicUrl,
NumFailures: numFailures, NumFailures: numFailures,
}) })
@ -84,7 +90,7 @@ func (m *MailService) SendWakatimeFailureNotification(recipient *models.User, nu
} }
func (m *MailService) SendImportNotification(recipient *models.User, duration time.Duration, numHeartbeats int) error { func (m *MailService) SendImportNotification(recipient *models.User, duration time.Duration, numHeartbeats int) error {
tpl, err := getImportNotificationTemplate(ImportNotificationTplData{ tpl, err := m.getImportNotificationTemplate(ImportNotificationTplData{
PublicUrl: m.config.Server.PublicUrl, PublicUrl: m.config.Server.PublicUrl,
Duration: fmt.Sprintf("%.0f seconds", duration.Seconds()), Duration: fmt.Sprintf("%.0f seconds", duration.Seconds()),
NumHeartbeats: numHeartbeats, NumHeartbeats: numHeartbeats,
@ -102,7 +108,7 @@ func (m *MailService) SendImportNotification(recipient *models.User, duration ti
} }
func (m *MailService) SendReport(recipient *models.User, report *models.Report) error { func (m *MailService) SendReport(recipient *models.User, report *models.Report) error {
tpl, err := getReportTemplate(ReportTplData{report}) tpl, err := m.getReportTemplate(ReportTplData{report})
if err != nil { if err != nil {
return err return err
} }
@ -115,68 +121,38 @@ func (m *MailService) SendReport(recipient *models.User, report *models.Report)
return m.sendingService.Send(mail) return m.sendingService.Send(mail)
} }
func getPasswordResetTemplate(data PasswordResetTplData) (*bytes.Buffer, error) { func (m *MailService) getPasswordResetTemplate(data PasswordResetTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNamePasswordReset)
if err != nil {
return nil, err
}
var rendered bytes.Buffer var rendered bytes.Buffer
if err := tpl.Execute(&rendered, data); err != nil { if err := m.templates[m.fmtName(tplNamePasswordReset)].Execute(&rendered, data); err != nil {
return nil, err return nil, err
} }
return &rendered, nil return &rendered, nil
} }
func getWakatimeFailureNotificationTemplate(data WakatimeFailureNotificationNotificationTplData) (*bytes.Buffer, error) { func (m *MailService) getWakatimeFailureNotificationTemplate(data WakatimeFailureNotificationNotificationTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNameWakatimeFailureNotification)
if err != nil {
return nil, err
}
var rendered bytes.Buffer var rendered bytes.Buffer
if err := tpl.Execute(&rendered, data); err != nil { if err := m.templates[m.fmtName(tplNameWakatimeFailureNotification)].Execute(&rendered, data); err != nil {
return nil, err return nil, err
} }
return &rendered, nil return &rendered, nil
} }
func getImportNotificationTemplate(data ImportNotificationTplData) (*bytes.Buffer, error) { func (m *MailService) getImportNotificationTemplate(data ImportNotificationTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNameImportNotification)
if err != nil {
return nil, err
}
var rendered bytes.Buffer var rendered bytes.Buffer
if err := tpl.Execute(&rendered, data); err != nil { if err := m.templates[m.fmtName(tplNameImportNotification)].Execute(&rendered, data); err != nil {
return nil, err return nil, err
} }
return &rendered, nil return &rendered, nil
} }
func getReportTemplate(data ReportTplData) (*bytes.Buffer, error) { func (m *MailService) getReportTemplate(data ReportTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNameReport)
if err != nil {
return nil, err
}
var rendered bytes.Buffer var rendered bytes.Buffer
if err := tpl.Execute(&rendered, data); err != nil { if err := m.templates[m.fmtName(tplNameReport)].Execute(&rendered, data); err != nil {
return nil, err return nil, err
} }
return &rendered, nil return &rendered, nil
} }
func loadTemplate(tplName string) (*template.Template, error) { func (m *MailService) fmtName(name string) string {
tplFile, err := views.TemplateFiles.Open(fmt.Sprintf("mail/%s.tpl.html", tplName)) return fmt.Sprintf("%s.tpl.html", name)
if err != nil {
return nil, err
}
defer tplFile.Close()
tplData, err := ioutil.ReadAll(tplFile)
if err != nil {
return nil, err
}
return template.
New(tplName).
Funcs(routes.DefaultTemplateFuncs()).
Parse(string(tplData))
} }

View File

@ -3,8 +3,13 @@ package utils
import ( import (
"encoding/json" "encoding/json"
"html/template" "html/template"
"io/fs"
"io/ioutil"
"path"
) )
type TemplateMap map[string]*template.Template
func Json(data interface{}) template.JS { func Json(data interface{}) template.JS {
d, err := json.Marshal(data) d, err := json.Marshal(data)
if err != nil { if err != nil {
@ -19,3 +24,40 @@ func ToRunes(s string) (r []string) {
} }
return r return r
} }
func LoadTemplates(templateFs fs.FS, funcs template.FuncMap) (TemplateMap, error) {
tpls := template.New("").Funcs(funcs)
templates := make(map[string]*template.Template)
files, err := fs.ReadDir(templateFs, ".")
if err != nil {
return nil, err
}
for _, file := range files {
tplName := file.Name()
if file.IsDir() || path.Ext(tplName) != ".html" {
continue
}
templateFile, err := templateFs.Open(tplName)
if err != nil {
return nil, err
}
templateData, err := ioutil.ReadAll(templateFile)
if err != nil {
return nil, err
}
templateFile.Close()
tpl, err := tpls.New(tplName).Parse(string(templateData))
if err != nil {
return nil, err
}
templates[tplName] = tpl
}
return templates, nil
}

88
views/mail/head.tpl.html Normal file
View File

@ -0,0 +1,88 @@
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wakapi</title>
<style>
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #047857 !important;
}
.btn-primary a:hover {
background-color: #047857 !important;
border-color: #047857 !important;
}
}
</style>
</head>

View File

@ -1,107 +1,14 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wakapi Data Import Finished</title>
<style>
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* ------------------------------------- {{ template "head.tpl.html" . }}
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #047857 !important;
}
.btn-primary a:hover {
background-color: #047857 !important;
border-color: #047857 !important;
}
}
</style>
</head>
<body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"> <body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;"> <table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;">
<tr> <tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;"> <td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "theader.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;"> <div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;"> <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
@ -134,15 +41,7 @@
</tr> </tr>
</table> </table>
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "tfooter.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://wakapi.dev" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">Wakapi.dev</a>.
</td>
</tr>
</table>
</div>
</div> </div>
</td> </td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>

6
views/mail/mail.go Normal file
View File

@ -0,0 +1,6 @@
package mail
import "embed"
//go:embed *.html
var TemplateFiles embed.FS

View File

@ -1,107 +1,14 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wakapi Report</title>
<style>
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* ------------------------------------- {{ template "head.tpl.html" . }}
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #047857 !important;
}
.btn-primary a:hover {
background-color: #047857 !important;
border-color: #047857 !important;
}
}
</style>
</head>
<body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"> <body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;"> <table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;">
<tr> <tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;"> <td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "theader.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;"> <div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;"> <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
@ -180,15 +87,8 @@
</td> </td>
</tr> </tr>
</table> </table>
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;"> {{ template "tfooter.tpl.html" . }}
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://wakapi.dev" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">Wakapi.dev</a>.
</td>
</tr>
</table>
</div>
</div> </div>
</td> </td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>

View File

@ -1,107 +1,14 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wakapi Reset Password</title>
<style>
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* ------------------------------------- {{ template "head.tpl.html" . }}
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #047857 !important;
}
.btn-primary a:hover {
background-color: #047857 !important;
border-color: #047857 !important;
}
}
</style>
</head>
<body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"> <body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;"> <table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;">
<tr> <tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;"> <td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "theader.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;"> <div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;"> <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
@ -135,15 +42,7 @@
</tr> </tr>
</table> </table>
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "tfooter.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://wakapi.dev" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">Wakapi.dev</a>.
</td>
</tr>
</table>
</div>
</div> </div>
</td> </td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>

View File

@ -0,0 +1,9 @@
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://wakapi.dev" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">Wakapi.dev</a>.
</td>
</tr>
</table>
</div>

View File

@ -0,0 +1,9 @@
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>

View File

@ -1,107 +1,14 @@
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wakapi WakaTime Connection Failure</title>
<style>
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* ------------------------------------- {{ template "head.tpl.html" . }}
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #047857 !important;
}
.btn-primary a:hover {
background-color: #047857 !important;
border-color: #047857 !important;
}
}
</style>
</head>
<body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;"> <body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;"> <table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;">
<tr> <tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;"> <td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "theader.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;"> <div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;"> <table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
@ -134,15 +41,7 @@
</tr> </tr>
</table> </table>
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;"> {{ template "tfooter.tpl.html" . }}
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://wakapi.dev" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">Wakapi.dev</a>.
</td>
</tr>
</table>
</div>
</div> </div>
</td> </td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td> <td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>

View File

@ -2,5 +2,5 @@ package views
import "embed" import "embed"
//go:embed *.html mail/*.html //go:embed *.html
var TemplateFiles embed.FS var TemplateFiles embed.FS