notify_user 0.0.1 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/app/assets/javascripts/notify_user/notification.js +7 -0
- data/app/assets/stylesheets/notify_user/notify_user.css +50 -0
- data/app/controllers/notify_user/base_notifications_controller.rb +144 -0
- data/app/controllers/notify_user/notifications_controller.rb +7 -32
- data/app/helpers/notify_user/application_helper.rb +9 -0
- data/app/mailers/notify_user/notification_mailer.rb +2 -0
- data/app/models/notify_user/apns.rb +37 -0
- data/app/models/notify_user/base_notification.rb +136 -32
- data/app/models/notify_user/unsubscribe.rb +55 -0
- data/app/models/notify_user/user_hash.rb +36 -0
- data/app/serializers/notify_user/notification_serializer.rb +2 -2
- data/app/views/notify_user/action_mailer/aggregate_notification.html.erb +2 -1
- data/app/views/notify_user/action_mailer/notification.html.erb +1 -1
- data/app/views/notify_user/base_notifications/index.html.erb +20 -0
- data/app/views/notify_user/base_notifications/unsubscribe.html.erb +19 -0
- data/config/routes.rb +8 -0
- data/lib/generators/notify_user/install/install_generator.rb +20 -3
- data/lib/generators/notify_user/install/templates/{migration.rb → create_notify_user_notifications.rb} +1 -1
- data/lib/generators/notify_user/install/templates/create_notify_user_unsubscribes.rb +10 -0
- data/lib/generators/notify_user/install/templates/create_notify_user_user_hashes.rb +12 -0
- data/lib/generators/notify_user/install/templates/initializer.rb +2 -0
- data/lib/generators/notify_user/install/templates/notifications_controller.rb +9 -0
- data/lib/generators/notify_user/json_update/USAGE +5 -0
- data/lib/generators/notify_user/json_update/json_update_generator.rb +36 -0
- data/lib/generators/notify_user/json_update/templates/add_json_column_to_notifications.rb +9 -0
- data/lib/generators/notify_user/json_update/templates/move_params_to_json.rb +8 -0
- data/lib/generators/notify_user/notification/notification_generator.rb +2 -0
- data/lib/generators/notify_user/notification/templates/email_layout_template.html.erb.erb +6 -0
- data/lib/generators/notify_user/notification/templates/notification.rb.erb +2 -1
- data/lib/notify_user.rb +4 -1
- data/lib/notify_user/channels/action_mailer/action_mailer_channel.rb +2 -1
- data/lib/notify_user/channels/apns/apns_channel.rb +17 -0
- data/lib/notify_user/engine.rb +2 -0
- data/lib/notify_user/railtie.rb +10 -0
- data/lib/notify_user/version.rb +1 -1
- data/lib/tasks/notify_user.rake +15 -0
- data/spec/controllers/notify_user/notifications_controller_spec.rb +89 -1
- data/spec/dummy/rails-4.0.2/Gemfile +2 -2
- data/spec/dummy/rails-4.0.2/app/controllers/notify_user/notifications_controller.rb +9 -0
- data/spec/dummy/rails-4.0.2/app/notifications/new_post_notification.rb +2 -1
- data/spec/dummy/rails-4.0.2/app/views/notify_user/layouts/action_mailer.html.erb +6 -0
- data/spec/dummy/rails-4.0.2/config/database.yml +42 -13
- data/spec/dummy/rails-4.0.2/config/database2.yml +57 -0
- data/spec/dummy/rails-4.0.2/config/initializers/notify_user.rb +2 -0
- data/spec/dummy/rails-4.0.2/config/initializers/secret_token.rb +1 -1
- data/spec/dummy/rails-4.0.2/db/migrate/{20140105070446_create_users.rb → 20140428015529_create_users.rb} +0 -0
- data/spec/dummy/rails-4.0.2/db/migrate/{20140105070448_create_notify_user_notifications.rb → 20140428015531189189694000_create_notify_user_notifications.rb} +1 -1
- data/spec/dummy/rails-4.0.2/db/migrate/20140428015531190190743000_create_notify_user_unsubscribes.rb +10 -0
- data/spec/dummy/rails-4.0.2/db/migrate/20140428015531191191953000_create_notify_user_user_hashes.rb +12 -0
- data/spec/dummy/rails-4.0.2/db/schema.rb +23 -2
- data/spec/dummy/rails-4.0.2/log/test.log +787 -1414
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/13195a56ea8581e42f709ea01ea4604f +0 -0
- data/{app/assets/stylesheets/notify_user/application.css → spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705} +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/148f39f7dc2ea6cb194598111dbd4598 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/1d6bc1877ba2bbb89f393e10e8303d39 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/311d2b645a860b78f79ff156f12092ce +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/39651f0f2ac78423732234ebf092c632 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/5c85b1b5ac27b699c5f800c4e7ec82fb +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/68752c7ddc300bee3e9823db8befc306 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/6961013077b8573ed19d1e33abb8ebc5 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/7a316b3629b980c6d3a28924cb5fbbd8 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/8698d6fed0ef2f173a377160752b959f +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/8bab520aad78da438df1c428288cf229 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/spec/dummy/rails-4.0.2/tmp/cache/assets/test/sprockets/fa138a16887e031c0ae1b4caccfb4c05 +0 -0
- data/spec/mailers/notify_user/notification_mailer_spec.rb +1 -0
- data/spec/models/notify_user/notification_spec.rb +122 -1
- data/spec/models/notify_user/unsubscribe_spec.rb +40 -0
- data/spec/models/notify_user/user_hash_spec.rb +35 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/database.yml +21 -0
- data/spec/support/rails_template.rb +9 -0
- metadata +196 -65
- data/spec/dummy/rails-4.0.2/db/test.sqlite3 +0 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6ccbda4d4f6f0bd85a37c2e9295789c8c3c28844
|
4
|
+
data.tar.gz: f8f67249b41082e9af5dc4686bb3f85639360507
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b9258b901edd1eb111a33354aafc2aa668b7520587594fad58e03d5d887042836633cc620a8b49d167220ebb16cac1c18423c78d9d45d8fc9bbbf76d4d5eaf78
|
7
|
+
data.tar.gz: ae8fd4a46fde87ffe996adc8e42e63b667a5b0525ceb269205a76e437a17df21209ff5f7f8e59d1298f4eee57cec35738b0d3059b094aa80876808cf8712f42f
|
@@ -0,0 +1,50 @@
|
|
1
|
+
.unread a{
|
2
|
+
font-weight: bold;
|
3
|
+
}
|
4
|
+
.read a{
|
5
|
+
font-weight: normal;
|
6
|
+
}
|
7
|
+
#notifications_list{
|
8
|
+
margin: 0 auto;
|
9
|
+
width: 100%;
|
10
|
+
width: 720px;
|
11
|
+
color: #000;
|
12
|
+
font-family: arial;
|
13
|
+
font-size: 14px;
|
14
|
+
text-align: right;
|
15
|
+
padding: 5px;
|
16
|
+
text-align: center;
|
17
|
+
}
|
18
|
+
|
19
|
+
#notifications_list .inner{
|
20
|
+
margin-top: 10px;
|
21
|
+
border: 1px solid #dedede;
|
22
|
+
text-align: left;
|
23
|
+
|
24
|
+
}
|
25
|
+
#notifications_list a{
|
26
|
+
color: #454545;
|
27
|
+
text-decoration: none;
|
28
|
+
}
|
29
|
+
#notifications_list .item:hover a{
|
30
|
+
text-decoration: underline;
|
31
|
+
}
|
32
|
+
|
33
|
+
#notifications_list .title{
|
34
|
+
text-align: left;
|
35
|
+
}
|
36
|
+
|
37
|
+
#notifications_list .item{
|
38
|
+
padding: 20px 10px;
|
39
|
+
border-bottom: 1px solid #dedede;
|
40
|
+
}
|
41
|
+
#notifications_list .item.read{
|
42
|
+
background: #eaeaea;
|
43
|
+
}
|
44
|
+
#notifications_list .item .time_ago{
|
45
|
+
font-size: 12px;
|
46
|
+
text-align: right;
|
47
|
+
}
|
48
|
+
#notifications_list .mark_as_read{
|
49
|
+
text-align: right;
|
50
|
+
}
|
@@ -0,0 +1,144 @@
|
|
1
|
+
class NotifyUser::BaseNotificationsController < ApplicationController
|
2
|
+
|
3
|
+
before_filter :authenticate!, :except => [:unauth_unsubscribe]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@notifications = NotifyUser::BaseNotification.for_target(@user)
|
7
|
+
.order("created_at DESC")
|
8
|
+
.limit(30)
|
9
|
+
.page(params[:page]).per(params[:per_page])
|
10
|
+
|
11
|
+
respond_to do |format|
|
12
|
+
format.html
|
13
|
+
format.json {render :json => @notifications, meta: { pagination: { per_page: @notifications.limit_value, total_pages: @notifications.total_pages, total_objects: @notifications.total_count } }}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def mark_read
|
18
|
+
@notifications = NotifyUser::BaseNotification.for_target(@user).where('id IN (?)', params[:ids])
|
19
|
+
@notifications.update_all(state: :read)
|
20
|
+
render json: @notifications
|
21
|
+
end
|
22
|
+
|
23
|
+
def mark_all
|
24
|
+
@notifications = NotifyUser::BaseNotification.for_target(@user).where('state IN (?)', ["pending","sent"])
|
25
|
+
@notifications.update_all(state: :read)
|
26
|
+
redirect_to notify_user_notifications_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def notifications_count
|
30
|
+
@notifications = NotifyUser::BaseNotification.for_target(@user).where('state IN (?)', ["sent"])
|
31
|
+
render json: {:count => @notifications.count}
|
32
|
+
end
|
33
|
+
|
34
|
+
#get
|
35
|
+
def read
|
36
|
+
@notification = NotifyUser::BaseNotification.for_target(@user).where('id = ?', params[:id]).first
|
37
|
+
@notification.mark_as_read
|
38
|
+
redirect_logic(@notification)
|
39
|
+
end
|
40
|
+
|
41
|
+
def redirect_logic(notification)
|
42
|
+
render :text => "redirect setup goes here"
|
43
|
+
end
|
44
|
+
|
45
|
+
def unsubscribe
|
46
|
+
if params[:type]
|
47
|
+
unsubscribe_from(params[:type])
|
48
|
+
redirect_to notify_user_notifications_unsubscribe_path
|
49
|
+
end
|
50
|
+
@unsubscribale_types = NotifyUser.unsubscribable_notifications
|
51
|
+
@unsubscribale_channels = NotifyUser::BaseNotification.channels
|
52
|
+
end
|
53
|
+
|
54
|
+
#endpoint for accessing subscriptions and their statuses
|
55
|
+
def subscriptions
|
56
|
+
update_subscriptions(params[:types]) if params[:types]
|
57
|
+
@types = build_notification_types
|
58
|
+
render :json => @types
|
59
|
+
end
|
60
|
+
|
61
|
+
def update_subscriptions(types)
|
62
|
+
types.each do |type|
|
63
|
+
unsubscribe = NotifyUser::Unsubscribe.has_unsubscribed_from(@user, type[:type])
|
64
|
+
if type[:status] == '0'
|
65
|
+
if unsubscribe.empty?
|
66
|
+
#if unsubscribe doesn't exist create it
|
67
|
+
unsubscribe = NotifyUser::Unsubscribe.create(target: @user, type: type[:type])
|
68
|
+
end
|
69
|
+
else
|
70
|
+
subscribe_to(type[:type])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def unauth_unsubscribe
|
76
|
+
if params[:token] && params[:type]
|
77
|
+
if NotifyUser::UserHash.confirm_hash(params[:token], params[:type])
|
78
|
+
user_hash = NotifyUser::UserHash.where(token: params[:token], type: params[:type]).first
|
79
|
+
@user = user_hash.target
|
80
|
+
unsubscribe = NotifyUser::Unsubscribe.create(target: @user, type: params[:type])
|
81
|
+
user_hash.deactivate
|
82
|
+
return render :text => "successfully unsubscribed from #{params[:type]} notifications"
|
83
|
+
else
|
84
|
+
return render :text => "invalid token"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
return render :text => "Something went wrong please try again later"
|
88
|
+
end
|
89
|
+
|
90
|
+
def subscribe
|
91
|
+
subscribe_to(params[:type]) if params[:type]
|
92
|
+
redirect_to notify_user_notifications_unsubscribe_path
|
93
|
+
end
|
94
|
+
|
95
|
+
protected
|
96
|
+
|
97
|
+
def default_serializer_options
|
98
|
+
{
|
99
|
+
each_serializer: NotifyUser::NotificationSerializer,
|
100
|
+
template_renderer: self
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
def authenticate!
|
105
|
+
method(NotifyUser.authentication_method).call
|
106
|
+
@user = method(NotifyUser.current_user_method).call
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def build_notification_types()
|
111
|
+
#dirty way to build a json hash with pagination
|
112
|
+
types = {:subscriptions => []}
|
113
|
+
|
114
|
+
notification_types = NotifyUser.unsubscribable_notifications
|
115
|
+
|
116
|
+
#iterates over channels
|
117
|
+
NotifyUser::BaseNotification.channels.each do |type, options|
|
118
|
+
channel = (type.to_s + "_channel").camelize.constantize
|
119
|
+
types[:subscriptions] << {type: type, description: channel.default_options[:description],
|
120
|
+
status: NotifyUser::Unsubscribe.has_unsubscribed_from(@user, type).empty?}
|
121
|
+
end
|
122
|
+
|
123
|
+
#iterates over type
|
124
|
+
notification_types.each do |type|
|
125
|
+
types[:subscriptions] << {type: type, description: type.constantize.description,
|
126
|
+
status: NotifyUser::Unsubscribe.has_unsubscribed_from(@user, type).empty?}
|
127
|
+
end
|
128
|
+
return types
|
129
|
+
end
|
130
|
+
|
131
|
+
def unsubscribe_from(type)
|
132
|
+
unsubscribe = NotifyUser::Unsubscribe.new(target: @user, type: type)
|
133
|
+
if unsubscribe.save
|
134
|
+
flash[:message] = "successfully unsubscribed from #{type} notifications"
|
135
|
+
else
|
136
|
+
flash[:message] = "Please try again"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def subscribe_to(type)
|
141
|
+
NotifyUser::Unsubscribe.unsubscribe(@user,type)
|
142
|
+
flash[:message] = "successfully subscribed to #{type} notifications"
|
143
|
+
end
|
144
|
+
end
|
@@ -1,33 +1,8 @@
|
|
1
|
-
class NotifyUser::NotificationsController <
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
.limit(30)
|
9
|
-
.page(params[:page])
|
10
|
-
|
11
|
-
render json: @notifications
|
12
|
-
end
|
13
|
-
|
14
|
-
def mark_read
|
15
|
-
@notifications = NotifyUser::BaseNotification.for_target(@user).where('id IN (?)', params[:ids])
|
16
|
-
@notifications.update_all(state: :read)
|
17
|
-
render json: @notifications
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
def default_serializer_options
|
23
|
-
{
|
24
|
-
each_serializer: NotifyUser::NotificationSerializer,
|
25
|
-
template_renderer: self
|
26
|
-
}
|
27
|
-
end
|
28
|
-
|
29
|
-
def authenticate!
|
30
|
-
method(NotifyUser.authentication_method).call
|
31
|
-
@user = method(NotifyUser.current_user_method).call
|
32
|
-
end
|
1
|
+
class NotifyUser::NotificationsController < NotifyUser::BaseNotificationsController
|
2
|
+
def redirect_logic(notification)
|
3
|
+
render :text => "set redirect logic in notify_user/notifications_controller.rb"
|
4
|
+
#notification redirect logic goes here
|
5
|
+
#property = Property.find(@notification.params[:property_id])
|
6
|
+
#redirect_to property_url(@property)
|
7
|
+
end
|
33
8
|
end
|
@@ -1,4 +1,13 @@
|
|
1
1
|
module NotifyUser
|
2
2
|
module ApplicationHelper
|
3
|
+
def unsubscribe_link(notification, text)
|
4
|
+
user_hash = notification.generate_unsubscribe_hash
|
5
|
+
html = link_to(text, notify_user_notifications_unauth_unsubscribe_url(:type => notification.type, :token => user_hash.token))
|
6
|
+
return html.to_s.html_safe
|
7
|
+
end
|
8
|
+
|
9
|
+
def is_unsubscribeable?(notification)
|
10
|
+
return NotifyUser.unsubscribable_notifications.include? notification.type
|
11
|
+
end
|
3
12
|
end
|
4
13
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module NotifyUser
|
2
2
|
class NotificationMailer < ActionMailer::Base
|
3
|
+
helper NotifyUser::ApplicationHelper
|
3
4
|
|
4
5
|
layout "notify_user/layouts/action_mailer"
|
5
6
|
|
@@ -15,6 +16,7 @@ module NotifyUser
|
|
15
16
|
|
16
17
|
def aggregate_notifications_email(notifications, options)
|
17
18
|
@notifications = notifications
|
19
|
+
@notification = notifications.first
|
18
20
|
|
19
21
|
mail to: @notifications.first.target.email,
|
20
22
|
template_name: "aggregate_notification",
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module NotifyUser
|
2
|
+
class Apns
|
3
|
+
SYMBOL_NAMES_SIZE = 10
|
4
|
+
PAYLOAD_LIMIT = 255
|
5
|
+
|
6
|
+
#sends push notification
|
7
|
+
def self.push_notification(notification)
|
8
|
+
#calculates the bytes already used
|
9
|
+
used_space = SYMBOL_NAMES_SIZE + notification.id.size + notification.created_at.to_time.to_i.size +
|
10
|
+
notification.type.size
|
11
|
+
|
12
|
+
used_space += notification.params[:action_id].size if notification.params[:action_id]
|
13
|
+
|
14
|
+
space_allowance = PAYLOAD_LIMIT - used_space
|
15
|
+
|
16
|
+
payload = {
|
17
|
+
:alias => notification.target_id,
|
18
|
+
:aps => {alert: notification.mobile_message(space_allowance), badge: 1},
|
19
|
+
:n_data => {
|
20
|
+
'#' => notification.id,
|
21
|
+
t: notification.created_at.to_time.to_i,
|
22
|
+
'?' => notification.type
|
23
|
+
}
|
24
|
+
}
|
25
|
+
payload[:n_data]['!'] = notification.params[:action_id] if notification.params[:action_id]
|
26
|
+
|
27
|
+
response = Urbanairship.push(payload)
|
28
|
+
if response.success?
|
29
|
+
puts "Push notification sent successfully."
|
30
|
+
return true
|
31
|
+
else
|
32
|
+
puts "Push notification failed."
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -3,6 +3,7 @@ require 'sidekiq'
|
|
3
3
|
|
4
4
|
module NotifyUser
|
5
5
|
class BaseNotification < ActiveRecord::Base
|
6
|
+
include ActionView::Helpers::TextHelper
|
6
7
|
|
7
8
|
if ActiveRecord::VERSION::MAJOR < 4
|
8
9
|
attr_accessible :params, :target, :type, :state
|
@@ -11,8 +12,11 @@ module NotifyUser
|
|
11
12
|
# Override point in case of collisions, plus keeps the table name tidy.
|
12
13
|
self.table_name = "notify_user_notifications"
|
13
14
|
|
15
|
+
#checks if user has unsubscribed from this notif type
|
16
|
+
validate :unsubscribed_validation
|
17
|
+
|
14
18
|
# Params for creating the notification message.
|
15
|
-
serialize :params, Hash
|
19
|
+
# serialize :params, Hash
|
16
20
|
|
17
21
|
# The user to send the notification to
|
18
22
|
belongs_to :target, polymorphic: true
|
@@ -46,8 +50,29 @@ module NotifyUser
|
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
49
|
-
|
53
|
+
def params
|
54
|
+
if super.nil?
|
55
|
+
{}
|
56
|
+
else
|
57
|
+
super.with_indifferent_access
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def message
|
62
|
+
ActionView::Base.new(
|
63
|
+
Rails.configuration.paths["app/views"]).render(
|
64
|
+
:template => self.class.views[:mobile_sdk][:template_path].call(self), :formats => [:html],
|
65
|
+
:locals => { :params => self.params}, :layout => false)
|
66
|
+
end
|
50
67
|
|
68
|
+
def mobile_message(length=115)
|
69
|
+
truncate(ActionView::Base.new(
|
70
|
+
Rails.configuration.paths["app/views"]).render(
|
71
|
+
:template => self.class.views[:mobile_sdk][:template_path].call(self), :formats => [:html],
|
72
|
+
:locals => { :params => self.params}, :layout => false), :length => length)
|
73
|
+
end
|
74
|
+
|
75
|
+
## Public Interface
|
51
76
|
def to(user)
|
52
77
|
self.target = user
|
53
78
|
self
|
@@ -59,7 +84,7 @@ module NotifyUser
|
|
59
84
|
end
|
60
85
|
|
61
86
|
def notify!
|
62
|
-
save
|
87
|
+
save
|
63
88
|
|
64
89
|
# Bang version of 'notify' ignores aggregation
|
65
90
|
self.deliver!
|
@@ -68,29 +93,35 @@ module NotifyUser
|
|
68
93
|
# Send any Emails/SMS/APNS
|
69
94
|
def notify
|
70
95
|
|
71
|
-
save
|
72
|
-
|
73
|
-
if self.class.aggregate_per
|
74
|
-
|
75
|
-
# Schedule to send later if there aren't already any scheduled.
|
76
|
-
# Otherwise ignore, as the already-scheduled aggregate job will pick this one up when it runs.
|
77
|
-
if not aggregation_pending?
|
96
|
+
save
|
78
97
|
|
79
|
-
|
80
|
-
|
98
|
+
#if aggregation is false bypass aggregation completely
|
99
|
+
self.channels.each do |channel_name, options|
|
100
|
+
if(options[:aggregate_per] == false)
|
101
|
+
self.class.delay.deliver_notification_channel(self.id, channel_name)
|
102
|
+
else
|
103
|
+
if not aggregation_pending?
|
104
|
+
self.class.delay_for(options[:aggregate_per] || self.aggregate_per).notify_aggregated_channel(self.id, channel_name)
|
105
|
+
end
|
81
106
|
end
|
82
|
-
else
|
83
|
-
# No aggregation, send immediately.
|
84
|
-
self.deliver
|
85
107
|
end
|
86
108
|
|
87
109
|
end
|
88
110
|
|
111
|
+
def generate_unsubscribe_hash
|
112
|
+
#check if a hash already exists for that user otherwise create a new one
|
113
|
+
return NotifyUser::UserHash.where(target_id: self.target.id).where(target_type: self.target.class.base_class).where(type: self.type).where(active: true).first || NotifyUser::UserHash.create(target: self.target, type: self.type, active: true)
|
114
|
+
end
|
115
|
+
|
116
|
+
## Notification description
|
117
|
+
class_attribute :description
|
118
|
+
self.description = ""
|
119
|
+
|
89
120
|
## Channels
|
90
121
|
|
91
122
|
mattr_accessor :channels
|
92
123
|
@@channels = {
|
93
|
-
action_mailer: {}
|
124
|
+
action_mailer: {description: 'Email notifications'}
|
94
125
|
}
|
95
126
|
|
96
127
|
# Not sure about this. The JSON and web feeds don't fit into channels, because nothing is broadcast through
|
@@ -109,14 +140,14 @@ module NotifyUser
|
|
109
140
|
|
110
141
|
## Aggregation
|
111
142
|
|
112
|
-
|
113
|
-
|
143
|
+
class_attribute :aggregate_per
|
144
|
+
self.aggregate_per = 1.minute
|
114
145
|
|
115
146
|
## Sending
|
116
147
|
|
117
148
|
def self.for_target(target)
|
118
149
|
where(target_id: target.id)
|
119
|
-
.where(target_type: target.class.
|
150
|
+
.where(target_type: target.class.base_class)
|
120
151
|
end
|
121
152
|
|
122
153
|
def self.pending_aggregation_with(notification)
|
@@ -131,35 +162,88 @@ module NotifyUser
|
|
131
162
|
return (self.class.pending_aggregation_with(self).where('id != ?', id).count > 0)
|
132
163
|
end
|
133
164
|
|
134
|
-
def deliver
|
135
|
-
|
136
|
-
|
165
|
+
# def deliver
|
166
|
+
# unless user_has_unsubscribed?
|
167
|
+
# self.mark_as_sent
|
168
|
+
# self.save
|
137
169
|
|
138
|
-
|
139
|
-
end
|
170
|
+
# self.class.delay.deliver_channels(self.id)
|
171
|
+
# end
|
172
|
+
# end
|
140
173
|
|
141
174
|
def deliver!
|
142
|
-
|
143
|
-
|
144
|
-
|
175
|
+
unless user_has_unsubscribed?
|
176
|
+
self.mark_as_sent
|
177
|
+
self.save
|
178
|
+
self.class.deliver_channels(self.id)
|
179
|
+
end
|
145
180
|
end
|
146
181
|
|
147
182
|
# Deliver a single notification across each channel.
|
148
183
|
def self.deliver_channels(notification_id)
|
149
184
|
notification = self.where(id: notification_id).first
|
150
185
|
return unless notification
|
151
|
-
|
152
186
|
self.channels.each do |channel_name, options|
|
153
|
-
|
154
|
-
|
187
|
+
unless unsubscribed_from_channel?(notification.target, channel_name)
|
188
|
+
channel = (channel_name.to_s + "_channel").camelize.constantize
|
189
|
+
channel.deliver(notification, options)
|
190
|
+
end
|
155
191
|
end
|
156
192
|
end
|
157
193
|
|
158
194
|
# Deliver multiple notifications across each channel as an aggregate message.
|
159
195
|
def self.deliver_channels_aggregated(notifications)
|
160
196
|
self.channels.each do |channel_name, options|
|
161
|
-
|
162
|
-
|
197
|
+
if options[:aggregate_per] != false && !unsubscribed_from_channel?(notifications.first.target, channel_name)
|
198
|
+
channel = (channel_name.to_s + "_channel").camelize.constantize
|
199
|
+
channel.deliver_aggregated(notifications, options)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
#deliver to specific channel methods
|
205
|
+
|
206
|
+
# Deliver a single notification to a specific channel.
|
207
|
+
def self.deliver_notification_channel(notification_id, channel_name)
|
208
|
+
notification = self.where(id: notification_id).first
|
209
|
+
return unless notification
|
210
|
+
channel_options = channels[channel_name.to_sym]
|
211
|
+
|
212
|
+
channel = (channel_name.to_s + "_channel").camelize.constantize
|
213
|
+
unless self.unsubscribed_from_channel?(notification.target, channel_name)
|
214
|
+
channel.deliver(notification, channel_options)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Deliver a aggregated notifications to a specific channel.
|
219
|
+
def self.deliver_notifications_channel(notifications, channel_name)
|
220
|
+
channel_options = channels[channel_name.to_sym]
|
221
|
+
channel = (channel_name.to_s + "_channel").camelize.constantize
|
222
|
+
|
223
|
+
#check if user unsubsribed from channel type
|
224
|
+
unless self.unsubscribed_from_channel?(notifications.first.target, channel_name)
|
225
|
+
channel.deliver_aggregated(notifications, channel_options)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
#notifies a single channel for aggregation
|
230
|
+
def self.notify_aggregated_channel(notification_id, channel_name)
|
231
|
+
notification = self.find(notification_id) # Raise an exception if not found.
|
232
|
+
|
233
|
+
# Find any pending notifications with the same type and target, which can all be sent in one message.
|
234
|
+
notifications = self.pending_aggregation_with(notification)
|
235
|
+
|
236
|
+
notifications.map(&:mark_as_sent)
|
237
|
+
notifications.map(&:save)
|
238
|
+
|
239
|
+
return if notifications.empty?
|
240
|
+
|
241
|
+
if notifications.length == 1
|
242
|
+
# Despite waiting for more to aggregate, we only got one in the end.
|
243
|
+
self.deliver_notification_channel(notifications.first.id, channel_name)
|
244
|
+
else
|
245
|
+
# We got several notifications while waiting, send them aggregated.
|
246
|
+
self.deliver_notifications_channel(notifications, channel_name)
|
163
247
|
end
|
164
248
|
end
|
165
249
|
|
@@ -183,5 +267,25 @@ module NotifyUser
|
|
183
267
|
end
|
184
268
|
end
|
185
269
|
|
270
|
+
private
|
271
|
+
def unsubscribed_validation
|
272
|
+
errors.add(:target, (" has unsubscribed from this type")) if user_has_unsubscribed?
|
273
|
+
end
|
274
|
+
|
275
|
+
def user_has_unsubscribed?
|
276
|
+
#return true if user has unsubscribed
|
277
|
+
return true unless NotifyUser::Unsubscribe.has_unsubscribed_from(self.target, self.type).empty?
|
278
|
+
|
279
|
+
return false
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.unsubscribed_from_channel?(user, type)
|
283
|
+
#return true if user has unsubscribed
|
284
|
+
return true unless NotifyUser::Unsubscribe.has_unsubscribed_from(user, type).empty?
|
285
|
+
|
286
|
+
return false
|
287
|
+
end
|
288
|
+
|
289
|
+
|
186
290
|
end
|
187
291
|
end
|