Browse Source

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.
Kailash Nadh 5 years ago
parent
commit
4abcb2852c
4 changed files with 51 additions and 31 deletions
  1. 1 1
      email-templates/default.tpl
  2. 1 1
      main.go
  3. 21 16
      manager/manager.go
  4. 28 13
      models/models.go

+ 1 - 1
email-templates/default.tpl

@@ -63,7 +63,7 @@
     </div>
     
     <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>
     </div>
     <div class="gutter" style="padding: 30px;">&nbsp;{{ TrackView }}</div>

+ 1 - 1
main.go

@@ -313,7 +313,7 @@ func main() {
 		FromEmail:     app.Constants.FromEmail,
 
 		// 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}
 		LinkTrackURL: fmt.Sprintf("%s/link/%%s/%%s/%%s", app.Constants.RootURL),

+ 21 - 16
manager/manager.go

@@ -59,12 +59,13 @@ type Manager struct {
 
 // Message represents an active subscriber that's being processed.
 type Message struct {
-	Campaign       *models.Campaign
-	Subscriber     *models.Subscriber
-	UnsubscribeURL string
-	Body           []byte
-	from           string
-	to             string
+	Campaign   *models.Campaign
+	Subscriber *models.Subscriber
+	Body       []byte
+
+	unsubURL string
+	from     string
+	to       string
 }
 
 // Config has parameters for configuring the manager.
@@ -74,7 +75,7 @@ type Config struct {
 	RequeueOnError bool
 	FromEmail      string
 	LinkTrackURL   string
-	UnsubscribeURL string
+	UnsubURL       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.
 func (m *Manager) NewMessage(c *models.Campaign, s *models.Subscriber) *Message {
 	return &Message{
-		from:           c.FromEmail,
-		to:             s.Email,
-		Campaign:       c,
-		Subscriber:     s,
-		UnsubscribeURL: fmt.Sprintf(m.cfg.UnsubscribeURL, c.UUID, s.UUID),
+		Campaign:   c,
+		Subscriber: s,
+
+		from:     c.FromEmail,
+		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.
 func (m *Manager) TemplateFuncs(c *models.Campaign) template.FuncMap {
 	return template.FuncMap{
-		"TrackLink": func(url, campUUID, subUUID string) string {
-			return m.trackLink(url, campUUID, subUUID)
+		"TrackLink": func(url string, msg *Message) string {
+			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="" />`,
-				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 {
 			if layout == "" {

+ 28 - 13
models/models.go

@@ -48,16 +48,27 @@ const (
 	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
 // and substituting it with {{ Track "http://link.com" .Campaign.UUID .Subscriber.UUID }}
 // before compilation. This string gimmick is to make linking easier for users.
-var (
-	regexpLinkTag        = regexp.MustCompile("{{(\\s+)?TrackLink\\s+?(\"|`)(.+?)(\"|`)(\\s+)?}}")
-	regexpLinkTagReplace = `{{ TrackLink "$3" .Campaign.UUID .Subscriber.UUID }}`
-
-	regexpViewTag        = regexp.MustCompile(`{{(\s+)?TrackView(\s+)?}}`)
-	regexpViewTagReplace = `{{ TrackView .Campaign.UUID .Subscriber.UUID }}`
-)
+var regTplFuncs = []regTplFunc{
+	regTplFunc{
+		regExp:  regexp.MustCompile("{{(\\s+)?TrackLink\\s+?(\"|`)(.+?)(\"|`)(\\s+)?}}"),
+		replace: `{{ TrackLink "$3" . }}`,
+	},
+	regTplFunc{
+		regExp:  regexp.MustCompile(`{{(\s+)?(TrackView|UnsubscribeURL|OptinURL)(\s+)?}}`),
+		replace: `{{ $2 . }}`,
+	},
+}
 
 // AdminNotifCallback is a callback function that's called
 // 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.
 func (c *Campaign) CompileTemplate(f template.FuncMap) error {
 	// Compile the base template.
-	t := regexpLinkTag.ReplaceAllString(c.TemplateBody, regexpLinkTagReplace)
-	t = regexpViewTag.ReplaceAllString(t, regexpViewTagReplace)
-	baseTPL, err := template.New(BaseTpl).Funcs(f).Parse(t)
+	body := c.TemplateBody
+	for _, r := range regTplFuncs {
+		body = r.regExp.ReplaceAllString(body, r.replace)
+	}
+	baseTPL, err := template.New(BaseTpl).Funcs(f).Parse(body)
 	if err != nil {
 		return fmt.Errorf("error compiling base template: %v", err)
 	}
 
 	// Compile the campaign message.
-	t = regexpLinkTag.ReplaceAllString(c.Body, regexpLinkTagReplace)
-	t = regexpViewTag.ReplaceAllString(t, regexpViewTagReplace)
-	msgTpl, err := template.New(ContentTpl).Funcs(f).Parse(t)
+	body = c.Body
+	for _, r := range regTplFuncs {
+		body = r.regExp.ReplaceAllString(body, r.replace)
+	}
+	msgTpl, err := template.New(ContentTpl).Funcs(f).Parse(body)
 	if err != nil {
 		return fmt.Errorf("error compiling message: %v", err)
 	}