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 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