This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/plugins/chat/lib/chat_message_updater.rb
Roman Rizzi b7c24e1d69
REFACTOR: Separate post-send warnings logic.
After #19666, we send notifications asynchronously. However, this has dramatically delayed the different post-send warnings we send.

This change moves all the post-send warnings logic from `Chat::ChatNotifier` into a separate service, allowing us to run this part synchronously, displaying the warnings almost instantly without doing all the heavy lifting for sending notifications. It also simplifies the notifier, making another refactor we planned simpler.

Finally, this removes the need to run jobs on the system specs that test the post-warning logic, hopefully making them faster.
2023-02-15 08:37:47 -03:00

100 lines
3.0 KiB
Ruby

# frozen_string_literal: true
class Chat::ChatMessageUpdater
attr_reader :error
def self.update(opts)
instance = new(**opts)
instance.update
instance
end
def initialize(guardian:, chat_message:, new_content:, upload_ids: nil)
@guardian = guardian
@user = guardian.user
@chat_message = chat_message
@old_message_content = chat_message.message
@chat_channel = @chat_message.chat_channel
@new_content = new_content
@upload_ids = upload_ids
@error = nil
end
def update
begin
validate_channel_status!
@guardian.ensure_can_edit_chat!(@chat_message)
@chat_message.message = @new_content
@chat_message.last_editor_id = @user.id
upload_info = get_upload_info
validate_message!(has_uploads: upload_info[:uploads].any?)
@chat_message.cook
@chat_message.save!
update_uploads(upload_info)
revision = save_revision!
@chat_message.reload
ChatPublisher.publish_edit!(@chat_channel, @chat_message)
Jobs.enqueue(:process_chat_message, { chat_message_id: @chat_message.id })
Chat::MessageMentionWarnings.new.dispatch(@chat_message)
Chat::ChatNotifier.notify_edit(chat_message: @chat_message, timestamp: revision.created_at)
DiscourseEvent.trigger(:chat_message_edited, @chat_message, @chat_channel, @user)
rescue => error
@error = error
end
end
def failed?
@error.present?
end
private
def validate_channel_status!
return if @guardian.can_modify_channel_message?(@chat_channel)
raise StandardError.new(
I18n.t(
"chat.errors.channel_modify_message_disallowed",
status: @chat_channel.status_name,
),
)
end
def validate_message!(has_uploads:)
@chat_message.validate_message(has_uploads: has_uploads)
if @chat_message.errors.present?
raise StandardError.new(@chat_message.errors.map(&:full_message).join(", "))
end
end
def get_upload_info
return { uploads: [] } if @upload_ids.nil? || !SiteSetting.chat_allow_uploads
uploads = Upload.where(id: @upload_ids, user_id: @user.id)
if uploads.count != @upload_ids.count
# User is passing upload_ids for uploads that they don't own. Don't change anything.
return { uploads: @chat_message.uploads, changed: false }
end
new_upload_ids = uploads.map(&:id)
existing_upload_ids = @chat_message.upload_ids
difference = (existing_upload_ids + new_upload_ids) - (existing_upload_ids & new_upload_ids)
{ uploads: uploads, changed: difference.any? }
end
def update_uploads(upload_info)
return unless upload_info[:changed]
DB.exec("DELETE FROM chat_uploads WHERE chat_message_id = #{@chat_message.id}")
UploadReference.where(target: @chat_message).destroy_all
@chat_message.attach_uploads(upload_info[:uploads])
end
def save_revision!
@chat_message.revisions.create!(
old_message: @old_message_content,
new_message: @chat_message.message,
user_id: @user.id,
)
end
end