fix: Update email alerts for Slack integration (#7739)

Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
Sojan Jose
2023-08-17 11:46:37 -07:00
committed by GitHub
parent ab039e14fd
commit 178bc80b25
8 changed files with 57 additions and 18 deletions

View File

@@ -85,7 +85,8 @@
"UPDATE": "Update", "UPDATE": "Update",
"BUTTON_TEXT": "Connect channel", "BUTTON_TEXT": "Connect channel",
"DESCRIPTION": "Your Slack workspace is now linked with Chatwoot. However, the integration is currently inactive. To activate the integration and connect a channel to Chatwoot, please click the button below.\n\n**Note:** If you are attempting to connect a private channel, add the Chatwoot app to the Slack channel before proceeding with this step.", "DESCRIPTION": "Your Slack workspace is now linked with Chatwoot. However, the integration is currently inactive. To activate the integration and connect a channel to Chatwoot, please click the button below.\n\n**Note:** If you are attempting to connect a private channel, add the Chatwoot app to the Slack channel before proceeding with this step.",
"ATTENTION_REQUIRED": "Attention required" "ATTENTION_REQUIRED": "Attention required",
"EXPIRED": "Your Slack integration has expired. To continue receiving messages on Slack, please delete the integration and connect your workspace again."
}, },
"UPDATE_ERROR": "There was an error updating the integration, please try again", "UPDATE_ERROR": "There was an error updating the integration, please try again",
"UPDATE_SUCCESS": "The channel is connected successfully", "UPDATE_SUCCESS": "The channel is connected successfully",

View File

@@ -21,7 +21,10 @@
/> />
</div> </div>
<div v-if="areHooksAvailable" class="p-6 flex-1"> <div v-if="areHooksAvailable" class="p-6 flex-1">
<select-channel-warning v-if="!isIntegrationHookEnabled" /> <select-channel-warning
v-if="!isIntegrationHookEnabled"
:has-connected-a-channel="hasConnectedAChannel"
/>
<slack-integration-help-text <slack-integration-help-text
:selected-channel-name="selectedChannelName" :selected-channel-name="selectedChannelName"
/> />
@@ -61,16 +64,20 @@ export default {
const { hooks = [] } = this.integration || {}; const { hooks = [] } = this.integration || {};
return !!hooks.length; return !!hooks.length;
}, },
isIntegrationHookEnabled() { hook() {
const { hooks = [] } = this.integration || {}; const { hooks = [] } = this.integration || {};
const [hook = {}] = hooks; const [hook] = hooks;
return hook.status || false; return hook || {};
},
isIntegrationHookEnabled() {
return this.hook.status || false;
},
hasConnectedAChannel() {
return !!this.hook.reference_id;
}, },
selectedChannelName() { selectedChannelName() {
const { hooks = [] } = this.integration || {}; if (this.hook.status) {
const [hook = {}] = hooks; const { settings: { channel_name: channelName = '' } = {} } = this.hook;
if (hook.status) {
const { settings: { channel_name: channelName = '' } = {} } = hook;
return channelName || 'customer-conversations'; return channelName || 'customer-conversations';
} }
return this.$t('INTEGRATION_SETTINGS.SLACK.HELP_TEXT.SELECTED'); return this.$t('INTEGRATION_SETTINGS.SLACK.HELP_TEXT.SELECTED');

View File

@@ -23,7 +23,7 @@
v-dompurify-html=" v-dompurify-html="
formatMessage( formatMessage(
useInstallationName( useInstallationName(
$t('INTEGRATION_SETTINGS.SLACK.SELECT_CHANNEL.DESCRIPTION'), errorDescription,
globalConfig.installationName globalConfig.installationName
), ),
false false
@@ -33,7 +33,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="ml-8 mt-2"> <div v-if="!hasConnectedAChannel" class="ml-8 mt-2">
<woot-submit-button <woot-submit-button
v-if="!availableChannels.length" v-if="!availableChannels.length"
button-class="smooth small warning" button-class="smooth small warning"
@@ -79,6 +79,12 @@ import alertMixin from 'shared/mixins/alertMixin';
export default { export default {
mixins: [alertMixin, globalConfigMixin, messageFormatterMixin], mixins: [alertMixin, globalConfigMixin, messageFormatterMixin],
props: {
hasConnectedAChannel: {
type: Boolean,
default: true,
},
},
data() { data() {
return { selectedChannelId: '', availableChannels: [] }; return { selectedChannelId: '', availableChannels: [] };
}, },
@@ -87,6 +93,11 @@ export default {
globalConfig: 'globalConfig/get', globalConfig: 'globalConfig/get',
uiFlags: 'integrations/getUIFlags', uiFlags: 'integrations/getUIFlags',
}), }),
errorDescription() {
return !this.hasConnectedAChannel
? this.$t('INTEGRATION_SETTINGS.SLACK.SELECT_CHANNEL.DESCRIPTION')
: this.$t('INTEGRATION_SETTINGS.SLACK.SELECT_CHANNEL.EXPIRED');
},
}, },
methods: { methods: {
async fetchChannels() { async fetchChannels() {

View File

@@ -6,3 +6,4 @@ json.account_id resource.account_id
json.hook_type resource.hook_type json.hook_type resource.hook_type
json.settings resource.settings if Current.account_user&.administrator? json.settings resource.settings if Current.account_user&.administrator?
json.reference_id resource.reference_id if Current.account_user&.administrator?

View File

@@ -1,7 +1,6 @@
<p>Hello,</p> <p>Hello,</p>
<p>Your Slack integration has expired. </p> <p>Your Slack integration has expired. To continue receiving messages on Slack, please delete the integration and connect your workspace again. </p>
<p>Please reconnect Slack to continue receiving messages on Slack</p>
<p> <p>
Click <a href="{{action_url}}">here</a> to re-connect. Click <a href="{{action_url}}">here</a> to re-connect.

View File

@@ -80,10 +80,10 @@ class Integrations::Slack::SendOnSlackService < Base::SendOnChannelService
def send_message def send_message
post_message if message_content.present? post_message if message_content.present?
upload_file if message.attachments.any? upload_file if message.attachments.any?
rescue Slack::Web::Api::Errors::AccountInactive => e rescue Slack::Web::Api::Errors::AccountInactive, Slack::Web::Api::Errors::MissingScope => e
Rails.logger.error e Rails.logger.error e
hook.authorization_error! hook.prompt_reauthorization!
hook.disable if hook.enabled? hook.disable
end end
def post_message def post_message

View File

@@ -194,11 +194,28 @@ describe Integrations::Slack::SendOnSlackService do
unfurl_links: true unfurl_links: true
).and_raise(Slack::Web::Api::Errors::AccountInactive.new('Account disconnected')) ).and_raise(Slack::Web::Api::Errors::AccountInactive.new('Account disconnected'))
allow(hook).to receive(:authorization_error!) allow(hook).to receive(:prompt_reauthorization!)
builder.perform builder.perform
expect(hook).to be_disabled expect(hook).to be_disabled
expect(hook).to have_received(:authorization_error!) expect(hook).to have_received(:prompt_reauthorization!)
end
it 'disables hook on Slack MissingScope error' do
expect(slack_client).to receive(:chat_postMessage).with(
channel: hook.reference_id,
text: message.content,
username: "#{message.sender.name} (Contact)",
thread_ts: conversation.identifier,
icon_url: anything,
unfurl_links: true
).and_raise(Slack::Web::Api::Errors::MissingScope.new('Account disconnected'))
allow(hook).to receive(:prompt_reauthorization!)
builder.perform
expect(hook).to be_disabled
expect(hook).to have_received(:prompt_reauthorization!)
end end
end end

View File

@@ -1,6 +1,9 @@
require 'rails_helper' require 'rails_helper'
require Rails.root.join 'spec/models/concerns/reauthorizable_shared.rb'
RSpec.describe Integrations::Hook do RSpec.describe Integrations::Hook do
it_behaves_like 'reauthorizable'
context 'with validations' do context 'with validations' do
it { is_expected.to validate_presence_of(:app_id) } it { is_expected.to validate_presence_of(:app_id) }
it { is_expected.to validate_presence_of(:account_id) } it { is_expected.to validate_presence_of(:account_id) }