activity_notification 1.3.0 → 1.4.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +41 -5
  3. data/CHANGELOG.md +20 -0
  4. data/Gemfile +4 -1
  5. data/Gemfile.lock +81 -70
  6. data/README.md +152 -12
  7. data/activity_notification.gemspec +6 -4
  8. data/gemfiles/Gemfile.rails-4.2.lock +27 -22
  9. data/gemfiles/Gemfile.rails-5.0.lock +26 -21
  10. data/gemfiles/Gemfile.rails-5.1 +15 -0
  11. data/gemfiles/Gemfile.rails-5.1.lock +229 -0
  12. data/lib/activity_notification/apis/notification_api.rb +2 -2
  13. data/lib/activity_notification/apis/subscription_api.rb +7 -7
  14. data/lib/activity_notification/controllers/common_controller.rb +2 -2
  15. data/lib/activity_notification/helpers/view_helpers.rb +1 -1
  16. data/lib/activity_notification/models/concerns/notifiable.rb +19 -1
  17. data/lib/activity_notification/models/concerns/target.rb +5 -3
  18. data/lib/activity_notification/orm/active_record/notification.rb +3 -1
  19. data/lib/activity_notification/orm/active_record/subscription.rb +3 -1
  20. data/lib/activity_notification/orm/mongoid.rb +2 -2
  21. data/lib/activity_notification/renderable.rb +1 -1
  22. data/lib/activity_notification/roles/acts_as_notifiable.rb +98 -17
  23. data/lib/activity_notification/version.rb +1 -1
  24. data/spec/concerns/apis/notification_api_spec.rb +9 -8
  25. data/spec/concerns/apis/subscription_api_spec.rb +28 -28
  26. data/spec/concerns/models/notifier_spec.rb +1 -1
  27. data/spec/concerns/models/subscriber_spec.rb +7 -7
  28. data/spec/concerns/models/target_spec.rb +20 -20
  29. data/spec/controllers/notifications_controller_shared_examples.rb +19 -8
  30. data/spec/controllers/subscriptions_controller_shared_examples.rb +16 -5
  31. data/spec/models/notification_spec.rb +4 -4
  32. data/spec/models/subscription_spec.rb +16 -12
  33. data/spec/rails_app/app/controllers/articles_controller.rb +1 -1
  34. data/spec/rails_app/app/controllers/comments_controller.rb +0 -1
  35. data/spec/rails_app/app/models/admin.rb +29 -8
  36. data/spec/rails_app/app/models/article.rb +45 -13
  37. data/spec/rails_app/app/models/comment.rb +107 -42
  38. data/spec/rails_app/app/models/user.rb +45 -12
  39. data/spec/rails_app/app/views/layouts/_header.html.erb +1 -0
  40. data/spec/rails_app/config/database.yml +26 -15
  41. data/spec/rails_app/config/initializers/devise.rb +5 -1
  42. data/spec/rails_app/db/migrate/20160715050420_create_activity_notification_tables.rb +1 -1
  43. data/spec/rails_app/db/migrate/20160715050433_create_test_tables.rb +1 -1
  44. data/spec/rails_app/db/seeds.rb +31 -8
  45. data/spec/roles/acts_as_notifiable_spec.rb +154 -1
  46. data/spec/spec_helper.rb +7 -2
  47. metadata +47 -17
@@ -125,11 +125,11 @@ module ActivityNotification
125
125
  }
126
126
 
127
127
  # Orders by latest (newest) first as created_at: :desc.
128
- # @return [Mongoid::Criteria<Notificaion>] Database query of notifications ordered by latest first
128
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by latest first
129
129
  scope :latest_order, -> { order(created_at: :desc) }
130
130
 
131
131
  # Orders by earliest (older) first as created_at: :asc.
132
- # @return [Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
132
+ # @return [ActiveRecord_AssociationRelation<Notificaion>, Mongoid::Criteria<Notificaion>] Database query of notifications ordered by earliest first
133
133
  scope :earliest_order, -> { order(created_at: :asc) }
134
134
  end
135
135
 
@@ -9,7 +9,7 @@ module ActivityNotification
9
9
  # @subscriptions = @user.subscriptions.filtered_by_key('comment.reply')
10
10
  # @scope class
11
11
  # @param [String] key Key of the subscription for filter
12
- # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of filtered subscriptions
12
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of filtered subscriptions
13
13
  scope :filtered_by_key, ->(key) { where(key: key) }
14
14
 
15
15
  # Selects filtered subscriptions by key with filter options.
@@ -21,7 +21,7 @@ module ActivityNotification
21
21
  # @param [Hash] options Options for filter
22
22
  # @option options [String] :filtered_by_key (nil) Key of the subscription for filter
23
23
  # @option options [Array|Hash] :custom_filter (nil) Custom subscription filter (e.g. ["created_at >= ?", time.hour.ago])
24
- # @return [Mongoid::Criteria<Notificaion>] Database query of filtered subscriptions
24
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of filtered subscriptions
25
25
  scope :filtered_by_options, ->(options = {}) {
26
26
  options = ActivityNotification.cast_to_indifferent_hash(options)
27
27
  filtered_subscriptions = all
@@ -35,23 +35,23 @@ module ActivityNotification
35
35
  }
36
36
 
37
37
  # Orders by latest (newest) first as created_at: :desc.
38
- # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by latest first
38
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of subscriptions ordered by latest first
39
39
  scope :latest_order, -> { order(created_at: :desc) }
40
40
 
41
41
  # Orders by earliest (older) first as created_at: :asc.
42
- # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by earliest first
42
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of subscriptions ordered by earliest first
43
43
  scope :earliest_order, -> { order(created_at: :asc) }
44
44
 
45
45
  # Orders by latest (newest) first as subscribed_at: :desc.
46
- # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by latest subscribed_at first
46
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of subscriptions ordered by latest subscribed_at first
47
47
  scope :latest_subscribed_order, -> { order(subscribed_at: :desc) }
48
48
 
49
49
  # Orders by earliest (older) first as subscribed_at: :asc.
50
- # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by earliest subscribed_at first
50
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of subscriptions ordered by earliest subscribed_at first
51
51
  scope :earliest_subscribed_order, -> { order(subscribed_at: :asc) }
52
52
 
53
53
  # Orders by key name as key: :asc.
54
- # @return [ActiveRecord_AssociationRelation<Subscription>] Database query of subscriptions ordered by key name
54
+ # @return [ActiveRecord_AssociationRelation<Subscription>, Mongoid::Criteria<Notificaion>] Database query of subscriptions ordered by key name
55
55
  scope :key_order, -> { order(key: :asc) }
56
56
  end
57
57
 
@@ -24,8 +24,8 @@ module ActivityNotification
24
24
  if (target_type = params[:target_type]).present?
25
25
  target_class = target_type.to_model_class
26
26
  @target = params[:target_id].present? ?
27
- target_class.find_by_id!(params[:target_id]) :
28
- target_class.find_by_id!(params["#{target_type.to_resource_name}_id"])
27
+ target_class.find_by!(id: params[:target_id]) :
28
+ target_class.find_by!(id: params["#{target_type.to_resource_name}_id"])
29
29
  else
30
30
  render plain: "400 Bad Request: Missing parameter", status: 400
31
31
  end
@@ -58,7 +58,7 @@ module ActivityNotification
58
58
  notification_options = options.merge( target: target.to_resources_name,
59
59
  partial: options[:notification_partial],
60
60
  layout: options[:notification_layout] )
61
- index_options = options.slice( :limit, :reverse, :with_group_members,
61
+ index_options = options.slice( :limit, :reverse, :with_group_members, :as_latest_group_member,
62
62
  :filtered_by_group, :filtered_by_group_type, :filtered_by_group_id,
63
63
  :filtered_by_type, :filtered_by_key, :custom_filter )
64
64
  notification_index = load_notification_index(target, options[:index_content], index_options)
@@ -285,11 +285,29 @@ module ActivityNotification
285
285
  # This method is able to be overriden.
286
286
  # "#{to_resource_name}.default" is defined as default key.
287
287
  #
288
- # @return [String] Default Key of the notification
288
+ # @return [String] Default key of the notification
289
289
  def default_notification_key
290
290
  "#{to_resource_name}.default"
291
291
  end
292
292
 
293
+ # Returns key of the notification for tracked notifiable creation.
294
+ # This method is able to be overriden.
295
+ # "#{to_resource_name}.create" is defined as default creation key.
296
+ #
297
+ # @return [String] Key of the notification for tracked notifiable creation
298
+ def notification_key_for_tracked_creation
299
+ "#{to_resource_name}.create"
300
+ end
301
+
302
+ # Returns key of the notification for tracked notifiable update.
303
+ # This method is able to be overriden.
304
+ # "#{to_resource_name}.update" is defined as default update key.
305
+ #
306
+ # @return [String] Key of the notification for tracked notifiable update
307
+ def notification_key_for_tracked_update
308
+ "#{to_resource_name}.update"
309
+ end
310
+
293
311
  private
294
312
 
295
313
  # Used to transform parameter value from configured field or defined method.
@@ -534,6 +534,7 @@ module ActivityNotification
534
534
  # @option options [Integer] :limit (nil) Limit to query for notifications
535
535
  # @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
536
536
  # @option options [Boolean] :with_group_members (false) If notification index will include group members
537
+ # @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
537
538
  # @option options [String] :filtered_by_type (nil) Notifiable type for filter
538
539
  # @option options [Object] :filtered_by_group (nil) Group instance for filter
539
540
  # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
@@ -560,6 +561,7 @@ module ActivityNotification
560
561
  # @option options [Integer] :limit (nil) Limit to query for notifications
561
562
  # @option options [Boolean] :reverse (false) If notification index will be ordered as earliest first
562
563
  # @option options [Boolean] :with_group_members (false) If notification index will include group members
564
+ # @option options [Boolean] :as_latest_group_member (false) If grouped notification will be shown as the latest group member (default is shown as the earliest member)
563
565
  # @option options [String] :filtered_by_type (nil) Notifiable type for filter
564
566
  # @option options [Object] :filtered_by_group (nil) Group instance for filter
565
567
  # @option options [String] :filtered_by_group_type (nil) Group type for filter, valid with :filtered_by_group_id
@@ -571,19 +573,19 @@ module ActivityNotification
571
573
  # When the target have unopened notifications
572
574
  if has_unopened_notifications?(options)
573
575
  # Return unopened notifications first
574
- target_unopened_index = loading_unopened_index_method.call(options).to_a
576
+ target_unopened_index = arrange_single_notification_index(loading_unopened_index_method, options)
575
577
  # Total limit if notification index
576
578
  total_limit = options[:limit] || ActivityNotification.config.opened_index_limit
577
579
  # Additionaly, return opened notifications unless unopened index size overs the limit
578
580
  if (opened_limit = total_limit - target_unopened_index.size) > 0
579
- target_opened_index = loading_opened_index_method.call(options.merge(limit: opened_limit))
581
+ target_opened_index = arrange_single_notification_index(loading_opened_index_method, options.merge(limit: opened_limit))
580
582
  target_unopened_index.concat(target_opened_index.to_a)
581
583
  else
582
584
  target_unopened_index
583
585
  end
584
586
  else
585
587
  # Otherwise, return opened notifications
586
- loading_opened_index_method.call(options).to_a
588
+ arrange_single_notification_index(loading_opened_index_method, options)
587
589
  end
588
590
  end
589
591
 
@@ -175,7 +175,9 @@ module ActivityNotification
175
175
  # Selects unique keys from query for notifications.
176
176
  # @return [Array<String>] Array of notification unique keys
177
177
  def self.uniq_keys
178
- select(:key).distinct.pluck(:key)
178
+ # select method cannot be chained with order by other columns like created_at
179
+ # select(:key).distinct.pluck(:key)
180
+ pluck(:key).uniq
179
181
  end
180
182
 
181
183
  protected
@@ -43,7 +43,9 @@ module ActivityNotification
43
43
  # Selects unique keys from query for subscriptions.
44
44
  # @return [Array<String>] Array of subscription unique keys
45
45
  def self.uniq_keys
46
- select(:key).distinct.pluck(:key)
46
+ # select method cannot be chained with order by other columns like created_at
47
+ # select(:key).distinct.pluck(:key)
48
+ pluck(:key).uniq
47
49
  end
48
50
 
49
51
  end
@@ -13,7 +13,7 @@ module ActivityNotification
13
13
  def belongs_to_polymorphic_xdb_record(name, _options = {})
14
14
  association_name = name.to_s.singularize.underscore
15
15
  id_field, type_field = "#{association_name}_id", "#{association_name}_type"
16
- field id_field, type: Integer
16
+ field id_field, type: String
17
17
  field type_field, type: String
18
18
 
19
19
  self.instance_eval do
@@ -22,7 +22,7 @@ module ActivityNotification
22
22
  if self.instance_variable_get("@#{name}").blank?
23
23
  if (class_name = self.send(type_field)).present?
24
24
  object_class = class_name.classify.constantize
25
- self.instance_variable_set("@#{name}", object_class.where(object_class.primary_key => self.send(id_field)).first)
25
+ self.instance_variable_set("@#{name}", object_class.where(id: self.send(id_field)).first)
26
26
  end
27
27
  end
28
28
  self.instance_variable_get("@#{name}")
@@ -152,7 +152,7 @@ module ActivityNotification
152
152
  context.render params.merge(partial: partial, layout: layout, locals: locals)
153
153
  rescue ActionView::MissingTemplate => e
154
154
  if params[:fallback] == :text
155
- context.render text: self.text(params)
155
+ context.render plain: self.text(params)
156
156
  elsif params[:fallback].present?
157
157
  partial = partial_path(*params.values_at(:fallback, :partial_root, :target))
158
158
  context.render params.merge(partial: partial, layout: layout, locals: locals)
@@ -105,6 +105,29 @@ module ActivityNotification
105
105
  # end
106
106
  # end
107
107
  #
108
+ # * :tracked
109
+ # * Adds required callbacks to generate notifications for creation and update of the notifiable model.
110
+ # Default callbacks are enabled for [:create, :update].
111
+ # You can use :only and :except options as hash for this option.
112
+ # @example Add all callbacks to generate notifications for creation and update
113
+ # # app/models/comment.rb
114
+ # class Comment < ActiveRecord::Base
115
+ # belongs_to :article
116
+ # acts_as_notifiable :users, targets: User.all, tracked: true
117
+ # end
118
+ # @example Add callbacks to generate notifications for creation only
119
+ # # app/models/comment.rb
120
+ # class Comment < ActiveRecord::Base
121
+ # belongs_to :article
122
+ # acts_as_notifiable :users, targets: User.all, tracked: { only: [:create] }
123
+ # end
124
+ # @example Add callbacks to generate notifications for creation (except update) only
125
+ # # app/models/comment.rb
126
+ # class Comment < ActiveRecord::Base
127
+ # belongs_to :article
128
+ # acts_as_notifiable :users, targets: User.all, tracked: { except: [:update] }
129
+ # end
130
+ #
108
131
  # * :printable_name or :printable_notifiable_name
109
132
  # * Printable notifiable name.
110
133
  # This parameter is a optional since `ActivityNotification::Common.printable_name` is used as default value.
@@ -168,26 +191,16 @@ module ActivityNotification
168
191
  include Notifiable
169
192
  configured_params = {}
170
193
 
171
- if [:delete_all, :destroy, :restrict_with_error, :restrict_with_exception, :update_group_and_delete_all, :update_group_and_destroy].include? options[:dependent_notifications]
172
- case options[:dependent_notifications]
173
- when :delete_all, :destroy, :restrict_with_error, :restrict_with_exception
174
- before_destroy -> { destroy_generated_notifications_with_dependency(options[:dependent_notifications], target_type) }
175
- when :update_group_and_delete_all
176
- before_destroy -> { destroy_generated_notifications_with_dependency(:delete_all, target_type, true) }
177
- when :update_group_and_destroy
178
- before_destroy -> { destroy_generated_notifications_with_dependency(:destroy, target_type, true) }
179
- end
180
- configured_params = { dependent_notifications: options[:dependent_notifications] }
194
+ if options[:tracked].present?
195
+ configured_params.update(add_tracked_callbacks(target_type, options[:tracked].is_a?(Hash) ? options[:tracked] : {}))
196
+ end
197
+
198
+ if available_dependent_notifications_options.include? options[:dependent_notifications]
199
+ configured_params.update(add_destroy_dependency(target_type, options[:dependent_notifications]))
181
200
  end
182
201
 
183
202
  if options[:optional_targets].is_a?(Hash)
184
- options[:optional_targets] = options[:optional_targets].map { |target_class, target_options|
185
- optional_target = target_class.new(target_options)
186
- unless optional_target.kind_of?(ActivityNotification::OptionalTarget::Base)
187
- raise TypeError, "#{optional_target.class.name} for an optional target is not a kind of ActivityNotification::OptionalTarget::Base"
188
- end
189
- optional_target
190
- }
203
+ options[:optional_targets] = arrange_optional_targets_option(options[:optional_targets])
191
204
  end
192
205
 
193
206
  options[:printable_notifiable_name] ||= options.delete(:printable_name)
@@ -212,6 +225,74 @@ module ActivityNotification
212
225
  ].freeze
213
226
  end
214
227
 
228
+ # Returns array of available notifiable options in acts_as_notifiable.
229
+ # @return [Array<Symbol>] Array of available notifiable options
230
+ def available_dependent_notifications_options
231
+ [ :delete_all,
232
+ :destroy,
233
+ :restrict_with_error,
234
+ :restrict_with_exception,
235
+ :update_group_and_delete_all,
236
+ :update_group_and_destroy
237
+ ].freeze
238
+ end
239
+
240
+ # Adds tracked callbacks.
241
+ # @param [Symbol] target_type Type of notification target as symbol
242
+ # @param [Hash] tracked_option Specified :tracked option
243
+ # @return [Hash<Symbol, Symbol>] Configured tracked callbacks options
244
+ def add_tracked_callbacks(target_type, tracked_option = {})
245
+ tracked_callbacks = [:create, :update]
246
+ if tracked_option[:except]
247
+ tracked_callbacks -= tracked_option.delete(:except)
248
+ elsif tracked_option[:only]
249
+ tracked_callbacks &= tracked_option.delete(:only)
250
+ end
251
+ if tracked_callbacks.include? :create
252
+ if tracked_option.has_key?(:key)
253
+ after_create -> { notify target_type, tracked_option }
254
+ else
255
+ after_create -> { notify target_type, *tracked_option, key: notification_key_for_tracked_creation }
256
+ end
257
+ end
258
+ if tracked_callbacks.include? :update
259
+ if tracked_option.has_key?(:key)
260
+ after_update -> { notify target_type, tracked_option }
261
+ else
262
+ after_update -> { notify target_type, *tracked_option, key: notification_key_for_tracked_update }
263
+ end
264
+ end
265
+ { tracked: tracked_callbacks }
266
+ end
267
+
268
+ # Adds destroy dependency.
269
+ # @param [Symbol] target_type Type of notification target as symbol
270
+ # @param [Symbol] dependent_notifications_option Specified :dependent_notifications option
271
+ # @return [Hash<Symbol, Symbol>] Configured dependency options
272
+ def add_destroy_dependency(target_type, dependent_notifications_option)
273
+ case dependent_notifications_option
274
+ when :delete_all, :destroy, :restrict_with_error, :restrict_with_exception
275
+ before_destroy -> { destroy_generated_notifications_with_dependency(dependent_notifications_option, target_type) }
276
+ when :update_group_and_delete_all
277
+ before_destroy -> { destroy_generated_notifications_with_dependency(:delete_all, target_type, true) }
278
+ when :update_group_and_destroy
279
+ before_destroy -> { destroy_generated_notifications_with_dependency(:destroy, target_type, true) }
280
+ end
281
+ { dependent_notifications: dependent_notifications_option }
282
+ end
283
+
284
+ # Arrange optional targets option.
285
+ # @param [Symbol] optional_targets_option Specified :optional_targets option
286
+ # @return [Hash<ActivityNotification::OptionalTarget::Base, Hash>] Arranged optional targets options
287
+ def arrange_optional_targets_option(optional_targets_option)
288
+ optional_targets_option.map { |target_class, target_options|
289
+ optional_target = target_class.new(target_options)
290
+ unless optional_target.kind_of?(ActivityNotification::OptionalTarget::Base)
291
+ raise TypeError, "#{optional_target.class.name} for an optional target is not a kind of ActivityNotification::OptionalTarget::Base"
292
+ end
293
+ optional_target
294
+ }
295
+ end
215
296
  end
216
297
  end
217
298
  end
@@ -1,3 +1,3 @@
1
1
  module ActivityNotification
2
- VERSION = "1.3.0"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -313,10 +313,11 @@ shared_examples_for :notification_api do
313
313
 
314
314
  context "out of the group expiry period" do
315
315
  it "does not belong to single group" do
316
- owner_notification = described_class.notify_to(@user_1, @comment_1, group: @article, group_expiry_delay: 1.second)
317
- member_notification_1 = described_class.notify_to(@user_1, @comment_2, group: @article, group_expiry_delay: 1.second)
318
- sleep(1)
319
- member_notification_2 = described_class.notify_to(@user_1, @comment_2, group: @article, group_expiry_delay: 1.second)
316
+ Timecop.travel(90.seconds.ago)
317
+ owner_notification = described_class.notify_to(@user_1, @comment_1, group: @article, group_expiry_delay: 1.minute)
318
+ member_notification_1 = described_class.notify_to(@user_1, @comment_2, group: @article, group_expiry_delay: 1.minute)
319
+ Timecop.return
320
+ member_notification_2 = described_class.notify_to(@user_1, @comment_2, group: @article, group_expiry_delay: 1.minute)
320
321
  expect(member_notification_1.group_owner).to eq(owner_notification)
321
322
  expect(member_notification_2.group_owner).to be_nil
322
323
  end
@@ -568,7 +569,7 @@ shared_examples_for :notification_api do
568
569
  context "as default" do
569
570
  it "open notification with current time" do
570
571
  expect(test_instance.opened_at.blank?).to be_truthy
571
- Timecop.freeze(Time.current)
572
+ Timecop.freeze(Time.at(Time.now.to_i))
572
573
  test_instance.open!
573
574
  expect(test_instance.opened_at.blank?).to be_falsey
574
575
  expect(test_instance.opened_at).to eq(Time.current)
@@ -578,7 +579,7 @@ shared_examples_for :notification_api do
578
579
  it "open group member notifications with current time" do
579
580
  group_member = create(test_class_name, group_owner: test_instance)
580
581
  expect(group_member.opened_at.blank?).to be_truthy
581
- Timecop.freeze(Time.current)
582
+ Timecop.freeze(Time.at(Time.now.to_i))
582
583
  test_instance.open!
583
584
  group_member = group_member.reload
584
585
  expect(group_member.opened_at.blank?).to be_falsey
@@ -593,7 +594,7 @@ shared_examples_for :notification_api do
593
594
  opened_at = Time.current - 1.months
594
595
  test_instance.open!(opened_at: opened_at)
595
596
  expect(test_instance.opened_at.blank?).to be_falsey
596
- expect(test_instance.opened_at).to eq(opened_at)
597
+ expect(test_instance.opened_at.to_i).to eq(opened_at.to_i)
597
598
  end
598
599
 
599
600
  it "open group member notifications with specified time" do
@@ -1146,7 +1147,7 @@ shared_examples_for :notification_api do
1146
1147
  context "with group member" do
1147
1148
  it "returns latest group member" do
1148
1149
  member1 = create(test_class_name, target: test_instance.target, group_owner: test_instance)
1149
- member2 = create(test_class_name, target: test_instance.target, group_owner: test_instance)
1150
+ member2 = create(test_class_name, target: test_instance.target, group_owner: test_instance, created_at: member1.created_at + 10.second)
1150
1151
  expect(test_instance.latest_group_member.becomes(ActivityNotification::Notification)).to eq(member2)
1151
1152
  end
1152
1153
  end
@@ -37,12 +37,12 @@ shared_examples_for :subscription_api do
37
37
  it "subscribe with current time" do
38
38
  expect(test_instance.subscribing?).to eq(false)
39
39
  expect(test_instance.subscribing_to_email?).to eq(false)
40
- Timecop.freeze(Time.current)
40
+ Timecop.freeze(Time.at(Time.now.to_i))
41
41
  test_instance.subscribe
42
42
  expect(test_instance.subscribing?).to eq(true)
43
43
  expect(test_instance.subscribing_to_email?).to eq(true)
44
- expect(test_instance.subscribed_at).to eq(Time.current)
45
- expect(test_instance.subscribed_to_email_at).to eq(Time.current)
44
+ expect(test_instance.subscribed_at).to eq(Time.current)
45
+ expect(test_instance.subscribed_to_email_at).to eq(Time.current)
46
46
  Timecop.return
47
47
  end
48
48
  end
@@ -55,8 +55,8 @@ shared_examples_for :subscription_api do
55
55
  test_instance.subscribe(subscribed_at: subscribed_at)
56
56
  expect(test_instance.subscribing?).to eq(true)
57
57
  expect(test_instance.subscribing_to_email?).to eq(true)
58
- expect(test_instance.subscribed_at).to eq(subscribed_at)
59
- expect(test_instance.subscribed_to_email_at).to eq(subscribed_at)
58
+ expect(test_instance.subscribed_at.to_i).to eq(subscribed_at.to_i)
59
+ expect(test_instance.subscribed_to_email_at.to_i).to eq(subscribed_at.to_i)
60
60
  end
61
61
  end
62
62
 
@@ -102,12 +102,12 @@ shared_examples_for :subscription_api do
102
102
  it "unsubscribe with current time" do
103
103
  expect(test_instance.subscribing?).to eq(true)
104
104
  expect(test_instance.subscribing_to_email?).to eq(true)
105
- Timecop.freeze(Time.current)
105
+ Timecop.freeze(Time.at(Time.now.to_i))
106
106
  test_instance.unsubscribe
107
107
  expect(test_instance.subscribing?).to eq(false)
108
108
  expect(test_instance.subscribing_to_email?).to eq(false)
109
- expect(test_instance.unsubscribed_at).to eq(Time.current)
110
- expect(test_instance.unsubscribed_to_email_at).to eq(Time.current)
109
+ expect(test_instance.unsubscribed_at).to eq(Time.current)
110
+ expect(test_instance.unsubscribed_to_email_at).to eq(Time.current)
111
111
  Timecop.return
112
112
  end
113
113
  end
@@ -120,8 +120,8 @@ shared_examples_for :subscription_api do
120
120
  test_instance.unsubscribe(unsubscribed_at: unsubscribed_at)
121
121
  expect(test_instance.subscribing?).to eq(false)
122
122
  expect(test_instance.subscribing_to_email?).to eq(false)
123
- expect(test_instance.unsubscribed_at).to eq(unsubscribed_at)
124
- expect(test_instance.unsubscribed_to_email_at).to eq(unsubscribed_at)
123
+ expect(test_instance.unsubscribed_at.to_i).to eq(unsubscribed_at.to_i)
124
+ expect(test_instance.unsubscribed_to_email_at.to_i).to eq(unsubscribed_at.to_i)
125
125
  end
126
126
  end
127
127
  end
@@ -152,11 +152,11 @@ shared_examples_for :subscription_api do
152
152
  it "subscribe_to_email with current time" do
153
153
  expect(test_instance.subscribing?).to eq(true)
154
154
  expect(test_instance.subscribing_to_email?).to eq(false)
155
- Timecop.freeze(Time.current)
155
+ Timecop.freeze(Time.at(Time.now.to_i))
156
156
  test_instance.subscribe_to_email
157
157
  expect(test_instance.subscribing?).to eq(true)
158
158
  expect(test_instance.subscribing_to_email?).to eq(true)
159
- expect(test_instance.subscribed_to_email_at).to eq(Time.current)
159
+ expect(test_instance.subscribed_to_email_at).to eq(Time.current)
160
160
  Timecop.return
161
161
  end
162
162
  end
@@ -169,7 +169,7 @@ shared_examples_for :subscription_api do
169
169
  test_instance.subscribe_to_email(subscribed_to_email_at: subscribed_to_email_at)
170
170
  expect(test_instance.subscribing?).to eq(true)
171
171
  expect(test_instance.subscribing_to_email?).to eq(true)
172
- expect(test_instance.subscribed_to_email_at).to eq(subscribed_to_email_at)
172
+ expect(test_instance.subscribed_to_email_at.to_i).to eq(subscribed_to_email_at.to_i)
173
173
  end
174
174
  end
175
175
  end
@@ -183,11 +183,11 @@ shared_examples_for :subscription_api do
183
183
  it "unsubscribe_to_email with current time" do
184
184
  expect(test_instance.subscribing?).to eq(true)
185
185
  expect(test_instance.subscribing_to_email?).to eq(true)
186
- Timecop.freeze(Time.current)
186
+ Timecop.freeze(Time.at(Time.now.to_i))
187
187
  test_instance.unsubscribe_to_email
188
188
  expect(test_instance.subscribing?).to eq(true)
189
189
  expect(test_instance.subscribing_to_email?).to eq(false)
190
- expect(test_instance.unsubscribed_to_email_at).to eq(Time.current)
190
+ expect(test_instance.unsubscribed_to_email_at).to eq(Time.current)
191
191
  Timecop.return
192
192
  end
193
193
  end
@@ -200,7 +200,7 @@ shared_examples_for :subscription_api do
200
200
  test_instance.unsubscribe_to_email(unsubscribed_to_email_at: unsubscribed_to_email_at)
201
201
  expect(test_instance.subscribing?).to eq(true)
202
202
  expect(test_instance.subscribing_to_email?).to eq(false)
203
- expect(test_instance.unsubscribed_to_email_at).to eq(unsubscribed_to_email_at)
203
+ expect(test_instance.unsubscribed_to_email_at.to_i).to eq(unsubscribed_to_email_at.to_i)
204
204
  end
205
205
  end
206
206
  end
@@ -275,7 +275,7 @@ shared_examples_for :subscription_api do
275
275
  it "subscribe_to_optional_target with current time" do
276
276
  expect(test_instance.subscribing?).to eq(true)
277
277
  expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(false)
278
- Timecop.freeze(Time.current)
278
+ Timecop.freeze(Time.at(Time.now.to_i))
279
279
  test_instance.subscribe_to_optional_target(:console_output)
280
280
  expect(test_instance.subscribing?).to eq(true)
281
281
  expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(true)
@@ -286,13 +286,13 @@ shared_examples_for :subscription_api do
286
286
 
287
287
  context "with subscribed_at option" do
288
288
  it "subscribe with specified time" do
289
- expect(test_instance.subscribing?).to eq(true)
290
- expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(false)
289
+ expect(test_instance.subscribing?).to eq(true)
290
+ expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(false)
291
291
  subscribed_at = Time.current - 1.months
292
292
  test_instance.subscribe_to_optional_target(:console_output, subscribed_at: subscribed_at)
293
- expect(test_instance.subscribing?).to eq(true)
294
- expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(true)
295
- expect(test_instance.optional_targets[:subscribed_to_console_output_at]).to eq(subscribed_at)
293
+ expect(test_instance.subscribing?).to eq(true)
294
+ expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(true)
295
+ expect(test_instance.optional_targets[:subscribed_to_console_output_at].to_i).to eq(subscribed_at.to_i)
296
296
  end
297
297
  end
298
298
  end
@@ -306,7 +306,7 @@ shared_examples_for :subscription_api do
306
306
  it "unsubscribe_to_optional_target with current time" do
307
307
  expect(test_instance.subscribing?).to eq(true)
308
308
  expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(true)
309
- Timecop.freeze(Time.current)
309
+ Timecop.freeze(Time.at(Time.now.to_i))
310
310
  test_instance.unsubscribe_to_optional_target(:console_output)
311
311
  expect(test_instance.subscribing?).to eq(true)
312
312
  expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(false)
@@ -317,13 +317,13 @@ shared_examples_for :subscription_api do
317
317
 
318
318
  context "with unsubscribed_at option" do
319
319
  it "unsubscribe with specified time" do
320
- expect(test_instance.subscribing?).to eq(true)
321
- expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(true)
320
+ expect(test_instance.subscribing?).to eq(true)
321
+ expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(true)
322
322
  unsubscribed_at = Time.current - 1.months
323
323
  test_instance.unsubscribe_to_optional_target(:console_output, unsubscribed_at: unsubscribed_at)
324
- expect(test_instance.subscribing?).to eq(true)
325
- expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(false)
326
- expect(test_instance.optional_targets[:unsubscribed_to_console_output_at]).to eq(unsubscribed_at)
324
+ expect(test_instance.subscribing?).to eq(true)
325
+ expect(test_instance.subscribing_to_optional_target?(:console_output)).to eq(false)
326
+ expect(test_instance.optional_targets[:unsubscribed_to_console_output_at].to_i).to eq(unsubscribed_at.to_i)
327
327
  end
328
328
  end
329
329
  end