From 1194ed10e1ffd1778cc5768a4c9790615d46e6dc Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Thu, 29 Jun 2023 09:22:17 +1000 Subject: [PATCH] FEATURE: Track last_viewed_at datetime for channel members (#22294) Whenever a user opens a channel or marks it read, we now update the last_viewed_at datetime for that channel membership record. This is so we will be able to show thread unread indicators in the channel sidebar that clear independently of the main thread unread indicators. This unread functionality will follow in another PR. --- .../app/models/chat/user_chat_channel_membership.rb | 1 + .../chat/app/services/chat/channel_view_builder.rb | 5 +++++ .../chat/app/services/chat/update_user_last_read.rb | 10 ++++++---- ...last_viewed_at_to_user_chat_channel_memberships.rb | 11 +++++++++++ .../spec/services/chat/channel_view_builder_spec.rb | 10 ++++++++++ .../spec/services/chat/update_user_last_read_spec.rb | 7 +++++++ 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 plugins/chat/db/migrate/20230627044755_add_last_viewed_at_to_user_chat_channel_memberships.rb diff --git a/plugins/chat/app/models/chat/user_chat_channel_membership.rb b/plugins/chat/app/models/chat/user_chat_channel_membership.rb index 23a64c1e02e..c2e59caa7b2 100644 --- a/plugins/chat/app/models/chat/user_chat_channel_membership.rb +++ b/plugins/chat/app/models/chat/user_chat_channel_membership.rb @@ -32,6 +32,7 @@ end # updated_at :datetime not null # last_unread_mention_when_emailed_id :integer # join_mode :integer default("manual"), not null +# last_viewed_at :datetime not null # # Indexes # diff --git a/plugins/chat/app/services/chat/channel_view_builder.rb b/plugins/chat/app/services/chat/channel_view_builder.rb index f37656c611a..0c3ba813b63 100644 --- a/plugins/chat/app/services/chat/channel_view_builder.rb +++ b/plugins/chat/app/services/chat/channel_view_builder.rb @@ -39,6 +39,7 @@ module Chat step :fetch_tracking step :fetch_thread_memberships step :fetch_thread_participants + step :update_channel_last_viewed_at step :build_view class Contract @@ -226,6 +227,10 @@ module Chat ::Chat::ThreadParticipantQuery.call(thread_ids: threads.map(&:id)) end + def update_channel_last_viewed_at(channel:, guardian:, **) + channel.membership_for(guardian.user)&.update!(last_viewed_at: Time.zone.now) + end + def build_view( guardian:, channel:, diff --git a/plugins/chat/app/services/chat/update_user_last_read.rb b/plugins/chat/app/services/chat/update_user_last_read.rb index 8327d167b33..6d9c06caffc 100644 --- a/plugins/chat/app/services/chat/update_user_last_read.rb +++ b/plugins/chat/app/services/chat/update_user_last_read.rb @@ -21,8 +21,10 @@ module Chat policy :invalid_access model :message policy :ensure_message_id_recency - step :update_last_read_message_id - step :mark_associated_mentions_as_read + transaction do + step :update_membership_state + step :mark_associated_mentions_as_read + end step :publish_new_last_read_to_clients # @!visibility private @@ -56,8 +58,8 @@ module Chat message.id >= active_membership.last_read_message_id end - def update_last_read_message_id(message:, active_membership:, **) - active_membership.update!(last_read_message_id: message.id) + def update_membership_state(message:, active_membership:, **) + active_membership.update!(last_read_message_id: message.id, last_viewed_at: Time.zone.now) end def mark_associated_mentions_as_read(active_membership:, message:, **) diff --git a/plugins/chat/db/migrate/20230627044755_add_last_viewed_at_to_user_chat_channel_memberships.rb b/plugins/chat/db/migrate/20230627044755_add_last_viewed_at_to_user_chat_channel_memberships.rb new file mode 100644 index 00000000000..b930d356ae1 --- /dev/null +++ b/plugins/chat/db/migrate/20230627044755_add_last_viewed_at_to_user_chat_channel_memberships.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class AddLastViewedAtToUserChatChannelMemberships < ActiveRecord::Migration[7.0] + def change + add_column :user_chat_channel_memberships, + :last_viewed_at, + :datetime, + null: false, + default: -> { "CURRENT_TIMESTAMP" } + end +end diff --git a/plugins/chat/spec/services/chat/channel_view_builder_spec.rb b/plugins/chat/spec/services/chat/channel_view_builder_spec.rb index 9717346cd94..39354b8128d 100644 --- a/plugins/chat/spec/services/chat/channel_view_builder_spec.rb +++ b/plugins/chat/spec/services/chat/channel_view_builder_spec.rb @@ -37,6 +37,8 @@ RSpec.describe Chat::ChannelViewBuilder do } end + before { channel.add(current_user) } + it "threads_enabled is false by default" do expect(result.threads_enabled).to eq(false) end @@ -76,6 +78,14 @@ RSpec.describe Chat::ChannelViewBuilder do ) end + it "updates the channel membership last_viewed_at" do + membership = channel.membership_for(current_user) + membership.update!(last_viewed_at: 1.day.ago) + old_last_viewed_at = membership.last_viewed_at + result + expect(membership.reload.last_viewed_at).not_to eq_time(old_last_viewed_at) + end + it "does not query thread tracking overview or state by default" do Chat::TrackingStateReportQuery.expects(:call).never result diff --git a/plugins/chat/spec/services/chat/update_user_last_read_spec.rb b/plugins/chat/spec/services/chat/update_user_last_read_spec.rb index 120834feeff..7345de703cd 100644 --- a/plugins/chat/spec/services/chat/update_user_last_read_spec.rb +++ b/plugins/chat/spec/services/chat/update_user_last_read_spec.rb @@ -109,6 +109,13 @@ RSpec.describe Chat::UpdateUserLastRead do it "publishes new last read to clients" do expect(messages.map(&:channel)).to include("/chat/user-tracking-state/#{current_user.id}") end + + it "updates the channel membership last_viewed_at datetime" do + membership.update!(last_viewed_at: 1.day.ago) + old_last_viewed_at = membership.last_viewed_at + result + expect(membership.reload.last_viewed_at).not_to eq_time(old_last_viewed_at) + end end end end