tolliver 1.0.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +56 -0
- data/app/mailers/tolliver/notification_mailer.rb +16 -0
- data/app/models/tolliver/notification.rb +17 -0
- data/app/models/tolliver/notification_delivery.rb +19 -0
- data/app/models/tolliver/notification_receiver.rb +19 -0
- data/app/models/tolliver/notification_template.rb +17 -0
- data/app/views/notification_mailer/notify.html.erb +1 -0
- data/app/views/notification_mailer/notify.text.erb +1 -0
- data/config/locales/cs.yml +86 -0
- data/config/locales/en.yml +86 -0
- data/config/routes.rb +13 -0
- data/db/migrate/20160121093817_create_notifications.rb +28 -0
- data/db/migrate/20160121094838_create_notification_receivers.rb +21 -0
- data/db/migrate/20160509144238_create_notification_templates.rb +21 -0
- data/db/migrate/20170630190600_create_notification_deliveries.rb +20 -0
- data/lib/tolliver.rb +167 -0
- data/lib/tolliver/engine.rb +17 -0
- data/lib/tolliver/mailers/notification_mailer.rb +44 -0
- data/lib/tolliver/models/notification.rb +121 -0
- data/lib/tolliver/models/notification_delivery.rb +112 -0
- data/lib/tolliver/models/notification_delivery/batch.rb +77 -0
- data/lib/tolliver/models/notification_delivery/instantly.rb +55 -0
- data/lib/tolliver/models/notification_receiver.rb +76 -0
- data/lib/tolliver/models/notification_receiver/email.rb +46 -0
- data/lib/tolliver/models/notification_receiver/sms.rb +45 -0
- data/lib/tolliver/models/notification_template.rb +54 -0
- data/lib/tolliver/services/delivery.rb +30 -0
- data/lib/tolliver/services/notification.rb +234 -0
- data/lib/tolliver/services/sms/plivo.rb +49 -0
- data/lib/tolliver/utils/enum.rb +133 -0
- metadata +89 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
class CreateNotificationDeliveries < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :notification_deliveries do |t|
|
4
|
+
|
5
|
+
# Timestamps
|
6
|
+
t.timestamps null: true
|
7
|
+
t.datetime :sent_at
|
8
|
+
|
9
|
+
# Relations
|
10
|
+
t.integer :notification_id, index: true
|
11
|
+
|
12
|
+
# Delivery kind (email, SMS, mailboxer, ...)
|
13
|
+
t.string :kind
|
14
|
+
|
15
|
+
# Statistics
|
16
|
+
t.integer :receivers_count
|
17
|
+
t.integer :sent_count
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/tolliver.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# *****************************************************************************
|
2
|
+
# * Copyright (c) 2019 Matěj Outlý
|
3
|
+
# *****************************************************************************
|
4
|
+
# *
|
5
|
+
# * Tolliver engine
|
6
|
+
# *
|
7
|
+
# * Author: Matěj Outlý
|
8
|
+
# * Date : 9. 6. 2015
|
9
|
+
# *
|
10
|
+
# *****************************************************************************
|
11
|
+
|
12
|
+
# Engine
|
13
|
+
require "tolliver/engine"
|
14
|
+
|
15
|
+
# Models
|
16
|
+
require "tolliver/models/notification"
|
17
|
+
require "tolliver/models/notification_delivery"
|
18
|
+
require "tolliver/models/notification_delivery/batch"
|
19
|
+
require "tolliver/models/notification_delivery/instantly"
|
20
|
+
require "tolliver/models/notification_receiver"
|
21
|
+
require "tolliver/models/notification_receiver/email"
|
22
|
+
require "tolliver/models/notification_receiver/sms"
|
23
|
+
require "tolliver/models/notification_template"
|
24
|
+
|
25
|
+
# Services
|
26
|
+
require "tolliver/services/notification"
|
27
|
+
require "tolliver/services/delivery"
|
28
|
+
|
29
|
+
# Mailers
|
30
|
+
require "tolliver/mailers/notification_mailer"
|
31
|
+
|
32
|
+
# Utils
|
33
|
+
require "tolliver/utils/enum"
|
34
|
+
|
35
|
+
module Tolliver
|
36
|
+
|
37
|
+
# This will keep Rails Engine from generating all table prefixes with the engines name
|
38
|
+
def self.table_name_prefix
|
39
|
+
end
|
40
|
+
|
41
|
+
# *************************************************************************
|
42
|
+
# Services
|
43
|
+
# *************************************************************************
|
44
|
+
|
45
|
+
include Tolliver::Services::Notification
|
46
|
+
include Tolliver::Services::Delivery
|
47
|
+
|
48
|
+
# *************************************************************************
|
49
|
+
# Configuration
|
50
|
+
# *************************************************************************
|
51
|
+
|
52
|
+
# Default way to setup module
|
53
|
+
def self.setup
|
54
|
+
yield self
|
55
|
+
end
|
56
|
+
|
57
|
+
# *************************************************************************
|
58
|
+
# SMS
|
59
|
+
# *************************************************************************
|
60
|
+
|
61
|
+
def self.sms_provider_obj
|
62
|
+
if @sms_provider_obj.nil?
|
63
|
+
sms_provider_class_name = "Tolliver::Services::Sms::#{Tolliver.sms_provider.to_s.to_camel}"
|
64
|
+
@sms_provider_obj = sms_provider_class_name.constantize.new(Tolliver.sms_provider_params)
|
65
|
+
end
|
66
|
+
return @sms_provider_obj
|
67
|
+
end
|
68
|
+
|
69
|
+
# *************************************************************************
|
70
|
+
# Config options
|
71
|
+
# *************************************************************************
|
72
|
+
|
73
|
+
# Notification model
|
74
|
+
mattr_accessor :notification_model
|
75
|
+
|
76
|
+
def self.notification_model
|
77
|
+
return @@notification_model.constantize
|
78
|
+
end
|
79
|
+
|
80
|
+
@@notification_model = "Tolliver::Notification"
|
81
|
+
|
82
|
+
# Notification delivery model
|
83
|
+
mattr_accessor :notification_delivery_model
|
84
|
+
|
85
|
+
def self.notification_delivery_model
|
86
|
+
return @@notification_delivery_model.constantize
|
87
|
+
end
|
88
|
+
|
89
|
+
@@notification_delivery_model = "Tolliver::NotificationDelivery"
|
90
|
+
|
91
|
+
# Notification receiver model
|
92
|
+
mattr_accessor :notification_receiver_model
|
93
|
+
|
94
|
+
def self.notification_receiver_model
|
95
|
+
return @@notification_receiver_model.constantize
|
96
|
+
end
|
97
|
+
|
98
|
+
@@notification_receiver_model = "Tolliver::NotificationReceiver"
|
99
|
+
|
100
|
+
# Notification template model
|
101
|
+
mattr_accessor :notification_template_model
|
102
|
+
|
103
|
+
def self.notification_template_model
|
104
|
+
return @@notification_template_model.constantize
|
105
|
+
end
|
106
|
+
|
107
|
+
@@notification_template_model = "Tolliver::NotificationTemplate"
|
108
|
+
|
109
|
+
# People selector model
|
110
|
+
mattr_accessor :people_selector_model
|
111
|
+
|
112
|
+
def self.people_selector_model
|
113
|
+
return @@people_selector_model.constantize
|
114
|
+
end
|
115
|
+
|
116
|
+
@@people_selector_model = nil
|
117
|
+
|
118
|
+
# Available notification template refs. For each defined ref there will be
|
119
|
+
# an automatically created record in the notification_templates table.
|
120
|
+
# System administrator can define content of this template via admin
|
121
|
+
# interface.
|
122
|
+
mattr_accessor :template_refs
|
123
|
+
@@template_refs = [
|
124
|
+
# :some_notification_ref_1,
|
125
|
+
# :some_notification_ref_2,
|
126
|
+
]
|
127
|
+
|
128
|
+
# Delivery kinds
|
129
|
+
#
|
130
|
+
# Available kinds:
|
131
|
+
# - email
|
132
|
+
# - sms
|
133
|
+
# - whatever
|
134
|
+
mattr_accessor :delivery_kinds
|
135
|
+
@@delivery_kinds = [
|
136
|
+
:email
|
137
|
+
]
|
138
|
+
|
139
|
+
# Load balancer defined in minutes
|
140
|
+
#
|
141
|
+
# If another notification have been delivered in last X minutes, delivery
|
142
|
+
# will be postponed. It should prevent delivery service overloading in case
|
143
|
+
# of some mistake or security problem.
|
144
|
+
mattr_accessor :load_balance
|
145
|
+
@@load_balance = nil
|
146
|
+
|
147
|
+
# Mailer sender
|
148
|
+
mattr_accessor :mailer_sender
|
149
|
+
#@@mailer_sender = "test@domain.com" to be set in module initializer if needed
|
150
|
+
|
151
|
+
# Mailer sender name
|
152
|
+
mattr_accessor :mailer_sender_name
|
153
|
+
#@@mailer_sender_name = "Test sender" to be set in module initializer if needed
|
154
|
+
|
155
|
+
# Used SMS provider
|
156
|
+
mattr_accessor :sms_provider
|
157
|
+
@@sms_provider = :plivo
|
158
|
+
|
159
|
+
# SMS provider params
|
160
|
+
mattr_accessor :sms_provider_params
|
161
|
+
@@sms_provider_params = {}
|
162
|
+
|
163
|
+
# Used SMS provider
|
164
|
+
mattr_accessor :sms_sender
|
165
|
+
#@@sms_sender = "+420 123 456 789" to be set in module initializer if needed
|
166
|
+
|
167
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# *****************************************************************************
|
2
|
+
# * Copyright (c) 2019 Matěj Outlý
|
3
|
+
# *****************************************************************************
|
4
|
+
# *
|
5
|
+
# * Engine
|
6
|
+
# *
|
7
|
+
# * Author: Matěj Outlý
|
8
|
+
# * Date : 9. 6. 2015
|
9
|
+
# *
|
10
|
+
# *****************************************************************************
|
11
|
+
|
12
|
+
module Tolliver
|
13
|
+
class Engine < ::Rails::Engine
|
14
|
+
isolate_namespace Tolliver
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# *****************************************************************************
|
2
|
+
# * Copyright (c) 2019 Matěj Outlý
|
3
|
+
# *****************************************************************************
|
4
|
+
# *
|
5
|
+
# * Notification mailer
|
6
|
+
# *
|
7
|
+
# * Author: Matěj Outlý
|
8
|
+
# * Date : 21. 1. 2016
|
9
|
+
# *
|
10
|
+
# *****************************************************************************
|
11
|
+
|
12
|
+
module Tolliver
|
13
|
+
module Mailers
|
14
|
+
module NotificationMailer
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
def notify(notification, receiver)
|
18
|
+
|
19
|
+
# Sender
|
20
|
+
@sender = Tolliver.mailer_sender
|
21
|
+
raise "Please specify sender." if @sender.nil?
|
22
|
+
if !Tolliver.mailer_sender_name.blank?
|
23
|
+
@sender = "#{Tolliver.mailer_sender_name} <#{@sender}>"
|
24
|
+
end
|
25
|
+
|
26
|
+
# Other view data
|
27
|
+
@notification = notification
|
28
|
+
@receiver = receiver
|
29
|
+
|
30
|
+
# Subject
|
31
|
+
subject = !@notification.subject.blank? ? @notification.subject : I18n.t("activerecord.mailers.tolliver.notification.notify.default_subject", url: main_app.root_url)
|
32
|
+
|
33
|
+
# Attachment
|
34
|
+
if !notification.attachment.blank?
|
35
|
+
attachments[File.basename(notification.attachment)] = File.read(notification.attachment)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Mail
|
39
|
+
mail(from: @sender, to: receiver.email, subject: subject)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# *****************************************************************************
|
2
|
+
# * Copyright (c) 2019 Matěj Outlý
|
3
|
+
# *****************************************************************************
|
4
|
+
# *
|
5
|
+
# * Notification
|
6
|
+
# *
|
7
|
+
# * Author: Matěj Outlý
|
8
|
+
# * Date : 21. 1. 2016
|
9
|
+
# *
|
10
|
+
# *****************************************************************************
|
11
|
+
|
12
|
+
module Tolliver
|
13
|
+
module Models
|
14
|
+
module Notification
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
included do
|
18
|
+
|
19
|
+
# *********************************************************************
|
20
|
+
# Structure
|
21
|
+
# *********************************************************************
|
22
|
+
|
23
|
+
has_many :notification_deliveries, class_name: Tolliver.notification_delivery_model.to_s, dependent: :destroy
|
24
|
+
belongs_to :sender, polymorphic: true
|
25
|
+
belongs_to :notification_template, class_name: Tolliver.notification_template_model.to_s
|
26
|
+
|
27
|
+
# *********************************************************************
|
28
|
+
# Kind
|
29
|
+
# *********************************************************************
|
30
|
+
|
31
|
+
enum_column :kind, [:notice, :alert, :warning], default: :notice
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
# ***********************************************************************
|
36
|
+
# Progress
|
37
|
+
# ***********************************************************************
|
38
|
+
|
39
|
+
def done
|
40
|
+
sent_count = 0
|
41
|
+
receivers_count = 0
|
42
|
+
self.notification_deliveries.each do |notification_delivery|
|
43
|
+
sent_count += notification_delivery.sent_count.to_i
|
44
|
+
receivers_count += notification_delivery.receivers_count.to_i
|
45
|
+
end
|
46
|
+
return sent_count.to_s + "/" + receivers_count.to_s
|
47
|
+
end
|
48
|
+
|
49
|
+
# ***********************************************************************
|
50
|
+
# Sender
|
51
|
+
# ***********************************************************************
|
52
|
+
|
53
|
+
# Get name or email in case name is not set
|
54
|
+
def sender_name_or_email
|
55
|
+
if self.sender
|
56
|
+
if self.sender.respond_to?(:name_formatted) && !self.sender.name_formatted.blank?
|
57
|
+
return self.sender.name_formatted
|
58
|
+
elsif self.sender.respond_to?(:name) && !self.sender.name.blank?
|
59
|
+
return self.sender.name
|
60
|
+
else
|
61
|
+
return self.sender.email
|
62
|
+
end
|
63
|
+
else
|
64
|
+
return nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# ***********************************************************************
|
69
|
+
# Delivery
|
70
|
+
# ***********************************************************************
|
71
|
+
|
72
|
+
# Enqueue for delivery
|
73
|
+
def enqueue_for_delivery
|
74
|
+
QC.enqueue("#{self.class.to_s}.deliver", self.id)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Deliver notification to receivers by all configured methods
|
78
|
+
def deliver
|
79
|
+
self.notification_deliveries.each do |notification_delivery|
|
80
|
+
notification_delivery.deliver
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module ClassMethods
|
85
|
+
|
86
|
+
# Deliver notification (defined by ID) to receivers by all configured methods
|
87
|
+
def deliver(notification_id)
|
88
|
+
|
89
|
+
# Find notification object
|
90
|
+
notification = Tolliver.notification_model.find_by_id(notification_id)
|
91
|
+
return nil if notification.nil?
|
92
|
+
|
93
|
+
# Load balance
|
94
|
+
if !Tolliver.load_balance.blank?
|
95
|
+
notifications_sent_in_protected_time_window = Tolliver.notification_model
|
96
|
+
.joins(:notification_deliveries)
|
97
|
+
.where.not(id: notification.id)
|
98
|
+
.where("notification_deliveries.sent_at > ?", Time.current - Tolliver.load_balance.minutes).distinct
|
99
|
+
if notifications_sent_in_protected_time_window.count > 0
|
100
|
+
|
101
|
+
# Sleep for given amount of time
|
102
|
+
sleep(Tolliver.load_balance * 60) # seconds
|
103
|
+
|
104
|
+
# Then try again
|
105
|
+
notification.enqueue_for_delivery
|
106
|
+
|
107
|
+
return notification
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Deliver
|
112
|
+
notification.deliver
|
113
|
+
|
114
|
+
return notification
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# *****************************************************************************
|
2
|
+
# * Copyright (c) 2019 Matěj Outlý
|
3
|
+
# *****************************************************************************
|
4
|
+
# *
|
5
|
+
# * Notification receiver
|
6
|
+
# *
|
7
|
+
# * Author: Matěj Outlý
|
8
|
+
# * Date : 21. 1. 2016
|
9
|
+
# *
|
10
|
+
# *****************************************************************************
|
11
|
+
|
12
|
+
module Tolliver
|
13
|
+
module Models
|
14
|
+
module NotificationDelivery
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
included do
|
18
|
+
|
19
|
+
# *********************************************************************
|
20
|
+
# Structure
|
21
|
+
# *********************************************************************
|
22
|
+
|
23
|
+
belongs_to :notification, class_name: Tolliver.notification_model.to_s
|
24
|
+
has_many :notification_receivers, class_name: Tolliver.notification_receiver_model.to_s, dependent: :destroy
|
25
|
+
|
26
|
+
# *********************************************************************
|
27
|
+
# Validators
|
28
|
+
# *********************************************************************
|
29
|
+
|
30
|
+
validates_presence_of :notification_id, :kind
|
31
|
+
|
32
|
+
# *********************************************************************
|
33
|
+
# Kind
|
34
|
+
# *********************************************************************
|
35
|
+
|
36
|
+
enum_column :kind, Tolliver.delivery_kinds
|
37
|
+
|
38
|
+
# *********************************************************************
|
39
|
+
# Queue kind
|
40
|
+
# *********************************************************************
|
41
|
+
|
42
|
+
enum_column :policy, [
|
43
|
+
:instantly,
|
44
|
+
:batch
|
45
|
+
]
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
# ***********************************************************************
|
50
|
+
# Policy
|
51
|
+
# ***********************************************************************
|
52
|
+
|
53
|
+
def policy
|
54
|
+
return case self.kind.to_sym
|
55
|
+
when :email then
|
56
|
+
:batch
|
57
|
+
when :sms then
|
58
|
+
:batch
|
59
|
+
else
|
60
|
+
:instantly
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# ***********************************************************************
|
65
|
+
# Progress
|
66
|
+
# ***********************************************************************
|
67
|
+
|
68
|
+
def done
|
69
|
+
if self.sent_count && self.receivers_count
|
70
|
+
return self.sent_count.to_s + "/" + self.receivers_count.to_s
|
71
|
+
else
|
72
|
+
return nil
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# ***********************************************************************
|
77
|
+
# Service
|
78
|
+
# ***********************************************************************
|
79
|
+
|
80
|
+
# Deliver by correct policy
|
81
|
+
def deliver
|
82
|
+
self.class.deliver(self.id)
|
83
|
+
end
|
84
|
+
|
85
|
+
module ClassMethods
|
86
|
+
|
87
|
+
# Deliver by correct policy
|
88
|
+
def deliver(notification_delivery_id)
|
89
|
+
|
90
|
+
# Find notification delivery object
|
91
|
+
notification_delivery = Tolliver.notification_delivery_model.find_by_id(notification_delivery_id)
|
92
|
+
return nil if notification_delivery.nil?
|
93
|
+
|
94
|
+
# "Instanly" policy
|
95
|
+
if notification_delivery.policy == :instantly
|
96
|
+
self.deliver_instantly(notification_delivery_id)
|
97
|
+
|
98
|
+
# "Batch" policy
|
99
|
+
elsif notification_delivery.policy == :batch
|
100
|
+
QC.enqueue("#{self.to_s}.deliver_batch_and_enqueue", notification_delivery_id)
|
101
|
+
else
|
102
|
+
return nil
|
103
|
+
end
|
104
|
+
|
105
|
+
return notification_delivery
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|