effective_messaging 0.8.1 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d1af8fb6d222cf7dc1f2ad5c9baaf139607cef5f724879fd3bc037107d56b4d
4
- data.tar.gz: f6315751785d8760aee7adb5593826f6b4ed80639ec1d0f54d1ee95f85462828
3
+ metadata.gz: 473c0318cc028c7e4eced72d90d9f257af48060615ab9368e267aefeb8912923
4
+ data.tar.gz: b113796bf1d6eb615d732817bfd1b773a7341255774b90fc4bc1a48d4074a3a1
5
5
  SHA512:
6
- metadata.gz: 657cc27116ca125f8102c2bc4ee1331d9359e673e7b9dc4647509541c217f4ad79c2a11e4dd4014ec0aff7f0b8fab9be45de9a104a8738f2a87d3d16d73dcf64
7
- data.tar.gz: 5c0de10cdbbf454298c7033f39ed5ca08cfffb51c1f54cd6ee65f5d23872b08fd93267e1f5281eecbc6205493d99e48d04b9c3f47109c4cf178c6d1d6e75723d
6
+ metadata.gz: 130940194d693e5dab80793b47a54ae2614f6e8df8ba80d986e20ac35fdd0071a017365807a076ad5ebf2f2e176582b6aa4eb5981fb1a8b0a491497bd062dc1f
7
+ data.tar.gz: '0356873babc77f9124b8164d179fe7852d19a70eb8e4a8fbf5e9966f017c71b69bd9588b61adcdc1b2784f38df6590f202636af690ccf17b71436e6f889118dc'
@@ -1,3 +1,2 @@
1
1
  module EffectiveMessagingHelper
2
-
3
2
  end
@@ -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
- # This is not an EffectiveEmailTemplatesMailer
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
- # Returns a Hash of params to pass to mail()
11
- # Includes a :to, :from, :subject and :body, etc
12
- rendered = notification.assign_renderer(view_context).render_email
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
- rendered.delete(:content_type) if notification.attach_report?
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
- headers.merge!(message_stream: 'broadcast-stream')
24
- attach_unsubscribe_link!(rendered)
21
+ opts.merge!(message_stream: 'broadcast-stream')
22
+ append_unsubscribe_link!(notification, opts)
25
23
  end
26
24
 
27
- # Calls effective_resources subject proc, so we can prepend [LETTERS]
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
- # Does not use effective_email_templates mailer
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
- # Pass everything to mail
56
- mail(rendered.merge(headers).merge(subject: subject))
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 attach_unsubscribe_link!(rendered)
78
- raise('expected a Hash') unless rendered.kind_of?(Hash)
79
- raise('expected a Hash with a :body') unless rendered.key?(:body)
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
- # Attach unsubscribe link
91
- rendered[:body] = "#{rendered[:body]}\r\n\r\n#{unsubscribe}"
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
- rendered
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', optional: true
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
- self.errors.add(:immediate_times, "must be 1 when when using every 0 days") if immediate_days == 0 && immediate_times != 1
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 template_subject
199
- Liquid::Template.parse(subject)
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 report_variables
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 force && already_notified_today?(resource)
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.notify_resource(self, resource).deliver_now
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.notify(self).deliver_now
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 render_email(resource = nil)
395
- raise('expected an acts_as_reportable resource') if resource.present? && !resource.class.try(:acts_as_reportable?)
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 3 places:
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 3
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
- = f.radios :audience, Effective::Notification::AUDIENCES, label: false, buttons: true
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
- %h2 Notification
56
- %p The following email notification will be sent
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
- = f.email_field :bcc
62
- = f.text_field :subject
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
- %p You can use the following variables in the subject and body:
68
-
69
- %ul
70
- - f.object.report_variables.each do |name|
71
- %li {{ #{name} }}
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
- - if notification.rows_count > 0
18
- %p Using a random row from the data source, a preview of the notification follows:
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
- - resource = notification.report.collection.order('RANDOM()').first
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= rendered.fetch(:to)
32
+ %td= Array(message.to).join(', ')
29
33
  %tr
30
34
  %th From
31
- %td= rendered.fetch(:from)
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 = rendered[:cc]).present?
42
+ - if (cc = message.cc).present?
34
43
  %tr
35
44
  %th CC
36
45
  %td= cc
37
46
 
38
- - if (bcc = rendered[:bcc]).present?
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= rendered.fetch(:subject)
54
+ %td= message.subject
46
55
 
47
56
  %tr
48
57
  %td{colspan: 2}
49
- = simple_format(rendered.fetch(:body).to_s)
58
+ - if email_message_html?(message)
59
+ = iframe_srcdoc_tag(email_message_body(message))
60
+ - else
61
+ = simple_format(email_message_body(message))
@@ -0,0 +1,10 @@
1
+ ---
2
+ subject: 'Subject of this notification'
3
+ ---
4
+ Hello,
5
+
6
+ You are receiving this notification for the following reason:
7
+
8
+ TODO
9
+
10
+ Thank you
@@ -69,6 +69,7 @@ class CreateEffectiveMessaging < ActiveRecord::Migration[6.0]
69
69
  t.string :from
70
70
  t.string :cc
71
71
  t.string :bcc
72
+ t.string :content_type
72
73
 
73
74
  t.datetime :last_notified_at
74
75
  t.integer :last_notified_count
@@ -1,3 +1,3 @@
1
1
  module EffectiveMessaging
2
- VERSION = '0.8.1'.freeze
2
+ VERSION = '0.9.0'.freeze
3
3
  end
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.8.1
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-17 00:00:00.000000000 Z
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