Merge branch 'develop' into feat/custom-attrs-automations
This commit is contained in:
commit
97481f92b6
17 changed files with 423 additions and 229 deletions
|
@ -38,9 +38,12 @@ class DashboardController < ActionController::Base
|
|||
end
|
||||
|
||||
def app_config
|
||||
{ APP_VERSION: Chatwoot.config[:version],
|
||||
{
|
||||
APP_VERSION: Chatwoot.config[:version],
|
||||
VAPID_PUBLIC_KEY: VapidService.public_key,
|
||||
ENABLE_ACCOUNT_SIGNUP: GlobalConfigService.load('ENABLE_ACCOUNT_SIGNUP', 'false'),
|
||||
FB_APP_ID: GlobalConfigService.load('FB_APP_ID', '') }
|
||||
FB_APP_ID: GlobalConfigService.load('FB_APP_ID', ''),
|
||||
FACEBOOK_API_VERSION: 'v13.0'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,6 +21,10 @@ class Platform::Api::V1::UsersController < PlatformController
|
|||
|
||||
def update
|
||||
@resource.assign_attributes(user_update_params)
|
||||
|
||||
# We are using devise's reconfirmable flow for changing emails
|
||||
# But in case of platform APIs we don't want user to go through this extra step
|
||||
@resource.skip_reconfirmation! if user_update_params[:email].present?
|
||||
@resource.save!
|
||||
end
|
||||
|
||||
|
|
|
@ -17,30 +17,30 @@ module ReportHelper
|
|||
end
|
||||
|
||||
def conversations_count
|
||||
(get_grouped_values scope.conversations).count
|
||||
(get_grouped_values scope.conversations.where(account_id: account.id)).count
|
||||
end
|
||||
|
||||
def incoming_messages_count
|
||||
(get_grouped_values scope.messages.incoming.unscope(:order)).count
|
||||
(get_grouped_values scope.messages.where(account_id: account.id).incoming.unscope(:order)).count
|
||||
end
|
||||
|
||||
def outgoing_messages_count
|
||||
(get_grouped_values scope.messages.outgoing.unscope(:order)).count
|
||||
(get_grouped_values scope.messages.where(account_id: account.id).outgoing.unscope(:order)).count
|
||||
end
|
||||
|
||||
def resolutions_count
|
||||
(get_grouped_values scope.conversations.resolved).count
|
||||
(get_grouped_values scope.conversations.where(account_id: account.id).resolved).count
|
||||
end
|
||||
|
||||
def avg_first_response_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'first_response'))
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'first_response', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
|
||||
grouped_reporting_events.average(:value)
|
||||
end
|
||||
|
||||
def avg_resolution_time
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved'))
|
||||
grouped_reporting_events = (get_grouped_values scope.reporting_events.where(name: 'conversation_resolved', account_id: account.id))
|
||||
return grouped_reporting_events.average(:value_in_business_hours) if params[:business_hours]
|
||||
|
||||
grouped_reporting_events.average(:value)
|
||||
|
@ -48,7 +48,7 @@ module ReportHelper
|
|||
|
||||
def avg_resolution_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'conversation_resolved', created_at: range)
|
||||
.where(name: 'conversation_resolved', account_id: account.id, created_at: range)
|
||||
avg_rt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
|
||||
|
||||
return 0 if avg_rt.blank?
|
||||
|
@ -58,7 +58,7 @@ module ReportHelper
|
|||
|
||||
def avg_first_response_time_summary
|
||||
reporting_events = scope.reporting_events
|
||||
.where(name: 'first_response', created_at: range)
|
||||
.where(name: 'first_response', account_id: account.id, created_at: range)
|
||||
avg_frt = params[:business_hours] ? reporting_events.average(:value_in_business_hours) : reporting_events.average(:value)
|
||||
|
||||
return 0 if avg_frt.blank?
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
export const createMessengerScript = pageId => `
|
||||
<script>
|
||||
window.fbAsyncInit = function() {
|
||||
FB.init({
|
||||
appId: "${window.chatwootConfig.fbAppId}",
|
||||
xfbml: true,
|
||||
version: "v4.0"
|
||||
});
|
||||
};
|
||||
(function(d, s, id){
|
||||
var js, fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) { return; }
|
||||
js = d.createElement(s); js.id = id;
|
||||
js.src = "//connect.facebook.net/en_US/sdk.js";
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
}(document, 'script', 'facebook-jssdk'));
|
||||
|
||||
</script>
|
||||
<div class="fb-messengermessageus"
|
||||
messenger_app_id="${window.chatwootConfig.fbAppId}"
|
||||
page_id="${pageId}"
|
||||
color="blue"
|
||||
size="standard" >
|
||||
</div>
|
||||
`;
|
|
@ -341,10 +341,6 @@
|
|||
"AUTO_ASSIGNMENT_SUCCESS_MESSAGE": "Auto assignment updated successfully",
|
||||
"ERROR_MESSAGE": "Could not update widget color. Please try again later."
|
||||
},
|
||||
"AUTO_ASSIGNMENT": {
|
||||
"ENABLED": "Enabled",
|
||||
"DISABLED": "Disabled"
|
||||
},
|
||||
"EMAIL_COLLECT_BOX": {
|
||||
"ENABLED": "Enabled",
|
||||
"DISABLED": "Disabled"
|
||||
|
@ -402,6 +398,8 @@
|
|||
"MESSENGER_SUB_HEAD": "Place this button inside your body tag",
|
||||
"INBOX_AGENTS": "Agents",
|
||||
"INBOX_AGENTS_SUB_TEXT": "Add or remove agents from this inbox",
|
||||
"AGENT_ASSIGNMENT": "Conversation Assignment",
|
||||
"AGENT_ASSIGNMENT_SUB_TEXT": "Update conversation assignment settings",
|
||||
"UPDATE": "Update",
|
||||
"ENABLE_EMAIL_COLLECT_BOX": "Enable email collect box",
|
||||
"ENABLE_EMAIL_COLLECT_BOX_SUB_TEXT": "Enable or disable email collect box on new conversation",
|
||||
|
|
|
@ -189,21 +189,6 @@
|
|||
</p>
|
||||
</label>
|
||||
|
||||
<label class="medium-9 columns settings-item">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
|
||||
<select v-model="autoAssignment">
|
||||
<option :value="true">
|
||||
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED') }}
|
||||
</option>
|
||||
<option :value="false">
|
||||
{{ $t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED') }}
|
||||
</option>
|
||||
</select>
|
||||
<p class="help-text">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
|
||||
</p>
|
||||
</label>
|
||||
|
||||
<label class="medium-9 columns settings-item">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.ENABLE_CSAT') }}
|
||||
<select v-model="csatSurveyEnabled">
|
||||
|
@ -316,114 +301,11 @@
|
|||
<facebook-reauthorize v-if="isAFacebookInbox" :inbox-id="inbox.id" />
|
||||
</div>
|
||||
|
||||
<!-- update agents in inbox -->
|
||||
|
||||
<div v-if="selectedTabKey === 'collaborators'" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS_SUB_TEXT')"
|
||||
>
|
||||
<multiselect
|
||||
v-model="selectedAgents"
|
||||
:options="agentList"
|
||||
track-by="id"
|
||||
label="name"
|
||||
:multiple="true"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:hide-selected="true"
|
||||
placeholder="Pick some"
|
||||
selected-label
|
||||
:select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
|
||||
:deselect-label="$t('FORMS.MULTISELECT.ENTER_TO_REMOVE')"
|
||||
@select="$v.selectedAgents.$touch"
|
||||
/>
|
||||
|
||||
<woot-submit-button
|
||||
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
||||
:loading="isAgentListUpdating"
|
||||
@click="updateAgents"
|
||||
/>
|
||||
</settings-section>
|
||||
<collaborators-page :inbox="inbox" />
|
||||
</div>
|
||||
<div v-if="selectedTabKey === 'configuration'">
|
||||
<div v-if="isATwilioChannel" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.SUBTITLE')"
|
||||
>
|
||||
<woot-code
|
||||
:script="inbox.callback_webhook_url"
|
||||
lang="html"
|
||||
></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<div v-else-if="isALineChannel" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.SUBTITLE')"
|
||||
>
|
||||
<woot-code
|
||||
:script="inbox.callback_webhook_url"
|
||||
lang="html"
|
||||
></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<div v-else-if="isAWebWidgetInbox">
|
||||
<div class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_HEADING')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_SUB_HEAD')"
|
||||
>
|
||||
<woot-code :script="inbox.web_widget_script"></woot-code>
|
||||
</settings-section>
|
||||
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_VERIFICATION')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_DESCRIPTION')"
|
||||
>
|
||||
<woot-code :script="inbox.hmac_token"></woot-code>
|
||||
</settings-section>
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
|
||||
:sub-title="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')
|
||||
"
|
||||
>
|
||||
<div class="enter-to-send--checkbox">
|
||||
<input
|
||||
id="hmacMandatory"
|
||||
v-model="hmacMandatory"
|
||||
type="checkbox"
|
||||
@change="handleHmacFlag"
|
||||
/>
|
||||
<label for="hmacMandatory">
|
||||
{{ $t('INBOX_MGMT.EDIT.ENABLE_HMAC.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
</settings-section>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="isAPIInbox" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_IDENTIFIER')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_IDENTIFIER_SUB_TEXT')"
|
||||
>
|
||||
<woot-code :script="inbox.inbox_identifier"></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<div v-else-if="isAnEmailChannel">
|
||||
<div class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_SUB_TEXT')"
|
||||
>
|
||||
<woot-code :script="inbox.forward_to_email"></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<imap-settings :inbox="inbox" />
|
||||
<smtp-settings v-if="inbox.imap_enabled" :inbox="inbox" />
|
||||
</div>
|
||||
<configuration-page :inbox="inbox" />
|
||||
</div>
|
||||
<div v-if="selectedTabKey === 'preChatForm'">
|
||||
<pre-chat-form-settings :inbox="inbox" />
|
||||
|
@ -436,7 +318,6 @@
|
|||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import { createMessengerScript } from 'dashboard/helper/scriptGenerator';
|
||||
import { required } from 'vuelidate/lib/validators';
|
||||
import { shouldBeUrl } from 'shared/helpers/Validators';
|
||||
import configMixin from 'shared/mixins/configMixin';
|
||||
|
@ -448,8 +329,8 @@ import FacebookReauthorize from './facebook/Reauthorize';
|
|||
import PreChatFormSettings from './PreChatForm/Settings';
|
||||
import WeeklyAvailability from './components/WeeklyAvailability';
|
||||
import GreetingsEditor from 'shared/components/GreetingsEditor';
|
||||
import ImapSettings from './ImapSettings';
|
||||
import SmtpSettings from './SmtpSettings';
|
||||
import ConfigurationPage from './settingsPage/ConfigurationPage';
|
||||
import CollaboratorsPage from './settingsPage/CollaboratorsPage';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
@ -459,22 +340,18 @@ export default {
|
|||
PreChatFormSettings,
|
||||
WeeklyAvailability,
|
||||
GreetingsEditor,
|
||||
ImapSettings,
|
||||
SmtpSettings,
|
||||
ConfigurationPage,
|
||||
CollaboratorsPage,
|
||||
},
|
||||
mixins: [alertMixin, configMixin, inboxMixin],
|
||||
data() {
|
||||
return {
|
||||
avatarFile: null,
|
||||
avatarUrl: '',
|
||||
selectedAgents: [],
|
||||
greetingEnabled: true,
|
||||
tweetsEnabled: true,
|
||||
hmacMandatory: null,
|
||||
greetingMessage: '',
|
||||
autoAssignment: false,
|
||||
emailCollectEnabled: false,
|
||||
isAgentListUpdating: false,
|
||||
csatSurveyEnabled: false,
|
||||
allowMessagesAfterResolved: true,
|
||||
continuityViaEmail: true,
|
||||
|
@ -485,22 +362,11 @@ export default {
|
|||
channelWelcomeTagline: '',
|
||||
selectedFeatureFlags: [],
|
||||
replyTime: '',
|
||||
autoAssignmentOptions: [
|
||||
{
|
||||
value: true,
|
||||
label: this.$t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.ENABLED'),
|
||||
},
|
||||
{
|
||||
value: false,
|
||||
label: this.$t('INBOX_MGMT.EDIT.AUTO_ASSIGNMENT.DISABLED'),
|
||||
},
|
||||
],
|
||||
selectedTabIndex: 0,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
agentList: 'agents/getAgents',
|
||||
uiFlags: 'inboxes/getUIFlags',
|
||||
}),
|
||||
selectedTabKey() {
|
||||
|
@ -568,9 +434,6 @@ export default {
|
|||
}
|
||||
return this.inbox.name;
|
||||
},
|
||||
messengerScript() {
|
||||
return createMessengerScript(this.inbox.page_id);
|
||||
},
|
||||
inboxNameLabel() {
|
||||
if (this.isAWebWidgetInbox) {
|
||||
return this.$t('INBOX_MGMT.ADD.WEBSITE_NAME.LABEL');
|
||||
|
@ -610,9 +473,6 @@ export default {
|
|||
e.target.value
|
||||
);
|
||||
},
|
||||
handleHmacFlag() {
|
||||
this.updateInbox();
|
||||
},
|
||||
toggleInput(selected, current) {
|
||||
if (selected.includes(current)) {
|
||||
const newSelectedFlags = selected.filter(flag => flag !== current);
|
||||
|
@ -630,15 +490,12 @@ export default {
|
|||
this.$store.dispatch('teams/get');
|
||||
this.$store.dispatch('labels/get');
|
||||
this.$store.dispatch('inboxes/get').then(() => {
|
||||
this.fetchAttachedAgents();
|
||||
this.avatarUrl = this.inbox.avatar_url;
|
||||
this.selectedInboxName = this.inbox.name;
|
||||
this.webhookUrl = this.inbox.webhook_url;
|
||||
this.greetingEnabled = this.inbox.greeting_enabled || false;
|
||||
this.tweetsEnabled = this.inbox.tweets_enabled || false;
|
||||
this.hmacMandatory = this.inbox.hmac_mandatory || false;
|
||||
this.greetingMessage = this.inbox.greeting_message || '';
|
||||
this.autoAssignment = this.inbox.enable_auto_assignment;
|
||||
this.emailCollectEnabled = this.inbox.enable_email_collect;
|
||||
this.csatSurveyEnabled = this.inbox.csat_survey_enabled;
|
||||
this.allowMessagesAfterResolved = this.inbox.allow_messages_after_resolved;
|
||||
|
@ -650,39 +507,11 @@ export default {
|
|||
this.replyTime = this.inbox.reply_time;
|
||||
});
|
||||
},
|
||||
async fetchAttachedAgents() {
|
||||
try {
|
||||
const response = await this.$store.dispatch('inboxMembers/get', {
|
||||
inboxId: this.currentInboxId,
|
||||
});
|
||||
const {
|
||||
data: { payload: inboxMembers },
|
||||
} = response;
|
||||
this.selectedAgents = inboxMembers;
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
}
|
||||
},
|
||||
async updateAgents() {
|
||||
const agentList = this.selectedAgents.map(el => el.id);
|
||||
this.isAgentListUpdating = true;
|
||||
try {
|
||||
await this.$store.dispatch('inboxMembers/create', {
|
||||
inboxId: this.currentInboxId,
|
||||
agentList,
|
||||
});
|
||||
this.showAlert(this.$t('AGENT_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('AGENT_MGMT.EDIT.API.ERROR_MESSAGE'));
|
||||
}
|
||||
this.isAgentListUpdating = false;
|
||||
},
|
||||
async updateInbox() {
|
||||
try {
|
||||
const payload = {
|
||||
id: this.currentInboxId,
|
||||
name: this.selectedInboxName,
|
||||
enable_auto_assignment: this.autoAssignment,
|
||||
enable_email_collect: this.emailCollectEnabled,
|
||||
csat_survey_enabled: this.csatSurveyEnabled,
|
||||
allow_messages_after_resolved: this.allowMessagesAfterResolved,
|
||||
|
@ -696,7 +525,6 @@ export default {
|
|||
welcome_tagline: this.channelWelcomeTagline || '',
|
||||
selectedFeatureFlags: this.selectedFeatureFlags,
|
||||
reply_time: this.replyTime || 'in_a_few_minutes',
|
||||
hmac_mandatory: this.hmacMandatory,
|
||||
tweets_enabled: this.tweetsEnabled,
|
||||
continuity_via_email: this.continuityViaEmail,
|
||||
},
|
||||
|
@ -737,11 +565,6 @@ export default {
|
|||
required,
|
||||
shouldBeUrl,
|
||||
},
|
||||
selectedAgents: {
|
||||
isEmpty() {
|
||||
return !!this.selectedAgents.length;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -163,7 +163,7 @@ export default {
|
|||
FB.init({
|
||||
appId: window.chatwootConfig.fbAppId,
|
||||
xfbml: true,
|
||||
version: 'v12.0',
|
||||
version: window.chatwootConfig.fbApiVersion,
|
||||
status: true,
|
||||
});
|
||||
window.fbSDKLoaded = true;
|
||||
|
|
|
@ -40,7 +40,7 @@ export default {
|
|||
FB.init({
|
||||
appId: window.chatwootConfig.fbAppId,
|
||||
xfbml: true,
|
||||
version: 'v12.0',
|
||||
version: window.chatwootConfig.fbApiVersion,
|
||||
status: true,
|
||||
});
|
||||
window.fbSDKLoaded = true;
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
<template>
|
||||
<div>
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_AGENTS_SUB_TEXT')"
|
||||
>
|
||||
<multiselect
|
||||
v-model="selectedAgents"
|
||||
:options="agentList"
|
||||
track-by="id"
|
||||
label="name"
|
||||
:multiple="true"
|
||||
:close-on-select="false"
|
||||
:clear-on-select="false"
|
||||
:hide-selected="true"
|
||||
placeholder="Pick some"
|
||||
selected-label
|
||||
:select-label="$t('FORMS.MULTISELECT.ENTER_TO_SELECT')"
|
||||
:deselect-label="$t('FORMS.MULTISELECT.ENTER_TO_REMOVE')"
|
||||
@select="$v.selectedAgents.$touch"
|
||||
/>
|
||||
|
||||
<woot-submit-button
|
||||
:button-text="$t('INBOX_MGMT.SETTINGS_POPUP.UPDATE')"
|
||||
:loading="isAgentListUpdating"
|
||||
@click="updateAgents"
|
||||
/>
|
||||
</settings-section>
|
||||
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.AGENT_ASSIGNMENT')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.AGENT_ASSIGNMENT_SUB_TEXT')"
|
||||
>
|
||||
<label class="medium-9 columns settings-item">
|
||||
<div class="enter-to-send--checkbox">
|
||||
<input
|
||||
id="enableAutoAssignment"
|
||||
v-model="enableAutoAssignment"
|
||||
type="checkbox"
|
||||
@change="handleEnableAutoAssignment"
|
||||
/>
|
||||
<label for="enableAutoAssignment">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT') }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<p class="help-text">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.AUTO_ASSIGNMENT_SUB_TEXT') }}
|
||||
</p>
|
||||
</label>
|
||||
</settings-section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import SettingsSection from '../../../../../components/SettingsSection';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsSection,
|
||||
},
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
inbox: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedAgents: [],
|
||||
isAgentListUpdating: false,
|
||||
enableAutoAssignment: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
agentList: 'agents/getAgents',
|
||||
}),
|
||||
},
|
||||
watch: {
|
||||
inbox() {
|
||||
this.setDefaults();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setDefaults();
|
||||
},
|
||||
methods: {
|
||||
setDefaults() {
|
||||
this.enableAutoAssignment = this.inbox.enable_auto_assignment;
|
||||
this.fetchAttachedAgents();
|
||||
},
|
||||
async fetchAttachedAgents() {
|
||||
try {
|
||||
const response = await this.$store.dispatch('inboxMembers/get', {
|
||||
inboxId: this.inbox.id,
|
||||
});
|
||||
const {
|
||||
data: { payload: inboxMembers },
|
||||
} = response;
|
||||
this.selectedAgents = inboxMembers;
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
}
|
||||
},
|
||||
handleEnableAutoAssignment() {
|
||||
this.updateInbox();
|
||||
},
|
||||
async updateAgents() {
|
||||
const agentList = this.selectedAgents.map(el => el.id);
|
||||
this.isAgentListUpdating = true;
|
||||
try {
|
||||
await this.$store.dispatch('inboxMembers/create', {
|
||||
inboxId: this.inbox.id,
|
||||
agentList,
|
||||
});
|
||||
this.showAlert(this.$t('AGENT_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('AGENT_MGMT.EDIT.API.ERROR_MESSAGE'));
|
||||
}
|
||||
this.isAgentListUpdating = false;
|
||||
},
|
||||
async updateInbox() {
|
||||
try {
|
||||
const payload = {
|
||||
id: this.inbox.id,
|
||||
formData: false,
|
||||
enable_auto_assignment: this.enableAutoAssignment,
|
||||
};
|
||||
await this.$store.dispatch('inboxes/updateInbox', payload);
|
||||
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
}
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
selectedAgents: {
|
||||
isEmpty() {
|
||||
return !!this.selectedAgents.length;
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,130 @@
|
|||
<template>
|
||||
<div v-if="isATwilioChannel" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.SUBTITLE')"
|
||||
>
|
||||
<woot-code :script="inbox.callback_webhook_url" lang="html"></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<div v-else-if="isALineChannel" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.SUBTITLE')"
|
||||
>
|
||||
<woot-code :script="inbox.callback_webhook_url" lang="html"></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<div v-else-if="isAWebWidgetInbox">
|
||||
<div class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_HEADING')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_SUB_HEAD')"
|
||||
>
|
||||
<woot-code :script="inbox.web_widget_script"></woot-code>
|
||||
</settings-section>
|
||||
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_VERIFICATION')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_DESCRIPTION')"
|
||||
>
|
||||
<woot-code :script="inbox.hmac_token"></woot-code>
|
||||
</settings-section>
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')"
|
||||
>
|
||||
<div class="enter-to-send--checkbox">
|
||||
<input
|
||||
id="hmacMandatory"
|
||||
v-model="hmacMandatory"
|
||||
type="checkbox"
|
||||
@change="handleHmacFlag"
|
||||
/>
|
||||
<label for="hmacMandatory">
|
||||
{{ $t('INBOX_MGMT.EDIT.ENABLE_HMAC.LABEL') }}
|
||||
</label>
|
||||
</div>
|
||||
</settings-section>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="isAPIInbox" class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_IDENTIFIER')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_IDENTIFIER_SUB_TEXT')"
|
||||
>
|
||||
<woot-code :script="inbox.inbox_identifier"></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<div v-else-if="isAnEmailChannel">
|
||||
<div class="settings--content">
|
||||
<settings-section
|
||||
:title="$t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_TITLE')"
|
||||
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_SUB_TEXT')"
|
||||
>
|
||||
<woot-code :script="inbox.forward_to_email"></woot-code>
|
||||
</settings-section>
|
||||
</div>
|
||||
<imap-settings :inbox="inbox" />
|
||||
<smtp-settings v-if="inbox.imap_enabled" :inbox="inbox" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import inboxMixin from 'shared/mixins/inboxMixin';
|
||||
import SettingsSection from '../../../../../components/SettingsSection';
|
||||
import ImapSettings from '../ImapSettings';
|
||||
import SmtpSettings from '../SmtpSettings';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsSection,
|
||||
ImapSettings,
|
||||
SmtpSettings,
|
||||
},
|
||||
mixins: [inboxMixin, alertMixin],
|
||||
props: {
|
||||
inbox: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hmacMandatory: false,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
inbox() {
|
||||
this.setDefaults();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.setDefaults();
|
||||
},
|
||||
methods: {
|
||||
setDefaults() {
|
||||
this.hmacMandatory = this.inbox.hmac_mandatory || false;
|
||||
},
|
||||
handleHmacFlag() {
|
||||
this.updateInbox();
|
||||
},
|
||||
async updateInbox() {
|
||||
try {
|
||||
const payload = {
|
||||
id: this.inbox.id,
|
||||
formData: false,
|
||||
channel: {
|
||||
hmac_mandatory: this.hmacMandatory,
|
||||
},
|
||||
};
|
||||
await this.$store.dispatch('inboxes/updateInbox', payload);
|
||||
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -22,7 +22,7 @@ class Instagram::MessageText < Instagram::WebhooksBaseService
|
|||
|
||||
return unsend_message if message_is_deleted?
|
||||
|
||||
ensure_contact(contact_id)
|
||||
ensure_contact(contact_id) if contacts_first_message?(contact_id)
|
||||
|
||||
create_message
|
||||
end
|
||||
|
@ -36,7 +36,7 @@ class Instagram::MessageText < Instagram::WebhooksBaseService
|
|||
rescue Koala::Facebook::AuthenticationError
|
||||
@inbox.channel.authorization_error!
|
||||
raise
|
||||
rescue StandardError => e
|
||||
rescue StandardError, Koala::Facebook::ClientError => e
|
||||
result = {}
|
||||
ChatwootExceptionTracker.new(e, account: @inbox.account).capture_exception
|
||||
end
|
||||
|
@ -52,6 +52,10 @@ class Instagram::MessageText < Instagram::WebhooksBaseService
|
|||
@messaging[:message][:is_deleted].present?
|
||||
end
|
||||
|
||||
def contacts_first_message?(ig_scope_id)
|
||||
@inbox.contact_inboxes.where(source_id: ig_scope_id).empty? && @inbox.channel.instagram_id.present?
|
||||
end
|
||||
|
||||
def unsend_message
|
||||
message_to_delete = @inbox.messages.find_by(
|
||||
source_id: @messaging[:message][:mid]
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
window.chatwootConfig = {
|
||||
hostURL: '<%= ENV.fetch('FRONTEND_URL', '') %>',
|
||||
fbAppId: '<%= ENV.fetch('FB_APP_ID', nil) %>',
|
||||
fbApiVersion: '<%= @global_config['FACEBOOK_API_VERSION'] %>',
|
||||
signupEnabled: '<%= @global_config['ENABLE_ACCOUNT_SIGNUP'] %>',
|
||||
<% if @global_config['VAPID_PUBLIC_KEY'] %>
|
||||
vapidPublicKey: new Uint8Array(<%= Base64.urlsafe_decode64(@global_config['VAPID_PUBLIC_KEY']).bytes %>),
|
||||
|
|
|
@ -37,7 +37,7 @@ class Integrations::Slack::IncomingMessageBuilder
|
|||
if message.present?
|
||||
SUPPORTED_MESSAGE_TYPES.include?(message[:type]) && !attached_file_message?
|
||||
else
|
||||
params[:event][:files].any? && !attached_file_message?
|
||||
params[:event][:files].present? && !attached_file_message?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ class Seeders::AccountSeeder
|
|||
|
||||
def seed!
|
||||
seed_canned_responses
|
||||
seed_inboxes
|
||||
end
|
||||
|
||||
def seed_canned_responses(count: 50)
|
||||
|
@ -24,4 +25,65 @@ class Seeders::AccountSeeder
|
|||
account.canned_responses.create(content: Faker::Quote.fortune_cookie, short_code: Faker::Alphanumeric.alpha(number: 10))
|
||||
end
|
||||
end
|
||||
|
||||
def seed_inboxes
|
||||
seed_website_inbox
|
||||
seed_facebook_inbox
|
||||
seed_twitter_inbox
|
||||
seed_whatsapp_inbox
|
||||
seed_sms_inbox
|
||||
seed_email_inbox
|
||||
seed_api_inbox
|
||||
seed_telegram_inbox
|
||||
seed_line_inbox
|
||||
end
|
||||
|
||||
def seed_website_inbox
|
||||
channel = Channel::WebWidget.create!(account: account, website_url: 'https://acme.inc')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Website')
|
||||
end
|
||||
|
||||
def seed_facebook_inbox
|
||||
channel = Channel::FacebookPage.create!(account: account, user_access_token: 'test', page_access_token: 'test', page_id: 'test')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Facebook')
|
||||
end
|
||||
|
||||
def seed_twitter_inbox
|
||||
channel = Channel::TwitterProfile.create!(account: account, twitter_access_token: 'test', twitter_access_token_secret: 'test', profile_id: '123')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Twitter')
|
||||
end
|
||||
|
||||
def seed_whatsapp_inbox
|
||||
channel = Channel::Whatsapp.create!(account: account, phone_number: '+123456789')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Whatsapp')
|
||||
end
|
||||
|
||||
def seed_sms_inbox
|
||||
channel = Channel::Sms.create!(account: account, phone_number: '+123456789')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme SMS')
|
||||
end
|
||||
|
||||
def seed_email_inbox
|
||||
channel = Channel::Email.create!(account: account, email: 'test@acme.inc', forward_to_email: 'test_fwd@acme.inc')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Email')
|
||||
end
|
||||
|
||||
def seed_api_inbox
|
||||
channel = Channel::Api.create!(account: account)
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme API')
|
||||
end
|
||||
|
||||
def seed_telegram_inbox
|
||||
# rubocop:disable Rails/SkipsModelValidations
|
||||
Channel::Telegram.insert({ account_id: account.id, bot_name: 'Acme', bot_token: 'test', created_at: Time.now.utc, updated_at: Time.now.utc },
|
||||
returning: %w[id])
|
||||
channel = Channel::Telegram.find_by(bot_token: 'test')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Telegram')
|
||||
# rubocop:enable Rails/SkipsModelValidations
|
||||
end
|
||||
|
||||
def seed_line_inbox
|
||||
channel = Channel::Line.create!(account: account, line_channel_id: 'test', line_channel_secret: 'test', line_channel_token: 'test')
|
||||
Inbox.create!(channel: channel, account: account, name: 'Acme Line')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -223,6 +223,40 @@ RSpec.describe 'Reports API', type: :request do
|
|||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an agent has access to multiple accounts' do
|
||||
let(:account1) { create(:account) }
|
||||
let(:account2) { create(:account) }
|
||||
|
||||
let(:params) do
|
||||
super().merge(
|
||||
type: :agent,
|
||||
since: 30.days.ago.to_i.to_s,
|
||||
until: date_timestamp.to_s
|
||||
)
|
||||
end
|
||||
|
||||
it 'returns agent metrics from the current account' do
|
||||
admin1 = create(:user, account: account1, role: :administrator)
|
||||
inbox1 = create(:inbox, account: account1)
|
||||
inbox2 = create(:inbox, account: account2)
|
||||
|
||||
create(:account_user, user: admin1, account: account2)
|
||||
create(:conversation, account: account1, inbox: inbox1,
|
||||
assignee: admin1, created_at: Time.zone.today - 2.days)
|
||||
create(:conversation, account: account2, inbox: inbox2,
|
||||
assignee: admin1, created_at: Time.zone.today - 2.days)
|
||||
|
||||
get "/api/v2/accounts/#{account1.id}/reports/summary",
|
||||
params: params.merge({ id: admin1.id }),
|
||||
headers: admin1.create_new_auth_token
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
|
||||
json_response = JSON.parse(response.body)
|
||||
expect(json_response['conversations_count']).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/accounts/:account_id/reports/inboxes' do
|
||||
|
|
|
@ -145,14 +145,17 @@ RSpec.describe 'Platform Users API', type: :request do
|
|||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'updates the user' do
|
||||
it 'updates the user attributes' do
|
||||
create(:platform_app_permissible, platform_app: platform_app, permissible: user)
|
||||
patch "/platform/api/v1/users/#{user.id}", params: { name: 'test123', custom_attributes: { test: 'test_update' } },
|
||||
patch "/platform/api/v1/users/#{user.id}", params: {
|
||||
name: 'test123', email: 'newtestemail@test.com', custom_attributes: { test: 'test_update' }
|
||||
},
|
||||
headers: { api_access_token: platform_app.access_token.token }, as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
data = JSON.parse(response.body)
|
||||
expect(data['name']).to eq('test123')
|
||||
expect(data['email']).to eq('newtestemail@test.com')
|
||||
expect(data['custom_attributes']['test']).to eq('test_update')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -61,6 +61,15 @@ describe Integrations::Slack::IncomingMessageBuilder do
|
|||
expect(conversation.messages.count).to eql(messages_count)
|
||||
end
|
||||
|
||||
it 'does not create message for invalid event type and event files is not present' do
|
||||
messages_count = conversation.messages.count
|
||||
message_with_attachments[:event][:files] = nil
|
||||
builder = described_class.new(message_with_attachments)
|
||||
allow(builder).to receive(:sender).and_return(nil)
|
||||
builder.perform
|
||||
expect(conversation.messages.count).to eql(messages_count)
|
||||
end
|
||||
|
||||
it 'saves attachment if params files present' do
|
||||
expect(hook).not_to eq nil
|
||||
messages_count = conversation.messages.count
|
||||
|
|
Loading…
Reference in a new issue