Feat: attachments automation (#4266)
This commit is contained in:
@@ -7,14 +7,22 @@ class Api::V1::Accounts::AutomationRulesController < Api::V1::Accounts::BaseCont
|
|||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@automation_rule = Current.account.automation_rules.create(automation_rules_permit)
|
@automation_rule = Current.account.automation_rules.new(automation_rules_permit)
|
||||||
@automation_rule.update(actions: params[:actions])
|
@automation_rule.actions = params[:actions]
|
||||||
|
|
||||||
|
render json: { error: @automation_rule.errors.messages }, status: :unprocessable_entity and return unless @automation_rule.valid?
|
||||||
|
|
||||||
|
@automation_rule.save!
|
||||||
|
process_attachments
|
||||||
|
@automation_rule
|
||||||
end
|
end
|
||||||
|
|
||||||
def show; end
|
def show; end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@automation_rule.update(automation_rules_permit)
|
@automation_rule.update(automation_rules_permit)
|
||||||
|
process_attachments
|
||||||
|
@automation_rule
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@@ -31,6 +39,14 @@ class Api::V1::Accounts::AutomationRulesController < Api::V1::Accounts::BaseCont
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def process_attachments
|
||||||
|
return if params[:attachments].blank?
|
||||||
|
|
||||||
|
params[:attachments].each do |uploaded_attachment|
|
||||||
|
@automation_rule.files.attach(uploaded_attachment)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def automation_rules_permit
|
def automation_rules_permit
|
||||||
params.permit(
|
params.permit(
|
||||||
:name, :description, :event_name, :account_id, :active,
|
:name, :description, :event_name, :account_id, :active,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#
|
#
|
||||||
class AutomationRule < ApplicationRecord
|
class AutomationRule < ApplicationRecord
|
||||||
belongs_to :account
|
belongs_to :account
|
||||||
|
has_many_attached :files
|
||||||
|
|
||||||
validate :json_conditions_format
|
validate :json_conditions_format
|
||||||
validate :json_actions_format
|
validate :json_actions_format
|
||||||
@@ -26,8 +27,8 @@ class AutomationRule < ApplicationRecord
|
|||||||
|
|
||||||
scope :active, -> { where(active: true) }
|
scope :active, -> { where(active: true) }
|
||||||
|
|
||||||
CONDITIONS_ATTRS = %w[country_code status browser_language assignee_id team_id referer].freeze
|
CONDITIONS_ATTRS = %w[email country_code status message_type browser_language assignee_id team_id referer city company].freeze
|
||||||
ACTIONS_ATTRS = %w[send_message add_label send_email_to_team assign_team assign_best_agents].freeze
|
ACTIONS_ATTRS = %w[send_message add_label send_email_to_team assign_team assign_best_agents send_attachments].freeze
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
@@ -35,13 +36,17 @@ class AutomationRule < ApplicationRecord
|
|||||||
return if conditions.nil?
|
return if conditions.nil?
|
||||||
|
|
||||||
attributes = conditions.map { |obj, _| obj['attribute_key'] }
|
attributes = conditions.map { |obj, _| obj['attribute_key'] }
|
||||||
(attributes - CONDITIONS_ATTRS).blank?
|
conditions = attributes - CONDITIONS_ATTRS
|
||||||
|
conditions -= account.custom_attribute_definitions.pluck(:attribute_key)
|
||||||
|
errors.add(:conditions, "Automation conditions #{conditions.join(',')} not supported.") if conditions.any?
|
||||||
end
|
end
|
||||||
|
|
||||||
def json_actions_format
|
def json_actions_format
|
||||||
return if actions.nil?
|
return if actions.nil?
|
||||||
|
|
||||||
attributes = actions.map { |obj, _| obj['attribute_key'] }
|
attributes = actions.map { |obj, _| obj['attribute_key'] }
|
||||||
(attributes - ACTIONS_ATTRS).blank?
|
actions = attributes - ACTIONS_ATTRS
|
||||||
|
|
||||||
|
errors.add(:actions, "Automation actions #{actions.join(',')} not supported.") if actions.any?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,6 +21,15 @@ class AutomationRules::ActionService
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def send_attachments(_file_params)
|
||||||
|
return if @rule.event_name == 'message_created'
|
||||||
|
|
||||||
|
blobs = @rule.files.map { |file, _| file.blob }
|
||||||
|
params = { content: nil, private: false, attachments: blobs }
|
||||||
|
mb = Messages::MessageBuilder.new(nil, @conversation, params)
|
||||||
|
mb.perform
|
||||||
|
end
|
||||||
|
|
||||||
def send_email_transcript(emails)
|
def send_email_transcript(emails)
|
||||||
emails.each do |email|
|
emails.each do |email|
|
||||||
ConversationReplyMailer.with(account: @conversation.account).conversation_transcript(@conversation, email)&.deliver_later
|
ConversationReplyMailer.with(account: @conversation.account).conversation_transcript(@conversation, email)&.deliver_later
|
||||||
@@ -48,7 +57,7 @@ class AutomationRules::ActionService
|
|||||||
return if @rule.event_name == 'message_created'
|
return if @rule.event_name == 'message_created'
|
||||||
|
|
||||||
params = { content: message[0], private: false }
|
params = { content: message[0], private: false }
|
||||||
mb = Messages::MessageBuilder.new(@administrator, @conversation, params)
|
mb = Messages::MessageBuilder.new(nil, @conversation, params)
|
||||||
mb.perform
|
mb.perform
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -85,10 +94,6 @@ class AutomationRules::ActionService
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def administrator
|
|
||||||
@administrator ||= @account.administrators.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def agent_belongs_to_account?(agent_ids)
|
def agent_belongs_to_account?(agent_ids)
|
||||||
@account.agents.pluck(:id).include?(agent_ids[0])
|
@account.agents.pluck(:id).include?(agent_ids[0])
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -84,6 +84,23 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do
|
|||||||
}.with_indifferent_access
|
}.with_indifferent_access
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'throws an error for unknown attributes in condtions' do
|
||||||
|
expect(account.automation_rules.count).to eq(0)
|
||||||
|
params[:conditions] << {
|
||||||
|
attribute_key: 'unknown_attribute',
|
||||||
|
filter_operator: 'equal_to',
|
||||||
|
values: ['en'],
|
||||||
|
query_operator: 'AND'
|
||||||
|
}
|
||||||
|
|
||||||
|
post "/api/v1/accounts/#{account.id}/automation_rules",
|
||||||
|
headers: administrator.create_new_auth_token,
|
||||||
|
params: params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unprocessable_entity)
|
||||||
|
expect(account.automation_rules.count).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
it 'Saves for automation_rules for account with country_code and browser_language conditions' do
|
it 'Saves for automation_rules for account with country_code and browser_language conditions' do
|
||||||
expect(account.automation_rules.count).to eq(0)
|
expect(account.automation_rules.count).to eq(0)
|
||||||
|
|
||||||
@@ -113,6 +130,67 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do
|
|||||||
expect(response).to have_http_status(:success)
|
expect(response).to have_http_status(:success)
|
||||||
expect(account.automation_rules.count).to eq(1)
|
expect(account.automation_rules.count).to eq(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'Saves file in the automation actions to send an attachments' do
|
||||||
|
file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png')
|
||||||
|
params[:attachments] = [file]
|
||||||
|
params[:actions] = [
|
||||||
|
{
|
||||||
|
action_name: :send_message,
|
||||||
|
action_params: ['Welcome to the chatwoot platform.']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action_name: :update_additional_attributes,
|
||||||
|
action_params: [{ intiated_at: '2021-12-03 17:25:26.844536 +0530' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action_name: :send_attachments
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(account.automation_rules.count).to eq(0)
|
||||||
|
|
||||||
|
post "/api/v1/accounts/#{account.id}/automation_rules",
|
||||||
|
headers: administrator.create_new_auth_token,
|
||||||
|
params: params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(account.automation_rules.count).to eq(1)
|
||||||
|
automation_rule = account.automation_rules.first
|
||||||
|
expect(automation_rule.files.presence).to be_truthy
|
||||||
|
expect(automation_rule.files.count).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'Saves files in the automation actions to send multiple attachments' do
|
||||||
|
file_1 = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png')
|
||||||
|
file_2 = fixture_file_upload(Rails.root.join('spec/assets/sample.pdf'), 'image/png')
|
||||||
|
params[:attachments] = [file_1, file_2]
|
||||||
|
params[:actions] = [
|
||||||
|
{
|
||||||
|
action_name: :send_message,
|
||||||
|
action_params: ['Welcome to the chatwoot platform.']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action_name: :update_additional_attributes,
|
||||||
|
action_params: [{ intiated_at: '2021-12-03 17:25:26.844536 +0530' }]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action_name: :send_attachments
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
expect(account.automation_rules.count).to eq(0)
|
||||||
|
|
||||||
|
post "/api/v1/accounts/#{account.id}/automation_rules",
|
||||||
|
headers: administrator.create_new_auth_token,
|
||||||
|
params: params
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
expect(account.automation_rules.count).to eq(1)
|
||||||
|
automation_rule = account.automation_rules.first
|
||||||
|
expect(automation_rule.files.presence).to be_truthy
|
||||||
|
expect(automation_rule.files.count).to eq(2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,12 @@ describe AutomationRuleListener do
|
|||||||
{ 'action_name' => 'send_email_transcript', 'action_params' => 'new_agent@example.com' },
|
{ 'action_name' => 'send_email_transcript', 'action_params' => 'new_agent@example.com' },
|
||||||
{ 'action_name' => 'mute_conversation', 'action_params' => nil },
|
{ 'action_name' => 'mute_conversation', 'action_params' => nil },
|
||||||
{ 'action_name' => 'change_status', 'action_params' => ['snoozed'] },
|
{ 'action_name' => 'change_status', 'action_params' => ['snoozed'] },
|
||||||
{ 'action_name' => 'send_message', 'action_params' => ['Send this message.'] }
|
{ 'action_name' => 'send_message', 'action_params' => ['Send this message.'] },
|
||||||
|
{ 'action_name' => 'send_attachments' }
|
||||||
])
|
])
|
||||||
|
file = fixture_file_upload(Rails.root.join('spec/assets/avatar.png'), 'image/png')
|
||||||
|
automation_rule.files.attach(file)
|
||||||
|
automation_rule.save
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#conversation_status_changed' do
|
describe '#conversation_status_changed' do
|
||||||
@@ -112,7 +116,7 @@ describe AutomationRuleListener do
|
|||||||
|
|
||||||
conversation.reload
|
conversation.reload
|
||||||
|
|
||||||
expect(conversation.messages.last.content).to eq('Send this message.')
|
expect(conversation.messages.first.content).to eq('Send this message.')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'triggers automation rule changes status to snoozed' do
|
it 'triggers automation rule changes status to snoozed' do
|
||||||
@@ -150,6 +154,18 @@ describe AutomationRuleListener do
|
|||||||
|
|
||||||
listener.conversation_status_changed(event)
|
listener.conversation_status_changed(event)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'triggers automation rule send attachments in messages' do
|
||||||
|
automation_rule
|
||||||
|
|
||||||
|
expect(TeamNotifications::AutomationNotificationMailer).to receive(:conversation_creation)
|
||||||
|
|
||||||
|
listener.conversation_status_changed(event)
|
||||||
|
|
||||||
|
conversation.reload
|
||||||
|
|
||||||
|
expect(conversation.messages.last.attachments.count).to eq(1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -225,7 +241,7 @@ describe AutomationRuleListener do
|
|||||||
|
|
||||||
conversation.reload
|
conversation.reload
|
||||||
|
|
||||||
expect(conversation.messages.last.content).to eq('Send this message.')
|
expect(conversation.messages.first.content).to eq('Send this message.')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'triggers automation_rule with contact standard attributes' do
|
it 'triggers automation_rule with contact standard attributes' do
|
||||||
@@ -333,7 +349,7 @@ describe AutomationRuleListener do
|
|||||||
|
|
||||||
conversation.reload
|
conversation.reload
|
||||||
|
|
||||||
expect(conversation.messages.last.content).to eq('Send this message.')
|
expect(conversation.messages.first.content).to eq('Send this message.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user