From a3243ae9e859b7a58950fa641012dd3eaf023d44 Mon Sep 17 00:00:00 2001 From: Ping Chen Date: Tue, 22 Mar 2022 11:59:20 +0200 Subject: [PATCH] Bug 159967 - Support importing semicolon separated csv file to address book. r=benc Differential Revision: https://phabricator.services.mozilla.com/D141060 --HG-- extra : amend_source : 501b5143b8de76d367da6174b77ea46090e9751a --- .../import/modules/AddrBookFileImporter.jsm | 5 ++++ .../test/unit/resources/addressbook.json | 8 ++++++- .../unit/resources/basic_csv_addressbook.csv | 5 ++-- .../test/unit/resources/csv_no_header.csv | 2 ++ .../test/unit/resources/csv_semicolon.csv | 3 +++ .../test/unit/test_AddrBookFileImporter.js | 23 +++++++++++++++++-- 6 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 mailnews/import/test/unit/resources/csv_no_header.csv create mode 100644 mailnews/import/test/unit/resources/csv_semicolon.csv diff --git a/mailnews/import/modules/AddrBookFileImporter.jsm b/mailnews/import/modules/AddrBookFileImporter.jsm index fcc0f84af0..433af3771f 100644 --- a/mailnews/import/modules/AddrBookFileImporter.jsm +++ b/mailnews/import/modules/AddrBookFileImporter.jsm @@ -98,8 +98,13 @@ class AddrBookFileImporter { let csvRows = d3.csv.parseRows(content); let tsvRows = d3.tsv.parseRows(content); + let dsvRows = d3.dsv(";").parseRows(content); // If we have more CSV columns, then it's a CSV file, otherwise a TSV file. this._csvRows = csvRows[0].length > tsvRows[0].length ? csvRows : tsvRows; + // See if it's semicolon separated. + if (this._csvRows[0].length < dsvRows[0].length) { + this._csvRows = dsvRows; + } let bundle = Services.strings.createBundle( "chrome://messenger/locale/importMsgs.properties" diff --git a/mailnews/import/test/unit/resources/addressbook.json b/mailnews/import/test/unit/resources/addressbook.json index b6b6f15127..7a70d737b4 100644 --- a/mailnews/import/test/unit/resources/addressbook.json +++ b/mailnews/import/test/unit/resources/addressbook.json @@ -95,7 +95,13 @@ "DisplayName" : "John Doe", "FirstName" : "John", "LastName" : "Doe", - "PrimaryEmail" : "johndoe@host.invalid" + "PrimaryEmail" : "john@doe.invalid" + }, + { + "DisplayName" : "Jane Doe", + "FirstName" : "Jane", + "LastName" : "Doe", + "PrimaryEmail" : "jane@doe.invalid" } ], "becky_addressbook" : diff --git a/mailnews/import/test/unit/resources/basic_csv_addressbook.csv b/mailnews/import/test/unit/resources/basic_csv_addressbook.csv index 5d97d36f17..d4ecd1a308 100644 --- a/mailnews/import/test/unit/resources/basic_csv_addressbook.csv +++ b/mailnews/import/test/unit/resources/basic_csv_addressbook.csv @@ -1,2 +1,3 @@ -First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes,Screen Name, -John,Doe,John Doe,,johndoe@host.invalid,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes,Screen Name +John,Doe,John Doe,,john@doe.invalid,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Jane,Doe,Jane Doe,,jane@doe.invalid,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, diff --git a/mailnews/import/test/unit/resources/csv_no_header.csv b/mailnews/import/test/unit/resources/csv_no_header.csv new file mode 100644 index 0000000000..f017ec3f7d --- /dev/null +++ b/mailnews/import/test/unit/resources/csv_no_header.csv @@ -0,0 +1,2 @@ +John Doe,John,Doe,john@doe.invalid +Jane Doe,Jane,Doe,jane@doe.invalid diff --git a/mailnews/import/test/unit/resources/csv_semicolon.csv b/mailnews/import/test/unit/resources/csv_semicolon.csv new file mode 100644 index 0000000000..6323d439ee --- /dev/null +++ b/mailnews/import/test/unit/resources/csv_semicolon.csv @@ -0,0 +1,3 @@ +Display Name;First Name;Last Name;Primary Email +John Doe;John;Doe;john@doe.invalid +Jane Doe;Jane;Doe;jane@doe.invalid diff --git a/mailnews/import/test/unit/test_AddrBookFileImporter.js b/mailnews/import/test/unit/test_AddrBookFileImporter.js index a08cb72e52..a54a8e4089 100644 --- a/mailnews/import/test/unit/test_AddrBookFileImporter.js +++ b/mailnews/import/test/unit/test_AddrBookFileImporter.js @@ -12,8 +12,9 @@ var { AddrBookFileImporter } = ChromeUtils.import( * @param {string} type - A source file type supported by AddrBookFileImporter. * @param {string} filePath - The path of a source file. * @param {string} refDataKey - The key of an object in addressbook.json. + * @param {string[]} [csvFieldMap] - Map of CSV fields to address book fields. */ -async function test_importAbFile(type, filePath, refDataKey) { +async function test_importAbFile(type, filePath, refDataKey, csvFieldMap) { // Create an address book and init the importer. let dirId = MailServices.ab.newAddressBook( `tmp-${type}`, @@ -26,7 +27,10 @@ async function test_importAbFile(type, filePath, refDataKey) { // Start importing. let sourceFile = do_get_file(filePath); if (type == "csv") { - await importer.parseCsvFile(sourceFile); + let unmatched = await importer.parseCsvFile(sourceFile); + if (unmatched.length) { + importer.setCsvFields(csvFieldMap); + } } await importer.startImport(sourceFile, targetDir); @@ -48,12 +52,27 @@ async function test_importAbFile(type, filePath, refDataKey) { /** Test importing .csv file works. */ add_task(async function test_importCsvFile() { + // A comma separated file. await test_importAbFile( "csv", "resources/basic_csv_addressbook.csv", "csv_import" ); + // A semicolon separated file. + await test_importAbFile("csv", "resources/csv_semicolon.csv", "csv_import"); + + // A comma separated file without header row. + Services.prefs.setBoolPref("mail.import.csv.skipfirstrow", false); + await test_importAbFile("csv", "resources/csv_no_header.csv", "csv_import", [ + 2, // DisplayName + 0, // FirstName + 1, // LastName + 4, // PrimaryEmail + ]); + Services.prefs.clearUserPref("mail.import.csv.skipfirstrow"); + + // A comma separated file with some fields containing quotes. await test_importAbFile("csv", "resources/quote.csv", "quote_csv"); });