diff --git a/app/models/user_stat.rb b/app/models/user_stat.rb index e39ca94aeaf..e6cab54c245 100644 --- a/app/models/user_stat.rb +++ b/app/models/user_stat.rb @@ -53,6 +53,14 @@ class UserStat < ActiveRecord::Base ) GROUP BY tau.user_id ) AS X ON X.user_id = u1.id + WHERE u1.id IN ( + SELECT id + FROM users + WHERE last_seen_at IS NOT NULL + AND last_seen_at > :last_seen + ORDER BY last_seen_at DESC + LIMIT :limit + ) ) AS Z WHERE us.user_id = Z.user_id SQL diff --git a/db/migrate/20211123033311_reset_first_unread_pm_at_on_user_stat.rb b/db/migrate/20211123033311_reset_first_unread_pm_at_on_user_stat.rb new file mode 100644 index 00000000000..fd823160717 --- /dev/null +++ b/db/migrate/20211123033311_reset_first_unread_pm_at_on_user_stat.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class ResetFirstUnreadPmAtOnUserStat < ActiveRecord::Migration[6.1] + def up + execute <<~SQL + UPDATE user_stats us + SET first_unread_pm_at = u.created_at + FROM users u + WHERE u.id = us.user_id + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/spec/models/user_stat_spec.rb b/spec/models/user_stat_spec.rb index 3a3a0a56fd3..1d99b5b063d 100644 --- a/spec/models/user_stat_spec.rb +++ b/spec/models/user_stat_spec.rb @@ -90,6 +90,8 @@ describe UserStat do end it 'updates first unread pm timestamp correctly' do + freeze_time + pm_topic = Fabricate(:private_message_topic) user = pm_topic.user user.update!(last_seen_at: Time.zone.now) @@ -107,26 +109,57 @@ describe UserStat do notification_level: TopicUser.notification_levels[:regular] ) - # User that has not been seen - user_3 = Fabricate(:user) + # User that has not been seen recently + user_3 = Fabricate(:user, last_seen_at: 1.year.ago) pm_topic.allowed_users << user_3 TopicUser.change(user_3.id, pm_topic.id, notification_level: TopicUser.notification_levels[:tracking] ) - freeze_time 10.minutes.from_now + user_3_orig_first_unread_pm_at = user_3.user_stat.first_unread_pm_at - post = create_post( - user: Fabricate(:admin), - topic_id: pm_topic.id + # User that is not related to the PM + user_4 = Fabricate(:user, last_seen_at: Time.zone.now) + user_4_orig_first_unread_pm_at = user_4.user_stat.first_unread_pm_at + + # User for another PM topic + pm_topic_2 = Fabricate(:private_message_topic) + user_5 = pm_topic_2.user + user_5.update!(last_seen_at: Time.zone.now) + create_post(user: user_5, topic_id: pm_topic_2.id) + + TopicUser.change(user_5.id, pm_topic_2.id, + notification_level: TopicUser.notification_levels[:tracking] ) - UserStat.ensure_consistency! + # User out of last seen limit + user_6 = Fabricate(:user, last_seen_at: Time.zone.now) + pm_topic.allowed_users << user_6 + create_post(user: user_6, topic_id: pm_topic.id) - expect(user.user_stat.reload.first_unread_pm_at).to eq_time(post.topic.updated_at) - expect(user_2.user_stat.reload.first_unread_pm_at).to_not eq_time(post.topic.updated_at) - expect(user_3.user_stat.reload.first_unread_pm_at).to_not eq_time(post.topic.updated_at) + TopicUser.change(user_6.id, pm_topic.id, + notification_level: TopicUser.notification_levels[:tracking] + ) + + user_6_orig_first_unread_pm_at = user_6.user_stat.first_unread_pm_at + + admin = Fabricate(:admin) + create_post(user: admin, topic_id: pm_topic.id) + create_post(user: admin, topic_id: pm_topic_2.id) + pm_topic.update!(updated_at: 10.minutes.from_now) + pm_topic_2.update!(updated_at: 20.minutes.from_now) + + stub_const(UserStat, "UPDATE_UNREAD_USERS_LIMIT", 4) do + UserStat.ensure_consistency! + end + + expect(user.user_stat.reload.first_unread_pm_at).to eq_time(pm_topic.reload.updated_at) + expect(user_2.user_stat.reload.first_unread_pm_at).to eq_time(UserStat::UPDATE_UNREAD_MINUTES_AGO.minutes.ago) + expect(user_3.user_stat.reload.first_unread_pm_at).to eq_time(user_3_orig_first_unread_pm_at) + expect(user_4.user_stat.reload.first_unread_pm_at).to eq_time(UserStat::UPDATE_UNREAD_MINUTES_AGO.minutes.ago) + expect(user_5.user_stat.reload.first_unread_pm_at).to eq_time(pm_topic_2.reload.updated_at) + expect(user_6.user_stat.reload.first_unread_pm_at).to eq_time(user_6_orig_first_unread_pm_at) end end