activity_notification 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +49 -9
- data/activity_notification.gemspec +1 -1
- data/app/controllers/activity_notification/notifications_controller.rb +75 -31
- data/app/mailers/activity_notification/mailer.rb +19 -4
- data/app/views/activity_notification/mailer/default/batch_default.html.erb +79 -0
- data/app/views/activity_notification/mailer/default/batch_default.text.erb +13 -0
- data/app/views/activity_notification/mailer/default/default.html.erb +75 -10
- data/app/views/activity_notification/mailer/default/default.text.erb +2 -2
- data/app/views/activity_notification/notifications/default/_default.html.erb +15 -14
- data/app/views/activity_notification/notifications/default/_default_without_grouping.html.erb +165 -0
- data/app/views/activity_notification/notifications/default/_index.html.erb +8 -4
- data/app/views/activity_notification/notifications/default/destroy.js.erb +2 -2
- data/app/views/activity_notification/notifications/default/index.html.erb +9 -5
- data/app/views/activity_notification/notifications/default/open.js.erb +6 -2
- data/app/views/activity_notification/notifications/default/open_all.js.erb +6 -2
- data/lib/activity_notification/apis/notification_api.rb +42 -9
- data/lib/activity_notification/helpers/view_helpers.rb +48 -19
- data/lib/activity_notification/mailers/helpers.rb +74 -37
- data/lib/activity_notification/models/concerns/target.rb +290 -26
- data/lib/activity_notification/models/notification.rb +85 -29
- data/lib/activity_notification/roles/acts_as_target.rb +4 -2
- data/lib/activity_notification/version.rb +1 -1
- data/spec/concerns/apis/notification_api_spec.rb +46 -0
- data/spec/concerns/models/target_spec.rb +281 -22
- data/spec/controllers/notifications_controller_shared_examples.rb +77 -0
- data/spec/helpers/view_helpers_spec.rb +39 -3
- data/spec/mailers/mailer_spec.rb +54 -1
- data/spec/models/notification_spec.rb +11 -0
- data/spec/rails_app/app/models/user.rb +1 -1
- data/spec/rails_app/app/views/layouts/_header.html.erb +2 -0
- data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +6 -0
- data/spec/roles/acts_as_target_spec.rb +1 -1
- metadata +7 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eafbddc7c4427310930baf3d6f23464f4d0c2baa
|
4
|
+
data.tar.gz: 38dce4c34e4e22e06be7132d588906500127c017
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4da1eff72e8906c9398bb43f9273ca1c788ce91debeccfc4ec9d371fa6032b11c12fb60594c5191e37717f88df4b1d020b82506357c469c9f1894ba0930ac992
|
7
|
+
data.tar.gz: 08ce06b4beaf320607e276d7dabd9486c58b7f979aa29ee522da90a7c9972eda2bc8148cadad1b90c66dd46bbead0fa819a0bff43a5fd17b9c8b9a1db5e4c113
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
activity_notification (1.0.
|
4
|
+
activity_notification (1.0.1)
|
5
5
|
activerecord (>= 4.2.0)
|
6
6
|
i18n (>= 0.5.0)
|
7
7
|
jquery-rails (>= 3.1.1)
|
@@ -164,7 +164,7 @@ GEM
|
|
164
164
|
actionpack (>= 4.0)
|
165
165
|
activesupport (>= 4.0)
|
166
166
|
sprockets (>= 3.0.0)
|
167
|
-
sqlite3 (1.3.
|
167
|
+
sqlite3 (1.3.12)
|
168
168
|
term-ansicolor (1.4.0)
|
169
169
|
tins (~> 1.0)
|
170
170
|
thor (0.19.1)
|
@@ -197,7 +197,7 @@ DEPENDENCIES
|
|
197
197
|
rails-controller-testing
|
198
198
|
rspec-rails (~> 3.5.1)
|
199
199
|
simplecov (~> 0.12.0)
|
200
|
-
sqlite3 (~> 1.3.
|
200
|
+
sqlite3 (~> 1.3.12)
|
201
201
|
timecop
|
202
202
|
yard (~> 0.9.5)
|
203
203
|
yard-activesupport-concern (~> 0.0.1)
|
data/README.md
CHANGED
@@ -21,6 +21,7 @@
|
|
21
21
|
* Notification views (presentation of notifications)
|
22
22
|
* Grouping notifications (grouping like `"Kevin and 7 other users posted comments to this article"`)
|
23
23
|
* Email notification
|
24
|
+
* Batch email notification
|
24
25
|
* Integration with [Devise](https://github.com/plataformatec/devise) authentication
|
25
26
|
|
26
27
|
### Notification index
|
@@ -55,8 +56,11 @@
|
|
55
56
|
1. [Setup mailer](#setup-mailer)
|
56
57
|
2. [Email templates](#email-templates)
|
57
58
|
3. [i18n for email](#i18n-for-email)
|
58
|
-
2. [
|
59
|
-
|
59
|
+
2. [Batch email notification](#batch-email-notification)
|
60
|
+
1. [Batch email templates](#batch-email-templates)
|
61
|
+
2. [i18n for batch email](#i18n-for-batch-email)
|
62
|
+
3. [Grouping notifications](#grouping-notifications)
|
63
|
+
4. [Integration with Devise](#integration-with-devise)
|
60
64
|
4. [Testing](#testing)
|
61
65
|
5. [Documentation](#documentation)
|
62
66
|
6. **[Common examples](#common-examples)**
|
@@ -308,7 +312,7 @@ If you want to set notification index in the common layout, such as common heade
|
|
308
312
|
<%= render_notifications_of current_user, index_content: :with_attributes %>
|
309
313
|
```
|
310
314
|
|
311
|
-
Then, content named
|
315
|
+
Then, content named `:notification_index` will be prepared and you can use it in your partial template.
|
312
316
|
|
313
317
|
```activity_notifications/notifications/users/_index.html.erb
|
314
318
|
...
|
@@ -330,29 +334,29 @@ For example, if you have an notification with `:key` set to `"notification.comme
|
|
330
334
|
|
331
335
|
*Hint*: the `"notification."` prefix in `:key` is completely optional, you can skip it in your projects or use this prefix only to make namespace.
|
332
336
|
|
333
|
-
If you would like to fallback to a partial, you can utilize the
|
337
|
+
If you would like to fallback to a partial, you can utilize the `:fallback` parameter to specify the path of a partial to use when one is missing:
|
334
338
|
|
335
339
|
```erb
|
336
|
-
<%= render_notification(@notification, target: :users, fallback:
|
340
|
+
<%= render_notification(@notification, target: :users, fallback: :default) %>
|
337
341
|
```
|
338
342
|
|
339
|
-
When used in this manner, if a partial with the specified `:key` cannot be located it will use the partial defined in the
|
343
|
+
When used in this manner, if a partial with the specified `:key` cannot be located it will use the partial defined in the `:fallback` instead. In the example above this would resolve to `activity_notification/notifications/users/_default.html.(|erb|haml|slim|something_else)`.
|
340
344
|
|
341
345
|
If you do not specify `:target` option like this,
|
342
346
|
|
343
347
|
```erb
|
344
|
-
<%= render_notification(@notification, fallback:
|
348
|
+
<%= render_notification(@notification, fallback: :default) %>
|
345
349
|
```
|
346
350
|
|
347
351
|
the gem will look for a partial in `default` as the target type which means `activity_notification/notifications/default/_default.html.(|erb|haml|slim|something_else)`.
|
348
352
|
|
349
|
-
If a view file does not exist then ActionView::MisingTemplate will be raised. If you wish to fallback to the old behaviour and use an i18n based translation in this situation you can specify a `:fallback` parameter of
|
353
|
+
If a view file does not exist then ActionView::MisingTemplate will be raised. If you wish to fallback to the old behaviour and use an i18n based translation in this situation you can specify a `:fallback` parameter of `:text` to fallback to this mechanism like such:
|
350
354
|
|
351
355
|
```erb
|
352
356
|
<%= render_notification(@notification, fallback: :text) %>
|
353
357
|
```
|
354
358
|
|
355
|
-
|
359
|
+
Finally, default views of `activity_notification` depends on jQuery and you have to add requirements to `application.js` in your apps:
|
356
360
|
|
357
361
|
```app/assets/javascripts/application.js
|
358
362
|
//= require jquery
|
@@ -456,6 +460,42 @@ notification:
|
|
456
460
|
mail_subject: 'New comment to your article'
|
457
461
|
```
|
458
462
|
|
463
|
+
### Batch email notification
|
464
|
+
|
465
|
+
`activity_notification` provides batch email notification to the notification targets. You can send notification daily or hourly with scheduler like `whenever`.
|
466
|
+
|
467
|
+
You can automatically send batch notification email for unopened notifications only to the all specified targets with `batch_key`.
|
468
|
+
|
469
|
+
```ruby
|
470
|
+
# Send batch notification email to the users with unopened notifications
|
471
|
+
User.send_batch_unopened_notification_email(batch_key: 'batch.comment.post')
|
472
|
+
```
|
473
|
+
|
474
|
+
You can also add conditions to filter notifications, like this:
|
475
|
+
|
476
|
+
```ruby
|
477
|
+
# Send batch notification email to the users with unopened notifications of specified key in 1 hour
|
478
|
+
User.send_batch_unopened_notification_email(batch_key: 'batch.comment.post', filtered_by_key: 'comment.post', custom_filter: ["created_at >= ?", time.hour.ago])
|
479
|
+
```
|
480
|
+
|
481
|
+
#### Batch email templates
|
482
|
+
|
483
|
+
`activity_notification` will look for batch email template in the same way as email notification using `batch_key`.
|
484
|
+
`batch_key` is specified by `:batch_key` option. If the option is not specified, The key of the first notification will be used as `batch_key`.
|
485
|
+
|
486
|
+
#### i18n for batch email
|
487
|
+
|
488
|
+
The subject of batch notification email also can be put in your locale `.yml` files as `mail_subject` field for `batch_key`.
|
489
|
+
|
490
|
+
```yaml
|
491
|
+
notification:
|
492
|
+
user:
|
493
|
+
batch:
|
494
|
+
comment:
|
495
|
+
post:
|
496
|
+
mail_subject: 'New comments to your article'
|
497
|
+
```
|
498
|
+
|
459
499
|
### Grouping notifications
|
460
500
|
|
461
501
|
`activity_notification` provides the function for automatically grouping notifications. When you created a notification like this, all *unopened* notifications to the same target will be grouped by `article` set as `:group` options:
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency 'activerecord', '>= 4.2.0'
|
26
26
|
s.add_dependency 'jquery-rails', '>= 3.1.1'
|
27
27
|
|
28
|
-
s.add_development_dependency 'sqlite3', '~> 1.3.
|
28
|
+
s.add_development_dependency 'sqlite3', '~> 1.3.12'
|
29
29
|
s.add_development_dependency 'rspec-rails', '~> 3.5.1'
|
30
30
|
s.add_development_dependency 'factory_girl_rails', '~> 4.7.0'
|
31
31
|
s.add_development_dependency 'simplecov', '~> 0.12.0'
|
@@ -15,13 +15,21 @@ module ActivityNotification
|
|
15
15
|
#
|
16
16
|
# GET /:target_type/:target_id/notifcations
|
17
17
|
# @overload index(params)
|
18
|
-
# @param [Hash] params Request
|
19
|
-
# @option params [String] :filter
|
20
|
-
# @option params [String] :limit
|
21
|
-
# @option params [String] :
|
18
|
+
# @param [Hash] params Request parameter options for notification index
|
19
|
+
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
20
|
+
# @option params [String] :limit (nil) Limit to query for notifications
|
21
|
+
# @option params [String] :reverse ('false') If notification index will be ordered as earliest first
|
22
|
+
# @option params [String] :without_grouping ('false') If notification index will include group members
|
23
|
+
# @option params [String] :with_group_members ('false') If notification index will include group members
|
24
|
+
# @option params [String] :filtered_by_type (nil) Notifiable type for filter
|
25
|
+
# @option params [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
26
|
+
# @option params [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
27
|
+
# @option params [String] :filtered_by_key (nil) Key of the notification for filter
|
28
|
+
# @option params [String] :reload ('true') Whether notification index will be reloaded
|
22
29
|
# @return [Responce] HTML view as default or JSON of notification index with json format parameter
|
23
30
|
def index
|
24
|
-
|
31
|
+
set_index_options
|
32
|
+
@notifications = load_notification_index(@index_options) if params[:reload].to_s.to_boolean(true)
|
25
33
|
respond_to do |format|
|
26
34
|
format.html # index.html.erb
|
27
35
|
format.json { render json: @notifications.to_json(include: [:target, :notifiable, :group]) }
|
@@ -36,6 +44,8 @@ module ActivityNotification
|
|
36
44
|
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
37
45
|
# @option params [String] :limit (nil) Limit to query for notifications
|
38
46
|
# @option params [String] :reload ('true') Whether notification index will be reloaded
|
47
|
+
# @option params [String] :without_grouping ('false') If notification index will include group members
|
48
|
+
# @option params [String] :with_group_members ('false') If notification index will include group members
|
39
49
|
# @option params [String] :filtered_by_type (nil) Notifiable type for filter
|
40
50
|
# @option params [String] :filtered_by_group_type (nil) Group type for filter, valid only :filtered_by_group_id
|
41
51
|
# @option params [String] :filtered_by_group_id (nil) Group instance id for filter, valid only :filtered_by_group_type
|
@@ -43,7 +53,7 @@ module ActivityNotification
|
|
43
53
|
# @return [Responce] JavaScript view for ajax request or redirects to back as default
|
44
54
|
def open_all
|
45
55
|
@target.open_all_notifications(params)
|
46
|
-
return_back_or_ajax
|
56
|
+
return_back_or_ajax
|
47
57
|
end
|
48
58
|
|
49
59
|
# Shows a notification.
|
@@ -61,13 +71,15 @@ module ActivityNotification
|
|
61
71
|
#
|
62
72
|
# @overload destroy(params)
|
63
73
|
# @param [Hash] params Request parameters
|
64
|
-
# @option params [String] :filter
|
65
|
-
# @option params [String] :limit
|
66
|
-
# @option params [String] :reload
|
74
|
+
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
75
|
+
# @option params [String] :limit (nil) Limit to query for notifications
|
76
|
+
# @option params [String] :reload ('true') Whether notification index will be reloaded
|
77
|
+
# @option params [String] :without_grouping ('false') If notification index will include group members
|
78
|
+
# @option params [String] :with_group_members ('false') If notification index will include group members
|
67
79
|
# @return [Responce] JavaScript view for ajax request or redirects to back as default
|
68
80
|
def destroy
|
69
81
|
@notification.destroy
|
70
|
-
return_back_or_ajax
|
82
|
+
return_back_or_ajax
|
71
83
|
end
|
72
84
|
|
73
85
|
# Opens a notification.
|
@@ -75,16 +87,19 @@ module ActivityNotification
|
|
75
87
|
# POST /:target_type/:target_id/notifcations/:id/open
|
76
88
|
# @overload open(params)
|
77
89
|
# @param [Hash] params Request parameters
|
78
|
-
# @option params [String] :move
|
79
|
-
# @option params [String] :filter
|
80
|
-
# @option params [String] :limit
|
81
|
-
# @option params [String] :reload
|
90
|
+
# @option params [String] :move ('false') Whether redirects to notifiable_path after the notification is opened
|
91
|
+
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
92
|
+
# @option params [String] :limit (nil) Limit to query for notifications
|
93
|
+
# @option params [String] :reload ('true') Whether notification index will be reloaded
|
94
|
+
# @option params [String] :without_grouping ('false') If notification index will include group members
|
95
|
+
# @option params [String] :with_group_members ('false') If notification index will include group members
|
82
96
|
# @return [Responce] JavaScript view for ajax request or redirects to back as default
|
83
97
|
def open
|
84
|
-
|
98
|
+
with_members = !(params[:with_group_members].to_s.to_boolean(false) || params[:without_grouping].to_s.to_boolean(false))
|
99
|
+
@notification.open!(with_members: with_members)
|
85
100
|
params[:move].to_s.to_boolean(false) ?
|
86
101
|
move :
|
87
|
-
return_back_or_ajax
|
102
|
+
return_back_or_ajax
|
88
103
|
end
|
89
104
|
|
90
105
|
# Moves to notifiable_path of the notification.
|
@@ -146,20 +161,40 @@ module ActivityNotification
|
|
146
161
|
end
|
147
162
|
end
|
148
163
|
|
164
|
+
# Sets options to load notification index from request parameters.
|
165
|
+
# @api protected
|
166
|
+
# @return [Hash] options to load notification index
|
167
|
+
def set_index_options
|
168
|
+
limit = params[:limit].to_i > 0 ? params[:limit].to_i : nil
|
169
|
+
reverse = params[:reverse].present? ?
|
170
|
+
params[:reverse].to_s.to_boolean(false) : nil
|
171
|
+
with_group_members = params[:with_group_members].present? || params[:without_grouping].present? ?
|
172
|
+
params[:with_group_members].to_s.to_boolean(false) || params[:without_grouping].to_s.to_boolean(false) : nil
|
173
|
+
@index_options = params.permit(:filter, :filtered_by_type, :filtered_by_group_type, :filtered_by_group_id, :filtered_by_key)
|
174
|
+
.to_h.symbolize_keys
|
175
|
+
.merge(limit: limit, reverse: reverse, with_group_members: with_group_members)
|
176
|
+
end
|
177
|
+
|
149
178
|
# Loads notification index with request parameters.
|
150
179
|
# @api protected
|
151
|
-
# @param [
|
152
|
-
# @
|
180
|
+
# @param [Hash] params Request parameter options for notification index
|
181
|
+
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
182
|
+
# @option params [Integer] :limit (nil) Limit to query for notifications
|
183
|
+
# @option params [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
184
|
+
# @option params [Boolean] :without_grouping (false) If notification index will include group members
|
185
|
+
# @option params [String] :filtered_by_type (nil) Notifiable type for filter
|
186
|
+
# @option params [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
187
|
+
# @option params [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
188
|
+
# @option params [String] :filtered_by_key (nil) Key of the notification for filter
|
153
189
|
# @return [Array] Array of notification index
|
154
|
-
def load_notification_index(
|
155
|
-
|
156
|
-
case filter
|
190
|
+
def load_notification_index(options = {})
|
191
|
+
case options[:filter]
|
157
192
|
when 'opened'
|
158
|
-
@target.opened_notification_index_with_attributes(
|
193
|
+
@target.opened_notification_index_with_attributes(options)
|
159
194
|
when 'unopened'
|
160
|
-
@target.unopened_notification_index_with_attributes(
|
195
|
+
@target.unopened_notification_index_with_attributes(options)
|
161
196
|
else
|
162
|
-
@target.notification_index_with_attributes(
|
197
|
+
@target.notification_index_with_attributes(options)
|
163
198
|
end
|
164
199
|
end
|
165
200
|
|
@@ -171,23 +206,32 @@ module ActivityNotification
|
|
171
206
|
|
172
207
|
# Returns JavaScript view for ajax request or redirects to back as default.
|
173
208
|
# @api protected
|
174
|
-
# @
|
175
|
-
# @
|
209
|
+
# @option params [String] :filter (nil) Filter option to load notification index (Nothing as auto, 'opened' or 'unopened')
|
210
|
+
# @option params [Integer] :limit (nil) Limit to query for notifications
|
211
|
+
# @option params [Boolean] :reverse (false) If notification index will be ordered as earliest first
|
212
|
+
# @option params [Boolean] :without_grouping (false) If notification index will include group members
|
213
|
+
# @option params [String] :filtered_by_type (nil) Notifiable type for filter
|
214
|
+
# @option params [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
|
215
|
+
# @option params [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
|
216
|
+
# @option params [String] :filtered_by_key (nil) Key of the notification for filter
|
176
217
|
# @return [Responce] JavaScript view for ajax request or redirects to back as default
|
177
|
-
def return_back_or_ajax
|
178
|
-
|
218
|
+
def return_back_or_ajax
|
219
|
+
set_index_options
|
220
|
+
if params[:reload].to_s.to_boolean(true)
|
221
|
+
@notifications = load_notification_index(@index_options)
|
222
|
+
end
|
179
223
|
respond_to do |format|
|
180
224
|
if request.xhr?
|
181
225
|
format.js
|
182
226
|
# :skip-rails4:
|
183
227
|
elsif Rails::VERSION::MAJOR >= 5
|
184
|
-
redirect_back fallback_location: { action: :index },
|
228
|
+
redirect_back fallback_location: { action: :index }, **@index_options and return
|
185
229
|
# :skip-rails4:
|
186
230
|
# :skip-rails5:
|
187
231
|
elsif request.referer
|
188
|
-
redirect_to :back,
|
232
|
+
redirect_to :back, **@index_options and return
|
189
233
|
else
|
190
|
-
redirect_to action: :index,
|
234
|
+
redirect_to action: :index, **@index_options and return
|
191
235
|
end
|
192
236
|
# :skip-rails5:
|
193
237
|
end
|
@@ -4,18 +4,33 @@ if defined?(ActionMailer)
|
|
4
4
|
include ActivityNotification::Mailers::Helpers
|
5
5
|
|
6
6
|
# Sends notification email.
|
7
|
+
#
|
7
8
|
# @param [Notification] notification Notification instance to send email
|
8
|
-
# @param [Hash]
|
9
|
+
# @param [Hash] options Options for notification email
|
9
10
|
# @option options [String, Symbol] :fallback (:default) Fallback template to use when MissingTemplate is raised
|
11
|
+
# @return [Mail::Message|ActionMailer::DeliveryJob] Email message or its delivery job, return NilClass for wrong target
|
10
12
|
def send_notification_email(notification, options = {})
|
11
13
|
options[:fallback] ||= :default
|
12
14
|
if options[:fallback] == :none
|
13
15
|
options.delete(:fallback)
|
14
16
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
notification_mail(notification, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Sends batch notification email.
|
21
|
+
#
|
22
|
+
# @param [Object] target Target of batch notification email
|
23
|
+
# @param [Array<Notification>] notifications Target notifications to send batch notification email
|
24
|
+
# @param [Hash] options Options for notification email
|
25
|
+
# @option options [String, Symbol] :fallback (:batch_default) Fallback template to use when MissingTemplate is raised
|
26
|
+
# @option options [String] :batch_key (nil) Key of the batch notification email, a key of the first notification will be used if not specified
|
27
|
+
# @return [Mail::Message|ActionMailer::DeliveryJob] Email message or its delivery job, return NilClass for wrong target
|
28
|
+
def send_batch_notification_email(target, notifications, options = {})
|
29
|
+
options[:fallback] ||= :batch_default
|
30
|
+
if options[:fallback] == :none
|
31
|
+
options.delete(:fallback)
|
18
32
|
end
|
33
|
+
batch_notification_mail(target, notifications, options)
|
19
34
|
end
|
20
35
|
|
21
36
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="ja">
|
3
|
+
<head>
|
4
|
+
<meta content="text/html; charset=UTF-8" />
|
5
|
+
<style>
|
6
|
+
body {
|
7
|
+
font-family: 'Lucida Grande', 'Hiragino Kaku Gothic ProN', Meiryo, sans-serif;
|
8
|
+
color: #4f4f4f;
|
9
|
+
font-weight: normal;
|
10
|
+
font-style: normal;
|
11
|
+
}
|
12
|
+
p{
|
13
|
+
font-size: 14px;
|
14
|
+
}
|
15
|
+
.activity_wrapper {
|
16
|
+
padding: 15px 10px;
|
17
|
+
position: relative;
|
18
|
+
}
|
19
|
+
.activity_wrapper:after{
|
20
|
+
content: "";
|
21
|
+
clear: both;
|
22
|
+
display: block;
|
23
|
+
}
|
24
|
+
.activity_wrapper .user_image {
|
25
|
+
float: left;
|
26
|
+
width: 40px;
|
27
|
+
height: 40px;
|
28
|
+
background-position: center;
|
29
|
+
background-repeat: no-repeat;
|
30
|
+
background-size: cover;
|
31
|
+
background-color: #979797;
|
32
|
+
}
|
33
|
+
.activity_wrapper .user_desc_wrapper {
|
34
|
+
float: left;
|
35
|
+
width: calc(100% - 130px);
|
36
|
+
margin-top: 0;
|
37
|
+
margin-left: 10px;
|
38
|
+
}
|
39
|
+
.activity_wrapper .user_desc_wrapper .user_desc {
|
40
|
+
font-size: 12px;
|
41
|
+
line-height: 1.6;
|
42
|
+
margin-top: 0;
|
43
|
+
margin-bottom: 0;
|
44
|
+
}
|
45
|
+
.activity_wrapper .user_desc_wrapper .user_desc span{
|
46
|
+
color: #979797;
|
47
|
+
font-weight: bold;
|
48
|
+
}
|
49
|
+
.activity_wrapper .user_desc_wrapper .user_desc strong{
|
50
|
+
font-weight: bold;
|
51
|
+
}
|
52
|
+
</style>
|
53
|
+
<%= yield :head %>
|
54
|
+
</head>
|
55
|
+
<body>
|
56
|
+
<p>Dear <%= @target.printable_target_name %></p>
|
57
|
+
<% @notifications.each do |notification| %>
|
58
|
+
<div class="activity_wrapper">
|
59
|
+
<div class="user_image"></div>
|
60
|
+
<div class="user_desc_wrapper">
|
61
|
+
<p class="user_desc">
|
62
|
+
<strong><%= notification.notifier.present? ? notification.notifier.printable_notifier_name : 'Someone' %></strong>
|
63
|
+
notified you of
|
64
|
+
<%= notification.notifiable.printable_notifiable_name(notification.target) %><%= notification.group.present? ? " in #{notification.group.printable_group_name}." : "." %><br>
|
65
|
+
<span><%= notification.created_at.strftime("%b %d %H:%M") %></span>
|
66
|
+
</p>
|
67
|
+
<p class="user_desc">
|
68
|
+
<span>
|
69
|
+
<%= link_to "Move to notified #{notification.notifiable.printable_type.downcase}", move_notification_url_for(notification, open: true) %>
|
70
|
+
</span>
|
71
|
+
</p>
|
72
|
+
</div>
|
73
|
+
</div>
|
74
|
+
<% end %>
|
75
|
+
<p>Thank you!</p>
|
76
|
+
</body>
|
77
|
+
</html>
|
78
|
+
|
79
|
+
|