diff --git a/chrome/content/zotero/xpcom/sync/syncEngine.js b/chrome/content/zotero/xpcom/sync/syncEngine.js index e9895dc00..66565f6cf 100644 --- a/chrome/content/zotero/xpcom/sync/syncEngine.js +++ b/chrome/content/zotero/xpcom/sync/syncEngine.js @@ -346,7 +346,9 @@ Zotero.Sync.Data.Engine.prototype._startDownload = Zotero.Promise.coroutine(func + " didn't exist after conflict resolution"); continue; } - yield obj.erase(); + yield obj.erase({ + skipEditCheck: true + }); } }.bind(this)); }.bind(this) @@ -358,6 +360,7 @@ Zotero.Sync.Data.Engine.prototype._startDownload = Zotero.Promise.coroutine(func yield Zotero.DB.executeTransaction(function* () { for (let obj of toDelete) { yield obj.erase({ + skipEditCheck: true, skipDeleteLog: true }); } @@ -1348,7 +1351,13 @@ Zotero.Sync.Data.Engine.prototype._fullSync = Zotero.Promise.coroutine(function* // Delete local objects that were deleted remotely if (toDelete.length) { Zotero.debug("Deleting remotely deleted synced " + objectTypePlural); - yield objectsClass.erase(toDelete, { skipDeleteLog: true }); + yield objectsClass.erase( + toDelete, + { + skipEditCheck: true, + skipDeleteLog: true + } + ); } // For remotely missing objects that exist locally, reset version, since old // version will no longer match remote, and mark for upload diff --git a/chrome/content/zotero/xpcom/sync/syncLocal.js b/chrome/content/zotero/xpcom/sync/syncLocal.js index 2166fec24..842a68cb1 100644 --- a/chrome/content/zotero/xpcom/sync/syncLocal.js +++ b/chrome/content/zotero/xpcom/sync/syncLocal.js @@ -1320,23 +1320,13 @@ Zotero.Sync.Data.Local = { markObjectAsSynced: Zotero.Promise.method(function (obj) { obj.synced = true; - return obj.saveTx({ - skipSyncedUpdate: true, - skipDateModifiedUpdate: true, - skipClientDateModifiedUpdate: true, - skipNotifier: true - }); + return obj.saveTx({ skipAll: true }); }), markObjectAsUnsynced: Zotero.Promise.method(function (obj) { obj.synced = false; - return obj.saveTx({ - skipSyncedUpdate: true, - skipDateModifiedUpdate: true, - skipClientDateModifiedUpdate: true, - skipNotifier: true - }); + return obj.saveTx({ skipAll: true }); }), diff --git a/test/tests/syncEngineTest.js b/test/tests/syncEngineTest.js index ec0f54ab9..b2df3d72b 100644 --- a/test/tests/syncEngineTest.js +++ b/test/tests/syncEngineTest.js @@ -286,6 +286,182 @@ describe("Zotero.Sync.Data.Engine", function () { yield assertInCache(obj); }) + it("should download items into a new read-only group", function* () { + var group = yield createGroup({ + editable: false, + filesEditable: false + }); + var libraryID = group.libraryID; + var itemToDelete = yield createDataObject( + 'item', { libraryID, synced: true }, { skipEditCheck: true } + ) + var itemToDeleteID = itemToDelete.id; + + ({ engine, client, caller } = yield setup({ libraryID })); + + var headers = { + "Last-Modified-Version": 3 + }; + setResponse({ + method: "GET", + url: `groups/${group.id}/settings`, + status: 200, + headers: headers, + json: { + tagColors: { + value: [ + { + name: "A", + color: "#CC66CC" + } + ], + version: 2 + } + } + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/collections?format=versions`, + status: 200, + headers: headers, + json: { + "AAAAAAAA": 1 + } + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/searches?format=versions`, + status: 200, + headers: headers, + json: { + "AAAAAAAA": 2 + } + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/items/top?format=versions&includeTrashed=1`, + status: 200, + headers: headers, + json: { + "AAAAAAAA": 3 + } + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/items?format=versions&includeTrashed=1`, + status: 200, + headers: headers, + json: { + "AAAAAAAA": 3, + "BBBBBBBB": 3 + } + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/collections?format=json&collectionKey=AAAAAAAA`, + status: 200, + headers: headers, + json: [ + makeCollectionJSON({ + key: "AAAAAAAA", + version: 1, + name: "A" + }) + ] + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/searches?format=json&searchKey=AAAAAAAA`, + status: 200, + headers: headers, + json: [ + makeSearchJSON({ + key: "AAAAAAAA", + version: 2, + name: "A" + }) + ] + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/items?format=json&itemKey=AAAAAAAA&includeTrashed=1`, + status: 200, + headers: headers, + json: [ + makeItemJSON({ + key: "AAAAAAAA", + version: 3, + itemType: "book", + title: "A" + }) + ] + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/items?format=json&itemKey=BBBBBBBB&includeTrashed=1`, + status: 200, + headers: headers, + json: [ + makeItemJSON({ + key: "BBBBBBBB", + version: 3, + itemType: "note", + parentItem: "AAAAAAAA", + note: "This is a note." + }) + ] + }); + setResponse({ + method: "GET", + url: `groups/${group.id}/deleted?since=0`, + status: 200, + headers: headers, + json: { + "items": [itemToDelete.key] + } + }); + yield engine.start(); + + // Check local library version + assert.equal(group.libraryVersion, 3); + + // Make sure local objects exist + var setting = Zotero.SyncedSettings.get(libraryID, "tagColors"); + assert.lengthOf(setting, 1); + assert.equal(setting[0].name, 'A'); + var settingMetadata = Zotero.SyncedSettings.getMetadata(libraryID, "tagColors"); + assert.equal(settingMetadata.version, 2); + assert.isTrue(settingMetadata.synced); + + var obj = Zotero.Collections.getByLibraryAndKey(libraryID, "AAAAAAAA"); + assert.equal(obj.name, 'A'); + assert.equal(obj.version, 1); + assert.isTrue(obj.synced); + yield assertInCache(obj); + + obj = Zotero.Searches.getByLibraryAndKey(libraryID, "AAAAAAAA"); + assert.equal(obj.name, 'A'); + assert.equal(obj.version, 2); + assert.isTrue(obj.synced); + yield assertInCache(obj); + + obj = Zotero.Items.getByLibraryAndKey(libraryID, "AAAAAAAA"); + assert.equal(obj.getField('title'), 'A'); + assert.equal(obj.version, 3); + assert.isTrue(obj.synced); + var parentItemID = obj.id; + yield assertInCache(obj); + + obj = Zotero.Items.getByLibraryAndKey(libraryID, "BBBBBBBB"); + assert.equal(obj.getNote(), 'This is a note.'); + assert.equal(obj.parentItemID, parentItemID); + assert.equal(obj.version, 3); + assert.isTrue(obj.synced); + yield assertInCache(obj); + + assert.isFalse(Zotero.Items.exists(itemToDeleteID)); + }); + it("should upload new full items and subsequent patches", function* () { ({ engine, client, caller } = yield setup());