From cc2570fce38579202d0e295c153310310f6feb14 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Wed, 10 May 2023 17:19:48 +0200 Subject: [PATCH] DEV: Create UserChatThreadMembership table and model (#21481) This will enable us to begin work on user tracking state for a thread so we can show thread-specific unreads and mentions indicators. In this case are following the core notification_level paradigm rather than the solution UserChatChannelMembership went with, and eventually we will want to refactor the other table to match this as well. Co-authored-by: Joffrey JAFFEUX --- plugins/chat/app/models/chat/thread.rb | 1 + .../chat/user_chat_thread_membership.rb | 26 +++++++++++++++++++ ...142249_add_user_chat_thread_memberships.rb | 18 +++++++++++++ .../lib/chat/notification_levels_extension.rb | 13 ++++++++++ plugins/chat/lib/chat/user_extension.rb | 3 +++ plugins/chat/plugin.rb | 1 + .../chat/spec/fabricators/chat_fabricator.rb | 2 ++ .../chat/user_chat_thread_membership_spec.rb | 16 ++++++++++++ 8 files changed, 80 insertions(+) create mode 100644 plugins/chat/app/models/chat/user_chat_thread_membership.rb create mode 100644 plugins/chat/db/migrate/20230510142249_add_user_chat_thread_memberships.rb create mode 100644 plugins/chat/lib/chat/notification_levels_extension.rb create mode 100644 plugins/chat/spec/models/chat/user_chat_thread_membership_spec.rb diff --git a/plugins/chat/app/models/chat/thread.rb b/plugins/chat/app/models/chat/thread.rb index dd6eec88205..64e41265b98 100644 --- a/plugins/chat/app/models/chat/thread.rb +++ b/plugins/chat/app/models/chat/thread.rb @@ -22,6 +22,7 @@ module Chat foreign_key: :thread_id, primary_key: :id, class_name: "Chat::Message" + has_many :user_chat_thread_memberships enum :status, { open: 0, read_only: 1, closed: 2, archived: 3 }, scopes: false diff --git a/plugins/chat/app/models/chat/user_chat_thread_membership.rb b/plugins/chat/app/models/chat/user_chat_thread_membership.rb new file mode 100644 index 00000000000..e439faf89c3 --- /dev/null +++ b/plugins/chat/app/models/chat/user_chat_thread_membership.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Chat + class Chat::UserChatThreadMembership < ActiveRecord::Base + self.table_name = "user_chat_thread_memberships" + + belongs_to :user + belongs_to :last_read_message, class_name: "Chat::Message", optional: true + belongs_to :thread, class_name: "Chat::Thread", foreign_key: :thread_id + + enum :notification_level, NotificationLevels.chat_levels + end +end + +# == Schema Information +# +# Table name: user_chat_thread_memberships +# +# id :bigint not null, primary key +# user_id :bigint not null +# thread_id :bigint not null +# last_read_message_id :bigint +# notification_level :integer default(2), not null +# created_at :datetime not null +# updated_at :datetime not null +# diff --git a/plugins/chat/db/migrate/20230510142249_add_user_chat_thread_memberships.rb b/plugins/chat/db/migrate/20230510142249_add_user_chat_thread_memberships.rb new file mode 100644 index 00000000000..bb8e88ce48d --- /dev/null +++ b/plugins/chat/db/migrate/20230510142249_add_user_chat_thread_memberships.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class AddUserChatThreadMemberships < ActiveRecord::Migration[7.0] + def change + create_table :user_chat_thread_memberships do |t| + t.bigint :user_id, null: false + t.bigint :thread_id, null: false + t.bigint :last_read_message_id + t.integer :notification_level, default: 2, null: false # default to tracking + t.timestamps + end + + add_index :user_chat_thread_memberships, + %i[user_id thread_id], + unique: true, + name: "user_chat_thread_unique_memberships" + end +end diff --git a/plugins/chat/lib/chat/notification_levels_extension.rb b/plugins/chat/lib/chat/notification_levels_extension.rb new file mode 100644 index 00000000000..d57a65218e7 --- /dev/null +++ b/plugins/chat/lib/chat/notification_levels_extension.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Chat + module NotificationLevelsExtension + extend ActiveSupport::Concern + + class_methods do + def chat_levels + @chat_levels ||= Enum.new(muted: 0, normal: 1, tracking: 2, watching: 3) + end + end + end +end diff --git a/plugins/chat/lib/chat/user_extension.rb b/plugins/chat/lib/chat/user_extension.rb index f4861d24a37..d5c7e14c926 100644 --- a/plugins/chat/lib/chat/user_extension.rb +++ b/plugins/chat/lib/chat/user_extension.rb @@ -8,6 +8,9 @@ module Chat has_many :user_chat_channel_memberships, class_name: "Chat::UserChatChannelMembership", dependent: :destroy + has_many :user_chat_thread_memberships, + class_name: "Chat::UserChatThreadMembership", + dependent: :destroy has_many :chat_message_reactions, class_name: "Chat::MessageReaction", dependent: :destroy has_many :chat_mentions, class_name: "Chat::Mention" end diff --git a/plugins/chat/plugin.rb b/plugins/chat/plugin.rb index d041adfeb3b..81e1ad040d8 100644 --- a/plugins/chat/plugin.rb +++ b/plugins/chat/plugin.rb @@ -63,6 +63,7 @@ after_initialize do User.prepend Chat::UserExtension Jobs::UserEmail.prepend Chat::UserEmailExtension Plugin::Instance.prepend Chat::PluginInstanceExtension + NotificationLevels.prepend Chat::NotificationLevelsExtension end if Oneboxer.respond_to?(:register_local_handler) diff --git a/plugins/chat/spec/fabricators/chat_fabricator.rb b/plugins/chat/spec/fabricators/chat_fabricator.rb index 29f0e78edc3..a62be7b22d5 100644 --- a/plugins/chat/spec/fabricators/chat_fabricator.rb +++ b/plugins/chat/spec/fabricators/chat_fabricator.rb @@ -154,3 +154,5 @@ Fabricator(:chat_thread, class_name: "Chat::Thread") do after_create { |thread| thread.original_message.update!(thread_id: thread.id) } end + +Fabricator(:user_chat_thread_membership, class_name: "Chat::UserChatThreadMembership") { user } diff --git a/plugins/chat/spec/models/chat/user_chat_thread_membership_spec.rb b/plugins/chat/spec/models/chat/user_chat_thread_membership_spec.rb new file mode 100644 index 00000000000..9786f30164d --- /dev/null +++ b/plugins/chat/spec/models/chat/user_chat_thread_membership_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +RSpec.describe Chat::UserChatThreadMembership do + it { is_expected.to belong_to(:user).class_name("User") } + it { is_expected.to belong_to(:last_read_message).class_name("Chat::Message") } + it { is_expected.to belong_to(:thread).class_name("Chat::Thread") } + + it do + is_expected.to define_enum_for(:notification_level).with_values( + muted: 0, + normal: 1, + tracking: 2, + watching: 3, + ) + end +end