feat(mailer): implement Prism and Mailer
This commit is contained in:
1 parent
97f8d8e4f8
commit
7611cf1a0e
1 file changed
+99
@@ -0,0 +1,99 @@
|
||||
module Prism
|
||||
module Mailer
|
||||
# A tiny Rack app that browses Mailer::Preview subclasses in a web
|
||||
# browser, mirroring Rails' /rails/mailers engine: an index of every
|
||||
# registered preview, a list of its actions, and a rendered view of one
|
||||
# email (HTML part if present, raw text part otherwise) - all without
|
||||
# ever touching Mailer.deliver!. Mount it directly:
|
||||
# BlogApp.mount('/rails/mailers', Prism::Mailer::PreviewApp.new)
|
||||
class PreviewApp
|
||||
def call(env)
|
||||
request = Request.new(env)
|
||||
return not_found unless request.request_method == 'GET'
|
||||
|
||||
# Links are built from SCRIPT_NAME (where this app was mounted)
|
||||
# rather than relative to PATH_INFO, so they work the same whether
|
||||
# this is mounted at "/rails/mailers" or served standalone at "/" -
|
||||
# relative hrefs would break the moment the current path lacks a
|
||||
# trailing slash (the classic Rack::URLMap gotcha).
|
||||
@base = env['SCRIPT_NAME'].to_s
|
||||
segments = request.path.split('/').reject(&:empty?)
|
||||
case segments.length
|
||||
when 0 then index
|
||||
when 1 then show_preview(segments[0])
|
||||
when 2 then show_email(segments[0], segments[1])
|
||||
else not_found
|
||||
end
|
||||
rescue ArgumentError
|
||||
not_found
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def index
|
||||
previews = Preview.registry.sort_by(&:preview_name)
|
||||
items = previews.map do |klass|
|
||||
%(<li><a href="#{@base}/#{klass.preview_name}">#{escape(klass.preview_name)}</a></li>)
|
||||
end
|
||||
body = "<h1>Mailer previews</h1><ul>#{items.join}</ul>"
|
||||
body = '<h1>Mailer previews</h1><p>No previews registered.</p>' if previews.empty?
|
||||
html(body)
|
||||
end
|
||||
|
||||
def show_preview(name)
|
||||
klass = Preview.find(name)
|
||||
return not_found unless klass
|
||||
|
||||
items = klass.emails.map do |email|
|
||||
%(<li><a href="#{@base}/#{klass.preview_name}/#{email}">#{escape(email)}</a></li>)
|
||||
end
|
||||
body = +%(<p><a href="#{@base}">« all previews</a></p>)
|
||||
body << "<h1>#{escape(klass.preview_name)}</h1><ul>#{items.join}</ul>"
|
||||
html(body)
|
||||
end
|
||||
|
||||
def show_email(name, email)
|
||||
klass = Preview.find(name)
|
||||
return not_found unless klass
|
||||
|
||||
delivery = klass.call(email)
|
||||
html(render_message(klass, email, delivery.message))
|
||||
end
|
||||
|
||||
def render_message(klass, email, message)
|
||||
body = +%(<p><a href="#{@base}/#{klass.preview_name}">« #{escape(klass.preview_name)}</a></p>)
|
||||
body << "<h1>#{escape(klass.preview_name)}##{escape(email)}</h1>"
|
||||
body << '<dl>'
|
||||
body << "<dt>Subject</dt><dd>#{escape(message.subject)}</dd>"
|
||||
body << "<dt>From</dt><dd>#{escape(message.from)}</dd>"
|
||||
body << "<dt>To</dt><dd>#{escape(message.to.join(', '))}</dd>"
|
||||
body << '</dl><hr>'
|
||||
body << render_body(message)
|
||||
body
|
||||
end
|
||||
|
||||
def render_body(message)
|
||||
if message.html_body
|
||||
message.html_body
|
||||
elsif message.text_body
|
||||
"<pre>#{escape(message.text_body)}</pre>"
|
||||
else
|
||||
'<p><em>empty body</em></p>'
|
||||
end
|
||||
end
|
||||
|
||||
def escape(text)
|
||||
CGI.escapeHTML(text.to_s)
|
||||
end
|
||||
|
||||
def html(body)
|
||||
[200, { 'Content-Type' => 'text/html; charset=UTF-8' },
|
||||
["<!doctype html><html><head><meta charset=\"utf-8\"></head><body>#{body}</body></html>"]]
|
||||
end
|
||||
|
||||
def not_found
|
||||
[404, { 'Content-Type' => 'text/plain' }, ['Not Found']]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user