feat: Export contact improvements (#8895)

This pull request enhances the export contacts feature by adding a confirmation step before exporting. Previously, clicking the export button would trigger the export action without confirmation.

Additionally, it ensures that only the intended recipient receives the export email, addressing the previous behaviour where all administrators received it.

Fixes: #8504

Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
Liam
2024-02-20 11:41:03 +00:00
committed by GitHub
parent 721a2f5052
commit 5d9fb55370
8 changed files with 34 additions and 16 deletions

View File

@@ -46,7 +46,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
def export def export
column_names = params['column_names'] column_names = params['column_names']
Account::ContactsExportJob.perform_later(Current.account.id, column_names) Account::ContactsExportJob.perform_later(Current.account.id, column_names, Current.user.email)
head :ok, message: I18n.t('errors.contacts.export.success') head :ok, message: I18n.t('errors.contacts.export.success')
end end

View File

@@ -79,7 +79,13 @@
"TITLE": "Export Contacts", "TITLE": "Export Contacts",
"DESC": "Export contacts to a CSV file.", "DESC": "Export contacts to a CSV file.",
"SUCCESS_MESSAGE": "Export is in progress. You will be notified on email when the export file is ready to download.", "SUCCESS_MESSAGE": "Export is in progress. You will be notified on email when the export file is ready to download.",
"ERROR_MESSAGE": "There was an error, please try again" "ERROR_MESSAGE": "There was an error, please try again",
"CONFIRM": {
"TITLE": "Export Contacts",
"MESSAGE": "Are you sure you want to export all contacts?",
"YES": "Yes, Export",
"NO": "No, Cancel"
}
}, },
"DELETE_NOTE": { "DELETE_NOTE": {
"CONFIRM": { "CONFIRM": {

View File

@@ -113,6 +113,13 @@
</woot-button> </woot-button>
</div> </div>
</div> </div>
<woot-confirm-modal
ref="confirmExportContactsDialog"
:title="$t('EXPORT_CONTACTS.CONFIRM.TITLE')"
:description="$t('EXPORT_CONTACTS.CONFIRM.MESSAGE')"
:confirm-label="$t('EXPORT_CONTACTS.CONFIRM.YES')"
:cancel-label="$t('EXPORT_CONTACTS.CONFIRM.NO')"
/>
</header> </header>
</template> </template>
@@ -175,8 +182,13 @@ export default {
toggleImport() { toggleImport() {
this.$emit('on-toggle-import'); this.$emit('on-toggle-import');
}, },
submitExport() { async submitExport() {
this.$emit('on-export-submit'); const ok =
await this.$refs.confirmExportContactsDialog.showConfirmation();
if (ok) {
this.$emit('on-export-submit');
}
}, },
submitSearch() { submitSearch() {
this.$emit('on-search-submit'); this.$emit('on-search-submit');

View File

@@ -1,13 +1,13 @@
class Account::ContactsExportJob < ApplicationJob class Account::ContactsExportJob < ApplicationJob
queue_as :low queue_as :low
def perform(account_id, column_names) def perform(account_id, column_names, email_to)
account = Account.find(account_id) account = Account.find(account_id)
headers = valid_headers(column_names) headers = valid_headers(column_names)
generate_csv(account, headers) generate_csv(account, headers)
file_url = account_contact_export_url(account) file_url = account_contact_export_url(account)
AdministratorNotifications::ChannelNotificationsMailer.with(account: account).contact_export_complete(file_url)&.deliver_later AdministratorNotifications::ChannelNotificationsMailer.with(account: account).contact_export_complete(file_url, email_to)&.deliver_later
end end
def generate_csv(account, headers) def generate_csv(account, headers)

View File

@@ -60,12 +60,13 @@ class AdministratorNotifications::ChannelNotificationsMailer < ApplicationMailer
send_mail_with_liquid(to: admin_emails, subject: subject) and return send_mail_with_liquid(to: admin_emails, subject: subject) and return
end end
def contact_export_complete(file_url) def contact_export_complete(file_url, email_to)
return unless smtp_config_set_or_development? return unless smtp_config_set_or_development?
@action_url = file_url @action_url = file_url
subject = "Your contact's export file is available to download." subject = "Your contact's export file is available to download."
send_mail_with_liquid(to: admin_emails, subject: subject) and return
send_mail_with_liquid(to: email_to, subject: subject) and return
end end
private private

View File

@@ -197,7 +197,7 @@ RSpec.describe 'Contacts API', type: :request do
let(:admin) { create(:user, account: account, role: :administrator) } let(:admin) { create(:user, account: account, role: :administrator) }
it 'enqueues a contact export job' do it 'enqueues a contact export job' do
expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, nil).once expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, nil, admin.email).once
get "/api/v1/accounts/#{account.id}/contacts/export", get "/api/v1/accounts/#{account.id}/contacts/export",
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,
@@ -207,7 +207,7 @@ RSpec.describe 'Contacts API', type: :request do
end end
it 'enqueues a contact export job with sent_columns' do it 'enqueues a contact export job with sent_columns' do
expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, %w[phone_number email]).once expect(Account::ContactsExportJob).to receive(:perform_later).with(account.id, %w[phone_number email], admin.email).once
get "/api/v1/accounts/#{account.id}/contacts/export", get "/api/v1/accounts/#{account.id}/contacts/export",
headers: admin.create_new_auth_token, headers: admin.create_new_auth_token,

View File

@@ -24,17 +24,17 @@ RSpec.describe Account::ContactsExportJob do
allow(AdministratorNotifications::ChannelNotificationsMailer).to receive(:with).with(account: account).and_return(mailer) allow(AdministratorNotifications::ChannelNotificationsMailer).to receive(:with).with(account: account).and_return(mailer)
allow(mailer).to receive(:contact_export_complete) allow(mailer).to receive(:contact_export_complete)
described_class.perform_now(account.id, []) described_class.perform_now(account.id, [], 'test@test.com')
file_url = Rails.application.routes.url_helpers.rails_blob_url(account.contacts_export) file_url = Rails.application.routes.url_helpers.rails_blob_url(account.contacts_export)
expect(account.contacts_export).to be_present expect(account.contacts_export).to be_present
expect(file_url).to be_present expect(file_url).to be_present
expect(mailer).to have_received(:contact_export_complete).with(file_url) expect(mailer).to have_received(:contact_export_complete).with(file_url, 'test@test.com')
end end
it 'generates valid data export file' do it 'generates valid data export file' do
described_class.perform_now(account.id, []) described_class.perform_now(account.id, [], 'test@test.com')
csv_data = CSV.parse(account.contacts_export.download, headers: true) csv_data = CSV.parse(account.contacts_export.download, headers: true)
emails = csv_data.pluck('email') emails = csv_data.pluck('email')

View File

@@ -10,7 +10,6 @@ RSpec.describe AdministratorNotifications::ChannelNotificationsMailer do
before do before do
allow(described_class).to receive(:new).and_return(class_instance) allow(described_class).to receive(:new).and_return(class_instance)
allow(class_instance).to receive(:smtp_config_set_or_development?).and_return(true) allow(class_instance).to receive(:smtp_config_set_or_development?).and_return(true)
Account::ContactsExportJob.perform_now(account.id, [])
end end
describe 'slack_disconnect' do describe 'slack_disconnect' do
@@ -92,8 +91,8 @@ RSpec.describe AdministratorNotifications::ChannelNotificationsMailer do
end end
describe 'contact_export_complete' do describe 'contact_export_complete' do
let!(:file_url) { Rails.application.routes.url_helpers.rails_blob_url(account.contacts_export) } let!(:file_url) { 'http://test.com/test' }
let(:mail) { described_class.with(account: account).contact_export_complete(file_url).deliver_now } let(:mail) { described_class.with(account: account).contact_export_complete(file_url, administrator.email).deliver_now }
it 'renders the subject' do it 'renders the subject' do
expect(mail.subject).to eq("Your contact's export file is available to download.") expect(mail.subject).to eq("Your contact's export file is available to download.")