discourse/plugins/chat/lib/chat_message_updater.rb
Martin Brennan 0924f874bd
DEV: Use UploadReference instead of ChatUpload in chat (#19947)
We've had the UploadReference table for some time now in core,
but it was added after ChatUpload was and chat was just never
moved over to this new system.

This commit changes all chat code dealing with uploads to create/
update/delete/query UploadReference records instead of ChatUpload
records for consistency. At a later date we will drop the ChatUpload
table, but for now keeping it for data backup.

The migration + post migration are the same, we need both in case
any chat uploads are added/removed during deploy.
2023-01-24 13:28:21 +10:00

99 lines
2.9 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::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