diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js index c80ae2b0c..11fd22e43 100644 --- a/chrome/content/zotero/xpcom/data/collection.js +++ b/chrome/content/zotero/xpcom/data/collection.js @@ -1016,7 +1016,9 @@ Zotero.Collection.prototype._getParent = function() { } var parentCollection = Zotero.Collections.getByLibraryAndKey(this.libraryID, this._parent); if (!parentCollection) { - throw ("Parent collection for keyed parent doesn't exist in Zotero.Collection._getParent()"); + var msg = "Parent collection for keyed parent doesn't exist in Zotero.Collection._getParent()"; + var e = new Zotero.Error(msg, "MISSING_OBJECT"); + throw (e); } // Replace stored key with id this._parent = parentCollection.id; diff --git a/chrome/content/zotero/xpcom/data/item.js b/chrome/content/zotero/xpcom/data/item.js index 14a8b3609..80f96a51b 100644 --- a/chrome/content/zotero/xpcom/data/item.js +++ b/chrome/content/zotero/xpcom/data/item.js @@ -1380,8 +1380,10 @@ Zotero.Item.prototype.save = function() { } var newSourceItemNotifierData = {}; - newSourceItemNotifierData[newSourceItem.id] = - { old: newSourceItem.serialize() }; + newSourceItemNotifierData[newSourceItem.id] = { + old: newSourceItem.serialize() + }; + Zotero.Notifier.trigger('modify', 'item', newSourceItem.id, newSourceItemNotifierData); switch (Zotero.ItemTypes.getName(this.itemTypeID)) { case 'note': @@ -1752,24 +1754,28 @@ Zotero.Item.prototype.save = function() { if (newSourceItem) { var newSourceItemNotifierData = {}; - newSourceItemNotifierData[newSourceItem.id] = - { old: newSourceItem.serialize() }; + newSourceItemNotifierData[newSourceItem.id] = { + old: newSourceItem.serialize() + }; + Zotero.Notifier.trigger('modify', 'item', newSourceItem.id, newSourceItemNotifierData); } if (this._previousData) { - var oldSourceItemID = this._previousData.sourceItemID; - if (oldSourceItemID) { - var oldSourceItem = Zotero.Items.get(oldSourceItemID); + var oldSourceItemKey = this._previousData.sourceItemKey; + if (oldSourceItemKey) { + var oldSourceItem = Zotero.Items.getByKey(this.libraryID, oldSourceItemKey); } if (oldSourceItem) { var oldSourceItemNotifierData = {}; - oldSourceItemNotifierData[oldSourceItem.id] = - { old: oldSourceItem.serialize() }; + oldSourceItemNotifierData[oldSourceItem.id] = { + old: oldSourceItem.serialize() + }; + Zotero.Notifier.trigger('modify', 'item', oldSourceItem.id, oldSourceItemNotifierData); } - else if (oldSourceItemID) { + else if (oldSourceItemKey) { var oldSourceItemNotifierData = null; - Zotero.debug("Old source item " + oldSourceItemID - + " didn't exist in setSource()", 2); + Zotero.debug("Old source item " + oldSourceItemKey + + " didn't exist in Zotero.Item.save()", 2); } } @@ -1777,7 +1783,7 @@ Zotero.Item.prototype.save = function() { // If this was an independent item, remove from any collections // where it existed previously and add source instead if // there is one - if (!oldSourceItemID) { + if (!oldSourceItemKey) { var sql = "SELECT collectionID FROM collectionItems " + "WHERE itemID=?"; var changedCollections = Zotero.DB.columnQuery(sql, this.id); @@ -1946,15 +1952,6 @@ Zotero.Item.prototype.save = function() { Zotero.Notifier.trigger('modify', 'item', this.id, { old: this._previousData }); } - if (oldSourceItem) { - Zotero.Notifier.trigger('modify', 'item', - oldSourceItemID, oldSourceItemNotifierData); - } - if (newSourceItem) { - Zotero.Notifier.trigger('modify', 'item', - newSourceItem.id, newSourceItemNotifierData); - } - if (isNew) { var id = this.id; this._disabled = true; @@ -2003,7 +2000,9 @@ Zotero.Item.prototype.getSource = function() { } var sourceItem = Zotero.Items.getByLibraryAndKey(this.libraryID, this._sourceItem); if (!sourceItem) { - throw ("Source item for keyed source doesn't exist in Zotero.Item.getSource()"); + var msg = "Source item for keyed source doesn't exist in Zotero.Item.getSource()"; + var e = new Zotero.Error(msg, "MISSING_OBJECT"); + throw (e); } // Replace stored key with id this._sourceItem = sourceItem.id; @@ -3836,9 +3835,9 @@ Zotero.Item.prototype.toArray = function (mode) { // Notes if (this.isNote()) { arr.note = this.getNote(); - var parent = this.getSource(); + var parent = this.getSourceKey(); if (parent) { - arr.sourceItemID = parent; + arr.sourceItemKey = parent; } } @@ -3847,9 +3846,9 @@ Zotero.Item.prototype.toArray = function (mode) { // Attachments can have embedded notes arr.note = this.getNote(); - var parent = this.getSource(); + var parent = this.getSourceKey(); if (parent) { - arr.sourceItemID = parent; + arr.sourceItemKey = parent; } } @@ -4005,9 +4004,9 @@ Zotero.Item.prototype.serialize = function(mode) { } arr.note = this.getNote(); - var parent = this.getSource(); + var parent = this.getSourceKey(); if (parent) { - arr.sourceItemID = parent; + arr.sourceItemKey = parent; } } diff --git a/chrome/content/zotero/xpcom/error.js b/chrome/content/zotero/xpcom/error.js new file mode 100644 index 000000000..30f62d534 --- /dev/null +++ b/chrome/content/zotero/xpcom/error.js @@ -0,0 +1,17 @@ +Zotero.Error = function (message, error) { + this.name = "ZOTERO_ERROR"; + this.message = message; + if (parseInt(error) == error) { + this.error = error; + } + else { + this.error = Zotero.Error["ERROR_" + error] ? Zotero.Error["ERROR_" + error] : 0; + } +} + +Zotero.Error.ERROR_UNKNOWN = 0; +Zotero.Error.ERROR_MISSING_OBJECT = 1; + +Zotero.Error.prototype.toString = function () { + return this.message; +} diff --git a/chrome/content/zotero/xpcom/sync.js b/chrome/content/zotero/xpcom/sync.js index 6a252236b..18f479ff9 100644 --- a/chrome/content/zotero/xpcom/sync.js +++ b/chrome/content/zotero/xpcom/sync.js @@ -837,6 +837,7 @@ Zotero.Sync.Server = new function () { var _sessionID; var _sessionLock; var _throttleTimeout; + var _canAutoResetClient = true; function login(callback, callbackCallback) { var url = _serverURL + "login"; @@ -1356,6 +1357,8 @@ Zotero.Sync.Server = new function () { function resetClient() { + Zotero.debug("Resetting client"); + Zotero.DB.beginTransaction(); var sql = "DELETE FROM version WHERE schema IN " @@ -1498,11 +1501,20 @@ Zotero.Sync.Server = new function () { break; case 'FULL_SYNC_REQUIRED': - Zotero.DB.rollbackAllTransactions(); // Let current sync fail, and then do a full sync var background = Zotero.Sync.Runner.background; setTimeout(function () { + if (Zotero.Prefs.get('sync.debugNoAutoResetClient')) { + Components.utils.reportError("Skipping automatic client reset due to debug pref"); + return; + } + if (!Zotero.Sync.Server.canAutoResetClient) { + Components.utils.reportError("Client has already been auto-reset in Zotero.Sync.Server._checkResponse() -- manual sync required"); + return; + } + Zotero.Sync.Server.resetClient(); + Zotero.Sync.Server.canAutoResetClient = false; Zotero.Sync.Runner.sync(background); }, 1); break; @@ -1511,8 +1523,6 @@ Zotero.Sync.Server = new function () { if (!Zotero.Sync.Runner.background) { var tag = xmlhttp.responseXML.firstChild.getElementsByTagName('tag'); if (tag.length) { - Zotero.DB.rollbackAllTransactions(); - var tag = tag[0].firstChild.nodeValue; setTimeout(function () { var callback = function () { @@ -1667,6 +1677,28 @@ Zotero.Sync.Server = new function () { function _error(e, extraInfo) { + if (e.name && e.name == 'ZOTERO_ERROR') { + switch (e.error) { + case Zotero.Error.ERROR_MISSING_OBJECT: + // Let current sync fail, and then do a full sync + var background = Zotero.Sync.Runner.background; + setTimeout(function () { + if (Zotero.Prefs.get('sync.debugNoAutoResetClient')) { + Components.utils.reportError("Skipping automatic client reset due to debug pref"); + return; + } + if (!Zotero.Sync.Server.canAutoResetClient) { + Components.utils.reportError("Client has already been auto-reset in Zotero.Sync.Server._error() -- manual sync required"); + return; + } + Zotero.Sync.Server.resetClient(); + Zotero.Sync.Server.canAutoResetClient = false; + Zotero.Sync.Runner.sync(background); + }, 1); + break; + } + } + if (extraInfo) { // Server errors will generally be HTML extraInfo = Zotero.Utilities.prototype.unescapeHTML(extraInfo); @@ -1685,7 +1717,7 @@ Zotero.Sync.Server = new function () { Zotero.Sync.Runner.setError(e.message ? e.message : e); Zotero.Sync.Runner.reset(); - throw(e); + Components.utils.reportError(e); } } @@ -3001,9 +3033,11 @@ Zotero.Sync.Server.Data = new function() { // the item's creator block, where a copy should be provided if (!creatorObj) { if (creator.creator.length() == 0) { - throw ("Data for missing local creator " + var msg = "Data for missing local creator " + data.libraryID + "/" + creator.@key.toString() - + " not provided in Zotero.Sync.Server.Data.xmlToItem()"); + + " not provided in Zotero.Sync.Server.Data.xmlToItem()"; + var e = new Zotero.Error(msg, "MISSING_OBJECT"); + throw (e); } var l = creator.@libraryID.toString(); l = l ? l : null; @@ -3054,8 +3088,10 @@ Zotero.Sync.Server.Data = new function() { for each(var key in related) { var relItem = Zotero.Items.getByLibraryAndKey(item.libraryID, key); if (!relItem) { - throw ("Related item " + item.libraryID + "/" + key - + " doesn't exist in Zotero.Sync.Server.Data.xmlToItem()"); + var msg = "Related item " + item.libraryID + "/" + key + + " doesn't exist in Zotero.Sync.Server.Data.xmlToItem()"; + var e = new Zotero.Error(msg, "MISSING_OBJECT"); + throw (e); } relatedIDs.push(relItem.id); } @@ -3172,8 +3208,11 @@ Zotero.Sync.Server.Data = new function() { for each(var key in childItems) { var childItem = Zotero.Items.getByLibraryAndKey(collection.libraryID, key); if (!childItem) { - throw ("Missing child item " + key + " for collection " + collection.libraryID + "/" + collection.key - + " in Zotero.Sync.Server.Data.xmlToCollection()"); + var msg = "Missing child item " + key + " for collection " + + collection.libraryID + "/" + collection.key + + " in Zotero.Sync.Server.Data.xmlToCollection()"; + var e = new Zotero.Error(msg, "MISSING_OBJECT"); + throw (e); } childItemIDs.push(childItem.id); } @@ -3446,7 +3485,9 @@ Zotero.Sync.Server.Data = new function() { for each(var key in keys) { var item = Zotero.Items.getByLibraryAndKey(tag.libraryID, key); if (!item) { - throw ("Linked item " + key + " doesn't exist in Zotero.Sync.Server.Data.xmlToTag()"); + var msg = "Linked item " + key + " doesn't exist in Zotero.Sync.Server.Data.xmlToTag()"; + var e = new Zotero.Error(msg, "MISSING_OBJECT"); + throw (e); } ids.push(item.id); } diff --git a/components/zotero-service.js b/components/zotero-service.js index 83a322b84..7a1d52be8 100644 --- a/components/zotero-service.js +++ b/components/zotero-service.js @@ -42,6 +42,7 @@ var xpcomFiles = [ 'db', 'duplicate', 'enstyle', + 'error', 'file', 'fulltext', 'id', @@ -68,9 +69,15 @@ var xpcomFiles = [ ]; for (var i=0; i