From 4a365bc4a27fda36b0eb8f48a98cb360723f30ac Mon Sep 17 00:00:00 2001 From: David Battersby Date: Fri, 12 Jul 2024 10:57:14 +0400 Subject: [PATCH] FEATURE: prevent chat emails for messages created via SDK (#27875) This change allows us to distinguish between regular user generated chat messages and those created via the Chat SDK. A new created_by_sdk boolean column is added to the Chat Messages table. When this value is true, we will not include the message in the user summary email that is sent to users. --- .../chat/app/services/chat/create_message.rb | 6 +++++ ...837_add_created_by_sdk_to_chat_messages.rb | 6 +++++ ...622_update_chat_messages_created_by_sdk.rb | 24 +++++++++++++++++++ plugins/chat/lib/chat/mailer.rb | 1 + plugins/chat/lib/chat_sdk/message.rb | 1 + .../chat/spec/components/chat/mailer_spec.rb | 5 ++++ .../chat/spec/lib/chat_sdk/message_spec.rb | 5 ++++ 7 files changed, 48 insertions(+) create mode 100644 plugins/chat/db/migrate/20240711153837_add_created_by_sdk_to_chat_messages.rb create mode 100644 plugins/chat/db/post_migrate/20240711154622_update_chat_messages_created_by_sdk.rb diff --git a/plugins/chat/app/services/chat/create_message.rb b/plugins/chat/app/services/chat/create_message.rb index 20daafd3818..f75e30a4c39 100644 --- a/plugins/chat/app/services/chat/create_message.rb +++ b/plugins/chat/app/services/chat/create_message.rb @@ -44,6 +44,7 @@ module Chat step :create_webhook_event step :update_channel_last_message step :update_membership_last_read + step :update_created_by_sdk step :process_direct_message_channel end step :publish_new_thread @@ -65,6 +66,7 @@ module Chat attribute :process_inline, :boolean, default: Rails.env.test? attribute :force_thread, :boolean, default: false attribute :strip_whitespaces, :boolean, default: true + attribute :created_by_sdk, :boolean, default: false validates :chat_channel_id, presence: true validates :message, presence: true, if: -> { upload_ids.blank? } @@ -187,6 +189,10 @@ module Chat membership.update!(last_read_message: message_instance) end + def update_created_by_sdk(message_instance:, contract:) + message_instance.created_by_sdk = contract.created_by_sdk + end + def process_direct_message_channel(membership:) Chat::Action::PublishAndFollowDirectMessageChannel.call(channel_membership: membership) end diff --git a/plugins/chat/db/migrate/20240711153837_add_created_by_sdk_to_chat_messages.rb b/plugins/chat/db/migrate/20240711153837_add_created_by_sdk_to_chat_messages.rb new file mode 100644 index 00000000000..5c0008e03a6 --- /dev/null +++ b/plugins/chat/db/migrate/20240711153837_add_created_by_sdk_to_chat_messages.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +class AddCreatedBySdkToChatMessages < ActiveRecord::Migration[7.1] + def change + add_column :chat_messages, :created_by_sdk, :boolean + end +end diff --git a/plugins/chat/db/post_migrate/20240711154622_update_chat_messages_created_by_sdk.rb b/plugins/chat/db/post_migrate/20240711154622_update_chat_messages_created_by_sdk.rb new file mode 100644 index 00000000000..19464c23d1e --- /dev/null +++ b/plugins/chat/db/post_migrate/20240711154622_update_chat_messages_created_by_sdk.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true +class UpdateChatMessagesCreatedBySdk < ActiveRecord::Migration[7.1] + def up + change_column_default :chat_messages, :created_by_sdk, false + + if DB.query_single("SELECT 1 FROM chat_messages WHERE created_by_sdk IS NULL LIMIT 1").first + batch_size = 10_000 + min_id = DB.query_single("SELECT MIN(id) FROM chat_messages").first.to_i + max_id = DB.query_single("SELECT MAX(id) FROM chat_messages").first.to_i + while max_id >= min_id + DB.exec( + "UPDATE chat_messages SET created_by_sdk = false WHERE id > #{max_id - batch_size} AND id <= #{max_id}", + ) + max_id -= batch_size + end + end + + change_column_null :chat_messages, :created_by_sdk, false + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/plugins/chat/lib/chat/mailer.rb b/plugins/chat/lib/chat/mailer.rb index 56e7806c3df..53ef482e820 100644 --- a/plugins/chat/lib/chat/mailer.rb +++ b/plugins/chat/lib/chat/mailer.rb @@ -56,6 +56,7 @@ module Chat AND chat_messages.deleted_at IS NULL AND chat_messages.created_at > now() - interval '1 week' AND chat_messages.user_id <> users.id + AND chat_messages.created_by_sdk = false AND ( (chat_channels.chatable_type = 'DirectMessage' AND user_options.allow_private_messages) OR (chat_channels.chatable_type = 'Category' AND uccm.following AND NOT notifications.read) diff --git a/plugins/chat/lib/chat_sdk/message.rb b/plugins/chat/lib/chat_sdk/message.rb index 0e4ba3c5d72..d5808abfbf3 100644 --- a/plugins/chat/lib/chat_sdk/message.rb +++ b/plugins/chat/lib/chat_sdk/message.rb @@ -133,6 +133,7 @@ module ChatSDK enforce_membership: enforce_membership, force_thread: force_thread, strip_whitespaces: strip_whitespaces, + created_by_sdk: true, ) do on_model_not_found(:channel) { raise "Couldn't find channel with id: `#{channel_id}`" } on_model_not_found(:membership) do diff --git a/plugins/chat/spec/components/chat/mailer_spec.rb b/plugins/chat/spec/components/chat/mailer_spec.rb index fadf1fb3d1f..89787e7879f 100644 --- a/plugins/chat/spec/components/chat/mailer_spec.rb +++ b/plugins/chat/spec/components/chat/mailer_spec.rb @@ -147,6 +147,11 @@ describe Chat::Mailer do expect_not_enqueued end + it "does not queue a chat summary email when chat message was created by the SDK" do + chat_message.update!(created_by_sdk: true) + expect_not_enqueued + end + it "queues a chat summary email even when user has private messages disabled" do user.user_option.update!(allow_private_messages: false) expect_enqueued diff --git a/plugins/chat/spec/lib/chat_sdk/message_spec.rb b/plugins/chat/spec/lib/chat_sdk/message_spec.rb index 045762edae7..a9814c123f7 100644 --- a/plugins/chat/spec/lib/chat_sdk/message_spec.rb +++ b/plugins/chat/spec/lib/chat_sdk/message_spec.rb @@ -15,6 +15,11 @@ describe ChatSDK::Message do expect(message.message).to eq("something") end + it "sets created_by_sdk to true" do + message = described_class.create(**params) + expect(message).to have_attributes(created_by_sdk: true) + end + context "when thread_id is present" do fab!(:thread_1) { Fabricate(:chat_thread, channel: channel_1) }