From 2e389de471fc76f330e9f7e357bbed8c0e4c0703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adomas=20Ven=C4=8Dkauskas?= Date: Wed, 23 Dec 2015 09:56:47 +0000 Subject: [PATCH] Closes #833, Displays a warning dialog if API key present but library empty --- chrome/content/zotero/xpcom/data/library.js | 9 ++++ .../content/zotero/xpcom/sync/syncRunner.js | 53 +++++++++++++++++-- chrome/locale/en-US/zotero/zotero.properties | 3 ++ test/tests/libraryTest.js | 33 ++++++++++++ 4 files changed, 94 insertions(+), 4 deletions(-) diff --git a/chrome/content/zotero/xpcom/data/library.js b/chrome/content/zotero/xpcom/data/library.js index f75b0ed16b..efb2b47b00 100644 --- a/chrome/content/zotero/xpcom/data/library.js +++ b/chrome/content/zotero/xpcom/data/library.js @@ -567,6 +567,15 @@ Zotero.Library.prototype.updateSearches = Zotero.Promise.coroutine(function* () this._hasSearches = !!(yield Zotero.DB.valueQueryAsync(sql, this.libraryID)); }); +Zotero.Library.prototype.hasItems = Zotero.Promise.coroutine(function* () { + if (!this.id) { + throw new Error("Library is not saved yet"); + } + let sql = 'SELECT COUNT(*)>0 FROM items WHERE libraryID=?'; + + return Zotero.DB.valueQueryAsync(sql, this.libraryID); +}); + Zotero.Library.prototype.hasItem = function (item) { if (!(item instanceof Zotero.Item)) { throw new Error("item must be a Zotero.Item"); diff --git a/chrome/content/zotero/xpcom/sync/syncRunner.js b/chrome/content/zotero/xpcom/sync/syncRunner.js index 3b3660aa14..caacb06b0f 100644 --- a/chrome/content/zotero/xpcom/sync/syncRunner.js +++ b/chrome/content/zotero/xpcom/sync/syncRunner.js @@ -136,14 +136,20 @@ Zotero.Sync.Runner_Module = function (options = {}) { try { let client = this.getAPIClient({ apiKey }); - let keyInfo = yield this.checkAccess(client, options); - if (!keyInfo) { + + let emptyLibraryContinue = yield this.checkEmptyLibrary(keyInfo); + if (!emptyLibraryContinue) { this.end(); - Zotero.debug("Syncing cancelled"); + Zotero.debug("Syncing cancelled because user library is empty"); return false; } - + + if (!Zotero.Users.getCurrentUserID()) { + Zotero.Users.setCurrentUserID(keyInfo.userID); + Zotero.Users.setCurrentUsername(keyInfo.username); + } + let engineOptions = { apiClient: client, caller: this.caller, @@ -231,6 +237,45 @@ Zotero.Sync.Runner_Module = function (options = {}) { return json; }); + + + // Prompt if library empty and there is no userID stored + this.checkEmptyLibrary = Zotero.Promise.coroutine(function* (keyInfo) { + let library = Zotero.Libraries.userLibrary; + let userID = Zotero.Users.getCurrentUserID(); + + if (!userID) { + let hasItems = yield library.hasItems(); + if (!hasItems) { + let ps = Services.prompt; + let index = ps.confirmEx( + null, + Zotero.getString('general.warning'), + Zotero.getString('sync.warning.emptyLibrary', [keyInfo.username, Zotero.clientName]) + "\n\n" + + Zotero.getString('sync.warning.existingDataElsewhere', Zotero.clientName), + (ps.BUTTON_POS_0 * ps.BUTTON_TITLE_IS_STRING) + + (ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL) + + (ps.BUTTON_POS_2 * ps.BUTTON_TITLE_IS_STRING), + Zotero.getString('sync.sync'), + null, + Zotero.getString('dataDir.changeDataDirectory'), + null, {} + ); + if (index == 1) { + return false; + } + else if (index == 2) { + var win = Services.wm.getMostRecentWindow("navigator:browser"); + win.openDialog("chrome://zotero/content/preferences/preferences.xul", null, null, { + pane: 'zotero-prefpane-advanced', + tabIndex: 1 + }); + return false; + } + } + } + return true; + }); this.checkLibraries = Zotero.Promise.coroutine(function* (client, options, keyInfo, libraries = []) { diff --git a/chrome/locale/en-US/zotero/zotero.properties b/chrome/locale/en-US/zotero/zotero.properties index fcf6f6c974..d189b9c35d 100644 --- a/chrome/locale/en-US/zotero/zotero.properties +++ b/chrome/locale/en-US/zotero/zotero.properties @@ -112,6 +112,7 @@ dataDir.notFound = The Zotero data directory could not be found. dataDir.previousDir = Previous directory: dataDir.useProfileDir = Use %S profile directory dataDir.selectDir = Select a Zotero data directory +dataDir.changeDataDirectory = Change Data Directory… dataDir.unsafeLocation.selected.dropbox = Choosing a data directory within Dropbox may corrupt your database. dataDir.unsafeLocation.selected.useAnyway = Use this directory anyway? dataDir.unsafeLocation.existing.dropbox = Your Zotero data directory is within Dropbox, which may lead to data corruption. @@ -828,6 +829,8 @@ sync.localDataWillBeCombined = If you continue, local Zotero data will be combi sync.localGroupsWillBeRemoved1 = Local groups, including any with changed items, will also be removed from this computer. sync.avoidCombiningData = To avoid combining data, revert to the '%S' account or use the Reset options in the Sync pane of the Zotero preferences. sync.unlinkWarning = Are you sure you want to unlink this account?\n\n%S will no longer sync your data, but your data will remain locally. +sync.warning.emptyLibrary = You are about to sync the ‘%1$S’ account to an empty %2$S database. This could happen if you removed your previous %2$S database or if the location of your data directory changed. +sync.warning.existingDataElsewhere = If your %S data exists elsewhere on your computer, you should move it to your current data directory or change your data directory location to point to the existing data. sync.conflict.autoChange.alert = One or more locally deleted Zotero %S have been modified remotely since the last sync. sync.conflict.autoChange.log = A Zotero %S has changed both locally and remotely since the last sync: diff --git a/test/tests/libraryTest.js b/test/tests/libraryTest.js index 548e69ad02..047aa3fe50 100644 --- a/test/tests/libraryTest.js +++ b/test/tests/libraryTest.js @@ -256,6 +256,39 @@ describe("Zotero.Library", function() { assert.isFalse(library.hasSearches()); }) }); + describe("#hasItems()", function() { + it("should throw if called before saving a library", function* () { + let library = new Zotero.Library(); + try { + yield library.hasItems(); + assert.isFalse(true, "Library#hasItems did not throw an error"); + } catch (e) { + assert.ok(e); + } + }); + it("should stay up to date as items are added and removed", function* () { + let library = yield createGroup({ editable: true }); + let libraryID = library.libraryID; + var hasItems = yield library.hasItems(); + assert.isFalse(hasItems); + + let i1 = yield createDataObject('item', { libraryID }); + hasItems = yield library.hasItems(); + assert.isTrue(hasItems); + + let i2 = yield createDataObject('item', { libraryID }); + hasItems = yield library.hasItems(); + assert.isTrue(hasItems); + + yield i1.eraseTx(); + hasItems = yield library.hasItems(); + assert.isTrue(hasItems); + + yield i2.eraseTx(); + hasItems = yield library.hasItems(); + assert.isFalse(hasItems); + }); + }); describe("#updateLastSyncTime()", function() { it("should set sync time to current time", function* () { let group = yield createGroup();