diff --git a/app/models/concerns/slack_message_creation.rb b/app/models/concerns/slack_message_creation.rb new file mode 100644 index 000000000..a6a59ccf7 --- /dev/null +++ b/app/models/concerns/slack_message_creation.rb @@ -0,0 +1,69 @@ +module SlackMessageCreation + extend ActiveSupport::Concern + + private + + def create_message + return unless conversation + + build_message + @message.save! + { status: 'success' } + rescue Slack::Web::Api::Errors::MissingScope => e + ChatwootExceptionTracker.new(e, account: conversation.account).capture_exception + disable_and_reauthorize + end + + def disable_and_reauthorize + integration_hook.prompt_reauthorization! + integration_hook.disable + end + + def build_message + @message = conversation.messages.build( + message_type: :outgoing, + account_id: conversation.account_id, + inbox_id: conversation.inbox_id, + content: Slack::Messages::Formatting.unescape(params[:event][:text] || ''), + external_source_id_slack: params[:event][:ts], + private: private_note?, + sender: sender + ) + process_attachments(params[:event][:files]) if attachments_present? + end + + def attachments_present? + params[:event][:files].present? + end + + def process_attachments(attachments) + attachments.each do |attachment| + tempfile = Down::NetHttp.download(attachment[:url_private], headers: { 'Authorization' => "Bearer #{integration_hook.access_token}" }) + + attachment_params = { + file_type: file_type(attachment), + account_id: @message.account_id, + external_url: attachment[:url_private], + file: { + io: tempfile, + filename: tempfile.original_filename, + content_type: tempfile.content_type + } + } + + attachment_obj = @message.attachments.new(attachment_params) + attachment_obj.file.content_type = attachment[:mimetype] + end + end + + def file_type(attachment) + return if attachment[:mimetype] == 'text/plain' + + case attachment[:filetype] + when 'png', 'jpeg', 'gif', 'bmp', 'tiff', 'jpg' + :image + when 'pdf' + :file + end + end +end diff --git a/config/integration/apps.yml b/config/integration/apps.yml index 05add0c1a..f55fd9f56 100644 --- a/config/integration/apps.yml +++ b/config/integration/apps.yml @@ -13,7 +13,7 @@ slack: id: slack logo: slack.png i18n_key: slack - action: https://slack.com/oauth/v2/authorize?scope=commands,chat:write,channels:read,channels:manage,channels:join,groups:read,groups:write,im:write,mpim:write,users:read,users:read.email,chat:write.customize,channels:history,groups:history,mpim:history,im:history + action: https://slack.com/oauth/v2/authorize?scope=commands,chat:write,channels:read,channels:manage,channels:join,groups:read,groups:write,im:write,mpim:write,users:read,users:read.email,chat:write.customize,channels:history,groups:history,mpim:history,im:history,files:read,files:write hook_type: account allow_multiple_hooks: false webhooks: diff --git a/lib/integrations/slack/incoming_message_builder.rb b/lib/integrations/slack/incoming_message_builder.rb index 44d373259..f20bb8d44 100644 --- a/lib/integrations/slack/incoming_message_builder.rb +++ b/lib/integrations/slack/incoming_message_builder.rb @@ -1,4 +1,5 @@ class Integrations::Slack::IncomingMessageBuilder + include SlackMessageCreation attr_reader :params SUPPORTED_EVENT_TYPES = %w[event_callback url_verification].freeze @@ -36,7 +37,11 @@ class Integrations::Slack::IncomingMessageBuilder def should_process_event? return true if params[:type] != 'event_callback' - params[:event][:user].present? && params[:event][:subtype].blank? + params[:event][:user].present? && valid_event_subtype? + end + + def valid_event_subtype? + params[:event][:subtype].blank? || params[:event][:subtype] == 'file_share' end def supported_event? @@ -90,62 +95,10 @@ class Integrations::Slack::IncomingMessageBuilder params[:event][:text].strip.downcase.starts_with?('note:', 'private:') end - def create_message - return unless conversation - - @message = conversation.messages.create!( - message_type: :outgoing, - account_id: conversation.account_id, - inbox_id: conversation.inbox_id, - content: Slack::Messages::Formatting.unescape(params[:event][:text] || ''), - external_source_id_slack: params[:event][:ts], - private: private_note?, - sender: sender - ) - - process_attachments(params[:event][:files]) if params[:event][:files].present? - - { status: 'success' } - end - def slack_client @slack_client ||= Slack::Web::Client.new(token: @integration_hook.access_token) end - # TODO: move process attachment for facebook instagram and slack in one place - # https://api.slack.com/messaging/files - def process_attachments(attachments) - attachments.each do |attachment| - tempfile = Down::NetHttp.download(attachment[:url_private], headers: { 'Authorization' => "Bearer #{integration_hook.access_token}" }) - - attachment_params = { - file_type: file_type(attachment), - account_id: @message.account_id, - external_url: attachment[:url_private], - file: { - io: tempfile, - filename: tempfile.original_filename, - content_type: tempfile.content_type - } - } - - attachment_obj = @message.attachments.new(attachment_params) - attachment_obj.file.content_type = attachment[:mimetype] - attachment_obj.save! - end - end - - def file_type(attachment) - return if attachment[:mimetype] == 'text/plain' - - case attachment[:filetype] - when 'png', 'jpeg', 'gif', 'bmp', 'tiff', 'jpg' - :image - when 'pdf' - :file - end - end - # Ignoring the changes added here https://github.com/chatwoot/chatwoot/blob/5b5a6d89c0cf7f3148a1439d6fcd847784a79b94/lib/integrations/slack/send_on_slack_service.rb#L69 # This make sure 'Attached File!' comment is not visible on CW dashboard. # This is showing because of https://github.com/chatwoot/chatwoot/pull/4494/commits/07a1c0da1e522d76e37b5f0cecdb4613389ab9b6 change.