- 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:
Dan Stillman 2009-10-12 08:14:11 +00:00
parent d8bdb6c11d
commit 67831bcb79
3 changed files with 37 additions and 37 deletions

View File

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

View File

@ -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 + ")";

View File

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