effective_messaging 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/helpers/effective_messaging_helper.rb +0 -1
- data/app/mailers/effective/notifications_mailer.rb +23 -47
- data/app/models/effective/notification.rb +32 -59
- data/app/views/admin/notifications/_form_notification.html.haml +20 -15
- data/app/views/admin/notifications/_summary.html.haml +22 -10
- data/app/views/effective/notifications_mailer/notification.liquid +10 -0
- data/db/migrate/101_create_effective_messaging.rb +1 -0
- data/lib/effective_messaging/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 473c0318cc028c7e4eced72d90d9f257af48060615ab9368e267aefeb8912923
|
4
|
+
data.tar.gz: b113796bf1d6eb615d732817bfd1b773a7341255774b90fc4bc1a48d4074a3a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 130940194d693e5dab80793b47a54ae2614f6e8df8ba80d986e20ac35fdd0071a017365807a076ad5ebf2f2e176582b6aa4eb5981fb1a8b0a491497bd062dc1f
|
7
|
+
data.tar.gz: '0356873babc77f9124b8164d179fe7852d19a70eb8e4a8fbf5e9966f017c71b69bd9588b61adcdc1b2784f38df6590f202636af690ccf17b71436e6f889118dc'
|
@@ -1,63 +1,36 @@
|
|
1
1
|
module Effective
|
2
2
|
class NotificationsMailer < EffectiveMessaging.parent_mailer_class
|
3
3
|
include EffectiveMailer
|
4
|
+
include EffectiveEmailTemplatesMailer
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
def notify(notification, opts = {})
|
6
|
+
def notification(notification, resource = nil, opts = {})
|
8
7
|
raise('expected an Effective::Notification') unless notification.kind_of?(Effective::Notification)
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
@assigns = assigns_for(notification, resource)
|
10
|
+
|
11
|
+
# Find the TO email address for this resource
|
12
|
+
to = notification.to_email(resource)
|
13
|
+
raise('expected a to email address') unless to.present?
|
13
14
|
|
14
15
|
# Attach report
|
15
16
|
attach_report!(notification)
|
16
|
-
|
17
|
-
|
18
|
-
# Works with effective_logging to associate this email with the notification
|
19
|
-
headers = headers_for(notification, opts)
|
17
|
+
opts.delete(:content_type) if notification.attach_report?
|
20
18
|
|
21
19
|
# Use postmark broadcast-stream
|
22
20
|
if defined?(Postmark)
|
23
|
-
|
24
|
-
|
21
|
+
opts.merge!(message_stream: 'broadcast-stream')
|
22
|
+
append_unsubscribe_link!(notification, opts)
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
|
-
subject = subject_for(__method__, rendered.fetch(:subject), notification, opts)
|
29
|
-
|
30
|
-
# Pass everything to mail
|
31
|
-
mail(rendered.merge(headers).merge(subject: subject))
|
25
|
+
mail(to: to, **headers_for(resource, opts))
|
32
26
|
end
|
33
27
|
|
34
|
-
|
35
|
-
def notify_resource(notification, resource, opts = {})
|
36
|
-
raise('expected an Effective::Notification') unless notification.kind_of?(Effective::Notification)
|
37
|
-
raise('expected an acts_as_reportable resource') unless resource.class.try(:acts_as_reportable?)
|
38
|
-
|
39
|
-
# Returns a Hash of params to pass to mail()
|
40
|
-
# Includes a :to, :from, :subject and :body
|
41
|
-
rendered = notification.assign_renderer(view_context).render_email(resource)
|
42
|
-
|
43
|
-
# Works with effective_logging to associate this email with the notification
|
44
|
-
headers = headers_for(notification, opts)
|
45
|
-
|
46
|
-
# Use postmark broadcast-stream
|
47
|
-
if defined?(Postmark)
|
48
|
-
headers.merge!(message_stream: 'broadcast-stream')
|
49
|
-
attach_unsubscribe_link!(rendered)
|
50
|
-
end
|
51
|
-
|
52
|
-
# Calls effective_resources subject proc, so we can prepend [LETTERS]
|
53
|
-
subject = subject_for(__method__, rendered.fetch(:subject), resource, opts)
|
28
|
+
private
|
54
29
|
|
55
|
-
|
56
|
-
|
30
|
+
def assigns_for(notification, resource)
|
31
|
+
notification.assign_renderer(view_context).assigns_for(resource)
|
57
32
|
end
|
58
33
|
|
59
|
-
private
|
60
|
-
|
61
34
|
def attach_report!(notification)
|
62
35
|
return unless notification.attach_report?
|
63
36
|
raise("expected a scheduled email notification") unless notification.scheduled_email?
|
@@ -74,9 +47,9 @@ module Effective
|
|
74
47
|
}
|
75
48
|
end
|
76
49
|
|
77
|
-
def
|
78
|
-
raise('expected a Hash') unless
|
79
|
-
raise('expected a Hash with a :body') unless
|
50
|
+
def append_unsubscribe_link!(notification, opts)
|
51
|
+
raise('expected a Hash') unless opts.kind_of?(Hash)
|
52
|
+
raise('expected a Hash with a :body') unless opts.key?(:body)
|
80
53
|
|
81
54
|
name = EffectiveResources.et('acronym')
|
82
55
|
url = view_context.root_url
|
@@ -87,10 +60,13 @@ module Effective
|
|
87
60
|
"Please understand that unsubscribing means you will no longer receive mandatory messages and announcements."
|
88
61
|
].join(" ")
|
89
62
|
|
90
|
-
|
91
|
-
|
63
|
+
if notification.email_notification_html?
|
64
|
+
opts.merge!(body: "#{opts[:body]}\r\n<br/><p>#{unsubscribe}</p>")
|
65
|
+
else
|
66
|
+
opts.merge!(body: "#{opts[:body]}\r\n\r\n#{unsubscribe}")
|
67
|
+
end
|
92
68
|
|
93
|
-
|
69
|
+
true
|
94
70
|
end
|
95
71
|
|
96
72
|
def mailer_settings
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# This could be called ReportNotification. It only sends notifications for effective_reports right now.
|
4
|
+
|
3
5
|
module Effective
|
4
6
|
class Notification < ActiveRecord::Base
|
5
7
|
self.table_name = (EffectiveMessaging.notifications_table_name || :notifications).to_s
|
@@ -8,6 +10,7 @@ module Effective
|
|
8
10
|
attr_accessor :current_resource
|
9
11
|
attr_accessor :view_context
|
10
12
|
|
13
|
+
acts_as_email_notification # effective_resources
|
11
14
|
log_changes if respond_to?(:log_changes)
|
12
15
|
|
13
16
|
# Unused. If we want to use notifications in a has_many way
|
@@ -17,7 +20,7 @@ module Effective
|
|
17
20
|
belongs_to :user, polymorphic: true, optional: true
|
18
21
|
|
19
22
|
# Effective namespace
|
20
|
-
belongs_to :report, class_name: 'Effective::Report'
|
23
|
+
belongs_to :report, class_name: 'Effective::Report'
|
21
24
|
|
22
25
|
# Tracks the send outs
|
23
26
|
has_many :notification_logs, dependent: :delete_all
|
@@ -65,6 +68,7 @@ module Effective
|
|
65
68
|
from :string
|
66
69
|
cc :string
|
67
70
|
bcc :string
|
71
|
+
content_type :string
|
68
72
|
|
69
73
|
# Background tracking
|
70
74
|
last_notified_at :datetime
|
@@ -108,7 +112,7 @@ module Effective
|
|
108
112
|
end
|
109
113
|
|
110
114
|
validate(if: -> { immediate? && immediate_days.present? && immediate_times.present? }) do
|
111
|
-
|
115
|
+
errors.add(:immediate_times, "must be 1 when when using every 0 days") if immediate_days == 0 && immediate_times != 1
|
112
116
|
end
|
113
117
|
|
114
118
|
# Scheduled
|
@@ -125,30 +129,10 @@ module Effective
|
|
125
129
|
end
|
126
130
|
end
|
127
131
|
|
128
|
-
# Email
|
129
|
-
validates :from, presence: true, email: true
|
130
|
-
validates :subject, presence: true, liquid: true
|
131
|
-
validates :body, presence: true, liquid: true
|
132
|
-
|
133
|
-
# Report
|
134
|
-
validates :report, presence: true
|
135
|
-
|
136
132
|
validate(if: -> { report.present? }) do
|
137
133
|
errors.add(:report, 'must include an email, user, organization or owner column') unless report.email_report_column || report.emailable_report_column
|
138
134
|
end
|
139
135
|
|
140
|
-
validate(if: -> { report.present? && subject.present? }) do
|
141
|
-
if(invalid = template_variables(body: false) - report_variables).present?
|
142
|
-
errors.add(:subject, "Invalid variable: #{invalid.to_sentence}")
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
validate(if: -> { report.present? && body.present? }) do
|
147
|
-
if(invalid = template_variables(subject: false) - report_variables).present?
|
148
|
-
errors.add(:body, "Invalid variable: #{invalid.to_sentence}")
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
136
|
def to_s
|
153
137
|
subject.presence || model_name.human
|
154
138
|
end
|
@@ -195,15 +179,11 @@ module Effective
|
|
195
179
|
Array(self[:scheduled_dates]) - [nil, '']
|
196
180
|
end
|
197
181
|
|
198
|
-
def
|
199
|
-
|
200
|
-
end
|
201
|
-
|
202
|
-
def template_body
|
203
|
-
Liquid::Template.parse(body)
|
182
|
+
def email_template
|
183
|
+
:notification # We always use this email template
|
204
184
|
end
|
205
185
|
|
206
|
-
def
|
186
|
+
def email_template_variables
|
207
187
|
assigns_for().keys
|
208
188
|
end
|
209
189
|
|
@@ -272,6 +252,20 @@ module Effective
|
|
272
252
|
scheduled_email? ? notify_by_schedule!(force: force) : notify_by_resources!(force: force)
|
273
253
|
end
|
274
254
|
|
255
|
+
# Returns a message. Do not call deliver.
|
256
|
+
def preview
|
257
|
+
return unless report.present?
|
258
|
+
|
259
|
+
if audience_emails?
|
260
|
+
# notify_by_schedule
|
261
|
+
Effective::NotificationsMailer.notification(self, nil, email_notification_params)
|
262
|
+
else
|
263
|
+
# notify_by_resources
|
264
|
+
resource = report.collection.order('RANDOM()').first
|
265
|
+
Effective::NotificationsMailer.notification(self, resource, email_notification_params) if resource
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
275
269
|
# Operates on every resource in the data source. Sends one email for each row
|
276
270
|
def notify_by_resources!(force: false)
|
277
271
|
notified = 0
|
@@ -280,7 +274,7 @@ module Effective
|
|
280
274
|
next unless notifiable?(resource) || force
|
281
275
|
|
282
276
|
# Send Now functionality. Don't duplicate if it's same day.
|
283
|
-
next if
|
277
|
+
next if already_notified_today?(resource) && !force
|
284
278
|
|
285
279
|
print('.')
|
286
280
|
|
@@ -289,7 +283,7 @@ module Effective
|
|
289
283
|
assign_attributes(current_resource: resource)
|
290
284
|
|
291
285
|
# Send the resource email
|
292
|
-
Effective::NotificationsMailer.
|
286
|
+
Effective::NotificationsMailer.notification(self, resource, email_notification_params).deliver_now
|
293
287
|
|
294
288
|
# Log that it was sent
|
295
289
|
build_notification_log(resource: resource).save!
|
@@ -299,6 +293,7 @@ module Effective
|
|
299
293
|
rescue => e
|
300
294
|
EffectiveLogger.error(e.message, associated: self) if defined?(EffectiveLogger)
|
301
295
|
ExceptionNotifier.notify_exception(e, data: { notification_id: id, resource_id: resource.id, resource_type: resource.class.name }) if defined?(ExceptionNotifier)
|
296
|
+
raise(e) if Rails.env.test? || Rails.env.development?
|
302
297
|
end
|
303
298
|
|
304
299
|
GC.start if (notified % 250) == 0
|
@@ -312,7 +307,7 @@ module Effective
|
|
312
307
|
|
313
308
|
if notifiable_scheduled? || force
|
314
309
|
begin
|
315
|
-
Effective::NotificationsMailer.
|
310
|
+
Effective::NotificationsMailer.notification(self, nil, email_notification_params).deliver_now
|
316
311
|
|
317
312
|
# Log that it was sent
|
318
313
|
build_notification_log(resource: nil).save!
|
@@ -322,6 +317,7 @@ module Effective
|
|
322
317
|
rescue => e
|
323
318
|
EffectiveLogger.error(e.message, associated: self) if defined?(EffectiveLogger)
|
324
319
|
ExceptionNotifier.notify_exception(e, data: { notification_id: id }) if defined?(ExceptionNotifier)
|
320
|
+
raise(e) if Rails.env.test? || Rails.env.development?
|
325
321
|
end
|
326
322
|
|
327
323
|
end
|
@@ -391,26 +387,11 @@ module Effective
|
|
391
387
|
end
|
392
388
|
end
|
393
389
|
|
394
|
-
def
|
395
|
-
|
396
|
-
|
397
|
-
to = (audience == 'emails' ? audience_emails.presence : resource_emails_to_s(resource))
|
398
|
-
raise('expected a to email address') unless to.present?
|
399
|
-
|
400
|
-
assigns = assigns_for(resource)
|
401
|
-
|
402
|
-
{
|
403
|
-
to: to,
|
404
|
-
from: from,
|
405
|
-
cc: cc.presence,
|
406
|
-
bcc: bcc.presence,
|
407
|
-
content_type: CONTENT_TYPES.first,
|
408
|
-
subject: template_subject.render(assigns),
|
409
|
-
body: template_body.render(assigns)
|
410
|
-
}.compact
|
390
|
+
def to_email(resource)
|
391
|
+
audience == 'emails' ? audience_emails.presence : resource_emails_to_s(resource)
|
411
392
|
end
|
412
393
|
|
413
|
-
# We pull the Assigns from
|
394
|
+
# We pull the Assigns from 2 places:
|
414
395
|
# 1. The report.report_columns
|
415
396
|
# 2. The class's def reportable_view_assigns(view) method
|
416
397
|
def assigns_for(resource = nil)
|
@@ -427,7 +408,7 @@ module Effective
|
|
427
408
|
reportable_view_assigns = resource.reportable_view_assigns(renderer).deep_stringify_keys
|
428
409
|
raise('expected notification assigns to return a Hash') unless reportable_view_assigns.kind_of?(Hash)
|
429
410
|
|
430
|
-
# Merge all
|
411
|
+
# Merge all assigns
|
431
412
|
report_assigns.merge(reportable_view_assigns)
|
432
413
|
end
|
433
414
|
|
@@ -442,14 +423,6 @@ module Effective
|
|
442
423
|
|
443
424
|
private
|
444
425
|
|
445
|
-
def template_variables(body: true, subject: true)
|
446
|
-
[(template_body.presence if body), (template_subject.presence if subject)].compact.map do |template|
|
447
|
-
Liquid::ParseTreeVisitor.for(template.root).add_callback_for(Liquid::VariableLookup) do |node|
|
448
|
-
[node.name, *node.lookups].join('.')
|
449
|
-
end.visit
|
450
|
-
end.flatten.uniq.compact
|
451
|
-
end
|
452
|
-
|
453
426
|
def audience_emails_to_s
|
454
427
|
audience_emails.presence&.join(', ')
|
455
428
|
end
|
@@ -1,7 +1,11 @@
|
|
1
1
|
= effective_form_with(model: [:admin, notification], engine: true) do |f|
|
2
2
|
%h2 Audience
|
3
3
|
%p Please select who the notifications should be sent to
|
4
|
-
|
4
|
+
|
5
|
+
= f.radios :audience, Effective::Notification::AUDIENCES, label: false, buttons: true,
|
6
|
+
'data-load-ajax-url': effective_messaging.new_admin_notification_path,
|
7
|
+
'data-load-ajax-div': '#effective-messaging-ajax',
|
8
|
+
'data-load-ajax-all': true
|
5
9
|
|
6
10
|
= f.show_if(:audience, 'report') do
|
7
11
|
%p The notification will be sent to the user or email from the report.
|
@@ -46,29 +50,30 @@
|
|
46
50
|
= f.select :report_id, Effective::Report.sorted.notifiable.all,
|
47
51
|
hint: "Please select a #{link_to 'report', effective_reports.admin_reports_path, target: '_blank'} with a user or email column to use as the data source",
|
48
52
|
'data-load-ajax-url': effective_messaging.new_admin_notification_path,
|
49
|
-
'data-load-ajax-div': '#effective-messaging-ajax'
|
53
|
+
'data-load-ajax-div': '#effective-messaging-ajax',
|
54
|
+
'data-load-ajax-all': true
|
50
55
|
|
51
56
|
= f.show_if(:audience, 'emails') do
|
52
57
|
= f.show_if(:schedule_type, 'scheduled') do
|
53
58
|
= f.check_box :attach_report, label: 'Yes, attach a .csv file with the report data', hint: 'only available to scheduled emails sent to specific addresses'
|
54
59
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
- f.object.from ||= EffectiveMessaging.mailer_froms.first
|
59
|
-
= f.select :from, mailer_froms_collection()
|
60
|
+
= f.show_if(:audience, 'report') do
|
61
|
+
= f.hidden_field :attach_report, value: false
|
60
62
|
|
61
|
-
|
62
|
-
= f
|
63
|
-
= f.text_area :body, rows: 20
|
63
|
+
%h2 Notification
|
64
|
+
= email_notification_fields(f, :notification)
|
64
65
|
|
65
66
|
#effective-messaging-ajax
|
66
67
|
- if f.object.report.present?
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
%
|
68
|
+
= card do
|
69
|
+
- if f.object.audience == 'report'
|
70
|
+
%p You can use the following variables in the subject and body:
|
71
|
+
|
72
|
+
%ul
|
73
|
+
- f.object.email_template_variables.each do |name|
|
74
|
+
%li {{ #{name} }}
|
75
|
+
- elsif f.object.audience == 'emails'
|
76
|
+
%p No variables available for Send to specific address audience.
|
72
77
|
|
73
78
|
= f.submit do
|
74
79
|
= f.save 'Save'
|
@@ -14,36 +14,48 @@
|
|
14
14
|
%h4= notification.report.to_s
|
15
15
|
= render 'admin/reports/report', report: notification.report
|
16
16
|
|
17
|
-
-
|
18
|
-
|
17
|
+
- message = notification.preview()
|
18
|
+
|
19
|
+
- if message.present?
|
20
|
+
- if notification.audience_emails?
|
21
|
+
%p A preview of the "Send to specific addresses" notification follows:
|
22
|
+
- else
|
23
|
+
%p Using a random row from the data source, a preview of the "Send to user or email from the report" notification follows:
|
19
24
|
|
20
25
|
= card('Preview') do
|
21
|
-
-
|
22
|
-
- rendered = notification.assign_renderer(self).render_email(resource)
|
26
|
+
- message = notification.preview()
|
23
27
|
|
24
28
|
%table.table
|
25
29
|
%tbody
|
26
30
|
%tr
|
27
31
|
%th To
|
28
|
-
%td=
|
32
|
+
%td= Array(message.to).join(', ')
|
29
33
|
%tr
|
30
34
|
%th From
|
31
|
-
%td=
|
35
|
+
%td= Array(message.from).join(', ')
|
36
|
+
|
37
|
+
- if (content_type = message.content_type).present?
|
38
|
+
%tr
|
39
|
+
%th Content-Type
|
40
|
+
%td= content_type
|
32
41
|
|
33
|
-
- if (cc =
|
42
|
+
- if (cc = message.cc).present?
|
34
43
|
%tr
|
35
44
|
%th CC
|
36
45
|
%td= cc
|
37
46
|
|
38
|
-
- if (bcc =
|
47
|
+
- if (bcc = message.bcc).present?
|
39
48
|
%tr
|
40
49
|
%th BCC
|
41
50
|
%td= bcc
|
42
51
|
|
43
52
|
%tr
|
44
53
|
%th Subject
|
45
|
-
%td=
|
54
|
+
%td= message.subject
|
46
55
|
|
47
56
|
%tr
|
48
57
|
%td{colspan: 2}
|
49
|
-
|
58
|
+
- if email_message_html?(message)
|
59
|
+
= iframe_srcdoc_tag(email_message_body(message))
|
60
|
+
- else
|
61
|
+
= simple_format(email_message_body(message))
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_messaging
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-06-
|
11
|
+
date: 2024-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -246,6 +246,7 @@ files:
|
|
246
246
|
- app/views/effective/chats/_summary.html.haml
|
247
247
|
- app/views/effective/messaging/_dashboard.html.haml
|
248
248
|
- app/views/effective/messaging_mailer/chat_new_message.liquid
|
249
|
+
- app/views/effective/notifications_mailer/notification.liquid
|
249
250
|
- config/effective_messaging.rb
|
250
251
|
- config/locales/effective_messaging.yml
|
251
252
|
- config/routes.rb
|