diff --git a/app/controllers/api/v1/accounts/automation_rules_controller.rb b/app/controllers/api/v1/accounts/automation_rules_controller.rb index e1e5ddbad..dc4f7b6c8 100644 --- a/app/controllers/api/v1/accounts/automation_rules_controller.rb +++ b/app/controllers/api/v1/accounts/automation_rules_controller.rb @@ -7,14 +7,22 @@ class Api::V1::Accounts::AutomationRulesController < Api::V1::Accounts::BaseCont end def create - @automation_rule = Current.account.automation_rules.create(automation_rules_permit) - @automation_rule.update(actions: params[:actions]) + @automation_rule = Current.account.automation_rules.new(automation_rules_permit) + @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 def show; end def update @automation_rule.update(automation_rules_permit) + process_attachments + @automation_rule end def destroy @@ -31,6 +39,14 @@ class Api::V1::Accounts::AutomationRulesController < Api::V1::Accounts::BaseCont 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 params.permit( :name, :description, :event_name, :account_id, :active, diff --git a/app/models/automation_rule.rb b/app/models/automation_rule.rb index 0d25a2786..b0b62eef9 100644 --- a/app/models/automation_rule.rb +++ b/app/models/automation_rule.rb @@ -19,6 +19,7 @@ # class AutomationRule < ApplicationRecord belongs_to :account + has_many_attached :files validate :json_conditions_format validate :json_actions_format @@ -26,8 +27,8 @@ class AutomationRule < ApplicationRecord scope :active, -> { where(active: true) } - CONDITIONS_ATTRS = %w[country_code status browser_language assignee_id team_id referer].freeze - ACTIONS_ATTRS = %w[send_message add_label send_email_to_team assign_team assign_best_agents].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 send_attachments].freeze private @@ -35,13 +36,17 @@ class AutomationRule < ApplicationRecord return if conditions.nil? 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 def json_actions_format return if actions.nil? 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 diff --git a/app/services/automation_rules/action_service.rb b/app/services/automation_rules/action_service.rb index 3848e30f5..75b1f0474 100644 --- a/app/services/automation_rules/action_service.rb +++ b/app/services/automation_rules/action_service.rb @@ -21,6 +21,15 @@ class AutomationRules::ActionService 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) emails.each do |email| 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' params = { content: message[0], private: false } - mb = Messages::MessageBuilder.new(@administrator, @conversation, params) + mb = Messages::MessageBuilder.new(nil, @conversation, params) mb.perform end @@ -85,10 +94,6 @@ class AutomationRules::ActionService end end - def administrator - @administrator ||= @account.administrators.first - end - def agent_belongs_to_account?(agent_ids) @account.agents.pluck(:id).include?(agent_ids[0]) end diff --git a/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb b/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb index 5755bf95a..0d3b3e784 100644 --- a/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/automation_rules_controller_spec.rb @@ -84,6 +84,23 @@ RSpec.describe 'Api::V1::Accounts::AutomationRulesController', type: :request do }.with_indifferent_access 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 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(account.automation_rules.count).to eq(1) 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 diff --git a/spec/listeners/automation_rule_listener_spec.rb b/spec/listeners/automation_rule_listener_spec.rb index bf015fab3..6c4fc0c2a 100644 --- a/spec/listeners/automation_rule_listener_spec.rb +++ b/spec/listeners/automation_rule_listener_spec.rb @@ -42,8 +42,12 @@ describe AutomationRuleListener do { 'action_name' => 'send_email_transcript', 'action_params' => 'new_agent@example.com' }, { 'action_name' => 'mute_conversation', 'action_params' => nil }, { '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 describe '#conversation_status_changed' do @@ -112,7 +116,7 @@ describe AutomationRuleListener do conversation.reload - expect(conversation.messages.last.content).to eq('Send this message.') + expect(conversation.messages.first.content).to eq('Send this message.') end it 'triggers automation rule changes status to snoozed' do @@ -150,6 +154,18 @@ describe AutomationRuleListener do listener.conversation_status_changed(event) 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 @@ -225,7 +241,7 @@ describe AutomationRuleListener do conversation.reload - expect(conversation.messages.last.content).to eq('Send this message.') + expect(conversation.messages.first.content).to eq('Send this message.') end it 'triggers automation_rule with contact standard attributes' do @@ -333,7 +349,7 @@ describe AutomationRuleListener do 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