- Add triggers for full sync on various errors

- Add Zotero.Error(message, error) constructor to create a throwable error object with an error code
- Allow only one automatic client reset between manual syncs
- Fix "Source item for keyed source doesn't exist in Zotero.Item.getSource()" error
- Object produced by item.serialize() now contains .sourceItemKey instead of .sourceItemID
- Better error logging for missing XPCOM files
This commit is contained in:
Dan Stillman 2009-07-06 10:13:02 +00:00
parent 46209bd4f3
commit 41437738b0
5 changed files with 110 additions and 44 deletions

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -42,6 +42,7 @@ var xpcomFiles = [
'db',
'duplicate',
'enstyle',
'error',
'file',
'fulltext',
'id',
@ -68,9 +69,15 @@ var xpcomFiles = [
];
for (var i=0; i<xpcomFiles.length; i++) {
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://zotero/content/xpcom/" + xpcomFiles[i] + ".js");
try {
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://zotero/content/xpcom/" + xpcomFiles[i] + ".js");
}
catch (e) {
Components.utils.reportError("Error loading " + xpcomFiles[i] + ".js");
throw (e);
}
}