effective_messaging 0.4.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +60 -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 +6 -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: dedeb21248c1deac281cc473a00f64e23fc41c74ccff84cde9cb8cad9f3295c9
|
4
|
+
data.tar.gz: 6b102bd482f7b03b62f1caaff60a406fd561439316d7a26c5c1839428b161c7d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8726856fc8632e2c7159ff98ca1b97098eee126dcaa5a29ae87905759769f8613ec02a1c711a8233fd236c1fecf8bfd3a75d638a87dea2c74903c6b5187bff78
|
7
|
+
data.tar.gz: f890bac4407411221c371fbcdcfd3e545db95b37ff078a782376b1d3e562debd15a622b3996a04b30422927488fe7157abc18c0ad9ef173b47f8a083f4efd792
|
@@ -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,55 @@ 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
|
+
# Enqueues this notification to send right away.
|
228
|
+
# Only applies to scheduled_email? notifications
|
214
229
|
def send_now!
|
215
230
|
raise('expected to be persisted') unless persisted?
|
216
|
-
NotificationJob.perform_later(id)
|
231
|
+
NotificationJob.perform_later(id, force: true)
|
217
232
|
true
|
218
233
|
end
|
219
234
|
|
220
|
-
#
|
221
|
-
|
222
|
-
|
235
|
+
# Only applies to immedate? notifications
|
236
|
+
# Skips over one notification on the immediate notifications
|
237
|
+
def skip_once!
|
238
|
+
notified = 0
|
239
|
+
|
240
|
+
report.collection().find_each do |resource|
|
241
|
+
print('.')
|
242
|
+
|
243
|
+
# For logging
|
244
|
+
assign_attributes(current_resource: resource)
|
245
|
+
|
246
|
+
# Send the resource email
|
247
|
+
build_notification_log(resource: resource, skipped: true).save!
|
248
|
+
|
249
|
+
notified += 1
|
250
|
+
|
251
|
+
GC.start if (notified % 250) == 0
|
252
|
+
end
|
253
|
+
|
254
|
+
touch
|
255
|
+
end
|
256
|
+
|
257
|
+
# The main function to send this thing
|
258
|
+
def notify!(force: false)
|
259
|
+
scheduled_email? ? notify_by_schedule!(force: force) : notify_by_resources!(force: force)
|
223
260
|
end
|
224
261
|
|
225
262
|
# Operates on every resource in the data source. Sends one email for each row
|
226
|
-
def notify_by_resources!
|
263
|
+
def notify_by_resources!(force: false)
|
227
264
|
notified = 0
|
228
265
|
|
229
266
|
report.collection().find_each do |resource|
|
230
|
-
next unless notifiable?(resource)
|
267
|
+
next unless notifiable?(resource) || force
|
231
268
|
print('.')
|
232
269
|
|
233
270
|
# For logging
|
@@ -245,10 +282,10 @@ module Effective
|
|
245
282
|
notified > 0 ? update!(last_notified_at: Time.zone.now, last_notified_count: notified) : touch
|
246
283
|
end
|
247
284
|
|
248
|
-
def notify_by_schedule!
|
285
|
+
def notify_by_schedule!(force: false)
|
249
286
|
notified = 0
|
250
287
|
|
251
|
-
if notifiable_scheduled?
|
288
|
+
if notifiable_scheduled? || force
|
252
289
|
build_notification_log(resource: nil).save!
|
253
290
|
Effective::NotificationsMailer.notify(self).deliver_now
|
254
291
|
notified += 1
|
@@ -257,22 +294,27 @@ module Effective
|
|
257
294
|
notified > 0 ? update!(last_notified_at: Time.zone.now, last_notified_count: notified) : touch
|
258
295
|
end
|
259
296
|
|
260
|
-
def notifiable?(resource)
|
297
|
+
def notifiable?(resource, date: nil)
|
261
298
|
raise('expected an acts_as_reportable resource') unless resource.class.try(:acts_as_reportable?)
|
262
299
|
|
263
300
|
if schedule_type == 'immediate'
|
264
|
-
notifiable_immediate?(resource: resource)
|
301
|
+
notifiable_immediate?(resource: resource, date: date)
|
265
302
|
elsif schedule_type == 'scheduled'
|
266
|
-
notifiable_scheduled?(date:
|
303
|
+
notifiable_scheduled?(date: date)
|
267
304
|
else
|
268
305
|
raise("unsupported schedule_type")
|
269
306
|
end
|
270
307
|
end
|
271
308
|
|
309
|
+
def notifiable_tomorrow?(resource)
|
310
|
+
date = Time.zone.now.beginning_of_day.advance(days: 1)
|
311
|
+
notifiable?(resource, date: date)
|
312
|
+
end
|
313
|
+
|
272
314
|
# Consider the notification logs which track how many and how long ago this notification was sent
|
273
315
|
# 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
|
316
|
+
def notifiable_immediate?(resource:, date: nil)
|
317
|
+
raise('expected an immediate? notification') unless immediate?
|
276
318
|
|
277
319
|
email = resource_email(resource) || resource_user(resource).try(:email)
|
278
320
|
raise("expected an email for #{report} #{report&.id} and #{resource} #{resource&.id}") unless email.present?
|
@@ -283,8 +325,8 @@ module Effective
|
|
283
325
|
true # This is the first time. We should send.
|
284
326
|
elsif logs.count < immediate_times
|
285
327
|
# We still have to send it but consider dates.
|
286
|
-
last_sent_days_ago = logs.map(
|
287
|
-
last_sent_days_ago >= immediate_days
|
328
|
+
last_sent_days_ago = logs.map { |log| log.days_ago(date: date) }.min || 0
|
329
|
+
(last_sent_days_ago >= immediate_days)
|
288
330
|
else
|
289
331
|
false # We've already sent enough times
|
290
332
|
end
|
@@ -348,13 +390,13 @@ module Effective
|
|
348
390
|
report_assigns.merge(reportable_view_assigns)
|
349
391
|
end
|
350
392
|
|
351
|
-
def build_notification_log(resource: nil)
|
393
|
+
def build_notification_log(resource: nil, skipped: false)
|
352
394
|
user = resource_user(resource)
|
353
395
|
|
354
396
|
email = resource_email(resource) || user.try(:email)
|
355
397
|
email ||= audience_emails_to_s if scheduled_email?
|
356
398
|
|
357
|
-
notification_logs.build(email: email, report: report, resource: resource, user: user)
|
399
|
+
notification_logs.build(email: email, report: report, resource: resource, user: user, skipped: skipped)
|
358
400
|
end
|
359
401
|
|
360
402
|
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,12 @@ 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 :send_now, on: :member
|
19
|
+
post :skip_once, on: :member
|
20
|
+
end
|
21
|
+
|
17
22
|
resources :notification_logs, only: [:index, :destroy]
|
18
23
|
end
|
19
24
|
|
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.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: 2023-08-
|
11
|
+
date: 2023-08-27 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
|