From 80a0826eb61c3844e67d501e0533cfc9424051bd Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Fri, 24 Feb 2017 02:31:08 -0500 Subject: [PATCH] Add archived group handling to sync runner - Archive remotely missing that user chooses to keep - Ignore archived groups that don't existing remotely - Unarchive groups that become available again --- .../content/zotero/xpcom/sync/syncRunner.js | 31 ++++-- test/tests/syncRunnerTest.js | 96 +++++++++++++++++-- 2 files changed, 113 insertions(+), 14 deletions(-) diff --git a/chrome/content/zotero/xpcom/sync/syncRunner.js b/chrome/content/zotero/xpcom/sync/syncRunner.js index bfdf16c8b..041d5fb16 100644 --- a/chrome/content/zotero/xpcom/sync/syncRunner.js +++ b/chrome/content/zotero/xpcom/sync/syncRunner.js @@ -371,9 +371,9 @@ Zotero.Sync.Runner_Module = function (options = {}) { let group = Zotero.Groups.get(id); if (syncAllLibraries) { - // If syncing all libraries, mark any that don't exist or are outdated - // locally for update. Group is added to the library list after downloading - if (!group || group.version < remoteGroupVersions[id]) { + // If syncing all libraries, mark any that don't exist, are outdated, or are + // archived locally for update. Group is added to the library list after downloading. + if (!group || group.version < remoteGroupVersions[id] || group.archived) { groupsToDownload.push(id); } // If not outdated, just add to library list @@ -421,6 +421,7 @@ Zotero.Sync.Runner_Module = function (options = {}) { // TODO: What about explicit deletions? let removedGroups = []; + let keptGroups = []; let ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] .getService(Components.interfaces.nsIPromptService); @@ -433,6 +434,12 @@ Zotero.Sync.Runner_Module = function (options = {}) { // // TODO: Localize for (let group of remotelyMissingGroups) { + // Ignore archived groups + if (group.archived) { + groupsToDownload.splice(groupsToDownload.indexOf(group.id), 1); + continue; + } + let msg; // If all-groups access but group is missing, user left it if (access.groups && access.groups.all) { @@ -467,18 +474,25 @@ Zotero.Sync.Runner_Module = function (options = {}) { return []; } else if (index == 2) { - // TODO: Mark groups to be ignored + keptGroups.push(group); } } let removedLibraryIDs = []; for (let group of removedGroups) { removedLibraryIDs.push(group.libraryID); - yield Zotero.DB.executeTransaction(function* () { - return group.erase(); - }); + yield group.eraseTx(); } libraries = Zotero.Utilities.arrayDiff(libraries, removedLibraryIDs); + + let keptLibraryIDs = []; + for (let group of keptGroups) { + keptLibraryIDs.push(group.libraryID); + group.editable = false; + group.archived = true; + yield group.saveTx(); + } + libraries = Zotero.Utilities.arrayDiff(libraries, keptLibraryIDs); } // Update metadata and permissions on missing or outdated groups @@ -508,6 +522,7 @@ Zotero.Sync.Runner_Module = function (options = {}) { group.id = groupID; } group.version = info.version; + group.archived = false; group.fromJSON(info.data, Zotero.Users.getCurrentUserID()); yield group.saveTx(); @@ -515,6 +530,8 @@ Zotero.Sync.Runner_Module = function (options = {}) { libraries.push(group.libraryID); } + // Note: If any non-group library types become archivable, they'll need to be unarchived here. + return [...new Set(libraries)]; }); diff --git a/test/tests/syncRunnerTest.js b/test/tests/syncRunnerTest.js index 1470bb3d6..ba81335af 100644 --- a/test/tests/syncRunnerTest.js +++ b/test/tests/syncRunnerTest.js @@ -296,6 +296,64 @@ describe("Zotero.Sync.Runner", function () { assert.equal(skippedGroup.version, responses.groups.memberGroup.json.version - 1); }); + it("should filter out remotely missing archived libraries if library list not provided", function* () { + var syncedGroupID = responses.groups.ownerGroup.json.id; + var archivedGroupID = 162512451; // nonexistent group id + + var syncedGroup = yield createGroup({ + id: syncedGroupID, + version: responses.groups.ownerGroup.json.version - 1 + }); + var archivedGroup = yield createGroup({ + id: archivedGroupID, + editable: false, + archived: true + }); + + setResponse('userGroups.groupVersions'); + setResponse('groups.ownerGroup'); + var libraries = yield runner.checkLibraries( + runner.getAPIClient({ apiKey }), + false, + responses.keyInfo.fullAccess.json + ); + + assert.lengthOf(libraries, 3); + assert.sameMembers(libraries, [userLibraryID, publicationsLibraryID, syncedGroup.libraryID]); + }); + + it("should unarchive library if available remotely", function* () { + var syncedGroupID = responses.groups.ownerGroup.json.id; + var archivedGroupID = responses.groups.memberGroup.json.id; + + var syncedGroup = yield createGroup({ + id: syncedGroupID, + version: responses.groups.ownerGroup.json.version + }); + var archivedGroup = yield createGroup({ + id: archivedGroupID, + version: responses.groups.memberGroup.json.version - 1, + editable: false, + archived: true + }); + + setResponse('userGroups.groupVersions'); + setResponse('groups.ownerGroup'); + setResponse('groups.memberGroup'); + var libraries = yield runner.checkLibraries( + runner.getAPIClient({ apiKey }), + false, + responses.keyInfo.fullAccess.json + ); + + assert.lengthOf(libraries, 4); + assert.sameMembers( + libraries, + [userLibraryID, publicationsLibraryID, syncedGroup.libraryID, archivedGroup.libraryID] + ); + assert.isFalse(archivedGroup.archived); + }); + it("shouldn't filter out skipped libraries if library list is provided", function* () { var groupData = responses.groups.memberGroup; var group = yield createGroup({ @@ -453,21 +511,45 @@ describe("Zotero.Sync.Runner", function () { assert.isTrue(Zotero.Groups.exists(groupData2.json.id)); }) - it.skip("should keep remotely missing groups", function* () { - var groupData = responses.groups.ownerGroup; - var group = yield createGroup({ id: groupData.json.id, version: groupData.json.version }); + it("should keep remotely missing groups", function* () { + var group1 = yield createGroup({ editable: true, filesEditable: true }); + var group2 = yield createGroup({ editable: true, filesEditable: true }); setResponse('userGroups.groupVersionsEmpty'); + var called = 0; + var otherGroup; waitForDialog(function (dialog) { + called++; var text = dialog.document.documentElement.textContent; - assert.include(text, group.name); + if (text.includes(group1.name)) { + otherGroup = group2; + } + else if (text.includes(group2.name)) { + otherGroup = group1; + } + else { + throw new Error("Dialog text does not include either group name"); + } + + waitForDialog(function (dialog) { + called++; + var text = dialog.document.documentElement.textContent; + assert.include(text, otherGroup.name); + }, "extra1"); }, "extra1"); var libraries = yield runner.checkLibraries( runner.getAPIClient({ apiKey }), false, responses.keyInfo.fullAccess.json ); - assert.lengthOf(libraries, 3); - assert.sameMembers(libraries, [userLibraryID, publicationsLibraryID, group.libraryID]); - assert.isTrue(Zotero.Groups.exists(groupData.json.id)); + assert.equal(called, 2); + assert.lengthOf(libraries, 2); + assert.sameMembers(libraries, [userLibraryID, publicationsLibraryID]); + // Groups should still exist but be read-only and archived + [group1, group2].forEach((group) => { + assert.isTrue(Zotero.Groups.exists(group.id)); + assert.isTrue(group.archived); + assert.isFalse(group.editable); + assert.isFalse(group.filesEditable); + }); }) it("should cancel sync with remotely missing groups", function* () {