activity_notification 1.0.2 → 1.1.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.
- 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
|
|