tolliver 1.0.0 → 2.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -11
  3. data/app/models/tolliver/notification.rb +0 -1
  4. data/app/models/tolliver/notification_attachment.rb +16 -0
  5. data/app/models/tolliver/notification_delivery.rb +1 -3
  6. data/app/models/tolliver/notification_receiver.rb +0 -2
  7. data/app/models/tolliver/notification_template.rb +0 -1
  8. data/app/views/{notification_mailer → tolliver/notification_mailer}/notify.html.erb +0 -0
  9. data/app/views/tolliver/notification_mailer/notify.text.erb +1 -0
  10. data/config/locales/en.yml +1 -1
  11. data/db/migrate/20160121093817_create_notifications.rb +1 -12
  12. data/db/migrate/20160121094838_create_notification_receivers.rb +6 -4
  13. data/db/migrate/20160509144238_create_notification_templates.rb +4 -4
  14. data/db/migrate/20170630190600_create_notification_deliveries.rb +10 -3
  15. data/db/migrate/20201027150000_create_notification_attachments.rb +17 -0
  16. data/lib/tolliver.rb +44 -47
  17. data/lib/tolliver/errors/bad_request.rb +17 -0
  18. data/lib/tolliver/errors/not_found.rb +17 -0
  19. data/lib/tolliver/errors/standard_error.rb +17 -0
  20. data/lib/tolliver/mailers/notification_mailer.rb +10 -13
  21. data/lib/tolliver/models/notification.rb +11 -64
  22. data/lib/tolliver/models/notification_attachment.rb +35 -0
  23. data/lib/tolliver/models/notification_delivery.rb +32 -40
  24. data/lib/tolliver/models/notification_receiver.rb +3 -25
  25. data/lib/tolliver/models/notification_template.rb +6 -10
  26. data/lib/tolliver/services/delivery.rb +52 -8
  27. data/lib/tolliver/services/methods/email.rb +42 -0
  28. data/lib/tolliver/services/methods/sms.rb +51 -0
  29. data/lib/tolliver/services/methods/sms/plivo.rb +51 -0
  30. data/lib/tolliver/services/notification.rb +109 -178
  31. data/lib/tolliver/services/policies/batch.rb +90 -0
  32. data/lib/tolliver/services/policies/instantly.rb +50 -0
  33. metadata +20 -14
  34. data/app/views/notification_mailer/notify.text.erb +0 -1
  35. data/lib/tolliver/models/notification_delivery/batch.rb +0 -77
  36. data/lib/tolliver/models/notification_delivery/instantly.rb +0 -55
  37. data/lib/tolliver/models/notification_receiver/email.rb +0 -46
  38. data/lib/tolliver/models/notification_receiver/sms.rb +0 -45
  39. data/lib/tolliver/services/sms/plivo.rb +0 -49
@@ -0,0 +1,17 @@
1
+ # *****************************************************************************
2
+ # * Copyright (c) 2019 Matěj Outlý
3
+ # *****************************************************************************
4
+ # *
5
+ # * Standard error
6
+ # *
7
+ # * Author: Matěj Outlý
8
+ # * Date : 19. 4. 2017
9
+ # *
10
+ # *****************************************************************************
11
+
12
+ module Tolliver
13
+ module Errors
14
+ class StandardError < ::StandardError
15
+ end
16
+ end
17
+ end
@@ -14,29 +14,26 @@ module Tolliver
14
14
  module NotificationMailer
15
15
  extend ActiveSupport::Concern
16
16
 
17
- def notify(notification, receiver)
17
+ def notify(notification, notification_receiver)
18
18
 
19
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}>"
20
+ @sender_email = Tolliver.email_sender
21
+ raise Tolliver::Errors::StandardError.new("Please specify sender.") if @sender_email.nil?
22
+ unless Tolliver.email_sender_name.blank?
23
+ @sender_email = "#{Tolliver.email_sender_name} <#{@sender_email}>"
24
24
  end
25
25
 
26
26
  # Other view data
27
27
  @notification = notification
28
- @receiver = receiver
28
+ @notification_receiver = notification_receiver
29
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)
30
+ # Attachments
31
+ notification.notification_attachments.each do |notification_attachment|
32
+ attachments[notification_attachment.name] = notification_attachment.attachment
36
33
  end
37
34
 
38
35
  # Mail
39
- mail(from: @sender, to: receiver.email, subject: subject)
36
+ mail(from: @sender_email, to: @notification_receiver.receiver_contact, subject: @notification.subject)
40
37
  end
41
38
 
42
39
  end
@@ -21,14 +21,15 @@ module Tolliver
21
21
  # *********************************************************************
22
22
 
23
23
  has_many :notification_deliveries, class_name: Tolliver.notification_delivery_model.to_s, dependent: :destroy
24
- belongs_to :sender, polymorphic: true
24
+ has_many :notification_receivers, class_name: Tolliver.notification_receiver_model.to_s, through: :notification_deliveries
25
+ has_many :notification_attachments, class_name: Tolliver.notification_attachment_model.to_s, dependent: :destroy
25
26
  belongs_to :notification_template, class_name: Tolliver.notification_template_model.to_s
26
27
 
27
28
  # *********************************************************************
28
- # Kind
29
+ # Validators
29
30
  # *********************************************************************
30
31
 
31
- enum_column :kind, [:notice, :alert, :warning], default: :notice
32
+ validates_presence_of :subject
32
33
 
33
34
  end
34
35
 
@@ -43,77 +44,23 @@ module Tolliver
43
44
  sent_count += notification_delivery.sent_count.to_i
44
45
  receivers_count += notification_delivery.receivers_count.to_i
45
46
  end
46
- return sent_count.to_s + "/" + receivers_count.to_s
47
+ sent_count.to_s + "/" + receivers_count.to_s
47
48
  end
48
49
 
49
50
  # ***********************************************************************
50
- # Sender
51
+ # Service
51
52
  # ***********************************************************************
52
53
 
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
54
+ def deliver
55
+ Tolliver::Services::Delivery.instance.deliver(self)
66
56
  end
67
57
 
68
- # ***********************************************************************
69
- # Delivery
70
- # ***********************************************************************
71
-
72
- # Enqueue for delivery
73
58
  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
59
+ Tolliver::Services::Delivery.instance.enqueue_for_delivery(self)
82
60
  end
83
61
 
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
-
62
+ def reset_delivery
63
+ Tolliver::Services::Delivery.instance.reset_delivery(self)
117
64
  end
118
65
 
119
66
  end
@@ -0,0 +1,35 @@
1
+ # *****************************************************************************
2
+ # * Copyright (c) 2019 Matěj Outlý
3
+ # *****************************************************************************
4
+ # *
5
+ # * Notification attachment
6
+ # *
7
+ # * Author: Matěj Outlý
8
+ # * Date : 27. 10. 2020
9
+ # *
10
+ # *****************************************************************************
11
+
12
+ module Tolliver
13
+ module Models
14
+ module NotificationAttachment
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
+
25
+ # *********************************************************************
26
+ # Validators
27
+ # *********************************************************************
28
+
29
+ validates_presence_of :notification_id
30
+
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -27,13 +27,13 @@ module Tolliver
27
27
  # Validators
28
28
  # *********************************************************************
29
29
 
30
- validates_presence_of :notification_id, :kind
30
+ validates_presence_of :notification_id, :method
31
31
 
32
32
  # *********************************************************************
33
- # Kind
33
+ # Delivery method
34
34
  # *********************************************************************
35
35
 
36
- enum_column :kind, Tolliver.delivery_kinds
36
+ enum_column :method, Tolliver.delivery_methods
37
37
 
38
38
  # *********************************************************************
39
39
  # Queue kind
@@ -46,19 +46,37 @@ module Tolliver
46
46
 
47
47
  end
48
48
 
49
+ # ***********************************************************************
50
+ # Delivery method
51
+ # ***********************************************************************
52
+
53
+ def method_service
54
+ if @method_service.nil?
55
+ @method_service = "Tolliver::Services::Methods::#{self.method.to_s.capitalize}".constantize.new
56
+ end
57
+ @method_service
58
+ end
59
+
49
60
  # ***********************************************************************
50
61
  # Policy
51
62
  # ***********************************************************************
52
63
 
53
64
  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
65
+ case self.method.to_sym
66
+ when :email then
67
+ :batch
68
+ when :sms then
69
+ :batch
70
+ else
71
+ :instantly
72
+ end
73
+ end
74
+
75
+ def policy_service
76
+ if @policy_service.nil?
77
+ @policy_service = "Tolliver::Services::Policies::#{self.policy.to_s.capitalize}".constantize.new
78
+ end
79
+ @policy_service
62
80
  end
63
81
 
64
82
  # ***********************************************************************
@@ -67,9 +85,9 @@ module Tolliver
67
85
 
68
86
  def done
69
87
  if self.sent_count && self.receivers_count
70
- return self.sent_count.to_s + "/" + self.receivers_count.to_s
88
+ self.sent_count.to_s + "/" + self.receivers_count.to_s
71
89
  else
72
- return nil
90
+ nil
73
91
  end
74
92
  end
75
93
 
@@ -77,34 +95,8 @@ module Tolliver
77
95
  # Service
78
96
  # ***********************************************************************
79
97
 
80
- # Deliver by correct policy
81
98
  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
-
99
+ self.policy_service.deliver(self)
108
100
  end
109
101
 
110
102
  end
@@ -21,54 +21,32 @@ module Tolliver
21
21
  # *********************************************************************
22
22
 
23
23
  belongs_to :notification_delivery, class_name: Tolliver.notification_delivery_model.to_s
24
- belongs_to :receiver, polymorphic: true
25
24
 
26
25
  # *********************************************************************
27
26
  # Validators
28
27
  # *********************************************************************
29
28
 
30
- validates_presence_of :notification_delivery_id, :receiver_id, :receiver_type
29
+ validates_presence_of :notification_delivery_id, :receiver_ref, :receiver_contact
31
30
 
32
31
  # *********************************************************************
33
32
  # State
34
33
  # *********************************************************************
35
34
 
36
- enum_column :state, [
35
+ enum_column :status, [
37
36
  :created,
38
37
  :sent,
39
38
  :received,
40
- :accepted,
41
39
  :error
42
40
  ], default: :created
43
41
 
44
42
  end
45
43
 
46
- # ***********************************************************************
47
- # Receiver
48
- # ***********************************************************************
49
-
50
- # Get name or email in case name is not set
51
- def receiver_name_or_email
52
- if self.receiver
53
- if self.receiver.respond_to?(:name_formatted) && !self.receiver.name_formatted.blank?
54
- return self.receiver.name_formatted
55
- elsif self.receiver.respond_to?(:name) && !self.receiver.name.blank?
56
- return self.receiver.name
57
- else
58
- return self.receiver.email
59
- end
60
- else
61
- return nil
62
- end
63
- end
64
-
65
44
  # ***********************************************************************
66
45
  # Delivery
67
46
  # ***********************************************************************
68
47
 
69
- # Deliver notification by correct delivery kind
70
48
  def deliver
71
- return self.send("deliver_by_#{self.notification_delivery.kind}")
49
+ self.notification_delivery.method_service.deliver(self)
72
50
  end
73
51
 
74
52
  end
@@ -20,19 +20,14 @@ module Tolliver
20
20
  # Structure
21
21
  # *********************************************************************
22
22
 
23
- has_many :notification_templates, class_name: Tolliver.notification_template_model.to_s, dependent: :nullify
23
+ has_many :notifications, class_name: Tolliver.notification_model.to_s, dependent: :nullify
24
24
 
25
25
  # *********************************************************************
26
26
  # Validators
27
27
  # *********************************************************************
28
28
 
29
- validates_presence_of :ref
30
-
31
- # *********************************************************************
32
- # Ref
33
- # *********************************************************************
34
-
35
- enum_column :ref, Tolliver.template_refs
29
+ validates_presence_of :ref, :subject
30
+ validates :ref, uniqueness: true
36
31
 
37
32
  end
38
33
 
@@ -40,10 +35,11 @@ module Tolliver
40
35
 
41
36
  def permitted_columns
42
37
  [
38
+ :ref,
43
39
  :subject,
44
40
  :message,
45
- :disabled,
46
- :dry
41
+ :is_disabled,
42
+ :is_dry
47
43
  ]
48
44
  end
49
45
 
@@ -9,20 +9,64 @@
9
9
  # *
10
10
  # *****************************************************************************
11
11
 
12
+ require 'singleton'
13
+
12
14
  module Tolliver
13
15
  module Services
14
- module Delivery
15
- extend ActiveSupport::Concern
16
+ class Delivery
17
+ include Singleton
18
+
19
+ def enqueue_for_delivery(notification)
20
+ return nil if notification.nil?
21
+ QC.enqueue("#{self.class.to_s}.deliver", notification.id)
22
+ end
23
+
24
+ # Entry point for QC
25
+ def self.deliver(notification_id)
26
+
27
+ # Instantiate notification object
28
+ notification = Tolliver.notification_model.find_by_id(notification_id)
29
+ return nil if notification.nil?
30
+
31
+ # Call standard API
32
+ self.instance.deliver(notification)
33
+ end
16
34
 
17
- module ClassMethods
35
+ # Deliver notification to receivers by all configured methods
36
+ def deliver(notification)
37
+ return nil if notification.nil?
18
38
 
19
- #
20
- # Deliver notification (defined by ID) to receivers by all configured methods
21
- #
22
- def deliver(notification_id)
23
- Tolliver.notification_model.deliver(notification_id)
39
+ # Load balancing
40
+ unless Tolliver.load_balance.blank?
41
+ notifications_sent_in_protected_time_window = Tolliver.notification_model
42
+ .joins(:notification_deliveries)
43
+ .where.not(id: notification.id)
44
+ .where("notification_deliveries.sent_at > ?", Time.current - Tolliver.load_balance.minutes).distinct
45
+ if notifications_sent_in_protected_time_window.count > 0
46
+
47
+ # Sleep for given amount of time
48
+ sleep(Tolliver.load_balance * 60) # seconds
49
+
50
+ # Then try again
51
+ enqueue_for_delivery(notification)
52
+
53
+ return false
54
+ end
24
55
  end
25
56
 
57
+ # Process all notification deliveries
58
+ notification.notification_deliveries.each do |notification_delivery|
59
+ notification_delivery.policy_service.deliver(notification_delivery)
60
+ end
61
+
62
+ true
63
+ end
64
+
65
+ def reset_delivery(notification)
66
+ return nil if notification.nil?
67
+ notification.notification_deliveries.update_all(sent_count: 0, sent_at: nil)
68
+ notification.notification_receivers.update_all(sent_at: nil, received_at: nil, status: :created, error_message: nil)
69
+ true
26
70
  end
27
71
 
28
72
  end