effective_messaging 0.4.2 → 0.5.1
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/app/controllers/admin/notifications_controller.rb +0 -2
- data/app/datatables/admin/effective_notification_logs_datatable.rb +4 -3
- data/app/datatables/admin/effective_notifications_datatable.rb +2 -0
- data/app/jobs/effective/notification_job.rb +2 -2
- data/app/mailers/effective/notifications_mailer.rb +1 -0
- data/app/models/effective/notification.rb +68 -18
- data/app/models/effective/notification_log.rb +3 -2
- data/app/views/admin/notifications/_form_notification.html.haml +0 -4
- data/app/views/admin/notifications/_notification.html.haml +9 -41
- data/app/views/admin/notifications/_summary.html.haml +49 -0
- data/config/routes.rb +9 -1
- 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: 1061a51a0950e3c322de72f007ce0380e2b9fa6d0089d85bbd905b1cad9a8acd
|
4
|
+
data.tar.gz: 5f1dcb71f399a6d94fb49ba3284bbec7f007c6f8f7494e05aa1bf8f4cde618cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e4facce29949bb6bfd8a56fcea0029c09da098da22aedcef8c018209c3091e87fcc8a53123cf56ea26b99735cb0d83119a135930428d672129125f3459e0debe
|
7
|
+
data.tar.gz: d97ffe863b7cb1d14829f49ddf012723d79a99b3c1b2038dbd48e99bf8caf1193388ff8fcd5813dad9b25168d9118d3c3abae5d790126d10ba916e6cb66fa278
|
@@ -8,9 +8,10 @@ module Admin
|
|
8
8
|
|
9
9
|
col :notification
|
10
10
|
col :report, visible: !attributes[:inline]
|
11
|
-
col :resource
|
12
|
-
col :user
|
13
|
-
col :email
|
11
|
+
col :resource, search: :string
|
12
|
+
col :user, search: :string
|
13
|
+
col :email
|
14
|
+
col :skipped
|
14
15
|
|
15
16
|
actions_col
|
16
17
|
end
|
@@ -11,6 +11,7 @@ module Effective
|
|
11
11
|
|
12
12
|
# Attach report
|
13
13
|
attach_report!(notification)
|
14
|
+
rendered.delete(:content_type) if notification.attach_report?
|
14
15
|
|
15
16
|
# Works with effective_logging to associate this email with the notification
|
16
17
|
headers = headers_for(notification, opts)
|
@@ -102,6 +102,10 @@ module Effective
|
|
102
102
|
validates :immediate_times, presence: true, numericality: { greater_than_or_equal_to: 1 }
|
103
103
|
end
|
104
104
|
|
105
|
+
validate(if: -> { immediate? && immediate_days.present? && immediate_times.present? }) do
|
106
|
+
self.errors.add(:immediate_times, "must be 1 when when using every 0 days") if immediate_days == 0 && immediate_times != 1
|
107
|
+
end
|
108
|
+
|
105
109
|
# Scheduled
|
106
110
|
validates :scheduled_method, presence: true, inclusion: { in: SCHEDULED_METHODS.map(&:last) }, if: -> { scheduled? }
|
107
111
|
|
@@ -154,6 +158,8 @@ module Effective
|
|
154
158
|
end
|
155
159
|
end
|
156
160
|
|
161
|
+
# This operates on each row of the resource.
|
162
|
+
# We track the number of notifications total to see if we should notify again or not
|
157
163
|
def immediate?
|
158
164
|
schedule_type == 'immediate'
|
159
165
|
end
|
@@ -210,24 +216,63 @@ module Effective
|
|
210
216
|
@rows_count ||= report.collection().count if report
|
211
217
|
end
|
212
218
|
|
213
|
-
|
219
|
+
def notifiable_rows_count
|
220
|
+
report.collection().select { |resource| notifiable?(resource) }.count if report
|
221
|
+
end
|
222
|
+
|
223
|
+
def notifiable_tomorrow_rows_count
|
224
|
+
report.collection().select { |resource| notifiable_tomorrow?(resource) }.count if report
|
225
|
+
end
|
226
|
+
|
227
|
+
def enable!
|
228
|
+
update!(enabled: true)
|
229
|
+
end
|
230
|
+
|
231
|
+
def disable!
|
232
|
+
update!(enabled: false)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Enqueues this notification to send right away.
|
236
|
+
# Only applies to scheduled_email? notifications
|
214
237
|
def send_now!
|
215
238
|
raise('expected to be persisted') unless persisted?
|
216
|
-
NotificationJob.perform_later(id)
|
239
|
+
NotificationJob.perform_later(id, force: true)
|
217
240
|
true
|
218
241
|
end
|
219
242
|
|
220
|
-
#
|
221
|
-
|
222
|
-
|
243
|
+
# Only applies to immedate? notifications
|
244
|
+
# Skips over one notification on the immediate notifications
|
245
|
+
def skip_once!
|
246
|
+
notified = 0
|
247
|
+
|
248
|
+
report.collection().find_each do |resource|
|
249
|
+
print('.')
|
250
|
+
|
251
|
+
# For logging
|
252
|
+
assign_attributes(current_resource: resource)
|
253
|
+
|
254
|
+
# Send the resource email
|
255
|
+
build_notification_log(resource: resource, skipped: true).save!
|
256
|
+
|
257
|
+
notified += 1
|
258
|
+
|
259
|
+
GC.start if (notified % 250) == 0
|
260
|
+
end
|
261
|
+
|
262
|
+
touch
|
263
|
+
end
|
264
|
+
|
265
|
+
# The main function to send this thing
|
266
|
+
def notify!(force: false)
|
267
|
+
scheduled_email? ? notify_by_schedule!(force: force) : notify_by_resources!(force: force)
|
223
268
|
end
|
224
269
|
|
225
270
|
# Operates on every resource in the data source. Sends one email for each row
|
226
|
-
def notify_by_resources!
|
271
|
+
def notify_by_resources!(force: false)
|
227
272
|
notified = 0
|
228
273
|
|
229
274
|
report.collection().find_each do |resource|
|
230
|
-
next unless notifiable?(resource)
|
275
|
+
next unless notifiable?(resource) || force
|
231
276
|
print('.')
|
232
277
|
|
233
278
|
# For logging
|
@@ -245,10 +290,10 @@ module Effective
|
|
245
290
|
notified > 0 ? update!(last_notified_at: Time.zone.now, last_notified_count: notified) : touch
|
246
291
|
end
|
247
292
|
|
248
|
-
def notify_by_schedule!
|
293
|
+
def notify_by_schedule!(force: false)
|
249
294
|
notified = 0
|
250
295
|
|
251
|
-
if notifiable_scheduled?
|
296
|
+
if notifiable_scheduled? || force
|
252
297
|
build_notification_log(resource: nil).save!
|
253
298
|
Effective::NotificationsMailer.notify(self).deliver_now
|
254
299
|
notified += 1
|
@@ -257,22 +302,27 @@ module Effective
|
|
257
302
|
notified > 0 ? update!(last_notified_at: Time.zone.now, last_notified_count: notified) : touch
|
258
303
|
end
|
259
304
|
|
260
|
-
def notifiable?(resource)
|
305
|
+
def notifiable?(resource, date: nil)
|
261
306
|
raise('expected an acts_as_reportable resource') unless resource.class.try(:acts_as_reportable?)
|
262
307
|
|
263
308
|
if schedule_type == 'immediate'
|
264
|
-
notifiable_immediate?(resource: resource)
|
309
|
+
notifiable_immediate?(resource: resource, date: date)
|
265
310
|
elsif schedule_type == 'scheduled'
|
266
|
-
notifiable_scheduled?(date:
|
311
|
+
notifiable_scheduled?(date: date)
|
267
312
|
else
|
268
313
|
raise("unsupported schedule_type")
|
269
314
|
end
|
270
315
|
end
|
271
316
|
|
317
|
+
def notifiable_tomorrow?(resource)
|
318
|
+
date = Time.zone.now.beginning_of_day.advance(days: 1)
|
319
|
+
notifiable?(resource, date: date)
|
320
|
+
end
|
321
|
+
|
272
322
|
# Consider the notification logs which track how many and how long ago this notification was sent
|
273
323
|
# It's notifiable? when first time or if it's been immediate_days since last notification
|
274
|
-
def notifiable_immediate?(resource:)
|
275
|
-
raise('expected an
|
324
|
+
def notifiable_immediate?(resource:, date: nil)
|
325
|
+
raise('expected an immediate? notification') unless immediate?
|
276
326
|
|
277
327
|
email = resource_email(resource) || resource_user(resource).try(:email)
|
278
328
|
raise("expected an email for #{report} #{report&.id} and #{resource} #{resource&.id}") unless email.present?
|
@@ -283,8 +333,8 @@ module Effective
|
|
283
333
|
true # This is the first time. We should send.
|
284
334
|
elsif logs.count < immediate_times
|
285
335
|
# We still have to send it but consider dates.
|
286
|
-
last_sent_days_ago = logs.map(
|
287
|
-
last_sent_days_ago >= immediate_days
|
336
|
+
last_sent_days_ago = logs.map { |log| log.days_ago(date: date) }.min || 0
|
337
|
+
(last_sent_days_ago >= immediate_days)
|
288
338
|
else
|
289
339
|
false # We've already sent enough times
|
290
340
|
end
|
@@ -348,13 +398,13 @@ module Effective
|
|
348
398
|
report_assigns.merge(reportable_view_assigns)
|
349
399
|
end
|
350
400
|
|
351
|
-
def build_notification_log(resource: nil)
|
401
|
+
def build_notification_log(resource: nil, skipped: false)
|
352
402
|
user = resource_user(resource)
|
353
403
|
|
354
404
|
email = resource_email(resource) || user.try(:email)
|
355
405
|
email ||= audience_emails_to_s if scheduled_email?
|
356
406
|
|
357
|
-
notification_logs.build(email: email, report: report, resource: resource, user: user)
|
407
|
+
notification_logs.build(email: email, report: report, resource: resource, user: user, skipped: skipped)
|
358
408
|
end
|
359
409
|
|
360
410
|
private
|
@@ -12,6 +12,7 @@ module Effective
|
|
12
12
|
|
13
13
|
effective_resource do
|
14
14
|
email :string
|
15
|
+
skipped :boolean
|
15
16
|
|
16
17
|
timestamps
|
17
18
|
end
|
@@ -25,8 +26,8 @@ module Effective
|
|
25
26
|
model_name.human
|
26
27
|
end
|
27
28
|
|
28
|
-
def days_ago
|
29
|
-
now = Time.zone.now.to_date
|
29
|
+
def days_ago(date: nil)
|
30
|
+
now = (date || Time.zone.now).to_date
|
30
31
|
(now - (created_at&.to_date || now)).to_i
|
31
32
|
end
|
32
33
|
|
@@ -76,9 +76,5 @@
|
|
76
76
|
|
77
77
|
= f.submit do
|
78
78
|
= f.save 'Save'
|
79
|
-
|
80
|
-
- if EffectiveResources.authorized?(self, :send_now, f.object)
|
81
|
-
= f.save 'Send Now', class: 'btn btn-warning', 'data-confirm': "Really send now?"
|
82
|
-
|
83
79
|
= f.save 'Add New', class: 'btn btn-secondary'
|
84
80
|
= f.save 'Continue', class: 'btn btn-secondary'
|
@@ -1,43 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
report at the time of sending.
|
1
|
+
= tabs do
|
2
|
+
= tab 'Notification' do
|
3
|
+
= render 'admin/notifications/summary', notification: notification
|
5
4
|
|
6
|
-
|
5
|
+
- if notification.persisted? && notification.respond_to?(:logs_datatable)
|
6
|
+
= tab 'Email Logs' do
|
7
|
+
- datatable = Admin::EffectiveNotificationLogsDatatable.new(notification: notification)
|
8
|
+
= render_inline_datatable(datatable)
|
7
9
|
|
8
|
-
=
|
9
|
-
|
10
|
-
|
11
|
-
- if notification.rows_count > 0
|
12
|
-
%p Using a random row from the data source, a preview of the notification follows:
|
13
|
-
|
14
|
-
= card('Preview of Notification') do
|
15
|
-
- resource = notification.report.collection.order('RANDOM()').first
|
16
|
-
- rendered = notification.assign_renderer(self).render_email(resource)
|
17
|
-
|
18
|
-
%table.table
|
19
|
-
%tbody
|
20
|
-
%tr
|
21
|
-
%th To
|
22
|
-
%td= rendered.fetch(:to)
|
23
|
-
%tr
|
24
|
-
%th From
|
25
|
-
%td= rendered.fetch(:from)
|
26
|
-
|
27
|
-
- if (cc = rendered[:cc]).present?
|
28
|
-
%tr
|
29
|
-
%th CC
|
30
|
-
%td= cc
|
31
|
-
|
32
|
-
- if (bcc = rendered[:bcc]).present?
|
33
|
-
%tr
|
34
|
-
%th BCC
|
35
|
-
%td= bcc
|
36
|
-
|
37
|
-
%tr
|
38
|
-
%th Subject
|
39
|
-
%td= rendered.fetch(:subject)
|
40
|
-
|
41
|
-
%tr
|
42
|
-
%td{colspan: 2}
|
43
|
-
= simple_format(rendered.fetch(:body).to_s)
|
10
|
+
= tab 'Logs' do
|
11
|
+
= render_inline_datatable(notification.logs_datatable)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
%p
|
2
|
+
This notification will be sent to all rows from the
|
3
|
+
= link_to(notification.report, effective_reports.admin_report_path(notification.report), target: '_blank')
|
4
|
+
report at the time of sending.
|
5
|
+
|
6
|
+
%p Tomorrow morning, #{pluralize(notification.notifiable_tomorrow_rows_count, 'rows')} notifications will be sent.
|
7
|
+
|
8
|
+
.mb-2
|
9
|
+
= collapse('Show notification details') do
|
10
|
+
= effective_table_with(notification)
|
11
|
+
|
12
|
+
.mb-2
|
13
|
+
= collapse("Show report data") do
|
14
|
+
%h4= notification.report.to_s
|
15
|
+
= render 'admin/reports/report', report: notification.report
|
16
|
+
|
17
|
+
- if notification.rows_count > 0
|
18
|
+
%p Using a random row from the data source, a preview of the notification follows:
|
19
|
+
|
20
|
+
= card('Preview') do
|
21
|
+
- resource = notification.report.collection.order('RANDOM()').first
|
22
|
+
- rendered = notification.assign_renderer(self).render_email(resource)
|
23
|
+
|
24
|
+
%table.table
|
25
|
+
%tbody
|
26
|
+
%tr
|
27
|
+
%th To
|
28
|
+
%td= rendered.fetch(:to)
|
29
|
+
%tr
|
30
|
+
%th From
|
31
|
+
%td= rendered.fetch(:from)
|
32
|
+
|
33
|
+
- if (cc = rendered[:cc]).present?
|
34
|
+
%tr
|
35
|
+
%th CC
|
36
|
+
%td= cc
|
37
|
+
|
38
|
+
- if (bcc = rendered[:bcc]).present?
|
39
|
+
%tr
|
40
|
+
%th BCC
|
41
|
+
%td= bcc
|
42
|
+
|
43
|
+
%tr
|
44
|
+
%th Subject
|
45
|
+
%td= rendered.fetch(:subject)
|
46
|
+
|
47
|
+
%tr
|
48
|
+
%td{colspan: 2}
|
49
|
+
= simple_format(rendered.fetch(:body).to_s)
|
data/config/routes.rb
CHANGED
@@ -13,7 +13,15 @@ EffectiveMessaging::Engine.routes.draw do
|
|
13
13
|
namespace :admin do
|
14
14
|
resources :chats
|
15
15
|
resources :chat_messages, only: [:index, :show, :destroy]
|
16
|
-
|
16
|
+
|
17
|
+
resources :notifications do
|
18
|
+
post :enable, on: :member
|
19
|
+
post :disable, on: :member
|
20
|
+
|
21
|
+
post :send_now, on: :member
|
22
|
+
post :skip_once, on: :member
|
23
|
+
end
|
24
|
+
|
17
25
|
resources :notification_logs, only: [:index, :destroy]
|
18
26
|
end
|
19
27
|
|
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.5.1
|
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: 2023-08-
|
11
|
+
date: 2023-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -237,6 +237,7 @@ files:
|
|
237
237
|
- app/views/admin/notifications/_form.html.haml
|
238
238
|
- app/views/admin/notifications/_form_notification.html.haml
|
239
239
|
- app/views/admin/notifications/_notification.html.haml
|
240
|
+
- app/views/admin/notifications/_summary.html.haml
|
240
241
|
- app/views/effective/chats/_chat.html.haml
|
241
242
|
- app/views/effective/chats/_chat_message.html.haml
|
242
243
|
- app/views/effective/chats/_form.html.haml
|