activity_notification 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +33 -0
- data/.rubocop.yml +1157 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +25 -0
- data/Gemfile.lock +15 -17
- data/README.md +154 -27
- data/activity_notification.gemspec +1 -1
- data/app/controllers/activity_notification/notifications_controller.rb +30 -104
- data/app/controllers/activity_notification/notifications_with_devise_controller.rb +1 -33
- data/app/controllers/activity_notification/subscriptions_controller.rb +184 -0
- data/app/controllers/activity_notification/subscriptions_with_devise_controller.rb +6 -0
- data/app/mailers/activity_notification/mailer.rb +3 -3
- data/app/views/activity_notification/notifications/default/_index.html.erb +3 -0
- data/app/views/activity_notification/notifications/default/index.html.erb +8 -10
- data/app/views/activity_notification/notifications/default/show.html.erb +24 -2
- data/app/views/activity_notification/subscriptions/default/_form.html.erb +52 -0
- data/app/views/activity_notification/subscriptions/default/_notification_keys.html.erb +89 -0
- data/app/views/activity_notification/subscriptions/default/_subscription.html.erb +73 -0
- data/app/views/activity_notification/subscriptions/default/_subscriptions.html.erb +13 -0
- data/app/views/activity_notification/subscriptions/default/create.js.erb +5 -0
- data/app/views/activity_notification/subscriptions/default/destroy.js.erb +5 -0
- data/app/views/activity_notification/subscriptions/default/index.html.erb +197 -0
- data/app/views/activity_notification/subscriptions/default/show.html.erb +177 -0
- data/app/views/activity_notification/subscriptions/default/subscribe.js.erb +8 -0
- data/app/views/activity_notification/subscriptions/default/subscribe_to_email.js.erb +6 -0
- data/app/views/activity_notification/subscriptions/default/unsubscribe.js.erb +8 -0
- data/app/views/activity_notification/subscriptions/default/unsubscribe_to_email.js.erb +6 -0
- data/gemfiles/Gemfile.rails-4.2.lock +18 -20
- data/gemfiles/Gemfile.rails-5.0.lock +18 -20
- data/lib/activity_notification.rb +7 -3
- data/lib/activity_notification/apis/notification_api.rb +95 -61
- data/lib/activity_notification/apis/subscription_api.rb +51 -0
- data/lib/activity_notification/common.rb +1 -1
- data/lib/activity_notification/config.rb +65 -17
- data/lib/activity_notification/controllers/common_controller.rb +118 -0
- data/lib/activity_notification/controllers/devise_authentication_controller.rb +41 -0
- data/lib/activity_notification/helpers/view_helpers.rb +131 -3
- data/lib/activity_notification/mailers/helpers.rb +6 -8
- data/lib/activity_notification/models/concerns/notifiable.rb +45 -27
- data/lib/activity_notification/models/concerns/subscriber.rb +149 -0
- data/lib/activity_notification/models/concerns/target.rb +100 -66
- data/lib/activity_notification/models/notification.rb +7 -5
- data/lib/activity_notification/models/subscription.rb +93 -0
- data/lib/activity_notification/rails/routes.rb +148 -33
- data/lib/activity_notification/renderable.rb +3 -4
- data/lib/activity_notification/roles/acts_as_notifiable.rb +14 -1
- data/lib/activity_notification/roles/acts_as_target.rb +11 -8
- data/lib/activity_notification/version.rb +1 -1
- data/lib/generators/activity_notification/controllers_generator.rb +2 -2
- data/lib/generators/activity_notification/install_generator.rb +0 -1
- data/lib/generators/activity_notification/migration/migration_generator.rb +8 -2
- data/lib/generators/activity_notification/models_generator.rb +53 -0
- data/lib/generators/activity_notification/views_generator.rb +7 -7
- data/lib/generators/templates/activity_notification.rb +17 -3
- data/lib/generators/templates/controllers/notifications_controller.rb +18 -17
- data/lib/generators/templates/controllers/notifications_with_devise_controller.rb +18 -17
- data/lib/generators/templates/controllers/subscriptions_controller.rb +79 -0
- data/lib/generators/templates/controllers/subscriptions_with_devise_controller.rb +87 -0
- data/lib/generators/templates/migrations/migration.rb +57 -0
- data/lib/generators/templates/models/README +10 -0
- data/lib/generators/templates/{notification → models}/notification.rb +1 -3
- data/lib/generators/templates/models/subscription.rb +4 -0
- data/spec/concerns/apis/notification_api_spec.rb +48 -11
- data/spec/concerns/apis/subscription_api_spec.rb +167 -0
- data/spec/concerns/models/notifiable_spec.rb +60 -0
- data/spec/concerns/models/subscriber_spec.rb +525 -0
- data/spec/concerns/models/target_spec.rb +271 -42
- data/spec/controllers/common_controller_spec.rb +25 -0
- data/spec/controllers/dummy_common_controller.rb +5 -0
- data/spec/controllers/notifications_controller_shared_examples.rb +2 -6
- data/spec/controllers/subscriptions_controller_shared_examples.rb +735 -0
- data/spec/controllers/subscriptions_controller_spec.rb +12 -0
- data/spec/controllers/subscriptions_with_devise_controller_spec.rb +91 -0
- data/spec/factories/dummy/dummy_subscriber.rb +4 -0
- data/spec/factories/subscriptions.rb +8 -0
- data/spec/generators/controllers_generator_spec.rb +25 -2
- data/spec/generators/migration/migration_generator_spec.rb +3 -3
- data/spec/generators/models_generator_spec.rb +96 -0
- data/spec/generators/views_generator_spec.rb +84 -0
- data/spec/helpers/view_helpers_spec.rb +143 -0
- data/spec/mailers/mailer_spec.rb +5 -4
- data/spec/models/dummy/dummy_subscriber_spec.rb +5 -0
- data/spec/models/notification_spec.rb +7 -7
- data/spec/models/subscription_spec.rb +158 -0
- data/spec/rails_app/app/controllers/users/notifications_controller.rb +67 -0
- data/spec/rails_app/app/controllers/users/notifications_with_devise_controller.rb +75 -0
- data/spec/rails_app/app/controllers/users/subscriptions_controller.rb +79 -0
- data/spec/rails_app/app/controllers/users/subscriptions_with_devise_controller.rb +87 -0
- data/spec/rails_app/app/models/admin.rb +1 -0
- data/spec/rails_app/app/models/dummy/dummy_subscriber.rb +4 -0
- data/spec/rails_app/app/models/user.rb +2 -1
- data/spec/rails_app/app/views/activity_notification/mailer/dummy_subscribers/test_key.text.erb +1 -0
- data/spec/rails_app/app/views/articles/index.html.erb +6 -0
- data/spec/rails_app/config/initializers/activity_notification.rb +17 -3
- data/spec/rails_app/config/routes.rb +2 -2
- data/spec/rails_app/db/migrate/20160715050420_create_activity_notification_tables.rb +33 -0
- data/spec/rails_app/db/schema.rb +18 -0
- data/spec/roles/acts_as_notifiable_spec.rb +1 -1
- data/spec/roles/acts_as_target_spec.rb +1 -1
- metadata +70 -11
- data/lib/generators/activity_notification/notification/notification_generator.rb +0 -20
- data/lib/generators/templates/active_record/migration.rb +0 -18
- data/spec/generators/notification/notification_generator_spec.rb +0 -41
- data/spec/rails_app/db/migrate/20160715050420_create_notifications.rb +0 -18
@@ -0,0 +1,93 @@
|
|
1
|
+
module ActivityNotification
|
2
|
+
# Subscription model implementation generated by ActivityNotification.
|
3
|
+
class Subscription < ActiveRecord::Base
|
4
|
+
include SubscriptionApi
|
5
|
+
self.table_name = ActivityNotification.config.subscription_table_name
|
6
|
+
|
7
|
+
# Belongs to target instance of this subscription as polymorphic association.
|
8
|
+
# @scope instance
|
9
|
+
# @return [Object] Target instance of this subscription
|
10
|
+
belongs_to :target, polymorphic: true
|
11
|
+
|
12
|
+
# Serialize parameters Hash
|
13
|
+
serialize :parameters, Hash
|
14
|
+
|
15
|
+
validates :target, presence: true
|
16
|
+
validates :key, presence: true
|
17
|
+
validates_inclusion_of :subscribing, in: [true, false]
|
18
|
+
validates_inclusion_of :subscribing_to_email, in: [true, false]
|
19
|
+
validate :subscribing_to_email_cannot_be_true_when_subscribing_is_false
|
20
|
+
validates :subscribed_at, presence: true, if: :subscribing
|
21
|
+
validates :unsubscribed_at, presence: true, unless: :subscribing
|
22
|
+
validates :subscribed_to_email_at, presence: true, if: :subscribing_to_email
|
23
|
+
validates :unsubscribed_to_email_at, presence: true, unless: :subscribing_to_email
|
24
|
+
|
25
|
+
# Selects filtered subscriptions by target instance.
|
26
|
+
# ActivityNotification::Subscription.filtered_by_target(@user)
|
27
|
+
# is the same as
|
28
|
+
# @user.subscriptions
|
29
|
+
# @scope class
|
30
|
+
# @param [Object] target Target instance for filter
|
31
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Array or database query of filtered subscriptions
|
32
|
+
scope :filtered_by_target, ->(target) { where(target: target) }
|
33
|
+
|
34
|
+
# Selects filtered subscriptions by key.
|
35
|
+
# @example Get filtered subscriptions of the @user with key 'comment.reply'
|
36
|
+
# @subscriptions = @user.subscriptions.filtered_by_key('comment.reply')
|
37
|
+
# @scope class
|
38
|
+
# @param [String] key Key of the subscription for filter
|
39
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Array or database query of filtered subscriptions
|
40
|
+
scope :filtered_by_key, ->(key) { where(key: key) }
|
41
|
+
|
42
|
+
# Selects filtered subscriptions by key with filter options.
|
43
|
+
# @example Get filtered subscriptions of the @user with key 'comment.reply'
|
44
|
+
# @subscriptions = @user.subscriptions.filtered_by_key('comment.reply')
|
45
|
+
# @example Get custom filtered subscriptions of the @user
|
46
|
+
# @subscriptions = @user.subscriptions.filtered_by_options({ custom_filter: ["created_at >= ?", time.hour.ago] })
|
47
|
+
# @scope class
|
48
|
+
# @param [Hash] options Options for filter
|
49
|
+
# @option options [String] :filtered_by_key (nil) Key of the subscription for filter
|
50
|
+
# @option options [Array|Hash] :custom_filter (nil) Custom subscription filter (e.g. ["created_at >= ?", time.hour.ago])
|
51
|
+
# @return [ActiveRecord_AssociationRelation<Notificaion>] Array or database query of filtered subscriptions
|
52
|
+
scope :filtered_by_options, ->(options = {}) {
|
53
|
+
options = ActivityNotification.cast_to_indifferent_hash(options)
|
54
|
+
filtered_subscriptions = all
|
55
|
+
if options.has_key?(:filtered_by_key)
|
56
|
+
filtered_subscriptions = filtered_subscriptions.filtered_by_key(options[:filtered_by_key])
|
57
|
+
end
|
58
|
+
if options.has_key?(:custom_filter)
|
59
|
+
filtered_subscriptions = filtered_subscriptions.where(options[:custom_filter])
|
60
|
+
end
|
61
|
+
filtered_subscriptions
|
62
|
+
}
|
63
|
+
|
64
|
+
# Orders by latest (newest) first as created_at: :desc.
|
65
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by latest first
|
66
|
+
scope :latest_order, -> { order(created_at: :desc) }
|
67
|
+
|
68
|
+
# Orders by earliest (older) first as created_at: :asc.
|
69
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by earliest first
|
70
|
+
scope :earliest_order, -> { order(created_at: :asc) }
|
71
|
+
|
72
|
+
# Orders by latest (newest) first as subscribed_at: :desc.
|
73
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by latest subscribed_at first
|
74
|
+
scope :latest_subscribed_order, -> { order(subscribed_at: :desc) }
|
75
|
+
|
76
|
+
# Orders by earliest (older) first as subscribed_at: :asc.
|
77
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by earliest subscribed_at first
|
78
|
+
scope :earliest_subscribed_order, -> { order(subscribed_at: :asc) }
|
79
|
+
|
80
|
+
# Orders by key name as key: :asc.
|
81
|
+
# @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by key name
|
82
|
+
scope :key_order, -> { order(key: :asc) }
|
83
|
+
|
84
|
+
private
|
85
|
+
# Validates subscribing_to_email cannot be true when subscribing isfalse.
|
86
|
+
def subscribing_to_email_cannot_be_true_when_subscribing_is_false
|
87
|
+
if !subscribing && subscribing_to_email
|
88
|
+
errors.add(:subscribing_to_email, "cannot be true when subscribing is false")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -4,7 +4,9 @@ require "active_support/core_ext/hash/slice"
|
|
4
4
|
module ActionDispatch::Routing
|
5
5
|
# Extended ActionDispatch::Routing::Mapper implementation to add routing method of ActivityNotification.
|
6
6
|
class Mapper
|
7
|
-
|
7
|
+
include ActivityNotification::PolymorphicHelpers
|
8
|
+
|
9
|
+
# Includes notify_to method for routes, which is responsible to generate all necessary routes for notifications of activity_notification.
|
8
10
|
#
|
9
11
|
# When you have an User model configured as a target (e.g. defined acts_as_target),
|
10
12
|
# you can create as follows in your routes:
|
@@ -19,7 +21,7 @@ module ActionDispatch::Routing
|
|
19
21
|
# { controller:"activity_notification/notifications", action:"destroy", target_type:"users" }
|
20
22
|
# open_all_user_notifications POST /users/:user_id/notifications/open_all(.:format)
|
21
23
|
# { controller:"activity_notification/notifications", action:"open_all", target_type:"users" }
|
22
|
-
# move_user_notification
|
24
|
+
# move_user_notification GET /users/:user_id/notifications/:id/move(.:format)
|
23
25
|
# { controller:"activity_notification/notifications", action:"move", target_type:"users" }
|
24
26
|
# open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
|
25
27
|
# { controller:"activity_notification/notifications", action:"open", target_type:"users" }
|
@@ -37,50 +39,46 @@ module ActionDispatch::Routing
|
|
37
39
|
# { controller:"activity_notification/notifications_with_devise", action:"destroy", target_type:"users", devise_type:"users" }
|
38
40
|
# open_all_user_notifications POST /users/:user_id/notifications/open_all(.:format)
|
39
41
|
# { controller:"activity_notification/notifications_with_devise", action:"open_all", target_type:"users", devise_type:"users" }
|
40
|
-
# move_user_notification
|
42
|
+
# move_user_notification GET /users/:user_id/notifications/:id/move(.:format)
|
41
43
|
# { controller:"activity_notification/notifications_with_devise", action:"move", target_type:"users", devise_type:"users" }
|
42
44
|
# open_user_notification POST /users/:user_id/notifications/:id/open(.:format)
|
43
45
|
# { controller:"activity_notification/notifications_with_devise", action:"open", target_type:"users", devise_type:"users" }
|
44
46
|
#
|
47
|
+
# When you would like to define subscription management paths with notification paths,
|
48
|
+
# you can create as follows in your routes:
|
49
|
+
# notify_to :users, with_subscription: true
|
50
|
+
# or you can also set options for subscription path:
|
51
|
+
# notify_to :users, with_subscription: { except: [:index] }
|
52
|
+
# If you configure this :with_subscription option with :with_devise option, with_subscription paths are also automatically configured with devise authentication as the same as notifications
|
53
|
+
# notify_to :users, with_devise: :users, with_subscription: true
|
54
|
+
#
|
45
55
|
# @example Define notify_to in config/routes.rb
|
46
56
|
# notify_to :users
|
47
57
|
# @example Define notify_to with options
|
48
58
|
# notify_to :users, only: [:open, :open_all, :move]
|
49
59
|
# @example Integrated with Devise authentication
|
50
60
|
# notify_to :users, with_devise: :users
|
61
|
+
# @example Define notification paths including subscription paths
|
62
|
+
# notify_to :users, with_subscription: true
|
51
63
|
#
|
52
64
|
# @overload notify_to(*resources, *options)
|
53
|
-
# @param [Symbol]
|
54
|
-
# @option options [Symbol]
|
55
|
-
# @option options [
|
56
|
-
# @option options [
|
57
|
-
# @option options [
|
58
|
-
# @option options [
|
65
|
+
# @param [Symbol] resources Resources to notify
|
66
|
+
# @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
|
67
|
+
# @option options [Hash|Boolean] :with_subscription (false) Subscription path options to define subscription management paths with notification paths. Calls subscribed_by routing when truthy value is passed as this option.
|
68
|
+
# @option options [String] :model (:notifications) Model name of notifications
|
69
|
+
# @option options [String] :controller ("activity_notification/notifications" | activity_notification/notifications_with_devise") :controller option as resources routing
|
70
|
+
# @option options [Symbol] :as (nil) :as option as resources routing
|
71
|
+
# @option options [Array] :only (nil) :only option as resources routing
|
72
|
+
# @option options [Array] :except (nil) :except option as resources routing
|
59
73
|
# @return [ActionDispatch::Routing::Mapper] Routing mapper instance
|
60
74
|
def notify_to(*resources)
|
61
|
-
options = resources.extract_options
|
62
|
-
|
63
|
-
#TODO check resources if it includes target module
|
64
|
-
|
65
|
-
if (with_devise = options.delete(:with_devise)).present?
|
66
|
-
options[:controller] ||= "activity_notification/notifications_with_devise"
|
67
|
-
options[:as] ||= "notifications"
|
68
|
-
#TODO check devise configuration in model
|
69
|
-
devise_defaults = { devise_type: with_devise.to_s }
|
70
|
-
else
|
71
|
-
options[:controller] ||= "activity_notification/notifications"
|
72
|
-
end
|
73
|
-
options[:except] ||= []
|
74
|
-
options[:except].concat( [:new, :create, :edit, :update] )
|
75
|
-
notification_resources = options[:model] || :notifications
|
75
|
+
options = create_options(:notifications, resources.extract_options!, [:new, :create, :edit, :update])
|
76
76
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
options[:defaults] = (devise_defaults || {}).merge({ target_type: resource.to_s })
|
83
|
-
self.resources notification_resources, options do
|
77
|
+
resources.each do |target|
|
78
|
+
self.resources target, only: :none do
|
79
|
+
options[:defaults] = { target_type: target.to_s }.merge(options[:devise_defaults])
|
80
|
+
resources_options = options.select { |key, _| [:with_devise, :with_subscription, :subscription_option, :model, :devise_defaults].exclude? key }
|
81
|
+
self.resources options[:model], resources_options do
|
84
82
|
collection do
|
85
83
|
post :open_all unless ignore_path?(:open_all, options)
|
86
84
|
end
|
@@ -90,18 +88,135 @@ module ActionDispatch::Routing
|
|
90
88
|
end
|
91
89
|
end
|
92
90
|
end
|
91
|
+
|
92
|
+
if options[:with_subscription].present? && target.to_s.to_model_class.subscription_enabled?
|
93
|
+
subscribed_by target, options[:subscription_option]
|
94
|
+
end
|
93
95
|
end
|
94
96
|
|
95
97
|
self
|
96
98
|
end
|
97
99
|
|
100
|
+
# Includes subscribed_by method for routes, which is responsible to generate all necessary routes for subscriptions of activity_notification.
|
101
|
+
#
|
102
|
+
# When you have an User model configured as a target (e.g. defined acts_as_target),
|
103
|
+
# you can create as follows in your routes:
|
104
|
+
# subscribed_by :users
|
105
|
+
# This method creates the needed routes:
|
106
|
+
# # Subscription routes
|
107
|
+
# user_subscriptions GET /users/:user_id/subscriptions(.:format)
|
108
|
+
# { controller:"activity_notification/subscriptions", action:"index", target_type:"users" }
|
109
|
+
# user_subscription GET /users/:user_id/subscriptions/:id(.:format)
|
110
|
+
# { controller:"activity_notification/subscriptions", action:"show", target_type:"users" }
|
111
|
+
# open_all_user_subscriptions POST /users/:user_id/subscriptions(.:format)
|
112
|
+
# { controller:"activity_notification/subscriptions", action:"create", target_type:"users" }
|
113
|
+
# user_subscription DELETE /users/:user_id/subscriptions/:id(.:format)
|
114
|
+
# { controller:"activity_notification/subscriptions", action:"destroy", target_type:"users" }
|
115
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/subscribe(.:format)
|
116
|
+
# { controller:"activity_notification/subscriptions", action:"subscribe", target_type:"users" }
|
117
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe(.:format)
|
118
|
+
# { controller:"activity_notification/subscriptions", action:"unsubscribe", target_type:"users" }
|
119
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
|
120
|
+
# { controller:"activity_notification/subscriptions", action:"subscribe_to_email", target_type:"users" }
|
121
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
|
122
|
+
# { controller:"activity_notification/subscriptions", action:"unsubscribe_to_email", target_type:"users" }
|
123
|
+
#
|
124
|
+
# When you use devise authentication and you want make subscription targets assciated with devise,
|
125
|
+
# you can create as follows in your routes:
|
126
|
+
# notify_to :users, with_devise: :users
|
127
|
+
# This with_devise option creates the needed routes assciated with devise authentication:
|
128
|
+
# # Subscription with devise routes
|
129
|
+
# user_subscriptions GET /users/:user_id/subscriptions(.:format)
|
130
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"index", target_type:"users", devise_type:"users" }
|
131
|
+
# user_subscription GET /users/:user_id/subscriptions/:id(.:format)
|
132
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"show", target_type:"users", devise_type:"users" }
|
133
|
+
# open_all_user_subscriptions POST /users/:user_id/subscriptions(.:format)
|
134
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"create", target_type:"users", devise_type:"users" }
|
135
|
+
# user_subscription DELETE /users/:user_id/subscriptions/:id(.:format)
|
136
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"destroy", target_type:"users", devise_type:"users" }
|
137
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/subscribe(.:format)
|
138
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"subscribe", target_type:"users", devise_type:"users" }
|
139
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe(.:format)
|
140
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe", target_type:"users", devise_type:"users" }
|
141
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/subscribe_to_email(.:format)
|
142
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"subscribe_to_email", target_type:"users", devise_type:"users" }
|
143
|
+
# open_user_subscription POST /users/:user_id/subscriptions/:id/unsubscribe_to_email(.:format)
|
144
|
+
# { controller:"activity_notification/subscriptions_with_devise", action:"unsubscribe_to_email", target_type:"users", devise_type:"users" }
|
145
|
+
#
|
146
|
+
# @example Define subscribed_by in config/routes.rb
|
147
|
+
# subscribed_by :users
|
148
|
+
# @example Define subscribed_by with options
|
149
|
+
# subscribed_by :users, except: [:index, :show]
|
150
|
+
# @example Integrated with Devise authentication
|
151
|
+
# subscribed_by :users, with_devise: :users
|
152
|
+
#
|
153
|
+
# @overload subscribed_by(*resources, *options)
|
154
|
+
# @param [Symbol] resources Resources to notify
|
155
|
+
# @option options [Symbol] :with_devise (false) Devise resources name for devise integration. Devise integration will be enabled by this option.
|
156
|
+
# @option options [String] :model (:subscriptions) Model name of subscriptions
|
157
|
+
# @option options [String] :controller ("activity_notification/subscriptions" | activity_notification/subscriptions_with_devise") :controller option as resources routing
|
158
|
+
# @option options [Symbol] :as (nil) :as option as resources routing
|
159
|
+
# @option options [Array] :only (nil) :only option as resources routing
|
160
|
+
# @option options [Array] :except (nil) :except option as resources routing
|
161
|
+
# @return [ActionDispatch::Routing::Mapper] Routing mapper instance
|
162
|
+
def subscribed_by(*resources)
|
163
|
+
options = create_options(:subscriptions, resources.extract_options!, [:new, :edit, :update])
|
164
|
+
|
165
|
+
resources.each do |target|
|
166
|
+
self.resources target, only: :none do
|
167
|
+
options[:defaults] = { target_type: target.to_s }.merge(options[:devise_defaults])
|
168
|
+
resources_options = options.select { |key, _| [:with_devise, :model, :devise_defaults].exclude? key }
|
169
|
+
self.resources options[:model], resources_options do
|
170
|
+
member do
|
171
|
+
post :subscribe unless ignore_path?(:subscribe, options)
|
172
|
+
post :unsubscribe unless ignore_path?(:unsubscribe, options)
|
173
|
+
post :subscribe_to_email unless ignore_path?(:subscribe_to_email, options)
|
174
|
+
post :unsubscribe_to_email unless ignore_path?(:unsubscribe_to_email, options)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
self
|
181
|
+
end
|
182
|
+
|
183
|
+
|
98
184
|
private
|
99
185
|
|
186
|
+
# Check whether action path is ignored by :except or :only options
|
187
|
+
# @api private
|
188
|
+
# @return [Boolean] Whether action path is ignored
|
100
189
|
def ignore_path?(action, options)
|
101
|
-
|
102
|
-
|
190
|
+
options[:except].present? && options[:except].include?(action) and return true
|
191
|
+
options[:only].present? && !options[:only].include?(action) and return true
|
103
192
|
false
|
104
193
|
end
|
105
194
|
|
195
|
+
# Create options fo routing
|
196
|
+
# @api private
|
197
|
+
# @param [Symbol] resource Name of the resource model
|
198
|
+
# @return [Boolean] Whether action path is ignored
|
199
|
+
def create_options(resource, options = {}, except_actions = [])
|
200
|
+
#TODO check resources if it includes target module
|
201
|
+
resources_name = resource.to_s.pluralize.underscore
|
202
|
+
options[:model] ||= resources_name.to_sym
|
203
|
+
if options[:with_devise].present?
|
204
|
+
options[:controller] ||= "activity_notification/#{resources_name}_with_devise"
|
205
|
+
options[:as] ||= resources_name
|
206
|
+
#TODO check devise configuration in model
|
207
|
+
options[:devise_defaults] = { devise_type: options[:with_devise].to_s }
|
208
|
+
else
|
209
|
+
options[:controller] ||= "activity_notification/#{resources_name}"
|
210
|
+
options[:devise_defaults] = {}
|
211
|
+
end
|
212
|
+
(options[:except] ||= []).concat(except_actions)
|
213
|
+
if options[:with_subscription].present?
|
214
|
+
options[:subscription_option] = (options[:with_subscription].is_a?(Hash) ? options[:with_subscription] : {})
|
215
|
+
.merge(with_devise: options[:with_devise])
|
216
|
+
end
|
217
|
+
#TODO other options like :as, :path_prefix, :path_names ...
|
218
|
+
options
|
219
|
+
end
|
220
|
+
|
106
221
|
end
|
107
222
|
end
|
@@ -120,7 +120,6 @@ module ActivityNotification
|
|
120
120
|
# == Variables in templates
|
121
121
|
#
|
122
122
|
# From within a template there are three variables at your disposal:
|
123
|
-
#
|
124
123
|
# * notification
|
125
124
|
# * controller
|
126
125
|
# * parameters [converted into a HashWithIndifferentAccess]
|
@@ -136,7 +135,7 @@ module ActivityNotification
|
|
136
135
|
# @param [Hash] params Parameters for rendering notifications
|
137
136
|
# @option params [String, Symbol] :target (nil) Target type name to find template or i18n text
|
138
137
|
# @option params [String] :partial_root ("activity_notification/notifications/#{target}", controller.target_view_path, 'activity_notification/notifications/default') Partial template name
|
139
|
-
# @option params [String] :partial (self.key.
|
138
|
+
# @option params [String] :partial (self.key.tr('.', '/')) Root path of partial template
|
140
139
|
# @option params [String] :layout (nil) Layout template name
|
141
140
|
# @option params [String] :layout_root ('layouts') Root path of layout template
|
142
141
|
# @option params [String, Symbol] :fallback (nil) Fallback template to use when MissingTemplate is raised. Set :text to use i18n text as fallback.
|
@@ -172,9 +171,9 @@ module ActivityNotification
|
|
172
171
|
def partial_path(path = nil, root = nil, target = nil)
|
173
172
|
controller = ActivityNotification.get_controller if ActivityNotification.respond_to?(:get_controller)
|
174
173
|
root ||= "activity_notification/notifications/#{target}" if target.present?
|
175
|
-
root ||= controller.target_view_path if controller.present?
|
174
|
+
root ||= controller.target_view_path if controller.present? && controller.respond_to?(:target_view_path)
|
176
175
|
root ||= 'activity_notification/notifications/default'
|
177
|
-
path ||= self.key.
|
176
|
+
path ||= self.key.tr('.', '/')
|
178
177
|
select_path(path, root)
|
179
178
|
end
|
180
179
|
|
@@ -39,6 +39,17 @@ module ActivityNotification
|
|
39
39
|
# acts_as_notifiable :users, targets: User.all, group: :article
|
40
40
|
# end
|
41
41
|
#
|
42
|
+
# * :group_expiry_delay
|
43
|
+
# * Expiry period of a notification group.
|
44
|
+
# Notifications will be bundled within the group expiry period.
|
45
|
+
# This parameter is a optional.
|
46
|
+
# @example All *unopened* notifications to the same target within 1 day will be grouped by `article`
|
47
|
+
# # app/models/comment.rb
|
48
|
+
# class Comment < ActiveRecord::Base
|
49
|
+
# belongs_to :article
|
50
|
+
# acts_as_notifiable :users, targets: User.all, group: :article, :group_expiry_delay: 1.day
|
51
|
+
# end
|
52
|
+
#
|
42
53
|
# * :notifier
|
43
54
|
# * Notifier of the notification.
|
44
55
|
# This will be stored as notifier with notification record.
|
@@ -119,6 +130,7 @@ module ActivityNotification
|
|
119
130
|
# @param [Hash] options Options for notifiable model configuration
|
120
131
|
# @option options [Symbol, Proc, Array] :targets (nil) Targets to send notifications
|
121
132
|
# @option options [Symbol, Proc, Object] :group (nil) Group unit of the notifications
|
133
|
+
# @option options [Symbol, Proc, Object] :group_expiry_delay (nil) Expiry period of a notification group
|
122
134
|
# @option options [Symbol, Proc, Object] :notifier (nil) Notifier of the notifications
|
123
135
|
# @option options [Symbol, Proc, Hash] :parameters ({}) Additional parameters of the notifications
|
124
136
|
# @option options [Symbol, Proc, Boolean] :email_allowed (ActivityNotification.config.email_enabled) Whether activity_notification sends notification email
|
@@ -137,7 +149,7 @@ module ActivityNotification
|
|
137
149
|
end
|
138
150
|
|
139
151
|
options[:printable_notifiable_name] ||= options.delete(:printable_name)
|
140
|
-
set_acts_as_parameters_for_target(target_type, [:targets, :group, :parameters, :email_allowed], options, "notification_")
|
152
|
+
set_acts_as_parameters_for_target(target_type, [:targets, :group, :group_expiry_delay, :parameters, :email_allowed], options, "notification_")
|
141
153
|
.merge set_acts_as_parameters_for_target(target_type, [:notifier, :notifiable_path, :printable_notifiable_name], options)
|
142
154
|
end
|
143
155
|
|
@@ -146,6 +158,7 @@ module ActivityNotification
|
|
146
158
|
def available_notifiable_options
|
147
159
|
[ :targets,
|
148
160
|
:group,
|
161
|
+
:group_expiry_delay,
|
149
162
|
:notifier,
|
150
163
|
:parameters,
|
151
164
|
:email_allowed,
|
@@ -85,26 +85,29 @@ module ActivityNotification
|
|
85
85
|
# end
|
86
86
|
#
|
87
87
|
# @param [Hash] options Options for notifiable model configuration
|
88
|
-
# @option options [Symbol, Proc, String] :email
|
89
|
-
# @option options [Symbol, Proc, Boolean] :email_allowed
|
90
|
-
# @option options [Symbol, Proc, Boolean] :
|
91
|
-
# @option options [Symbol, Proc,
|
92
|
-
# @option options [Symbol, Proc,
|
88
|
+
# @option options [Symbol, Proc, String] :email (nil) Email address to send notification email
|
89
|
+
# @option options [Symbol, Proc, Boolean] :email_allowed (ActivityNotification.config.email_enabled) Whether activity_notification sends notification email to this target
|
90
|
+
# @option options [Symbol, Proc, Boolean] :batch_email_allowed (ActivityNotification.config.email_enabled) Whether activity_notification sends batch notification email to this target
|
91
|
+
# @option options [Symbol, Proc, Boolean] :subscription_allowed (ActivityNotification.config.subscription_enabled) Whether activity_notification manages subscriptions of this target
|
92
|
+
# @option options [Symbol, Proc, Object] :devise_resource (nil) Integrated resource with devise authentication
|
93
|
+
# @option options [Symbol, Proc, String] :printable_name (ActivityNotification::Common.printable_name) Printable notification target name
|
93
94
|
# @return [Hash] Configured parameters as target model
|
94
95
|
def acts_as_target(options = {})
|
95
96
|
include Target
|
96
97
|
|
97
98
|
options[:printable_notification_target_name] ||= options.delete(:printable_name)
|
98
99
|
options[:batch_notification_email_allowed] ||= options.delete(:batch_email_allowed)
|
99
|
-
set_acts_as_parameters([:email, :email_allowed, :devise_resource], options, "notification_")
|
100
|
-
|
100
|
+
acts_as_params = set_acts_as_parameters([:email, :email_allowed, :subscription_allowed, :devise_resource], options, "notification_")
|
101
|
+
.merge set_acts_as_parameters([:batch_notification_email_allowed, :printable_notification_target_name], options)
|
102
|
+
include Subscriber if subscription_enabled?
|
103
|
+
acts_as_params
|
101
104
|
end
|
102
105
|
alias_method :acts_as_notification_target, :acts_as_target
|
103
106
|
|
104
107
|
# Returns array of available target options in acts_as_target.
|
105
108
|
# @return [Array<Symbol>] Array of available target options
|
106
109
|
def available_target_options
|
107
|
-
[:email, :email_allowed, :batch_email_allowed, :devise_resource, :printable_notification_target_name, :printable_name].freeze
|
110
|
+
[:email, :email_allowed, :batch_email_allowed, :subscription_allowed, :devise_resource, :printable_notification_target_name, :printable_name].freeze
|
108
111
|
end
|
109
112
|
end
|
110
113
|
end
|
@@ -6,7 +6,7 @@ module ActivityNotification
|
|
6
6
|
# @example Run controller generator for users as target
|
7
7
|
# rails generate activity_notification:controllers users
|
8
8
|
class ControllersGenerator < Rails::Generators::Base
|
9
|
-
CONTROLLERS = ['notifications', 'notifications_with_devise'].freeze
|
9
|
+
CONTROLLERS = ['notifications', 'notifications_with_devise', 'subscriptions', 'subscriptions_with_devise'].freeze
|
10
10
|
|
11
11
|
desc <<-DESC.strip_heredoc
|
12
12
|
Create inherited ActivityNotification controllers in your app/controllers folder.
|
@@ -15,7 +15,7 @@ module ActivityNotification
|
|
15
15
|
If you do no specify a controller, all controllers will be created.
|
16
16
|
For example:
|
17
17
|
|
18
|
-
rails generate activity_notification:controllers users -c
|
18
|
+
rails generate activity_notification:controllers users -c notifications
|
19
19
|
|
20
20
|
This will create a controller class at app/controllers/users/notifications_controller.rb like this:
|
21
21
|
|