Refactor template functions.
- Better template function shorthand substitution. - Make `UnsubscribeURL` a function consitent with TrackLink. This is a breaking change that makes the old `.UnsubscrbeURL` obsolete.
This commit is contained in:
parent
9a88c2ed7b
commit
4abcb2852c
|
@ -63,7 +63,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer" style="text-align: center;font-size: 12px;color: #888;">
|
<div class="footer" style="text-align: center;font-size: 12px;color: #888;">
|
||||||
<p>Don't want to receive these e-mails? <a href="{{ .UnsubscribeURL }}" style="color: #888;">Unsubscribe</a></p>
|
<p>Don't want to receive these e-mails? <a href="{{ UnsubscribeURL }}" style="color: #888;">Unsubscribe</a></p>
|
||||||
<p>Powered by <a href="https://listmonk.app" target="_blank" style="color: #888;">listmonk</a></p>
|
<p>Powered by <a href="https://listmonk.app" target="_blank" style="color: #888;">listmonk</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="gutter" style="padding: 30px;"> {{ TrackView }}</div>
|
<div class="gutter" style="padding: 30px;"> {{ TrackView }}</div>
|
||||||
|
|
2
main.go
2
main.go
|
@ -313,7 +313,7 @@ func main() {
|
||||||
FromEmail: app.Constants.FromEmail,
|
FromEmail: app.Constants.FromEmail,
|
||||||
|
|
||||||
// url.com/unsubscribe/{campaign_uuid}/{subscriber_uuid}
|
// url.com/unsubscribe/{campaign_uuid}/{subscriber_uuid}
|
||||||
UnsubscribeURL: fmt.Sprintf("%s/subscription/%%s/%%s", app.Constants.RootURL),
|
UnsubURL: fmt.Sprintf("%s/subscription/%%s/%%s", app.Constants.RootURL),
|
||||||
|
|
||||||
// url.com/link/{campaign_uuid}/{subscriber_uuid}/{link_uuid}
|
// url.com/link/{campaign_uuid}/{subscriber_uuid}/{link_uuid}
|
||||||
LinkTrackURL: fmt.Sprintf("%s/link/%%s/%%s/%%s", app.Constants.RootURL),
|
LinkTrackURL: fmt.Sprintf("%s/link/%%s/%%s/%%s", app.Constants.RootURL),
|
||||||
|
|
|
@ -59,12 +59,13 @@ type Manager struct {
|
||||||
|
|
||||||
// Message represents an active subscriber that's being processed.
|
// Message represents an active subscriber that's being processed.
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Campaign *models.Campaign
|
Campaign *models.Campaign
|
||||||
Subscriber *models.Subscriber
|
Subscriber *models.Subscriber
|
||||||
UnsubscribeURL string
|
Body []byte
|
||||||
Body []byte
|
|
||||||
from string
|
unsubURL string
|
||||||
to string
|
from string
|
||||||
|
to string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config has parameters for configuring the manager.
|
// Config has parameters for configuring the manager.
|
||||||
|
@ -74,7 +75,7 @@ type Config struct {
|
||||||
RequeueOnError bool
|
RequeueOnError bool
|
||||||
FromEmail string
|
FromEmail string
|
||||||
LinkTrackURL string
|
LinkTrackURL string
|
||||||
UnsubscribeURL string
|
UnsubURL string
|
||||||
ViewTrackURL string
|
ViewTrackURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,11 +105,12 @@ func New(cfg Config, src DataSource, notifCB models.AdminNotifCallback, l *log.L
|
||||||
// to message templates while they're compiled.
|
// to message templates while they're compiled.
|
||||||
func (m *Manager) NewMessage(c *models.Campaign, s *models.Subscriber) *Message {
|
func (m *Manager) NewMessage(c *models.Campaign, s *models.Subscriber) *Message {
|
||||||
return &Message{
|
return &Message{
|
||||||
from: c.FromEmail,
|
Campaign: c,
|
||||||
to: s.Email,
|
Subscriber: s,
|
||||||
Campaign: c,
|
|
||||||
Subscriber: s,
|
from: c.FromEmail,
|
||||||
UnsubscribeURL: fmt.Sprintf(m.cfg.UnsubscribeURL, c.UUID, s.UUID),
|
to: s.Email,
|
||||||
|
unsubURL: fmt.Sprintf(m.cfg.UnsubURL, c.UUID, s.UUID),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,12 +415,15 @@ func (m *Manager) sendNotif(c *models.Campaign, status, reason string) error {
|
||||||
// compiled campaign templates.
|
// compiled campaign templates.
|
||||||
func (m *Manager) TemplateFuncs(c *models.Campaign) template.FuncMap {
|
func (m *Manager) TemplateFuncs(c *models.Campaign) template.FuncMap {
|
||||||
return template.FuncMap{
|
return template.FuncMap{
|
||||||
"TrackLink": func(url, campUUID, subUUID string) string {
|
"TrackLink": func(url string, msg *Message) string {
|
||||||
return m.trackLink(url, campUUID, subUUID)
|
return m.trackLink(url, msg.Campaign.UUID, msg.Subscriber.UUID)
|
||||||
},
|
},
|
||||||
"TrackView": func(campUUID, subUUID string) template.HTML {
|
"TrackView": func(msg *Message) template.HTML {
|
||||||
return template.HTML(fmt.Sprintf(`<img src="%s" alt="" />`,
|
return template.HTML(fmt.Sprintf(`<img src="%s" alt="" />`,
|
||||||
fmt.Sprintf(m.cfg.ViewTrackURL, campUUID, subUUID)))
|
fmt.Sprintf(m.cfg.ViewTrackURL, msg.Campaign.UUID, msg.Subscriber.UUID)))
|
||||||
|
},
|
||||||
|
"UnsubscribeURL": func(msg *Message) string {
|
||||||
|
return msg.unsubURL
|
||||||
},
|
},
|
||||||
"Date": func(layout string) string {
|
"Date": func(layout string) string {
|
||||||
if layout == "" {
|
if layout == "" {
|
||||||
|
|
|
@ -48,16 +48,27 @@ const (
|
||||||
ContentTpl = "content"
|
ContentTpl = "content"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// regTplFunc represents contains a regular expression for wrapping and
|
||||||
|
// substituting a Go template function from the user's shorthand to a full
|
||||||
|
// function call.
|
||||||
|
type regTplFunc struct {
|
||||||
|
regExp *regexp.Regexp
|
||||||
|
replace string
|
||||||
|
}
|
||||||
|
|
||||||
// Regular expression for matching {{ Track "http://link.com" }} in the template
|
// Regular expression for matching {{ Track "http://link.com" }} in the template
|
||||||
// and substituting it with {{ Track "http://link.com" .Campaign.UUID .Subscriber.UUID }}
|
// and substituting it with {{ Track "http://link.com" .Campaign.UUID .Subscriber.UUID }}
|
||||||
// before compilation. This string gimmick is to make linking easier for users.
|
// before compilation. This string gimmick is to make linking easier for users.
|
||||||
var (
|
var regTplFuncs = []regTplFunc{
|
||||||
regexpLinkTag = regexp.MustCompile("{{(\\s+)?TrackLink\\s+?(\"|`)(.+?)(\"|`)(\\s+)?}}")
|
regTplFunc{
|
||||||
regexpLinkTagReplace = `{{ TrackLink "$3" .Campaign.UUID .Subscriber.UUID }}`
|
regExp: regexp.MustCompile("{{(\\s+)?TrackLink\\s+?(\"|`)(.+?)(\"|`)(\\s+)?}}"),
|
||||||
|
replace: `{{ TrackLink "$3" . }}`,
|
||||||
regexpViewTag = regexp.MustCompile(`{{(\s+)?TrackView(\s+)?}}`)
|
},
|
||||||
regexpViewTagReplace = `{{ TrackView .Campaign.UUID .Subscriber.UUID }}`
|
regTplFunc{
|
||||||
)
|
regExp: regexp.MustCompile(`{{(\s+)?(TrackView|UnsubscribeURL|OptinURL)(\s+)?}}`),
|
||||||
|
replace: `{{ $2 . }}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// AdminNotifCallback is a callback function that's called
|
// AdminNotifCallback is a callback function that's called
|
||||||
// when a campaign's status changes.
|
// when a campaign's status changes.
|
||||||
|
@ -264,17 +275,21 @@ func (camps Campaigns) LoadStats(stmt *sqlx.Stmt) error {
|
||||||
// template and sets the resultant template to Campaign.Tpl.
|
// template and sets the resultant template to Campaign.Tpl.
|
||||||
func (c *Campaign) CompileTemplate(f template.FuncMap) error {
|
func (c *Campaign) CompileTemplate(f template.FuncMap) error {
|
||||||
// Compile the base template.
|
// Compile the base template.
|
||||||
t := regexpLinkTag.ReplaceAllString(c.TemplateBody, regexpLinkTagReplace)
|
body := c.TemplateBody
|
||||||
t = regexpViewTag.ReplaceAllString(t, regexpViewTagReplace)
|
for _, r := range regTplFuncs {
|
||||||
baseTPL, err := template.New(BaseTpl).Funcs(f).Parse(t)
|
body = r.regExp.ReplaceAllString(body, r.replace)
|
||||||
|
}
|
||||||
|
baseTPL, err := template.New(BaseTpl).Funcs(f).Parse(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error compiling base template: %v", err)
|
return fmt.Errorf("error compiling base template: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile the campaign message.
|
// Compile the campaign message.
|
||||||
t = regexpLinkTag.ReplaceAllString(c.Body, regexpLinkTagReplace)
|
body = c.Body
|
||||||
t = regexpViewTag.ReplaceAllString(t, regexpViewTagReplace)
|
for _, r := range regTplFuncs {
|
||||||
msgTpl, err := template.New(ContentTpl).Funcs(f).Parse(t)
|
body = r.regExp.ReplaceAllString(body, r.replace)
|
||||||
|
}
|
||||||
|
msgTpl, err := template.New(ContentTpl).Funcs(f).Parse(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error compiling message: %v", err)
|
return fmt.Errorf("error compiling message: %v", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue