Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bff1c07164 | ||
|
|
f245f4b2a4 | ||
|
|
7b8bb78d3a | ||
|
|
c55a0665b8 | ||
|
|
92503ae0b5 | ||
|
|
dc35d28c95 | ||
|
|
c1480e0951 | ||
|
|
f6484f8530 | ||
|
|
617f18ff03 |
@@ -29,6 +29,6 @@ class Api::V1::Accounts::CampaignsController < Api::V1::Accounts::BaseController
|
||||
|
||||
def campaign_params
|
||||
params.require(:campaign).permit(:title, :description, :message, :enabled, :trigger_only_during_business_hours, :inbox_id, :sender_id,
|
||||
:scheduled_at, audience: [:type, :id], trigger_rules: {}, template_params: {})
|
||||
:scheduled_at, :allow_bots, audience: [:type, :id], trigger_rules: {}, template_params: {})
|
||||
end
|
||||
end
|
||||
|
||||
+11
@@ -47,6 +47,7 @@ const initialState = {
|
||||
senderId: 0,
|
||||
enabled: true,
|
||||
triggerOnlyDuringBusinessHours: false,
|
||||
allowBots: false,
|
||||
endPoint: '',
|
||||
timeOnPage: 10,
|
||||
};
|
||||
@@ -139,6 +140,7 @@ const prepareCampaignDetails = () => ({
|
||||
sender_id: state.senderId || null,
|
||||
enabled: state.enabled,
|
||||
trigger_only_during_business_hours: state.triggerOnlyDuringBusinessHours,
|
||||
allow_bots: state.allowBots,
|
||||
trigger_rules: {
|
||||
url: state.endPoint,
|
||||
time_on_page: state.timeOnPage,
|
||||
@@ -166,6 +168,7 @@ const updateStateFromCampaign = campaign => {
|
||||
sender,
|
||||
enabled,
|
||||
trigger_only_during_business_hours: triggerOnlyDuringBusinessHours,
|
||||
allow_bots: allowBots,
|
||||
trigger_rules: { url: endPoint, time_on_page: timeOnPage },
|
||||
} = campaign;
|
||||
|
||||
@@ -176,6 +179,7 @@ const updateStateFromCampaign = campaign => {
|
||||
senderId: sender?.id ?? 0,
|
||||
enabled,
|
||||
triggerOnlyDuringBusinessHours,
|
||||
allowBots,
|
||||
endPoint,
|
||||
timeOnPage,
|
||||
});
|
||||
@@ -295,6 +299,13 @@ defineExpose({ prepareCampaignDetails, isSubmitDisabled });
|
||||
}}
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<label class="flex items-center gap-2">
|
||||
<input v-model="state.allowBots" type="checkbox" />
|
||||
<span class="text-sm font-medium text-n-slate-12">
|
||||
{{ t('CAMPAIGN.LIVE_CHAT.CREATE.FORM.OTHER_PREFERENCES.ALLOW_BOTS') }}
|
||||
</span>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
<div
|
||||
|
||||
@@ -57,7 +57,8 @@
|
||||
"OTHER_PREFERENCES": {
|
||||
"TITLE": "Other preferences",
|
||||
"ENABLED": "Enable campaign",
|
||||
"TRIGGER_ONLY_BUSINESS_HOURS": "Trigger only during business hours"
|
||||
"TRIGGER_ONLY_BUSINESS_HOURS": "Trigger only during business hours",
|
||||
"ALLOW_BOTS": "Allow bots to handle conversations"
|
||||
},
|
||||
"BUTTONS": {
|
||||
"CREATE": "Create",
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Table name: campaigns
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# allow_bots :boolean default(FALSE), not null
|
||||
# audience :jsonb
|
||||
# campaign_status :integer default("active"), not null
|
||||
# campaign_type :integer default("ongoing"), not null
|
||||
|
||||
@@ -228,9 +228,13 @@ class Conversation < ApplicationRecord
|
||||
def determine_conversation_status
|
||||
self.status = :resolved and return if contact.blocked?
|
||||
|
||||
# Message template hooks aren't executed for conversations from campaigns
|
||||
# So making these conversations open for agent visibility
|
||||
return if campaign.present?
|
||||
# Handle campaign conversations
|
||||
if campaign.present?
|
||||
# If campaign allows bots and inbox has an active bot, start as pending
|
||||
# Otherwise, start as open (default) for immediate agent visibility
|
||||
self.status = :pending if campaign.allow_bots && inbox.active_bot?
|
||||
return
|
||||
end
|
||||
|
||||
# TODO: make this an inbox config instead of assuming bot conversations should start as pending
|
||||
self.status = :pending if inbox.active_bot?
|
||||
|
||||
@@ -19,5 +19,6 @@ if resource.campaign_type == 'one_off'
|
||||
end
|
||||
json.trigger_rules resource.trigger_rules
|
||||
json.trigger_only_during_business_hours resource.trigger_only_during_business_hours
|
||||
json.allow_bots resource.allow_bots
|
||||
json.created_at resource.created_at
|
||||
json.updated_at resource.updated_at
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddAllowBotsToCampaigns < ActiveRecord::Migration[7.1]
|
||||
def change
|
||||
add_column :campaigns, :allow_bots, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
||||
+2
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_10_22_152158) do
|
||||
ActiveRecord::Schema[7.1].define(version: 2025_11_05_114654) do
|
||||
# These extensions should be enabled to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "pg_trgm"
|
||||
@@ -278,6 +278,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_22_152158) do
|
||||
t.datetime "scheduled_at", precision: nil
|
||||
t.boolean "trigger_only_during_business_hours", default: false
|
||||
t.jsonb "template_params"
|
||||
t.boolean "allow_bots", default: false, null: false
|
||||
t.index ["account_id"], name: "index_campaigns_on_account_id"
|
||||
t.index ["campaign_status"], name: "index_campaigns_on_campaign_status"
|
||||
t.index ["campaign_type"], name: "index_campaigns_on_campaign_type"
|
||||
|
||||
@@ -108,6 +108,29 @@ RSpec.describe 'Campaigns API', type: :request do
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:title]).to eq('test')
|
||||
end
|
||||
|
||||
it 'creates a new campaign with allow_bots enabled' do
|
||||
post "/api/v1/accounts/#{account.id}/campaigns",
|
||||
params: { inbox_id: inbox.id, title: 'test', message: 'test message', allow_bots: true },
|
||||
headers: administrator.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:title]).to eq('test')
|
||||
expect(response_data[:allow_bots]).to be true
|
||||
end
|
||||
|
||||
it 'creates a new campaign with allow_bots disabled by default' do
|
||||
post "/api/v1/accounts/#{account.id}/campaigns",
|
||||
params: { inbox_id: inbox.id, title: 'test', message: 'test message' },
|
||||
headers: administrator.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
response_data = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(response_data[:allow_bots]).to be false
|
||||
end
|
||||
|
||||
it 'creates a new ongoing campaign' do
|
||||
post "/api/v1/accounts/#{account.id}/campaigns",
|
||||
params: { inbox_id: inbox.id, title: 'test', message: 'test message', trigger_rules: { url: 'https://test.com' } },
|
||||
@@ -189,6 +212,16 @@ RSpec.describe 'Campaigns API', type: :request do
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:title]).to eq('test')
|
||||
end
|
||||
|
||||
it 'updates the campaign allow_bots setting' do
|
||||
patch "/api/v1/accounts/#{account.id}/campaigns/#{campaign.display_id}",
|
||||
params: { allow_bots: true },
|
||||
headers: administrator.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(JSON.parse(response.body, symbolize_names: true)[:allow_bots]).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -576,10 +576,28 @@ RSpec.describe Conversation do
|
||||
expect(conversation.status).to eq('pending')
|
||||
end
|
||||
|
||||
it 'returns conversation as open if campaign is present' do
|
||||
conversation = create(:conversation, inbox: bot_inbox.inbox, campaign: create(:campaign))
|
||||
it 'returns conversation as open if campaign is present without allow_bots' do
|
||||
conversation = create(:conversation, inbox: bot_inbox.inbox, campaign: create(:campaign, allow_bots: false))
|
||||
expect(conversation.status).to eq('open')
|
||||
end
|
||||
|
||||
it 'returns conversation as pending if campaign has allow_bots enabled' do
|
||||
conversation = create(:conversation, inbox: bot_inbox.inbox, campaign: create(:campaign, allow_bots: true))
|
||||
expect(conversation.status).to eq('pending')
|
||||
end
|
||||
|
||||
it 'returns conversation as open if campaign has allow_bots but inbox has no bot' do
|
||||
regular_inbox = create(:inbox, account: bot_inbox.inbox.account)
|
||||
conversation = create(:conversation, inbox: regular_inbox, campaign: create(:campaign, allow_bots: true))
|
||||
expect(conversation.status).to eq('open')
|
||||
end
|
||||
|
||||
it 'does not start as pending when allow_bots is explicitly disabled even with bot inbox' do
|
||||
campaign = create(:campaign, allow_bots: false)
|
||||
conversation = create(:conversation, inbox: bot_inbox.inbox, campaign: campaign)
|
||||
expect(conversation.status).to eq('open')
|
||||
expect(conversation.status).not_to eq('pending')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#botintegration: when conversation created in inbox with dialogflow integration' do
|
||||
|
||||
Reference in New Issue
Block a user