rails-alerter 0.0.5

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 (89) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +36 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Appraisals +11 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +22 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +111 -0
  11. data/Rakefile +10 -0
  12. data/alerter.gemspec +60 -0
  13. data/app/builders/alerter/base_builder.rb +26 -0
  14. data/app/builders/alerter/message_builder.rb +16 -0
  15. data/app/builders/alerter/receipt_builder.rb +13 -0
  16. data/app/mailers/alerter/base_mailer.rb +15 -0
  17. data/app/mailers/alerter/message_mailer.rb +12 -0
  18. data/app/models/alerter/mailbox.rb +74 -0
  19. data/app/models/alerter/message.rb +171 -0
  20. data/app/models/alerter/notification_type.rb +20 -0
  21. data/app/models/alerter/preference.rb +19 -0
  22. data/app/models/alerter/receipt.rb +89 -0
  23. data/app/views/alerter/message_mailer/new_message_email.html.erb +20 -0
  24. data/app/views/alerter/message_mailer/new_message_email.text.erb +10 -0
  25. data/db/migrate/20150821000000_create_alerter.rb +65 -0
  26. data/lib/alerter/cleaner.rb +9 -0
  27. data/lib/alerter/engine.rb +31 -0
  28. data/lib/alerter/message_dispatcher.rb +62 -0
  29. data/lib/alerter/models/notifiable.rb +174 -0
  30. data/lib/alerter/version.rb +3 -0
  31. data/lib/generators/alerter/install_generator.rb +37 -0
  32. data/lib/generators/alerter/namespacing_compatibility_generator.rb +24 -0
  33. data/lib/generators/alerter/templates/initializer.rb +29 -0
  34. data/lib/generators/alerter/views_generator.rb +11 -0
  35. data/lib/rails-alerter.rb +71 -0
  36. data/spec/alerter/message_dispatcher_spec.rb +101 -0
  37. data/spec/alerter_spec.rb +8 -0
  38. data/spec/dummy/.gitignore +5 -0
  39. data/spec/dummy/Rakefile +7 -0
  40. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  41. data/spec/dummy/app/controllers/home_controller.rb +4 -0
  42. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  43. data/spec/dummy/app/mailers/.gitkeep +0 -0
  44. data/spec/dummy/app/models/.gitkeep +0 -0
  45. data/spec/dummy/app/models/cylon.rb +4 -0
  46. data/spec/dummy/app/models/duck.rb +3 -0
  47. data/spec/dummy/app/models/user.rb +3 -0
  48. data/spec/dummy/app/views/home/index.html.haml +7 -0
  49. data/spec/dummy/app/views/layouts/application.html.haml +11 -0
  50. data/spec/dummy/config.ru +4 -0
  51. data/spec/dummy/config/application.rb +47 -0
  52. data/spec/dummy/config/boot.rb +10 -0
  53. data/spec/dummy/config/database.yml +24 -0
  54. data/spec/dummy/config/environment.rb +5 -0
  55. data/spec/dummy/config/environments/development.rb +29 -0
  56. data/spec/dummy/config/environments/production.rb +51 -0
  57. data/spec/dummy/config/environments/test.rb +37 -0
  58. data/spec/dummy/config/initializers/alerter.rb +26 -0
  59. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  60. data/spec/dummy/config/initializers/inflections.rb +10 -0
  61. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  62. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  63. data/spec/dummy/config/initializers/session_store.rb +8 -0
  64. data/spec/dummy/config/locales/en.yml +5 -0
  65. data/spec/dummy/config/routes.rb +58 -0
  66. data/spec/dummy/config/sunspot.yml +17 -0
  67. data/spec/dummy/db/migrate/20110228120600_create_users.rb +14 -0
  68. data/spec/dummy/db/migrate/20110306002940_create_ducks.rb +14 -0
  69. data/spec/dummy/db/migrate/20110306015107_create_cylons.rb +14 -0
  70. data/spec/dummy/db/schema.rb +77 -0
  71. data/spec/dummy/public/404.html +26 -0
  72. data/spec/dummy/public/422.html +26 -0
  73. data/spec/dummy/public/500.html +26 -0
  74. data/spec/dummy/public/favicon.ico +0 -0
  75. data/spec/dummy/public/index.html +239 -0
  76. data/spec/dummy/public/robots.txt +5 -0
  77. data/spec/dummy/public/uploads/testfile.txt +1 -0
  78. data/spec/dummy/script/rails +6 -0
  79. data/spec/factories/general.rb +37 -0
  80. data/spec/integration/message_and_receipt_spec.rb +42 -0
  81. data/spec/integration/navigation_spec.rb +8 -0
  82. data/spec/mailers/message_mailer_spec.rb +44 -0
  83. data/spec/models/alerter_models_messageable_spec.rb +311 -0
  84. data/spec/models/mailbox_spec.rb +55 -0
  85. data/spec/models/message_spec.rb +51 -0
  86. data/spec/models/preference_spec.rb +35 -0
  87. data/spec/models/receipt_spec.rb +61 -0
  88. data/spec/spec_helper.rb +54 -0
  89. metadata +330 -0
@@ -0,0 +1,174 @@
1
+ module Alerter
2
+ module Models
3
+ module Notifiable
4
+ extend ActiveSupport::Concern
5
+
6
+ module ActiveRecordExtension
7
+ #Converts the model into messageable allowing it to interchange messages and
8
+ #receive notifications
9
+ def acts_as_notifiable
10
+ include Notifiable
11
+ end
12
+ end
13
+
14
+
15
+ included do
16
+ has_many :messages, :class_name => "Alerter::Message", :as => :sender
17
+ has_many :preferences, :class_name => "Alerter::Preference", :as => :notifiable, dependent: :destroy
18
+ if Rails::VERSION::MAJOR == 4
19
+ has_many :receipts, -> { order 'created_at DESC' }, :class_name => "Alerter::Receipt", dependent: :destroy, as: :receiver
20
+ else
21
+ # Rails 3 does it this way
22
+ has_many :receipts, :order => 'created_at DESC', :class_name => "Alerter::Receipt", :dependent => :destroy, :as => :receiver
23
+ end
24
+ end
25
+
26
+ # unless defined?(Alerter.name_method)
27
+ # # Returning any kind of identification you want for the model
28
+ # define_method Alerter.name_method do
29
+ # begin
30
+ # super
31
+ # rescue NameError
32
+ # return "You should add method :#{Alerter.name_method} in your Notifiable model"
33
+ # end
34
+ # end
35
+ # end
36
+ #
37
+ # unless defined?(Alerter.email_method)
38
+ # #Returning the email address of the model if an email should be sent for this Message.
39
+ # #If no mail has to be sent, return nil.
40
+ # define_method Alerter.email_method do |object|
41
+ # begin
42
+ # super
43
+ # rescue NameError
44
+ # return "You should add method :#{Alerter.email_method} in your Notifiable model"
45
+ # end
46
+ # end
47
+ # end
48
+
49
+ #Gets the mailbox of the notifiable
50
+ def mailbox
51
+ @mailbox ||= Alerter::Mailbox.new(self)
52
+ end
53
+
54
+ # Get number of unread messages
55
+ def unread_inbox_count
56
+ mailbox.inbox(unread: true).count
57
+ end
58
+
59
+
60
+ #Sends a notification
61
+ #as originator
62
+ def send_message(short_msg, long_msg, notification_type_name, sanitize_text = true)
63
+ message = Alerter::MessageBuilder.new({
64
+ :recipients => self,
65
+ :short_msg => short_msg,
66
+ :long_msg => long_msg,
67
+ :notification_type => NotificationType.find_or_create_by(name: notification_type_name),
68
+ }).build
69
+ message.save!
70
+ message.deliver sanitize_text
71
+ end
72
+
73
+
74
+
75
+ #Mark the object as read for notifiable.
76
+ #Object can be:
77
+ #* A Receipt
78
+ #* A Message
79
+ #* An Array of these
80
+ #Optionally pass in details of the read receipt as String
81
+ def mark_as_read(obj, details = nil)
82
+ case obj
83
+ when Alerter::Receipt
84
+ obj.mark_as_read if obj.receiver == self
85
+ when Alerter::Message
86
+ obj.mark_as_read(self)
87
+ when Array
88
+ obj.map{ |sub_obj| mark_as_read(sub_obj) }
89
+ end
90
+
91
+ end
92
+
93
+ #Mark the object as unread for notifiable.
94
+ #
95
+ #Object can be:
96
+ #* A Receipt
97
+ #* A Message
98
+ #* An Array of these
99
+ #Optionally pass in details of the un-read receipt as String
100
+ def mark_as_unread(obj, details = nil)
101
+ case obj
102
+ when Alerter::Receipt
103
+ obj.mark_as_unread if obj.receiver == self
104
+ when Alerter::Message
105
+ obj.mark_as_unread(self)
106
+ when Array
107
+ obj.map{ |sub_obj| mark_as_unread(sub_obj) }
108
+ end
109
+ end
110
+
111
+ #Mark the object as deleted for notifiable.
112
+ #
113
+ #Object can be:
114
+ #* A Receipt
115
+ #* A Message
116
+ #* An Array of these
117
+ #Optionally pass in details of the deletion as String
118
+ def mark_as_deleted(obj, details = nil)
119
+ case obj
120
+ when Receipt
121
+ return obj.mark_as_deleted if obj.receiver == self
122
+ when Message
123
+ obj.mark_as_deleted(self)
124
+ when Array
125
+ obj.map{ |sub_obj| mark_as_deleted(sub_obj) }
126
+ else
127
+ return nil
128
+ end
129
+ end
130
+
131
+ #Mark the object as not deleted for notifiable.
132
+ #
133
+ #Object can be:
134
+ #* A Receipt
135
+ #* A Message
136
+ #* An Array of these
137
+ #Optionally pass in details of the deletion as String
138
+ def mark_as_not_deleted(obj, details = nil)
139
+ case obj
140
+ when Receipt
141
+ return obj.mark_as_not_deleted if obj.receiver == self
142
+ when Message
143
+ obj.mark_as_not_deleted(self)
144
+ when Array
145
+ obj.map{ |sub_obj| mark_as_not_deleted(sub_obj) }
146
+ else
147
+ return nil
148
+ end
149
+ end
150
+
151
+ # Get the notification preferences for a given notification_type
152
+ def notification_methods(notification_type)
153
+ return [] unless notification_type.is_a?(Alerter::NotificationType)
154
+ prefs = preferences.find_by(notification_type: notification_type).try(:alert_methods)
155
+ prefs ||= []
156
+ end
157
+
158
+ # configure methods for a given notification type
159
+ # methods can be an array of methods, a single method, or nil
160
+ def configure_notification_methods(notification_type, methods)
161
+ preference = preferences.find_or_create_by(notification_type: notification_type)
162
+ if methods.is_a?(Array)
163
+ preference.alert_methods = methods
164
+ elsif methods.is_a?(String)
165
+ preference.alert_methods = [ methods ]
166
+ elsif methods.nil?
167
+ preference.alert_methods = [ ]
168
+ end
169
+ preference.save
170
+ end
171
+
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,3 @@
1
+ module Alerter
2
+ VERSION = "0.0.5"
3
+ end
@@ -0,0 +1,37 @@
1
+ module Alerter
2
+ class InstallGenerator < Rails::Generators::Base #:nodoc:
3
+ include Rails::Generators::Migration
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ require 'rails/generators/migration'
6
+
7
+ def self.next_migration_number path
8
+ unless @prev_migration_nr
9
+ @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
10
+ else
11
+ @prev_migration_nr += 1
12
+ end
13
+ @prev_migration_nr.to_s
14
+ end
15
+
16
+ def create_initializer_file
17
+ template 'initializer.rb', 'config/initializers/alerter.rb'
18
+ end
19
+
20
+ def copy_migrations
21
+ if Rails.version < "3.1"
22
+ migrations = [
23
+ %w[20150821000000_create_alerter.rb create_alerter.rb]
24
+ ]
25
+ migrations.each do |migration|
26
+ migration_template "../../../../db/migrate/" + migration[0], "db/migrate/" + migration[1]
27
+ end
28
+ # Rails 4 is handled by a initializer
29
+ # else
30
+ # require 'rake'
31
+ # Rails.application.load_tasks
32
+ # Rake::Task['railties:install:migrations'].reenable
33
+ # Rake::Task['rails-alerter_engine:install:migrations'].invoke
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,24 @@
1
+ module Alerter
2
+ class NamespacingCompatibilityGenerator < Rails::Generators::Base
3
+ include Rails::Generators::Migration
4
+ source_root File.expand_path('../templates', __FILE__)
5
+ require 'rails/generators/migration'
6
+
7
+ FILENAME = 'alerter_namespacing_compatibility.rb'
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ def create_model_file
12
+ migration_template FILENAME, "db/migrate/#{FILENAME}"
13
+ end
14
+
15
+ def self.next_migration_number path
16
+ unless @prev_migration_nr
17
+ @prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
18
+ else
19
+ @prev_migration_nr += 1
20
+ end
21
+ @prev_migration_nr.to_s
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ Alerter.setup do |config|
2
+
3
+ #Configures the default from for emails sent for Messages
4
+ config.default_from = "no-reply@alert.com"
5
+
6
+ #Configures the default subject line (only used in emails)
7
+ config.default_subject = "Alerter: you have a new message!"
8
+
9
+ #Configures the methods needed by alerter to get information about the model its attached to
10
+ #config.email_method = :email
11
+ #config.name_method = :name
12
+
13
+ #Configures the array of available (supported) notification methods
14
+ # Available choices are: none email push sms twitter
15
+ config.available_notification_methods = %w( none email ios_push android_push sms twitter )
16
+
17
+ config.notification_method = %w( none email ios_push android_push sms twitter )
18
+
19
+ #Configures maximum length of the message
20
+ config.short_msg_length = 144 # twitter support
21
+ config.long_msg_length = 2048
22
+
23
+ # Base application URL - to be used in messages
24
+ config.root_url = 'www.alert.com'
25
+ end
26
+
27
+ if Alerter::NotificationType.all.count == 0
28
+ Alerter::NotificationType.create(name: 'Default')
29
+ end
@@ -0,0 +1,11 @@
1
+ module Alerter
2
+ class ViewsGenerator < Rails::Generators::Base
3
+ source_root File.expand_path("../../../../app/views/alerter", __FILE__)
4
+
5
+ desc "Copy Alerter views into your app"
6
+
7
+ def copy_views
8
+ directory('message_mailer', 'app/views/alerter/message_mailer')
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,71 @@
1
+ require "alerter/version"
2
+
3
+ module Alerter
4
+ module Models
5
+ autoload :Notifiable, 'alerter/models/notifiable'
6
+ end
7
+
8
+ # Default from address for email notifications
9
+ mattr_accessor :default_from
10
+ @@default_from = "no-reply@alerter.com"
11
+
12
+ # default subject to use on emails only
13
+ mattr_accessor :default_subject
14
+ @@default_from = "Alerter: you have a new message!"
15
+
16
+ # method used to retrieve the recipient's name
17
+ mattr_accessor :name_method
18
+ @@name_method = :name
19
+
20
+ # method used to retrieve the recipient's email
21
+ mattr_accessor :email_method
22
+ @@email_method = :email
23
+
24
+ mattr_accessor :short_msg_length
25
+ @@short_msg_length = 144
26
+
27
+ mattr_accessor :long_msg_length
28
+ @@long_msg_length = 512
29
+
30
+ mattr_accessor :mailer_wants_array
31
+ @@mailer_wants_array = false
32
+
33
+ # array of available (supported) notification types
34
+ mattr_accessor :available_notification_types
35
+ @@available_notification_types = %w( info warning error action )
36
+
37
+ # array of available (supported) notification methods
38
+ mattr_accessor :available_notification_methods
39
+ @@available_notification_methods = %w( none email ios_push android_push sms twitter )
40
+
41
+ # the chosen notification method for this object
42
+ mattr_accessor :notification_method
43
+ @@notification_method = %w( none )
44
+
45
+ # Base url to use in messages
46
+ @@root_url = 'www.alerter.com'
47
+
48
+ mattr_accessor :email_message_mailer
49
+ mattr_accessor :custom_email_delivery_proc
50
+ mattr_accessor :sms_message_mailer
51
+ mattr_accessor :custom_sms_delivery_proc
52
+ mattr_accessor :push_message_mailer
53
+ mattr_accessor :custom_push_delivery_proc
54
+ mattr_accessor :root_url
55
+
56
+ class << self
57
+ def setup
58
+ yield self
59
+ end
60
+
61
+ def protected_attributes?
62
+ Rails.version < '4' || defined?(ProtectedAttributes)
63
+ end
64
+ end
65
+ end
66
+
67
+ # reopen ActiveRecord and include all the above to make
68
+ # them available to all our models if they want it
69
+ require 'alerter/engine'
70
+ require 'alerter/cleaner'
71
+ require 'alerter/message_dispatcher'
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Alerter::MessageDispatcher do
4
+
5
+ subject(:instance) { described_class.new(message, recipients) }
6
+
7
+ let(:message) { FactoryGirl.create :message }
8
+ let(:recipient1) { FactoryGirl.create :user_with_email_pref, email: nil }
9
+ let(:recipient2) { FactoryGirl.create :user_with_email_pref }
10
+ let(:recipients) { [ recipient1, recipient2 ] }
11
+
12
+ describe "call" do
13
+ context "supported methods" do
14
+ before { Alerter.notification_method = %w( bad ) }
15
+ after { Alerter.notification_method = %w( none email ios_push android_push sms twitter )}
16
+ its(:call) { should be false }
17
+ end
18
+
19
+ context "mailer wants array" do
20
+ before { Alerter.mailer_wants_array = true }
21
+ after { Alerter.mailer_wants_array = false }
22
+ it 'sends collection' do
23
+ expect(subject).to receive(:send_email).with(recipients)
24
+ subject.call
25
+ end
26
+ end
27
+
28
+ context "mailer doesnt want array" do
29
+ it 'sends collection' do
30
+ expect(subject).not_to receive(:send_email).with(recipient1) #email is blank
31
+ expect(subject).to receive(:send_email).with(recipient2)
32
+ subject.call
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "send_email" do
38
+
39
+ let(:mailer) { double 'mailer' }
40
+
41
+ before(:each) do
42
+ allow(subject).to receive(:mailer).and_return mailer
43
+ end
44
+
45
+ context "with custom_deliver_proc" do
46
+ let(:my_proc) { double 'proc' }
47
+
48
+ before { Alerter.custom_email_delivery_proc = my_proc }
49
+ after { Alerter.custom_email_delivery_proc = nil }
50
+ it "triggers proc" do
51
+ expect(my_proc).to receive(:call).with(mailer, message, recipient1)
52
+ subject.send :send_email, recipient1
53
+ end
54
+ end
55
+
56
+ context "without custom_deliver_proc" do
57
+ let(:email) { double :email }
58
+
59
+ it "triggers standard deliver chain" do
60
+ expect(mailer).to receive(:send_email).with(message, recipient1).and_return email
61
+ expect(email).to receive :deliver
62
+
63
+ subject.send :send_email, recipient1
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "send_push_notification" do
69
+
70
+ pending 'test push notifications'
71
+ # let(:mailer) { double 'mailer' }
72
+ #
73
+ # before(:each) do
74
+ # allow(subject).to receive(:mailer).and_return mailer
75
+ # end
76
+ #
77
+ # context "with custom_deliver_proc" do
78
+ # let(:my_proc) { double 'proc' }
79
+ #
80
+ # before { Alerter.custom_deliver_proc = my_proc }
81
+ # after { Alerter.custom_deliver_proc = nil }
82
+ # it "triggers proc" do
83
+ # expect(my_proc).to receive(:call).with(mailer, mailable, recipient1)
84
+ # subject.send :send_email, recipient1
85
+ # end
86
+ # end
87
+ #
88
+ # context "without custom_deliver_proc" do
89
+ # let(:email) { double :email }
90
+ #
91
+ # it "triggers standard deliver chain" do
92
+ # expect(mailer).to receive(:send_email).with(mailable, recipient1).and_return email
93
+ # expect(email).to receive :deliver
94
+ #
95
+ # subject.send :send_email, recipient1
96
+ # end
97
+ # end
98
+ end
99
+
100
+
101
+ end