FEATURE: add custom fields to chat (channel/message/thread) (#29504)

This allows various extensions to store extra information the 3 most popular
chat entities

Useful for certain plugins and migrations
This commit is contained in:
Sam 2024-11-01 09:12:19 +11:00 committed by GitHub
parent 29d3b9b03e
commit e7f62ab52b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 140 additions and 11 deletions

View File

@ -4,6 +4,7 @@ module Chat
class Channel < ActiveRecord::Base
include Trashable
include TypeMappable
include HasCustomFields
# TODO (martin) Remove once we are using last_message instead,
# should be around August 2023.

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Chat
class ChannelCustomField < ActiveRecord::Base
belongs_to :channel
end
end
# == Schema Information
#
# Table name: chat_channel_custom_fields
#
# id :bigint not null, primary key
# channel_id :bigint not null
# name :string(256) not null
# value :string(1000000)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_chat_channel_custom_fields_on_channel_id_and_name (channel_id,name) UNIQUE
#

View File

@ -4,6 +4,7 @@ module Chat
class Message < ActiveRecord::Base
include Trashable
include TypeMappable
include HasCustomFields
self.table_name = "chat_messages"

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Chat
class MessageCustomField < ActiveRecord::Base
belongs_to :message
end
end
# == Schema Information
#
# Table name: chat_message_custom_fields
#
# id :bigint not null, primary key
# message_id :bigint not null
# name :string(256) not null
# value :string(1000000)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_chat_message_custom_fields_on_message_id_and_name (message_id,name) UNIQUE
#

View File

@ -5,6 +5,7 @@ module Chat
MAX_TITLE_LENGTH = 100
include Chat::ThreadCache
include HasCustomFields
self.table_name = "chat_threads"

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Chat
class ThreadCustomField < ActiveRecord::Base
belongs_to :thread
end
end
# == Schema Information
#
# Table name: chat_thread_custom_fields
#
# id :bigint not null, primary key
# thread_id :bigint not null
# name :string(256) not null
# value :string(1000000)
# created_at :datetime not null
# updated_at :datetime not null
#
# Indexes
#
# index_chat_thread_custom_fields_on_thread_id_and_name (thread_id,name) UNIQUE
#

View File

@ -0,0 +1,30 @@
# frozen_string_literal: true
class AddCustomFieldsToChat < ActiveRecord::Migration[7.1]
def change
create_table :chat_thread_custom_fields do |t|
t.bigint :thread_id, null: false
t.string :name, limit: 256, null: false
t.string :value, limit: 1_000_000
t.timestamps null: false
end
create_table :chat_message_custom_fields do |t|
t.bigint :message_id, null: false
t.string :name, limit: 256, null: false
t.string :value, limit: 1_000_000
t.timestamps null: false
end
create_table :chat_channel_custom_fields do |t|
t.bigint :channel_id, null: false
t.string :name, limit: 256, null: false
t.string :value, limit: 1_000_000
t.timestamps null: false
end
add_index :chat_thread_custom_fields, %i[thread_id name], unique: true
add_index :chat_message_custom_fields, %i[message_id name], unique: true
add_index :chat_channel_custom_fields, %i[channel_id name], unique: true
end
end

View File

@ -11,6 +11,14 @@ RSpec.describe Chat::Channel do
it { is_expected.to validate_length_of(:chatable_type).is_at_most(100) }
it { is_expected.to validate_length_of(:type).is_at_most(100) }
it "supports custom fields" do
channel.custom_fields["test"] = "test"
channel.save_custom_fields
loaded_channel = Chat::Channel.find(channel.id)
expect(loaded_channel.custom_fields["test"]).to eq("test")
expect(Chat::ChannelCustomField.first.channel.id).to eq(channel.id)
end
describe ".last_message" do
context "when there are no last message" do
it "returns an instance of NullMessage" do

View File

@ -5,6 +5,14 @@ describe Chat::Message do
it { is_expected.to have_many(:chat_mentions).dependent(:destroy) }
it "supports custom fields" do
message.custom_fields["test"] = "test"
message.save_custom_fields
loaded_message = Chat::Message.find(message.id)
expect(loaded_message.custom_fields["test"]).to eq("test")
expect(Chat::MessageCustomField.first.message.id).to eq(message.id)
end
describe "validations" do
subject(:message) { described_class.new(message: "") }
@ -509,7 +517,7 @@ describe Chat::Message do
it "destroys upload_references" do
message_1 = Fabricate(:chat_message)
upload_reference_1 = Fabricate(:upload_reference, target: message_1)
upload_1 = Fabricate(:upload)
_upload_1 = Fabricate(:upload)
message_1.destroy!

View File

@ -9,18 +9,16 @@ RSpec.describe Chat::Thread do
fab!(:thread_2) { Fabricate(:chat_thread, channel: channel) }
fab!(:thread_3) { Fabricate(:chat_thread, channel: channel) }
before do
Fabricate(:chat_message, chat_channel: channel, thread: thread_1)
Fabricate(:chat_message, chat_channel: channel, thread: thread_1)
Fabricate(:chat_message, chat_channel: channel, thread: thread_1)
fab!(:thread_1_message_1) { Fabricate(:chat_message, chat_channel: channel, thread: thread_1) }
fab!(:thread_1_message_2) { Fabricate(:chat_message, chat_channel: channel, thread: thread_1) }
fab!(:thread_1_message_3) { Fabricate(:chat_message, chat_channel: channel, thread: thread_1) }
Fabricate(:chat_message, chat_channel: channel, thread: thread_2)
Fabricate(:chat_message, chat_channel: channel, thread: thread_2)
Fabricate(:chat_message, chat_channel: channel, thread: thread_2)
Fabricate(:chat_message, chat_channel: channel, thread: thread_2)
fab!(:thread_2_message_1) { Fabricate(:chat_message, chat_channel: channel, thread: thread_2) }
fab!(:thread_2_message_2) { Fabricate(:chat_message, chat_channel: channel, thread: thread_2) }
fab!(:thread_2_message_3) { Fabricate(:chat_message, chat_channel: channel, thread: thread_2) }
fab!(:thread_2_message_4) { Fabricate(:chat_message, chat_channel: channel, thread: thread_2) }
Fabricate(:chat_message, chat_channel: channel, thread: thread_3)
end
fab!(:thread_3_message_1) { Fabricate(:chat_message, chat_channel: channel, thread: thread_3) }
describe "updating replies_count for all threads" do
it "counts correctly and does not include the original message" do
@ -233,4 +231,17 @@ RSpec.describe Chat::Thread do
expect(thread.latest_not_deleted_message_id).to eq(old_message.id)
end
end
describe "custom fields" do
fab!(:channel) { Fabricate(:category_channel) }
fab!(:thread) { Fabricate(:chat_thread, channel: channel) }
it "allows create and save" do
thread.custom_fields["test"] = "test"
thread.save_custom_fields
loaded_thread = Chat::Thread.find(thread.id)
expect(loaded_thread.custom_fields["test"]).to eq("test")
expect(Chat::ThreadCustomField.first.thread.id).to eq(thread.id)
end
end
end