padrino-mailer 0.16.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/padrino-mailer/ext.rb +61 -15
- data/test/fixtures/padrino_app/app.rb +7 -6
- data/test/test_email.rb +129 -0
- data/test/test_message.rb +23 -0
- data/test/test_padrino_mailer.rb +1 -2
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 825e119978637255f86e4e8a3cbe59129020a951480750cd4d292731a112708c
|
|
4
|
+
data.tar.gz: 4cd8ae7354cfffabf9afa6a6b9b68158d6d37acf65b7053a79ca232ee208ad47
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ce4c8d3e8abb2b464939852ffc204a7fa1798daefb11b0119b7a642bd88b293d41f3c6b31d0fd357ce0b2e33c6688af2bdc96afea3e642611ff023283f9f8263
|
|
7
|
+
data.tar.gz: bca72b42a36c242cb4cd27662b5e386ffda7e027d46f2b0d14a762ac3477b22afb1530472716e7cf93e8024f4a1d07c10d84fa72c2246cfc1e4647684eaf8a24
|
data/lib/padrino-mailer/ext.rb
CHANGED
|
@@ -5,18 +5,19 @@ module Mail # @private
|
|
|
5
5
|
include Sinatra::Templates
|
|
6
6
|
include Padrino::Rendering if defined?(Padrino::Rendering)
|
|
7
7
|
include Padrino::Helpers::RenderHelpers if defined? Padrino::Helpers::RenderHelpers
|
|
8
|
+
include Padrino::Helpers if defined?(Padrino::Helpers)
|
|
8
9
|
attr_reader :template_cache
|
|
9
10
|
attr_accessor :mailer_name, :message_name
|
|
10
11
|
|
|
11
12
|
def initialize_with_app(*args, &block)
|
|
12
|
-
@template_cache =
|
|
13
|
+
@template_cache = Sinatra::TemplateCache.new
|
|
13
14
|
# Check if we have an app passed into initialize
|
|
14
15
|
if args[0].respond_to?(:views) && args[0].respond_to?(:reload_templates?)
|
|
15
16
|
app = args.shift
|
|
16
|
-
|
|
17
|
+
@_views = File.join(app.views, 'mailers')
|
|
17
18
|
settings.reload_templates = app.reload_templates?
|
|
18
19
|
else
|
|
19
|
-
|
|
20
|
+
@_views = File.expand_path('./mailers')
|
|
20
21
|
settings.reload_templates = true
|
|
21
22
|
end
|
|
22
23
|
|
|
@@ -107,7 +108,7 @@ module Mail # @private
|
|
|
107
108
|
def part(params = {}, &block)
|
|
108
109
|
part_block = params.delete(:part_block)
|
|
109
110
|
new_part = Mail::Part.new(params)
|
|
110
|
-
new_part.
|
|
111
|
+
new_part.views(@_views)
|
|
111
112
|
new_part.settings.reload_templates = settings.reload_templates?
|
|
112
113
|
new_part.instance_eval(&part_block) if part_block
|
|
113
114
|
yield new_part if block_given?
|
|
@@ -137,14 +138,17 @@ module Mail # @private
|
|
|
137
138
|
# Sinatra almost compatibility.
|
|
138
139
|
#
|
|
139
140
|
def self.set(name, value)
|
|
140
|
-
|
|
141
|
+
singleton_class.class_eval do
|
|
142
|
+
define_method(name) { value } unless method_defined?(name)
|
|
143
|
+
end
|
|
141
144
|
end
|
|
142
145
|
|
|
143
146
|
##
|
|
144
147
|
# Sets the message defined template path to the given view path.
|
|
145
148
|
#
|
|
146
149
|
def views(value)
|
|
147
|
-
|
|
150
|
+
@_views = value
|
|
151
|
+
@_mailer_views = false
|
|
148
152
|
end
|
|
149
153
|
|
|
150
154
|
##
|
|
@@ -211,6 +215,21 @@ module Mail # @private
|
|
|
211
215
|
@_defaults.each_pair { |k, v| default(k.to_sym, v) } if @_defaults.is_a?(Hash)
|
|
212
216
|
end
|
|
213
217
|
|
|
218
|
+
##
|
|
219
|
+
# Emails have no session to check a token against, so forms in mailer
|
|
220
|
+
# templates are built without a CSRF token.
|
|
221
|
+
#
|
|
222
|
+
def self.protect_from_csrf
|
|
223
|
+
false
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
##
|
|
227
|
+
# The form builder form_for and fields_for use in mailer templates.
|
|
228
|
+
#
|
|
229
|
+
def self.default_builder
|
|
230
|
+
'StandardFormBuilder'
|
|
231
|
+
end
|
|
232
|
+
|
|
214
233
|
##
|
|
215
234
|
# Check if we can log.
|
|
216
235
|
#
|
|
@@ -259,28 +278,55 @@ module Mail # @private
|
|
|
259
278
|
locals = @_locals || {} if !options[:locals] && locals.empty?
|
|
260
279
|
@template_cache.clear if settings.reload_templates?
|
|
261
280
|
|
|
281
|
+
# render(nil, 'template', ...) as RenderHelpers#partial calls it: shift the arguments
|
|
282
|
+
# the way Padrino::Rendering#render does, before defaulting to the message name.
|
|
283
|
+
engine, data, options = data, options, locals if engine.nil? && data && !data.is_a?(Hash)
|
|
262
284
|
engine ||= message_name
|
|
263
285
|
|
|
264
286
|
if mailer_name && !engine.to_s.index('/')
|
|
265
|
-
|
|
287
|
+
@_views = File.join(@_views, mailer_name.to_s) unless @_mailer_views
|
|
288
|
+
@_mailer_views = true
|
|
266
289
|
engine = engine.to_s.sub(%r{^#{mailer_name}/}, '')
|
|
267
290
|
end
|
|
268
291
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
end
|
|
292
|
+
# Pass the views path per render: class-level settings are shared by every message.
|
|
293
|
+
if data.is_a?(Hash)
|
|
294
|
+
data = { views: @_views }.merge(data)
|
|
295
|
+
else
|
|
296
|
+
options = { views: @_views }.merge(options)
|
|
275
297
|
end
|
|
276
298
|
|
|
277
|
-
|
|
299
|
+
# A render nested in a template (a partial) returns its output; only the outermost one sets the body.
|
|
300
|
+
return super(engine, data, options, locals, &block) if @_rendering
|
|
301
|
+
|
|
302
|
+
begin
|
|
303
|
+
@_rendering = true
|
|
304
|
+
provides.each do |format|
|
|
305
|
+
part do |p|
|
|
306
|
+
p.content_type(format)
|
|
307
|
+
p.send(:render, engine, data, options, locals, &block)
|
|
308
|
+
add_multipart_alternate_header if html_part || provides.include?(:html)
|
|
309
|
+
end
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
self.body = super(engine, data, options, locals, &block) if provides.empty?
|
|
313
|
+
ensure
|
|
314
|
+
@_rendering = false
|
|
315
|
+
end
|
|
278
316
|
end
|
|
279
317
|
|
|
280
318
|
alias original_partial partial if instance_methods.include?(:partial)
|
|
281
319
|
def partial(template, options = {}, &block)
|
|
282
320
|
raise "gem 'padrino-helpers' is required to render partials" unless respond_to?(:original_partial)
|
|
283
|
-
|
|
321
|
+
return original_partial(template, options, &block) if @_rendering
|
|
322
|
+
|
|
323
|
+
begin
|
|
324
|
+
@_rendering = true
|
|
325
|
+
output = original_partial(template, options, &block)
|
|
326
|
+
ensure
|
|
327
|
+
@_rendering = false
|
|
328
|
+
end
|
|
329
|
+
self.body = output
|
|
284
330
|
end
|
|
285
331
|
|
|
286
332
|
##
|
|
@@ -37,12 +37,13 @@ class PadrinoApp < Padrino::Application
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
message :helper do |name|
|
|
40
|
-
subject
|
|
41
|
-
to
|
|
42
|
-
from
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
subject 'Welcome Helper!'
|
|
41
|
+
to 'jim@fake.com'
|
|
42
|
+
from 'noreply@custom.com'
|
|
43
|
+
content_type :html
|
|
44
|
+
locals name: name
|
|
45
|
+
via :test
|
|
46
|
+
render 'sample/helper_message'
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
message :default_mailer_name do |name|
|
data/test/test_email.rb
CHANGED
|
@@ -158,4 +158,133 @@ describe 'Email' do
|
|
|
158
158
|
end
|
|
159
159
|
end
|
|
160
160
|
end
|
|
161
|
+
|
|
162
|
+
describe 'the mailer views path' do
|
|
163
|
+
def mailer_views(root)
|
|
164
|
+
views = File.join(@tmp, root, 'views')
|
|
165
|
+
{ 'alpha/hello.erb' => 'alpha hello', 'beta/hello.erb' => 'beta hello',
|
|
166
|
+
'gamma/hello.plain.erb' => 'gamma plain', 'gamma/hello.html.erb' => 'gamma html' }.each do |path, content|
|
|
167
|
+
file = File.join(views, 'mailers', path)
|
|
168
|
+
FileUtils.mkdir_p(File.dirname(file))
|
|
169
|
+
File.write(file, content)
|
|
170
|
+
end
|
|
171
|
+
views
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def mailer_app(views)
|
|
175
|
+
mock_app do
|
|
176
|
+
register Padrino::Mailer
|
|
177
|
+
set :views, views
|
|
178
|
+
set :delivery_method, :test
|
|
179
|
+
set :mailer_defaults, from: 'padrino@me.com', to: 'padrino@you.com'
|
|
180
|
+
mailer(:alpha) { email(:hello) { via :test; render :hello } }
|
|
181
|
+
mailer(:beta) { email(:hello) { via :test; render :hello } }
|
|
182
|
+
mailer(:gamma) { email(:hello) { via :test; provides :plain, :html; render :hello } }
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def build_message(mailer_name)
|
|
187
|
+
message = @app.settings._padrino_mailer::Message.new(@app)
|
|
188
|
+
message.mailer_name = mailer_name
|
|
189
|
+
message
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
before { @tmp = Dir.mktmpdir }
|
|
193
|
+
after { FileUtils.rm_rf(@tmp) }
|
|
194
|
+
|
|
195
|
+
it 'should add the mailer name when the app path contains it' do
|
|
196
|
+
mailer_app(mailer_views('beta_site'))
|
|
197
|
+
email = @app.deliver(:beta, :hello)
|
|
198
|
+
assert_equal 'beta hello', email.body.to_s
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'should not leak the mailer path between messages' do
|
|
202
|
+
mailer_app(mailer_views('site'))
|
|
203
|
+
alpha = build_message(:alpha)
|
|
204
|
+
beta = build_message(:beta)
|
|
205
|
+
assert_equal 'beta hello', beta.send(:render, :hello)
|
|
206
|
+
assert_equal 'alpha hello', alpha.send(:render, :hello)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it 'should not reuse a cached template from another mailer' do
|
|
210
|
+
views = mailer_views('site')
|
|
211
|
+
File.write(File.join(views, 'mailers', 'beta', 'greet.haml'), '%p beta greet')
|
|
212
|
+
File.write(File.join(views, 'mailers', 'alpha', 'greet.erb'), 'alpha greet')
|
|
213
|
+
mailer_app(views)
|
|
214
|
+
@app.set :reload_templates, false
|
|
215
|
+
@app.mailer(:alpha) { email(:greet) { via :test; render :greet } }
|
|
216
|
+
@app.mailer(:beta) { email(:greet) { via :test; render :greet } }
|
|
217
|
+
assert_equal 'alpha greet', @app.deliver(:alpha, :greet).body.to_s
|
|
218
|
+
assert_equal '<p>beta greet</p>', @app.deliver(:beta, :greet).body.to_s.strip
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it 'should render a partial from a mailer template' do
|
|
222
|
+
views = mailer_views('site')
|
|
223
|
+
File.write(File.join(views, 'mailers', 'alpha', 'listing.erb'), "<%= partial 'item', object: 'one' %>")
|
|
224
|
+
File.write(File.join(views, 'mailers', 'alpha', '_item.erb'), 'item <%= item %>')
|
|
225
|
+
mailer_app(views)
|
|
226
|
+
@app.mailer(:alpha) { email(:listing) { via :test; render :listing } }
|
|
227
|
+
assert_equal 'item one', @app.deliver(:alpha, :listing).body.to_s.strip
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'should render the message template with options when the engine is nil' do
|
|
231
|
+
views = mailer_views('site')
|
|
232
|
+
File.write(File.join(views, 'mailers', 'alpha', 'boxed.erb'), 'boxed')
|
|
233
|
+
File.write(File.join(views, 'mailers', 'alpha', 'box.erb'), '[<%= yield %>]')
|
|
234
|
+
mailer_app(views)
|
|
235
|
+
@app.mailer(:alpha) { email(:boxed) { via :test; render nil, layout: :box } }
|
|
236
|
+
assert_equal '[boxed]', @app.deliver(:alpha, :boxed).body.to_s.strip
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it 'should not add a part per partial to a message with an attachment' do
|
|
240
|
+
views = mailer_views('site')
|
|
241
|
+
File.write(File.join(views, 'mailers', 'alpha', 'listing.erb'), "<%= partial 'item', collection: %w[a b] %>")
|
|
242
|
+
File.write(File.join(views, 'mailers', 'alpha', '_item.erb'), '<%= item %>')
|
|
243
|
+
mailer_app(views)
|
|
244
|
+
@app.mailer(:alpha) { email(:listing) { via :test; add_file filename: 'a.txt', content: 'file'; render :listing } }
|
|
245
|
+
email = @app.deliver(:alpha, :listing)
|
|
246
|
+
assert_equal(%w[ab file], email.parts.map { |part| part.body.to_s.strip })
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
it 'should not reuse a cached layout from another mailer' do
|
|
250
|
+
views = mailer_views('site')
|
|
251
|
+
File.write(File.join(views, 'mailers', 'alpha', 'box.erb'), 'A[<%= yield %>]')
|
|
252
|
+
FileUtils.mkdir_p(File.join(views, 'mailers', 'beta', 'layouts'))
|
|
253
|
+
File.write(File.join(views, 'mailers', 'beta', 'layouts', 'box.erb'), 'B[<%= yield %>]')
|
|
254
|
+
mailer_app(views)
|
|
255
|
+
@app.set :reload_templates, false
|
|
256
|
+
@app.mailer(:alpha) { email(:boxed) { via :test; render :hello, layout: :box } }
|
|
257
|
+
@app.mailer(:beta) { email(:boxed) { via :test; render :hello, layout: :box } }
|
|
258
|
+
assert_equal 'A[alpha hello]', @app.deliver(:alpha, :boxed).body.to_s.strip
|
|
259
|
+
assert_equal 'B[beta hello]', @app.deliver(:beta, :boxed).body.to_s.strip
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
MailerFormUser = Struct.new(:name) unless defined?(MailerFormUser)
|
|
263
|
+
|
|
264
|
+
it 'should build forms with form_for in a mailer template' do
|
|
265
|
+
views = mailer_views('site')
|
|
266
|
+
File.write(File.join(views, 'mailers', 'alpha', 'signup.erb'), "<% @user = MailerFormUser.new('Joe') %><%= form_for(:user, '/signup') { |f| f.text_field(:name) } %>")
|
|
267
|
+
mailer_app(views)
|
|
268
|
+
@app.mailer(:alpha) { email(:signup) { via :test; render :signup } }
|
|
269
|
+
body = @app.deliver(:alpha, :signup).body.to_s
|
|
270
|
+
assert_match(%r{<form[^>]*action="/signup"}, body)
|
|
271
|
+
assert_match(/<input type="text" name="mailer_form_user\[name\]" value="Joe"/, body)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it 'should build forms in a mailer template without a CSRF token' do
|
|
275
|
+
views = mailer_views('site')
|
|
276
|
+
File.write(File.join(views, 'mailers', 'alpha', 'confirm.erb'), "<%= button_to 'Confirm', '/confirm' %>")
|
|
277
|
+
mailer_app(views)
|
|
278
|
+
@app.mailer(:alpha) { email(:confirm) { via :test; render :confirm } }
|
|
279
|
+
body = @app.deliver(:alpha, :confirm).body.to_s
|
|
280
|
+
assert_match(%r{<form[^>]*action="/confirm"}, body)
|
|
281
|
+
refute_match(/authenticity_token/, body)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it 'should render each provided format from the mailer path' do
|
|
285
|
+
mailer_app(mailer_views('site'))
|
|
286
|
+
email = @app.deliver(:gamma, :hello)
|
|
287
|
+
assert_equal(['gamma plain', 'gamma html'], email.parts.map { |part| part.body.to_s })
|
|
288
|
+
end
|
|
289
|
+
end
|
|
161
290
|
end
|
data/test/test_message.rb
CHANGED
|
@@ -166,4 +166,27 @@ describe 'Message' do
|
|
|
166
166
|
assert_equal "Object 1<br>\nObject 2<br>\nObject <evil><br>\nObject <good><br>", message.body.to_s.chomp
|
|
167
167
|
end
|
|
168
168
|
end
|
|
169
|
+
|
|
170
|
+
describe 'Mail::Message.set' do
|
|
171
|
+
it 'should define accessor methods for settings' do
|
|
172
|
+
Mail::Message.set(:_test_custom_setting, 'custom_value')
|
|
173
|
+
message = Mail::Message.new
|
|
174
|
+
assert_equal 'custom_value', message.settings._test_custom_setting
|
|
175
|
+
ensure
|
|
176
|
+
if Mail::Message.singleton_class.method_defined?(:_test_custom_setting)
|
|
177
|
+
Mail::Message.singleton_class.send(:remove_method, :_test_custom_setting)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it 'should not redefine an already defined method' do
|
|
182
|
+
Mail::Message.set(:_test_another_setting, 'first')
|
|
183
|
+
Mail::Message.set(:_test_another_setting, 'second')
|
|
184
|
+
message = Mail::Message.new
|
|
185
|
+
assert_equal 'first', message.settings._test_another_setting
|
|
186
|
+
ensure
|
|
187
|
+
if Mail::Message.singleton_class.method_defined?(:_test_another_setting)
|
|
188
|
+
Mail::Message.singleton_class.send(:remove_method, :_test_another_setting)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
169
192
|
end
|
data/test/test_padrino_mailer.rb
CHANGED
|
@@ -102,12 +102,11 @@ describe 'PadrinoMailer' do
|
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
it 'should be able to deliver a basic email using Padrino::Helpers' do
|
|
105
|
-
skip # FIXME
|
|
106
105
|
post '/deliver/helper'
|
|
107
106
|
assert_equal 'mail delivered', body
|
|
108
107
|
assert_email_sent(to: 'jim@fake.com', from: 'noreply@custom.com',
|
|
109
108
|
content_type: 'text/html',
|
|
110
|
-
subject: 'Welcome Helper!', body: '<a href="#">
|
|
109
|
+
subject: 'Welcome Helper!', body: '<a href="#">Jim</a>')
|
|
111
110
|
end
|
|
112
111
|
|
|
113
112
|
it 'should fail with proper message if mailer is not registered' do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: padrino-mailer
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Padrino Team
|
|
@@ -19,14 +19,14 @@ dependencies:
|
|
|
19
19
|
requirements:
|
|
20
20
|
- - '='
|
|
21
21
|
- !ruby/object:Gem::Version
|
|
22
|
-
version: 0.
|
|
22
|
+
version: 0.17.0
|
|
23
23
|
type: :runtime
|
|
24
24
|
prerelease: false
|
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
|
26
26
|
requirements:
|
|
27
27
|
- - '='
|
|
28
28
|
- !ruby/object:Gem::Version
|
|
29
|
-
version: 0.
|
|
29
|
+
version: 0.17.0
|
|
30
30
|
- !ruby/object:Gem::Dependency
|
|
31
31
|
name: mime-types
|
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|