www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit 34c90fd156eb83486459ec0370626a7c7006ff96
parent cbed716424acca3552acf9fc36aa3a616a57fac4
Author: Dan Stillman <dstillman@zotero.org>
Date:   Thu, 16 Feb 2017 18:01:53 -0500

If parent item is missing remotely, mark as unsynced and add to queue

This shouldn't happen, but there've been some reports of it.

Diffstat:
Mchrome/content/zotero/xpcom/sync/syncEngine.js | 26++++++++++++++++++++++++++
Mtest/tests/syncEngineTest.js | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 95 insertions(+), 0 deletions(-)

diff --git a/chrome/content/zotero/xpcom/sync/syncEngine.js b/chrome/content/zotero/xpcom/sync/syncEngine.js @@ -1113,6 +1113,32 @@ Zotero.Sync.Data.Engine.prototype._uploadObjects = Zotero.Promise.coroutine(func Zotero.logError("Error for " + objectType + " " + jsonBatch[index].key + " in " + this.library.name + ":\n\n" + e); + // If parent item is missing remotely and it isn't in the queue (which shouldn't happen), + // mark it as unsynced and add to queue + if (e.code == 400 && objectType == 'item' && data && data.parentItem) { + let parentItem = Zotero.Items.getByLibraryAndKey(this.libraryID, data.parentItem); + if (!parentItem) { + throw new Error(`Item ${this.libraryID}/${jsonBatch[index].key} references parent ` + + `item ${data.parentItem}, which doesn't exist`); + } + + let id = parentItem.id; + // If parent item isn't already in queue, mark it as unsynced and add it + if (!queue.find(o => o.id == id) && !batch.find(o => o.id == id)) { + yield Zotero.Sync.Data.Local.markObjectAsUnsynced(parentItem); + Zotero.logError(`Adding parent item ${data.parentItem} to upload queue`); + queue.push({ + id, + json: null, + tries: 0, + failed: false + }); + // Pretend that we were successful so syncing continues + numSuccessful++; + continue; + } + } + // This shouldn't happen, because the upload request includes a library version and should // prevent an outdated upload before the object version is checked. If it does, we need to // do a full sync. This error is checked in handleUploadError(). diff --git a/test/tests/syncEngineTest.js b/test/tests/syncEngineTest.js @@ -2175,6 +2175,75 @@ describe("Zotero.Sync.Data.Engine", function () { var result = yield engine._startUpload(); assert.equal(result, engine.UPLOAD_RESULT_OBJECT_CONFLICT); }); + + + it("should mark local parent item as unsynced if it doesn't exist when uploading child", function* () { + ({ engine, client, caller } = yield setup()); + + var library = Zotero.Libraries.userLibrary; + var libraryID = library.id; + var lastLibraryVersion = 5; + library.libraryVersion = lastLibraryVersion; + yield library.saveTx(); + + var item = createUnsavedDataObject('item'); + // Set the parent item as synced (though this shouldn't happen) + item.synced = true; + yield item.saveTx(); + var note = yield createDataObject('item', { itemType: 'note', parentID: item.id }); + + var called = 0; + server.respond(function (req) { + let requestJSON = JSON.parse(req.requestBody); + + if (called == 0) { + assert.lengthOf(requestJSON, 1); + assert.equal(requestJSON[0].key, note.key); + req.respond( + 200, + { + "Last-Modified-Version": lastLibraryVersion + }, + JSON.stringify({ + successful: {}, + unchanged: {}, + failed: { + 0: { + code: 400, + message: `Parent item '${item.key}' doesn't exist`, + data: { + parentItem: item.key + } + } + } + }) + ); + } + else if (called == 1) { + assert.lengthOf(requestJSON, 2); + assert.sameMembers(requestJSON.map(o => o.key), [item.key, note.key]); + req.respond( + 200, + { + "Last-Modified-Version": ++lastLibraryVersion + }, + JSON.stringify({ + successful: { + 0: item.toResponseJSON(), + 1: note.toResponseJSON() + }, + unchanged: {}, + failed: {} + }) + ); + } + called++; + }); + + var result = yield engine._startUpload(); + assert.equal(result, engine.UPLOAD_RESULT_SUCCESS); + assert.equal(called, 2); + }); });