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.
Files changed (33) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +56 -0
  4. data/app/mailers/tolliver/notification_mailer.rb +16 -0
  5. data/app/models/tolliver/notification.rb +17 -0
  6. data/app/models/tolliver/notification_delivery.rb +19 -0
  7. data/app/models/tolliver/notification_receiver.rb +19 -0
  8. data/app/models/tolliver/notification_template.rb +17 -0
  9. data/app/views/notification_mailer/notify.html.erb +1 -0
  10. data/app/views/notification_mailer/notify.text.erb +1 -0
  11. data/config/locales/cs.yml +86 -0
  12. data/config/locales/en.yml +86 -0
  13. data/config/routes.rb +13 -0
  14. data/db/migrate/20160121093817_create_notifications.rb +28 -0
  15. data/db/migrate/20160121094838_create_notification_receivers.rb +21 -0
  16. data/db/migrate/20160509144238_create_notification_templates.rb +21 -0
  17. data/db/migrate/20170630190600_create_notification_deliveries.rb +20 -0
  18. data/lib/tolliver.rb +167 -0
  19. data/lib/tolliver/engine.rb +17 -0
  20. data/lib/tolliver/mailers/notification_mailer.rb +44 -0
  21. data/lib/tolliver/models/notification.rb +121 -0
  22. data/lib/tolliver/models/notification_delivery.rb +112 -0
  23. data/lib/tolliver/models/notification_delivery/batch.rb +77 -0
  24. data/lib/tolliver/models/notification_delivery/instantly.rb +55 -0
  25. data/lib/tolliver/models/notification_receiver.rb +76 -0
  26. data/lib/tolliver/models/notification_receiver/email.rb +46 -0
  27. data/lib/tolliver/models/notification_receiver/sms.rb +45 -0
  28. data/lib/tolliver/models/notification_template.rb +54 -0
  29. data/lib/tolliver/services/delivery.rb +30 -0
  30. data/lib/tolliver/services/notification.rb +234 -0
  31. data/lib/tolliver/services/sms/plivo.rb +49 -0
  32. data/lib/tolliver/utils/enum.rb +133 -0
  33. 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
@@ -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