- Address "Delete reconciliation unimplemented for collections" message
- If collection items were added/removed on both sides, items from both sides were not always added - Fix a couple other related glitches which may or may not have shown up before the above issues were fixed
This commit is contained in:
parent
d8bdb6c11d
commit
67831bcb79
|
@ -2472,6 +2472,13 @@ Zotero.Schema = new function(){
|
||||||
Zotero.DB.query("UPDATE version SET schema='storage_webdav' WHERE schema='storage'");
|
Zotero.DB.query("UPDATE version SET schema='storage_webdav' WHERE schema='storage'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i==64) {
|
||||||
|
Zotero.DB.query("ALTER TABLE syncDeleteLog RENAME TO syncDeleteLogOld");
|
||||||
|
Zotero.DB.query("CREATE TABLE syncDeleteLog (\n syncObjectTypeID INT NOT NULL,\n libraryID INT NOT NULL,\n key TEXT NOT NULL,\n timestamp INT NOT NULL,\n UNIQUE (syncObjectTypeID, libraryID, key),\n FOREIGN KEY (syncObjectTypeID) REFERENCES syncObjectTypes(syncObjectTypeID)\n)");
|
||||||
|
Zotero.DB.query("INSERT INTO syncDeleteLog SELECT * FROM syncDeleteLogOld");
|
||||||
|
Zotero.DB.query("DROP TABLE syncDeleteLogOld");
|
||||||
|
}
|
||||||
|
|
||||||
Zotero.wait();
|
Zotero.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -374,7 +374,7 @@ Zotero.Sync.EventListener = new function () {
|
||||||
Zotero.DB.beginTransaction();
|
Zotero.DB.beginTransaction();
|
||||||
|
|
||||||
if (event == 'delete') {
|
if (event == 'delete') {
|
||||||
var sql = "INSERT INTO syncDeleteLog VALUES (?, ?, ?, ?)";
|
var sql = "REPLACE INTO syncDeleteLog VALUES (?, ?, ?, ?)";
|
||||||
var syncStatement = Zotero.DB.getStatement(sql);
|
var syncStatement = Zotero.DB.getStatement(sql);
|
||||||
|
|
||||||
if (isItem && Zotero.Sync.Storage.active) {
|
if (isItem && Zotero.Sync.Storage.active) {
|
||||||
|
@ -2337,6 +2337,7 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
Zotero.debug("Processing remote " + type + " " + libraryID + "/" + key, 4);
|
Zotero.debug("Processing remote " + type + " " + libraryID + "/" + key, 4);
|
||||||
var isNewObject;
|
var isNewObject;
|
||||||
var localDelete = false;
|
var localDelete = false;
|
||||||
|
var skipCR = false;
|
||||||
|
|
||||||
// Get local object with same library and key
|
// Get local object with same library and key
|
||||||
var obj = Zotero[Types].getByLibraryAndKey(libraryID, key);
|
var obj = Zotero[Types].getByLibraryAndKey(libraryID, key);
|
||||||
|
@ -2391,8 +2392,6 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
}
|
}
|
||||||
// Mark other types for conflict resolution
|
// Mark other types for conflict resolution
|
||||||
else {
|
else {
|
||||||
var skipCR = false;
|
|
||||||
|
|
||||||
// Skip item if dateModified is the only modified
|
// Skip item if dateModified is the only modified
|
||||||
// field (and no linked creators changed)
|
// field (and no linked creators changed)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -2455,8 +2454,7 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'collection':
|
case 'collection':
|
||||||
// TODO: move childItemStore to syncSession
|
var changed = _mergeCollection(obj, remoteObj, syncSession);
|
||||||
var changed = _mergeCollection(obj, remoteObj, childItemStore, syncSession);
|
|
||||||
if (!changed) {
|
if (!changed) {
|
||||||
syncSession.removeFromUpdated(obj);
|
syncSession.removeFromUpdated(obj);
|
||||||
continue;
|
continue;
|
||||||
|
@ -2476,7 +2474,6 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
// TODO: order reconcile by parent/child?
|
// TODO: order reconcile by parent/child?
|
||||||
|
|
||||||
if (!skipCR) {
|
if (!skipCR) {
|
||||||
Zotero.debug("ADDING " + type + " TO CR");
|
|
||||||
toReconcile.push([
|
toReconcile.push([
|
||||||
obj,
|
obj,
|
||||||
remoteObj
|
remoteObj
|
||||||
|
@ -2512,15 +2509,16 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
localDelete = true;
|
localDelete = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Auto-restore locally deleted tags that have
|
// Auto-restore locally deleted tags and collections that
|
||||||
// changed remotely
|
// have changed remotely
|
||||||
case 'tag':
|
case 'tag':
|
||||||
|
case 'collection':
|
||||||
syncSession.removeFromDeleted(fakeObj);
|
syncSession.removeFromDeleted(fakeObj);
|
||||||
var msg = _generateAutoChangeMessage(
|
var msg = _generateAutoChangeMessage(
|
||||||
type, null, xmlNode.@name.toString()
|
type, null, xmlNode.@name.toString()
|
||||||
);
|
);
|
||||||
alert(msg);
|
alert(msg);
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
alert('Delete reconciliation unimplemented for ' + types);
|
alert('Delete reconciliation unimplemented for ' + types);
|
||||||
|
@ -2539,7 +2537,11 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or overwrite locally
|
// Create or overwrite locally
|
||||||
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode, obj);
|
//
|
||||||
|
// If we skipped CR above, we already have an object to use
|
||||||
|
if (!skipCR) {
|
||||||
|
obj = Zotero.Sync.Server.Data['xmlTo' + Type](xmlNode, obj);
|
||||||
|
}
|
||||||
|
|
||||||
if (isNewObject && type == 'tag') {
|
if (isNewObject && type == 'tag') {
|
||||||
// If a local tag matches the name of a different remote tag,
|
// If a local tag matches the name of a different remote tag,
|
||||||
|
@ -2653,6 +2655,7 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'tag':
|
case 'tag':
|
||||||
|
case 'collection':
|
||||||
var msg = _generateAutoChangeMessage(
|
var msg = _generateAutoChangeMessage(
|
||||||
type, obj.name, null
|
type, obj.name, null
|
||||||
);
|
);
|
||||||
|
@ -2961,7 +2964,7 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function _mergeCollection(localObj, remoteObj, childItemStore, syncSession) {
|
function _mergeCollection(localObj, remoteObj, syncSession) {
|
||||||
var diff = localObj.diff(remoteObj, false, true);
|
var diff = localObj.diff(remoteObj, false, true);
|
||||||
if (!diff) {
|
if (!diff) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2972,20 +2975,18 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
|
|
||||||
// Local is newer
|
// Local is newer
|
||||||
if (diff[0].primary.dateModified > diff[1].primary.dateModified) {
|
if (diff[0].primary.dateModified > diff[1].primary.dateModified) {
|
||||||
|
Zotero.debug("Local is newer");
|
||||||
var remoteIsTarget = false;
|
var remoteIsTarget = false;
|
||||||
var targetObj = localObj;
|
var targetObj = localObj;
|
||||||
var targetDiff = diff[0];
|
|
||||||
var otherDiff = diff[1];
|
|
||||||
}
|
}
|
||||||
// Remote is newer
|
// Remote is newer
|
||||||
else {
|
else {
|
||||||
|
Zotero.debug("Remote is newer");
|
||||||
var remoteIsTarget = true;
|
var remoteIsTarget = true;
|
||||||
var targetObj = remoteObj;
|
var targetObj = remoteObj;
|
||||||
var targetDiff = diff[1];
|
|
||||||
var otherDiff = diff[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetDiff.fields.name) {
|
if (diff[0].fields.name) {
|
||||||
if (!syncSession.suppressWarnings) {
|
if (!syncSession.suppressWarnings) {
|
||||||
var msg = _generateAutoChangeMessage(
|
var msg = _generateAutoChangeMessage(
|
||||||
'collection', diff[0].fields.name, diff[1].fields.name, remoteIsTarget
|
'collection', diff[0].fields.name, diff[1].fields.name, remoteIsTarget
|
||||||
|
@ -2997,27 +2998,26 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
|
|
||||||
// Check for child collections in the other object
|
// Check for child collections in the other object
|
||||||
// that aren't in the target one
|
// that aren't in the target one
|
||||||
if (otherDiff.childCollections.length) {
|
if (diff[1].childCollections.length) {
|
||||||
// TODO: log
|
// TODO: log
|
||||||
// TODO: add
|
// TODO: add
|
||||||
throw ("Collection hierarchy conflict resolution is unimplemented");
|
throw ("Collection hierarchy conflict resolution is unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add items in other object to target one
|
// Add items to local object, which is what's saved
|
||||||
if (otherDiff.childItems.length) {
|
if (diff[1].childItems.length) {
|
||||||
var childItems = targetObj.getChildItems(true);
|
var childItems = localObj.getChildItems(true);
|
||||||
if (childItems) {
|
if (childItems) {
|
||||||
targetObj.childItems = childItems.concat(otherDiff.childItems);
|
localObj.childItems = childItems.concat(diff[1].childItems);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
targetObj.childItems = otherDiff.childItems;
|
localObj.childItems = diff[1].childItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!syncSession.suppressWarnings) {
|
if (!syncSession.suppressWarnings) {
|
||||||
var msg = _generateCollectionItemMergeMessage(
|
var msg = _generateCollectionItemMergeMessage(
|
||||||
targetObj.name,
|
targetObj.name,
|
||||||
otherDiff.childItems,
|
diff[0].childItems.concat(diff[1].childItems)
|
||||||
remoteIsTarget
|
|
||||||
);
|
);
|
||||||
// TODO: log rather than alert
|
// TODO: log rather than alert
|
||||||
alert(msg);
|
alert(msg);
|
||||||
|
@ -3123,25 +3123,18 @@ Zotero.Sync.Server.Data = new function() {
|
||||||
/**
|
/**
|
||||||
* @param {String} collectionName
|
* @param {String} collectionName
|
||||||
* @param {Integer[]} addedItemIDs
|
* @param {Integer[]} addedItemIDs
|
||||||
* @param {Boolean} remoteIsTarget
|
|
||||||
*/
|
*/
|
||||||
function _generateCollectionItemMergeMessage(collectionName, addedItemIDs, remoteIsTarget) {
|
function _generateCollectionItemMergeMessage(collectionName, addedItemIDs) {
|
||||||
// TODO: localize
|
// TODO: localize
|
||||||
var introMsg = "Items in the collection '" + collectionName + "' have been "
|
var introMsg = "Items in the collection '" + collectionName + "' have been "
|
||||||
+ "added and/or removed in multiple locations."
|
+ "added and/or removed in multiple locations."
|
||||||
|
|
||||||
introMsg += " ";
|
introMsg += " The following items have been added to the collection:";
|
||||||
if (remoteIsTarget) {
|
|
||||||
introMsg += "The following items have been added to the remote collection:";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
introMsg += "The following items have been added to the local collection:";
|
|
||||||
}
|
|
||||||
var itemText = [];
|
var itemText = [];
|
||||||
for each(var id in addedItemIDs) {
|
for each(var id in addedItemIDs) {
|
||||||
var item = Zotero.Items.get(id);
|
var item = Zotero.Items.get(id);
|
||||||
var title = item.getField('title');
|
var title = item.getField('title');
|
||||||
var text = " - " + title;
|
var text = " \u2022 " + title;
|
||||||
var firstCreator = item.getField('firstCreator');
|
var firstCreator = item.getField('firstCreator');
|
||||||
if (firstCreator) {
|
if (firstCreator) {
|
||||||
text += " (" + firstCreator + ")";
|
text += " (" + firstCreator + ")";
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- 63
|
-- 64
|
||||||
|
|
||||||
-- This file creates tables containing user-specific data for new users --
|
-- This file creates tables containing user-specific data for new users --
|
||||||
-- any changes made here must be mirrored in transition steps in schema.js::_migrateSchema()
|
-- any changes made here must be mirrored in transition steps in schema.js::_migrateSchema()
|
||||||
|
@ -258,10 +258,10 @@ CREATE INDEX fulltextItemWords_itemID ON fulltextItemWords(itemID);
|
||||||
|
|
||||||
CREATE TABLE syncDeleteLog (
|
CREATE TABLE syncDeleteLog (
|
||||||
syncObjectTypeID INT NOT NULL,
|
syncObjectTypeID INT NOT NULL,
|
||||||
libraryID INT,
|
libraryID INT NOT NULL,
|
||||||
key TEXT NOT NULL,
|
key TEXT NOT NULL,
|
||||||
timestamp INT NOT NULL,
|
timestamp INT NOT NULL,
|
||||||
UNIQUE (libraryID, key),
|
UNIQUE (syncObjectTypeID, libraryID, key),
|
||||||
FOREIGN KEY (syncObjectTypeID) REFERENCES syncObjectTypes(syncObjectTypeID)
|
FOREIGN KEY (syncObjectTypeID) REFERENCES syncObjectTypes(syncObjectTypeID)
|
||||||
);
|
);
|
||||||
CREATE INDEX syncDeleteLog_timestamp ON syncDeleteLog(timestamp);
|
CREATE INDEX syncDeleteLog_timestamp ON syncDeleteLog(timestamp);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user