activity_notification 0.0.10 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -0
  3. data/Gemfile +6 -3
  4. data/Gemfile.lock +74 -58
  5. data/README.md +53 -26
  6. data/activity_notification.gemspec +2 -0
  7. data/app/controllers/activity_notification/notifications_controller.rb +4 -4
  8. data/app/mailers/activity_notification/mailer.rb +9 -3
  9. data/app/views/activity_notification/mailer/default/default.html.erb +9 -4
  10. data/app/views/activity_notification/mailer/default/default.text.erb +10 -0
  11. data/app/views/activity_notification/notifications/default/_default.html.erb +173 -34
  12. data/app/views/activity_notification/notifications/default/_index.html.erb +119 -11
  13. data/app/views/activity_notification/notifications/default/destroy.js.erb +2 -2
  14. data/app/views/activity_notification/notifications/default/index.html.erb +25 -14
  15. data/app/views/activity_notification/notifications/default/open.js.erb +2 -2
  16. data/app/views/activity_notification/notifications/default/open_all.js.erb +2 -2
  17. data/app/views/activity_notification/notifications/default/show.html.erb +1 -1
  18. data/gemfiles/Gemfile.rails-4.2 +0 -2
  19. data/gemfiles/Gemfile.rails-4.2.lock +3 -3
  20. data/gemfiles/Gemfile.rails-5.0 +1 -3
  21. data/lib/activity_notification.rb +10 -9
  22. data/lib/activity_notification/apis/notification_api.rb +108 -14
  23. data/lib/activity_notification/common.rb +11 -2
  24. data/lib/activity_notification/config.rb +13 -13
  25. data/lib/activity_notification/helpers/view_helpers.rb +26 -4
  26. data/lib/activity_notification/mailers/helpers.rb +8 -4
  27. data/lib/activity_notification/models.rb +4 -0
  28. data/lib/activity_notification/models/concerns/group.rb +32 -0
  29. data/lib/activity_notification/models/concerns/notifiable.rb +60 -32
  30. data/lib/activity_notification/models/concerns/notifier.rb +17 -1
  31. data/lib/activity_notification/models/concerns/target.rb +114 -55
  32. data/lib/activity_notification/models/notification.rb +26 -25
  33. data/lib/activity_notification/rails.rb +1 -0
  34. data/lib/activity_notification/renderable.rb +8 -3
  35. data/lib/activity_notification/roles/acts_as_common.rb +28 -0
  36. data/lib/activity_notification/roles/acts_as_group.rb +38 -0
  37. data/lib/activity_notification/roles/acts_as_notifiable.rb +56 -22
  38. data/lib/activity_notification/roles/acts_as_notifier.rb +25 -2
  39. data/lib/activity_notification/roles/acts_as_target.rb +27 -9
  40. data/lib/activity_notification/version.rb +1 -1
  41. data/lib/generators/templates/activity_notification.rb +1 -1
  42. data/spec/concerns/apis/notification_api_spec.rb +361 -2
  43. data/spec/concerns/common_spec.rb +36 -0
  44. data/spec/concerns/models/group_spec.rb +61 -0
  45. data/spec/concerns/models/notifiable_spec.rb +37 -0
  46. data/spec/concerns/models/notifier_spec.rb +48 -0
  47. data/spec/concerns/models/target_spec.rb +81 -31
  48. data/spec/factories/dummy/dummy_group.rb +4 -0
  49. data/spec/helpers/view_helpers_spec.rb +13 -0
  50. data/spec/mailers/mailer_spec.rb +8 -1
  51. data/spec/models/dummy/dummy_group_spec.rb +6 -0
  52. data/spec/rails_app/app/assets/stylesheets/application.css +15 -0
  53. data/spec/rails_app/app/assets/stylesheets/reset.css +85 -0
  54. data/spec/rails_app/app/assets/stylesheets/style.css +244 -0
  55. data/spec/rails_app/app/controllers/articles_controller.rb +1 -1
  56. data/spec/rails_app/app/models/admin.rb +2 -1
  57. data/spec/rails_app/app/models/article.rb +9 -2
  58. data/spec/rails_app/app/models/comment.rb +8 -2
  59. data/spec/rails_app/app/models/dummy/dummy_group.rb +4 -0
  60. data/spec/rails_app/app/models/user.rb +8 -3
  61. data/spec/rails_app/app/views/articles/_form.html.erb +14 -10
  62. data/spec/rails_app/app/views/articles/edit.html.erb +8 -6
  63. data/spec/rails_app/app/views/articles/index.html.erb +59 -67
  64. data/spec/rails_app/app/views/articles/new.html.erb +7 -5
  65. data/spec/rails_app/app/views/articles/show.html.erb +47 -36
  66. data/spec/rails_app/app/views/layouts/_header.html.erb +36 -9
  67. data/spec/rails_app/app/views/layouts/application.html.erb +8 -6
  68. data/spec/rails_app/config/environments/development.rb +9 -0
  69. data/spec/rails_app/config/initializers/activity_notification.rb +1 -1
  70. data/spec/rails_app/db/schema.rb +14 -20
  71. data/spec/rails_app/db/seeds.rb +5 -5
  72. data/spec/rails_app/lib/mailer_previews/mailer_preview.rb +13 -0
  73. data/spec/roles/acts_as_group_spec.rb +32 -0
  74. data/spec/roles/acts_as_notifiable_spec.rb +1 -1
  75. data/spec/roles/acts_as_notifier_spec.rb +15 -0
  76. data/spec/roles/acts_as_target_spec.rb +1 -1
  77. metadata +52 -2
@@ -1,14 +1,18 @@
1
+ require 'activity_notification/roles/acts_as_common'
1
2
  require 'activity_notification/roles/acts_as_target'
2
3
  require 'activity_notification/roles/acts_as_notifiable'
3
4
  require 'activity_notification/roles/acts_as_notifier'
5
+ require 'activity_notification/roles/acts_as_group'
4
6
 
5
7
  module ActivityNotification
6
8
  module Models
7
9
  extend ActiveSupport::Concern
8
10
  included do
11
+ include ActivityNotification::ActsAsCommon
9
12
  include ActivityNotification::ActsAsTarget
10
13
  include ActivityNotification::ActsAsNotifiable
11
14
  include ActivityNotification::ActsAsNotifier
15
+ include ActivityNotification::ActsAsGroup
12
16
  end
13
17
  end
14
18
  end
@@ -0,0 +1,32 @@
1
+ module ActivityNotification
2
+ # Notification group implementation included in group model to bundle notification.
3
+ module Group
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ include Common
7
+ class_attribute :_printable_notification_group_name
8
+ set_group_class_defaults
9
+ end
10
+
11
+ class_methods do
12
+ # Checks if the model includes notification group methods are available.
13
+ # @return [Boolean] Always true
14
+ def available_as_group?
15
+ true
16
+ end
17
+
18
+ # Sets default values to group class fields.
19
+ # @return [NilClass] nil
20
+ def set_group_class_defaults
21
+ self._printable_notification_group_name = :printable_name
22
+ nil
23
+ end
24
+ end
25
+
26
+ # Returns printable group model name to show in view or email.
27
+ # @return [String] Printable group model name
28
+ def printable_group_name
29
+ resolve_value(_printable_notification_group_name)
30
+ end
31
+ end
32
+ end
@@ -9,21 +9,31 @@ module ActivityNotification
9
9
  include Common
10
10
  include ActionDispatch::Routing::PolymorphicRoutes
11
11
  include Rails.application.routes.url_helpers
12
+
13
+ # Has many notification instances for this notifiable.
14
+ # Dependency for these notifications can be overriden from acts_as_notifiable.
15
+ # @scope instance
16
+ # @return [Array<Notificaion>] Array or database query of notifications for this notifiable
17
+ has_many :generated_notifications_as_notifiable,
18
+ class_name: "::ActivityNotification::Notification",
19
+ as: :notifiable
20
+
12
21
  class_attribute :_notification_targets,
13
22
  :_notification_group,
14
23
  :_notifier,
15
24
  :_notification_parameters,
16
25
  :_notification_email_allowed,
17
- :_notifiable_path
26
+ :_notifiable_path,
27
+ :_printable_notifiable_name
18
28
  set_notifiable_class_defaults
19
29
  end
20
-
30
+
21
31
  # Returns default_url_options for polymorphic_path.
22
32
  # @return [Hash] Rails.application.routes.default_url_options
23
33
  def default_url_options
24
34
  Rails.application.routes.default_url_options
25
35
  end
26
-
36
+
27
37
  class_methods do
28
38
  # Checks if the model includes notifiable and notifiable methods are available.
29
39
  # @return [Boolean] Always true
@@ -32,7 +42,7 @@ module ActivityNotification
32
42
  end
33
43
 
34
44
  # Sets default values to notifiable class fields.
35
- # @return [Nil] nil
45
+ # @return [NilClass] nil
36
46
  def set_notifiable_class_defaults
37
47
  self._notification_targets = {}
38
48
  self._notification_group = {}
@@ -40,6 +50,7 @@ module ActivityNotification
40
50
  self._notification_parameters = {}
41
51
  self._notification_email_allowed = {}
42
52
  self._notifiable_path = {}
53
+ self._printable_notifiable_name = {}
43
54
  nil
44
55
  end
45
56
  end
@@ -50,13 +61,12 @@ module ActivityNotification
50
61
  # @param [String] target_type Target type to notify
51
62
  # @param [String] key Key of the notification
52
63
  # @return [Array<Notificaion> | ActiveRecord_AssociationRelation<Notificaion>] Array or database query of the notification targets
53
- def notification_targets(target_type, key)
54
- target_typed_method_name = "notification_#{target_type.to_s.to_resources_name}"
64
+ def notification_targets(target_type, key = nil)
65
+ target_typed_method_name = "notification_#{cast_to_resources_name(target_type)}"
55
66
  resolved_parameter = resolve_parameter(
56
67
  target_typed_method_name,
57
- _notification_targets[target_type.to_s.to_resources_name.to_sym],
58
- nil,
59
- key)
68
+ _notification_targets[cast_to_resources_sym(target_type)],
69
+ nil, key)
60
70
  unless resolved_parameter
61
71
  raise NotImplementedError, "You have to implement #{self.class}##{target_typed_method_name} "\
62
72
  "or set :targets in acts_as_notifiable"
@@ -70,12 +80,11 @@ module ActivityNotification
70
80
  # @param [String] target_type Target type to notify
71
81
  # @param [String] key Key of the notification
72
82
  # @return [Object] Group owner of the notification
73
- def notification_group(target_type, key)
83
+ def notification_group(target_type, key = nil)
74
84
  resolve_parameter(
75
- "notification_group_for_#{target_type.to_s.to_resources_name}",
76
- _notification_group[target_type.to_s.to_resources_name.to_sym],
77
- nil,
78
- key)
85
+ "notification_group_for_#{cast_to_resources_name(target_type)}",
86
+ _notification_group[cast_to_resources_sym(target_type)],
87
+ nil, key)
79
88
  end
80
89
 
81
90
  # Returns additional notification parameters from configured field or overriden method.
@@ -84,12 +93,11 @@ module ActivityNotification
84
93
  # @param [String] target_type Target type to notify
85
94
  # @param [String] key Key of the notification
86
95
  # @return [Hash] Additional notification parameters
87
- def notification_parameters(target_type, key)
96
+ def notification_parameters(target_type, key = nil)
88
97
  resolve_parameter(
89
- "notification_parameters_for_#{target_type.to_s.to_resources_name}",
90
- _notification_parameters[target_type.to_s.to_resources_name.to_sym],
91
- {},
92
- key)
98
+ "notification_parameters_for_#{cast_to_resources_name(target_type)}",
99
+ _notification_parameters[cast_to_resources_sym(target_type)],
100
+ {}, key)
93
101
  end
94
102
 
95
103
  # Returns notifier of the notification from configured field or overriden method.
@@ -98,12 +106,11 @@ module ActivityNotification
98
106
  # @param [String] target_type Target type to notify
99
107
  # @param [String] key Key of the notification
100
108
  # @return [Object] Notifier of the notification
101
- def notifier(target_type, key)
109
+ def notifier(target_type, key = nil)
102
110
  resolve_parameter(
103
- "notifier_for_#{target_type.to_s.to_resources_name}",
104
- _notifier[target_type.to_s.to_resources_name.to_sym],
105
- nil,
106
- key)
111
+ "notifier_for_#{cast_to_resources_name(target_type)}",
112
+ _notifier[cast_to_resources_sym(target_type)],
113
+ nil, key)
107
114
  end
108
115
 
109
116
  # Returns if sending notification email is allowed for the notifiable from configured field or overriden method.
@@ -112,10 +119,10 @@ module ActivityNotification
112
119
  # @param [Object] target Target instance to notify
113
120
  # @param [String] key Key of the notification
114
121
  # @return [Boolean] If sending notification email is allowed for the notifiable
115
- def notification_email_allowed?(target, key)
122
+ def notification_email_allowed?(target, key = nil)
116
123
  resolve_parameter(
117
- "notification_email_allowed_for_#{target.class.to_s.to_resources_name}?",
118
- _notification_email_allowed[target.class.to_s.to_resources_name.to_sym],
124
+ "notification_email_allowed_for_#{cast_to_resources_name(target.class)}?",
125
+ _notification_email_allowed[cast_to_resources_sym(target.class)],
119
126
  ActivityNotification.config.email_enabled,
120
127
  target, key)
121
128
  end
@@ -126,12 +133,11 @@ module ActivityNotification
126
133
  # @param [String] target_type Target type to notify
127
134
  # @param [String] key Key of the notification
128
135
  # @return [String] Notifiable path URL to move after opening notification
129
- def notifiable_path(target_type, key)
136
+ def notifiable_path(target_type, key = nil)
130
137
  resolved_parameter = resolve_parameter(
131
- "notifiable_path_for_#{target_type.to_s.to_resources_name}",
132
- _notifiable_path[target_type.to_s.to_resources_name.to_sym],
133
- nil,
134
- key)
138
+ "notifiable_path_for_#{cast_to_resources_name(target_type)}",
139
+ _notifiable_path[cast_to_resources_sym(target_type)],
140
+ nil, key)
135
141
  unless resolved_parameter
136
142
  begin
137
143
  resolved_parameter = polymorphic_path(self)
@@ -144,6 +150,16 @@ module ActivityNotification
144
150
  resolved_parameter
145
151
  end
146
152
 
153
+ # Returns printable notifiable model name to show in view or email.
154
+ # @return [String] Printable notifiable model name
155
+ def printable_notifiable_name(target, key = nil)
156
+ resolve_parameter(
157
+ "printable_notifiable_name_for_#{cast_to_resources_name(target.class)}?",
158
+ _printable_notifiable_name[cast_to_resources_sym(target.class)],
159
+ printable_name,
160
+ target, key)
161
+ end
162
+
147
163
  # overriding_notification_email_key is the method to override key definition for Mailer
148
164
  # When respond_to?(overriding_notification_email_key) returns true,
149
165
  # Mailer uses overriding_notification_email_key instead of original key.
@@ -230,5 +246,17 @@ module ActivityNotification
230
246
  default_value
231
247
  end
232
248
  end
249
+
250
+ # Casts to resources name.
251
+ # @api private
252
+ def cast_to_resources_name(target_type)
253
+ target_type.to_s.to_resources_name
254
+ end
255
+
256
+ # Casts to symbol of resources name.
257
+ # @api private
258
+ def cast_to_resources_sym(target_type)
259
+ target_type.to_s.to_resources_name.to_sym
260
+ end
233
261
  end
234
262
  end
@@ -1,4 +1,5 @@
1
1
  module ActivityNotification
2
+ # Notifier implementation included in notifier model to be notified, like users or administrators.
2
3
  module Notifier
3
4
  extend ActiveSupport::Concern
4
5
  included do
@@ -6,14 +7,29 @@ module ActivityNotification
6
7
  has_many :sent_notifications,
7
8
  class_name: "::ActivityNotification::Notification",
8
9
  as: :notifier
10
+ class_attribute :_printable_notifier_name
11
+ set_notifier_class_defaults
9
12
  end
10
13
 
11
14
  class_methods do
12
- # Checks if the model includes notifier and notifier methods are available.
15
+ # Checks if the model includes notifier methods are available.
13
16
  # @return [Boolean] Always true
14
17
  def available_as_notifier?
15
18
  true
16
19
  end
20
+
21
+ # Sets default values to notifier class fields.
22
+ # @return [NilClass] nil
23
+ def set_notifier_class_defaults
24
+ self._printable_notifier_name = :printable_name
25
+ nil
26
+ end
27
+ end
28
+
29
+ # Returns printable notifier model name to show in view or email.
30
+ # @return [String] Printable notifier model name
31
+ def printable_notifier_name
32
+ resolve_value(_printable_notifier_name)
17
33
  end
18
34
  end
19
35
  end
@@ -10,9 +10,13 @@ module ActivityNotification
10
10
  # @return [Array<Notificaion>] Array or database query of notifications of this target
11
11
  has_many :notifications,
12
12
  class_name: "::ActivityNotification::Notification",
13
- as: :target
13
+ as: :target,
14
+ dependent: :delete_all
14
15
 
15
- class_attribute :_notification_email, :_notification_email_allowed, :_notification_devise_resource
16
+ class_attribute :_notification_email,
17
+ :_notification_email_allowed,
18
+ :_notification_devise_resource,
19
+ :_printable_notification_target_name
16
20
  set_target_class_defaults
17
21
  end
18
22
 
@@ -24,11 +28,12 @@ module ActivityNotification
24
28
  end
25
29
 
26
30
  # Sets default values to target class fields.
27
- # @return [Nil] nil
31
+ # @return [NilClass] nil
28
32
  def set_target_class_defaults
29
- self._notification_email = nil
30
- self._notification_email_allowed = ActivityNotification.config.email_enabled
31
- self._notification_devise_resource = ->(model) { model }
33
+ self._notification_email = nil
34
+ self._notification_email_allowed = ActivityNotification.config.email_enabled
35
+ self._notification_devise_resource = ->(model) { model }
36
+ self._printable_notification_target_name = :printable_name
32
37
  nil
33
38
  end
34
39
  end
@@ -58,48 +63,58 @@ module ActivityNotification
58
63
  # @return [Boolean] If current resource signed in with Devise is authenticated for the notification
59
64
  def authenticated_with_devise?(current_resource)
60
65
  devise_resource = resolve_value(_notification_devise_resource)
61
- unless current_resource.instance_of? devise_resource.class
66
+ unless current_resource.blank? or current_resource.instance_of? devise_resource.class
62
67
  raise TypeError,
63
68
  "Defferent type of current resource #{current_resource.class} "\
64
69
  "with devise resource #{devise_resource.class} has been passed to #{self.class}##{__method__}. "\
65
70
  "You have to override #{self.class}##{__method__} method or set devise_resource in acts_as_target."
66
71
  end
67
- current_resource == devise_resource
72
+ current_resource.present? and current_resource == devise_resource
73
+ end
74
+
75
+ # Returns printable target model name to show in view or email.
76
+ # @return [String] Printable target model name
77
+ def printable_target_name
78
+ resolve_value(_printable_notification_target_name)
68
79
  end
69
80
 
70
81
  # Returns count of unopened notifications of the target.
71
82
  #
83
+ # @param [Hash] options Options for notification index
84
+ # @option options [Integer] :limit (nil) Limit to query for notifications
72
85
  # @return [Integer] Count of unopened notifications of the target
73
- def unopened_notification_count
74
- unopened_notification_index.count
86
+ # @todo Add filter and reverse options
87
+ def unopened_notification_count(options = {})
88
+ unopened_notification_index(options).count
75
89
  end
76
90
 
77
91
  # Returns if the target has unopened notifications.
78
92
  #
93
+ # @param [Hash] options Options for notification index
94
+ # @option options [Integer] :limit (nil) Limit to query for notifications
79
95
  # @return [Boolean] If the target has unopened notifications
80
- def has_unopened_notifications?
81
- unopened_notification_index.exists?
96
+ # @todo Add filter and reverse options
97
+ def has_unopened_notifications?(options = {})
98
+ unopened_notification_index(options).present?
82
99
  end
83
100
 
84
101
  # Gets automatically arranged notification index of the target.
85
- # When the target has unopened notifications, returns unopened index with unopened_notification_index.
86
- # Otherwise, returns opened index with opened_notification_index.
102
+ # This method is the typical way to get notifications index from controller of view.
103
+ # When the target have unopened notifications, it returns unopened notifications first.
104
+ # Additionaly, it returns opened notifications unless unopened index size overs the limit.
87
105
  # @todo Is this switching the best solution?
88
106
  #
89
107
  # @example Get automatically arranged notification index of the @user
90
108
  # @notifications = @user.notification_index
91
109
  #
92
- # @param [Integer] limit Limit to query for notifications
110
+ # @param [Hash] options Options for notification index
111
+ # @option options [Integer] :limit (nil) Limit to query for notifications
93
112
  # @return [Array<Notificaion>] Notification index of the target
94
- def notification_index(limit = nil)
95
- # When the target have unopened notifications
96
- notifications.unopened_index.exists? ?
97
- # Return unopened notifications
98
- unopened_notification_index(limit) :
99
- # Otherwise, return opened notifications
100
- limit.present? ?
101
- opened_notification_index(limit) :
102
- opened_notification_index
113
+ # @todo Add filter and reverse options
114
+ def notification_index(options = {})
115
+ arrange_notification_index(method(:unopened_notification_index),
116
+ method(:opened_notification_index),
117
+ options)
103
118
  end
104
119
 
105
120
  # Gets unopened notification index of the target.
@@ -107,11 +122,13 @@ module ActivityNotification
107
122
  # @example Get unopened notification index of the @user
108
123
  # @notifications = @user.unopened_notification_index
109
124
  #
110
- # @param [Integer] limit Limit to query for notifications
125
+ # @param [Hash] options Options for notification index
126
+ # @option options [Integer] :limit (nil) Limit to query for notifications
111
127
  # @return [Array<Notificaion>] Unopened notification index of the target
112
- def unopened_notification_index(limit = nil)
113
- limit.present? ?
114
- notifications.unopened_index.limit(limit) :
128
+ # @todo Add filter and reverse options
129
+ def unopened_notification_index(options = {})
130
+ options[:limit].present? ?
131
+ notifications.unopened_index.limit(options[:limit]) :
115
132
  notifications.unopened_index
116
133
  end
117
134
 
@@ -120,9 +137,12 @@ module ActivityNotification
120
137
  # @example Get opened notification index of the @user
121
138
  # @notifications = @user.opened_notification_index(10)
122
139
  #
123
- # @param [Integer] limit Limit to query for notifications
140
+ # @param [Hash] options Options for notification index
141
+ # @option options [Integer] :limit (ActivityNotification.config.opened_index_limit) Limit to query for notifications
124
142
  # @return [Array<Notificaion>] Opened notification index of the target
125
- def opened_notification_index(limit = ActivityNotification.config.opened_limit)
143
+ # @todo Add filter and reverse options
144
+ def opened_notification_index(options = {})
145
+ limit = options[:limit] || ActivityNotification.config.opened_index_limit
126
146
  notifications.opened_index(limit)
127
147
  end
128
148
 
@@ -149,8 +169,12 @@ module ActivityNotification
149
169
  #
150
170
  # @param [Hash] options Options for opening notifications
151
171
  # @option options [DateTime] :opened_at (DateTime.now) Time to set to opened_at of the notification record
172
+ # @option options [String] :filtered_by_type (nil) Notifiable type for filter
173
+ # @option options [Object] :filtered_by_group (nil) Group instance for filter
174
+ # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
175
+ # @option options [String] :filtered_by_group_id (nil) Group instance id for filter, valid with :filtered_by_group_type
176
+ # @option options [String] :filtered_by_key (nil) Key of the notification for filter
152
177
  # @return [Integer] Number of opened notification records
153
- # @todo Add filter option
154
178
  def open_all_notifications(options = {})
155
179
  Notification.open_all_of(self, options)
156
180
  end
@@ -158,21 +182,21 @@ module ActivityNotification
158
182
 
159
183
  # Gets automatically arranged notification index of the target with included attributes like target, notifiable, group and notifier.
160
184
  # This method is the typical way to get notifications index from controller of view.
185
+ # When the target have unopened notifications, it returns unopened notifications first.
186
+ # Additionaly, it returns opened notifications unless unopened index size overs the limit.
187
+ # @todo Is this switching the best solution?
161
188
  #
162
189
  # @example Get automatically arranged notification index of the @user with included attributes
163
190
  # @notifications = @user.notification_index_with_attributes
164
191
  #
165
- # @param [Integer] limit Limit to query for notifications
192
+ # @param [Hash] options Options for notification index
193
+ # @option options [Integer] :limit (nil) Limit to query for notifications
166
194
  # @return [Array<Notificaion>] Notification index of the target with attributes
167
- def notification_index_with_attributes(limit = nil)
168
- # When the target have unopened notifications
169
- unopened_notification_index.exists? ?
170
- # Return unopened notifications
171
- unopened_notification_index_with_attributes(limit) :
172
- # Otherwise, return opened notifications
173
- limit.present? ?
174
- opened_notification_index_with_attributes(limit) :
175
- opened_notification_index_with_attributes
195
+ # @todo Add filter and reverse options
196
+ def notification_index_with_attributes(options = {})
197
+ arrange_notification_index(method(:unopened_notification_index_with_attributes),
198
+ method(:opened_notification_index_with_attributes),
199
+ options)
176
200
  end
177
201
 
178
202
  # Gets unopened notification index of the target with included attributes like target, notifiable, group and notifier.
@@ -180,10 +204,12 @@ module ActivityNotification
180
204
  # @example Get unopened notification index of the @user with included attributes
181
205
  # @notifications = @user.unopened_notification_index_with_attributes
182
206
  #
183
- # @param [Integer] limit Limit to query for notifications
207
+ # @param [Hash] options Options for notification index
208
+ # @option options [Integer] :limit (nil) Limit to query for notifications
184
209
  # @return [Array<Notificaion>] Unopened notification index of the target with attributes
185
- def unopened_notification_index_with_attributes(limit = nil)
186
- include_attributes unopened_notification_index(limit)
210
+ # @todo Add filter and reverse options
211
+ def unopened_notification_index_with_attributes(options = {})
212
+ include_attributes unopened_notification_index(options)
187
213
  end
188
214
 
189
215
  # Gets opened notification index of the target with including attributes like target, notifiable, group and notifier.
@@ -191,10 +217,12 @@ module ActivityNotification
191
217
  # @example Get opened notification index of the @user with included attributes
192
218
  # @notifications = @user.opened_notification_index_with_attributes(10)
193
219
  #
194
- # @param [Integer] limit Limit to query for notifications
220
+ # @param [Hash] options Options for notification index
221
+ # @option options [Integer] :limit (ActivityNotification.config.opened_index_limit) Limit to query for notifications
195
222
  # @return [Array<Notificaion>] Opened notification index of the target with attributes
196
- def opened_notification_index_with_attributes(limit = ActivityNotification.config.opened_limit)
197
- include_attributes opened_notification_index(limit)
223
+ # @todo Add filter and reverse options
224
+ def opened_notification_index_with_attributes(options = {})
225
+ include_attributes opened_notification_index(options)
198
226
  end
199
227
 
200
228
  private
@@ -204,15 +232,46 @@ module ActivityNotification
204
232
  # Otherwise, target, notifiable and or notifier will be include without group.
205
233
  # @api private
206
234
  #
207
- # @param [Array<Notificaion>] notification_index Notification index
208
- # @return [Array<Notificaion>] Notification index with attributes
209
- def include_attributes(notification_index)
210
- if notification_index.present?
211
- Notification.group_member_exists?(notification_index) ?
212
- notification_index.with_target.with_notifiable.with_group.with_notifier :
213
- notification_index.with_target.with_notifiable.with_notifier
235
+ # @param [ActiveRecord_AssociationRelation<Notificaion>] target_index Notification index
236
+ # @return [ActiveRecord_AssociationRelation<Notificaion>] Notification index with attributes
237
+ def include_attributes(target_index)
238
+ if target_index.present?
239
+ Notification.group_member_exists?(target_index) ?
240
+ target_index.with_target.with_notifiable.with_group.with_notifier :
241
+ target_index.with_target.with_notifiable.with_notifier
242
+ else
243
+ Notification.none
244
+ end
245
+ end
246
+
247
+ # Gets automatically arranged notification index of the target.
248
+ # When the target have unopened notifications, it returns unopened notifications first.
249
+ # Additionaly, it returns opened notifications unless unopened index size overs the limit.
250
+ # @api private
251
+ # @todo Is this switching the best solution?
252
+ #
253
+ # @param [Method] loading_unopened_index_method Method to load unopened index
254
+ # @param [Method] loading_opened_index_method Method to load opened index
255
+ # @param [Hash] options Options for notification index
256
+ # @option options [Integer] :limit (nil) Limit to query for notifications
257
+ # @return [Array<Notificaion>] Notification index of the target
258
+ def arrange_notification_index(loading_unopened_index_method, loading_opened_index_method, options = {})
259
+ # When the target have unopened notifications
260
+ if has_unopened_notifications?(options)
261
+ # Return unopened notifications first
262
+ target_unopened_index = loading_unopened_index_method.call(options).to_a
263
+ # Total limit if notification index
264
+ total_limit = options[:limit] || ActivityNotification.config.opened_index_limit
265
+ # Additionaly, return opened notifications unless unopened index size overs the limit
266
+ if (opened_limit = total_limit - target_unopened_index.size) > 0
267
+ target_opened_index = loading_opened_index_method.call(options.merge(limit: opened_limit))
268
+ target_unopened_index.concat(target_opened_index.to_a)
269
+ else
270
+ target_unopened_index
271
+ end
214
272
  else
215
- notifications.none
273
+ # Otherwise, return opened notifications
274
+ loading_opened_index_method.call(options)
216
275
  end
217
276
  end
218
277