Skip to content
Snippets Groups Projects
Commit 7cd21618 authored by Tom Robinson's avatar Tom Robinson
Browse files

Refactor email mustache templates to use partials, for use in pulse email (and password reset)

parent 9320236b
No related branches found
No related tags found
No related merge requests found
</div>
<div style="padding: 3em; text-align: center; color: #CCCCCC; font-size: small;">"{{quotation}}"<br/>- {{quotationAuthor}}</div>
</body>
</html>
<html>
<body style="font-family: 'Helvetica Neue', Helvetica, sans-serif; font-size: 0.875rem; color: #727479; padding-top: 2em; padding-bottom: 1em; background-color: #F9FBFC; ">
<div style="padding-bottom: 2em; text-align: center;">
<img width="32" height="40" src="http://static.metabase.com/email_logo.png"/>
</div>
<div style="margin: 0 auto; max-width: 560px; padding: 2em 4em 2em 4em; color: #9F9F9F; border: 1px solid #dddddd; background-color: #FFFFFF; box-shadow: 0 1px 2px rgba(0, 0, 0, .08);">
......@@ -4,18 +4,21 @@
(:require [hiccup.core :refer [html]]
[metabase.email :as email]
[metabase.models.setting :as setting]
[metabase.pulse :as p :refer [render-pulse-section]]
[metabase.util :as u]
[metabase.util.quotation :as q]
[stencil.core :as stencil]))
[stencil.core :as stencil]
[stencil.loader :as loader]))
;; NOTE: uncomment this in development to disable template caching
;; (loader/set-cache (clojure.core.cache/ttl-cache-factory {} :ttl 0))
;;; ### Public Interface
(defn send-new-user-email
"Format and Send an welcome email for newly created users."
[invited invitor join-url]
(let [tmpl (slurp (clojure.java.io/resource "metabase/email/new_user_invite.html"))
data-quote (rand-nth q/quotations)
(let [data-quote (rand-nth q/quotations)
company (or (setting/get :site-name)
"Unknown")
message-body (->> {:invitedName (:first_name invited)
......@@ -26,7 +29,7 @@
:quotation (:quote data-quote)
:quotationAuthor (:author data-quote)
:today (u/format-date "MMM'&nbsp;'dd,'&nbsp;'yyyy" (System/currentTimeMillis))}
(stencil/render-string tmpl))]
(stencil/render-file "metabase/email/new_user_invite"))]
(email/send-message
:subject (str "You're invited to join " company "'s Metabase")
:recipients [(:email invited)]
......@@ -40,13 +43,42 @@
(u/is-email? email)
(string? hostname)
(string? password-reset-url)]}
(let [message-body (html [:html
[:body
[:p (str (format "You're receiving this e-mail because you or someone else has requested a password for your user account at %s. " hostname)
"It can be safely ignored if you did not request a password reset. Click the link below to reset your password.")]
[:p [:a {:href password-reset-url} password-reset-url]]]])]
(let [message-body (->> {:hostname hostname
:passwordResetUrl password-reset-url}
(stencil/render-file "metabase/email/password_reset"))]
(email/send-message
:subject "[Metabase] Password Reset Request"
:recipients [email]
:message-type :html
:message message-body)))
;; HACK: temporary workaround to postal requiring a file as the attachment
(defn- write-byte-array-to-temp-file
[img-bytes]
(let [file (java.io.File/createTempFile "metabase_pulse_image_" ".png")
fos (new java.io.FileOutputStream file)]
(.deleteOnExit file)
(.write fos img-bytes)
(.close fos)
file))
(defn render-pulse-email
"Take a pulse object and list of results, returns an array of attachment objects for an email"
[pulse results]
(let [images (atom [])
render-img (fn [bytes] (reset! images (conj @images bytes)) (str "cid:IMAGE_" (-> @images count dec)))
body (apply vector :div (mapv (partial render-pulse-section render-img) results))
data-quote (rand-nth q/quotations)
message-body (->> {:pulse (html body)
:pulseName (:name pulse)
:sectionStype p/section-style
:colorGrey4 p/color-grey-4
:quotation (:quote data-quote)
:quotationAuthor (:author data-quote)}
(stencil/render-file "metabase/email/pulse"))]
(apply vector {:type "text/html" :content message-body}
(map-indexed (fn [idx bytes] {:type :inline
:content-id (str "IMAGE_" idx)
:content-type "image/png"
:content (write-byte-array-to-temp-file bytes)})
@images))))
<html>
<body style="font-family: 'Helvetica Neue', Helvetica, sans-serif; font-size: 0.875rem; color: #727479; padding-top: 2em; padding-bottom: 1em; background-color: #F9FBFC; ">
<div style="padding-bottom: 2em; text-align: center;">
<img width="32" height="40" src="http://static.metabase.com/email_logo.png"/>
</div>
<div style="margin: 0 auto; max-width: 560px; padding: 2em 4em 2em 4em; text-align: center; color: #9F9F9F; border: 1px solid #dddddd; background-color: #FFFFFF; box-shadow: 0 1px 2px rgba(0, 0, 0, .08);">
<div style="padding-bottom: 1em;">
<h2 style="font-weight: normal; color: #4C545B;line-height: 1.65rem;">{{invitedName}}, you're invited to {{company}}'s&nbsp;Metabase</h2>
<h4 style="font-weight: normal;"><a style="color: #4A90E2; text-decoration: none;" href="mailto:{{invitorEmail}}">{{invitorName}} ({{invitorEmail}})</a> invited you to join them.</h4>
</div>
<div style="border-top: 1px solid #ededed; border-bottom: 1px solid #ededed; padding: 3em 0em 2em 0em; text-align: center; margin-left: auto; margin-right: auto; max-width: 400px; position: relative;">
<table width="296" height="141" cellpadding="0" cellspacing="0" style="display:block;margin:0 auto;">
<tr><td colspan="3"><img src="http://static.metabase.com/email_graph_top.png" width="296" height="73" style="display:block" /></td></tr>
<tr>
<td height="15" width="60"><img src="http://static.metabase.com/email_graph_left.png" width="60" height="15" style="display:block" /></td>
<td height="15" width="68" valign="middle" align="center" style="font-weight: bold; font-size: 0.72rem; line-height:15px;color: #fff; background-color:#333">{{{today}}}</td>
<td height="15" width="168"><img src="http://static.metabase.com/email_graph_right.png" width="168" height="15" style="display:block" /></td></tr>
<tr><td colspan="3" height="46"><img src="http://static.metabase.com/email_graph_bottom.png" width="296" height="56" style="display:block" /></td></tr>
</table>
<p style="line-height: 1.3rem;">{{invitedName}}'s Happiness and Productivity Over&nbsp;Time</p>
</div>
<div style="max-width: 400px; margin-left: auto; margin-right: auto; padding-top: 1em; line-height: 1.2rem;">
<p>Metabase is a simple and powerful analytics tool which lets <span style="color: #595959;">anyone</span> learn and <span style="color: #595959;">make decisions</span> from their company's data.</p>
<p>No technical knowledge required!</p>
</div>
<div style="padding: 1em;">
<a style="display: inline-block; box-sizing: border-box; text-decoration: none; font-size: 1.063rem; padding: 0.5rem 1.375rem; background: #FBFCFD; border: 1px solid #ddd; color: #444; cursor: pointer; text-decoration: none; font-weight: bold; border-radius: 4px; background-color: #4990E2; border-color: #4990E2; color: #fff;" href="{{joinUrl}}">Join Now</a>
</div>
<div style="padding-bottom: 2em; font-size: x-small;">
Or you can paste this link into your browser:<br/>{{joinUrl}}
</div>
</div>
<div style="padding: 3em; text-align: center; color: #CCCCCC; font-size: small;">"{{quotation}}"<br/>- {{quotationAuthor}}</div>
</body>
</html>
{{> metabase/email/_header }}
<div style="text-align: center;">
<div style="padding-bottom: 1em;">
<h2 style="font-weight: normal; color: #4C545B;line-height: 1.65rem;">{{invitedName}}, you're invited to {{company}}'s&nbsp;Metabase</h2>
<h4 style="font-weight: normal;"><a style="color: #4A90E2; text-decoration: none;" href="mailto:{{invitorEmail}}">{{invitorName}} ({{invitorEmail}})</a> invited you to join them.</h4>
</div>
<div style="border-top: 1px solid #ededed; border-bottom: 1px solid #ededed; padding: 3em 0em 2em 0em; text-align: center; margin-left: auto; margin-right: auto; max-width: 400px; position: relative;">
<table width="296" height="141" cellpadding="0" cellspacing="0" style="display:block;margin:0 auto;">
<tr><td colspan="3"><img src="http://static.metabase.com/email_graph_top.png" width="296" height="73" style="display:block" /></td></tr>
<tr>
<td height="15" width="60"><img src="http://static.metabase.com/email_graph_left.png" width="60" height="15" style="display:block" /></td>
<td height="15" width="68" valign="middle" align="center" style="font-weight: bold; font-size: 0.72rem; line-height:15px;color: #fff; background-color:#333">{{{today}}}</td>
<td height="15" width="168"><img src="http://static.metabase.com/email_graph_right.png" width="168" height="15" style="display:block" /></td></tr>
<tr><td colspan="3" height="46"><img src="http://static.metabase.com/email_graph_bottom.png" width="296" height="56" style="display:block" /></td></tr>
</table>
<p style="line-height: 1.3rem;">{{invitedName}}'s Happiness and Productivity Over&nbsp;Time</p>
</div>
<div style="max-width: 400px; margin-left: auto; margin-right: auto; padding-top: 1em; line-height: 1.2rem;">
<p>Metabase is a simple and powerful analytics tool which lets <span style="color: #595959;">anyone</span> learn and <span style="color: #595959;">make decisions</span> from their company's data.</p>
<p>No technical knowledge required!</p>
</div>
<div style="padding: 1em;">
<a style="display: inline-block; box-sizing: border-box; text-decoration: none; font-size: 1.063rem; padding: 0.5rem 1.375rem; background: #FBFCFD; border: 1px solid #ddd; color: #444; cursor: pointer; text-decoration: none; font-weight: bold; border-radius: 4px; background-color: #4990E2; border-color: #4990E2; color: #fff;" href="{{joinUrl}}">Join Now</a>
</div>
<div style="padding-bottom: 2em; font-size: x-small;">
Or you can paste this link into your browser:<br/>{{joinUrl}}
</div>
</div>
{{> metabase/email/_footer }}
{{> metabase/email/_header }}
<p>
You're receiving this e-mail because you or someone else has requested a password for your user account at {{hostname}}.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.
</p>
<p>
<a href="{{passwordResetUrl}}">{{passwordResetUrl}}</a>
</p>
{{> metabase/email/footer }}
{{> metabase/email/_header}}
<h1 style="{{sectionStyle}} margin: 16px; color: {{colorGrey4}};">
{{pulseName}}
</h1>
{{{pulse}}}
{{> metabase/email/_footer}}
......@@ -271,7 +271,7 @@
(defn render-pulse-card
[card data include-title render-img]
(try
[:div {:style (str section-style "margin: 16px;")}
[:div {:style (str section-style "margin: 16px; margin-bottom: 32px;")}
(if include-title [:div {:style "margin-bottom: 16px;"}
[:a {:style header-style :href (card-href card)}
(-> card :name h)]])
......@@ -286,36 +286,11 @@
(log/warn (str "Pulse card render error:" e))
[:div {:style (str font-style "color: #EF8C8C; font-weight: 700;")} "An error occurred while displaying this card."])))
(defn- render-pulse-section
(defn render-pulse-section
[render-img {:keys [card result]}]
[:div {:style "margin-top: 10px; margin-bottom: 20px;"}
(render-pulse-card card (:data result) true render-img)])
;; HACK: temporary workaround to postal requiring a file as the attachment
(defn- write-byte-array-to-temp-file
[img-bytes]
(let [file (java.io.File/createTempFile "metabase_pulse_image_" ".png")
fos (new java.io.FileOutputStream file)]
(.deleteOnExit file)
(.write fos img-bytes)
(.close fos)
file))
(defn render-pulse-email
"Take a pulse object and list of results, returns an array of attachment objects for an email"
[pulse results]
(let [images (atom [])
render-img (fn [bytes] (reset! images (conj @images bytes)) (str "cid:IMAGE_" (-> @images count dec)))
header [:h1 {:style (str section-style "margin: 16px; color: " color-grey-4 ";")} (-> pulse :name h)]
body (apply vector :div (mapv (partial render-pulse-section render-img) results))
content (html [:html [:body [:div header body]]])]
(apply vector {:type "text/html" :content content}
(map-indexed (fn [idx bytes] {:type :inline
:content-id (str "IMAGE_" idx)
:content-type "image/png"
:content (write-byte-array-to-temp-file bytes)})
@images))))
(defn render-pulse-card-to-png
[card data include-title]
(render-html-to-png (render-pulse-card card data include-title render-img-data-uri) card-width))
......@@ -9,6 +9,7 @@
[metabase.db :as db]
[metabase.driver :as driver]
[metabase.email :as email]
[metabase.email.messages :as messages]
[metabase.integrations.slack :as slack]
(metabase.models [card :refer [Card]]
[hydrate :refer :all]
......@@ -84,7 +85,7 @@
:subject email-subject
:recipients email-recipients
:message-type :attachments
:message (p/render-pulse-email pulse results))))
:message (messages/render-pulse-email pulse results))))
(defn- create-slack-attachment
"Create an attachment in Slack for a given Card by rendering its result into an image and uploading it."
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment