Fix various conflict resolution bugs
Among other things, when choosing the local side for a conflict, the remote version could still end up being saved.
This commit is contained in:
parent
7f8699b937
commit
f0770fa84d
5 changed files with 235 additions and 134 deletions
|
@ -168,7 +168,6 @@ var Zotero_Merge_Window = new function () {
|
|||
if (x.data) {
|
||||
x.data.version = _conflicts[i][x.selected].version;
|
||||
}
|
||||
a[i] = x.data;
|
||||
})
|
||||
|
||||
_io.dataOut = _merged;
|
||||
|
|
|
@ -880,10 +880,9 @@ Zotero.Sync.Data.Engine.prototype._downloadDeletions = Zotero.Promise.coroutine(
|
|||
function (chunk) {
|
||||
return Zotero.DB.executeTransaction(function* () {
|
||||
for (let json of chunk) {
|
||||
if (!json.deleted) continue;
|
||||
let obj = objectsClass.getByLibraryAndKey(
|
||||
this.libraryID, json.key
|
||||
);
|
||||
let data = json.data;
|
||||
if (!data.deleted) continue;
|
||||
let obj = objectsClass.getByLibraryAndKey(this.libraryID, data.key);
|
||||
if (!obj) {
|
||||
Zotero.logError("Remotely deleted " + objectType
|
||||
+ " didn't exist after conflict resolution");
|
||||
|
|
|
@ -835,7 +835,6 @@ Zotero.Sync.Data.Local = {
|
|||
let cachedJSON = yield this.getCacheObject(
|
||||
objectType, obj.libraryID, obj.key, obj.version
|
||||
);
|
||||
|
||||
let result = this._reconcileChanges(
|
||||
objectType,
|
||||
cachedJSON.data,
|
||||
|
@ -844,20 +843,21 @@ Zotero.Sync.Data.Local = {
|
|||
['mtime', 'md5', 'dateAdded', 'dateModified']
|
||||
);
|
||||
|
||||
// If no changes, update local version number and mark as synced
|
||||
// If no changes, just update local version number and mark as synced
|
||||
if (!result.changes.length && !result.conflicts.length) {
|
||||
Zotero.debug("No remote changes to apply to local "
|
||||
+ objectType + " " + obj.libraryKey);
|
||||
|
||||
saveOptions.skipData = true;
|
||||
// If local object is different but we ignored the changes
|
||||
// (e.g., ISBN hyphenation), save as unsynced. Since we're skipping
|
||||
// data, the local version won't be overwritten.
|
||||
if (result.localChanged) {
|
||||
saveOptions.saveAsUnsynced = true;
|
||||
}
|
||||
let saveResults = yield this._saveObjectFromJSON(
|
||||
obj,
|
||||
jsonObject,
|
||||
{
|
||||
skipData: true,
|
||||
notifierQueue,
|
||||
// Save as unsynced
|
||||
saveAsChanged: !!result.localChanged
|
||||
}
|
||||
saveOptions
|
||||
);
|
||||
results.push(saveResults);
|
||||
if (!saveResults.processed) {
|
||||
|
@ -902,11 +902,6 @@ Zotero.Sync.Data.Local = {
|
|||
jsonDataLocal[x] = jsonData[x];
|
||||
})
|
||||
jsonObject.data = jsonDataLocal;
|
||||
|
||||
// Save as unsynced
|
||||
if (results.localChanged) {
|
||||
saveOptions.saveAsChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Object doesn't exist locally
|
||||
|
@ -1190,19 +1185,26 @@ Zotero.Sync.Data.Local = {
|
|||
let notifierQueues = [];
|
||||
try {
|
||||
for (let i = 0; i < mergeData.length; i++) {
|
||||
// Batch notifier updates
|
||||
// Batch notifier updates, despite multiple transactions
|
||||
if (notifierQueues.length == batchSize) {
|
||||
yield Zotero.Notifier.commit(notifierQueues);
|
||||
notifierQueues = [];
|
||||
}
|
||||
let notifierQueue = new Zotero.Notifier.Queue;
|
||||
|
||||
let json = mergeData[i];
|
||||
let json = mergeData[i].data;
|
||||
|
||||
let saveOptions = {};
|
||||
Object.assign(saveOptions, options);
|
||||
// Tell _saveObjectFromJSON() to save as unsynced
|
||||
saveOptions.saveAsChanged = true;
|
||||
// If choosing local object, save as unsynced with remote version (or 0 if remote is
|
||||
// deleted) and remote object in cache, to simulate a save and edit
|
||||
if (mergeData[i].selected == 'left') {
|
||||
json.version = conflicts[i].right.version || 0;
|
||||
saveOptions.saveAsUnsynced = true;
|
||||
if (conflicts[i].right.version) {
|
||||
saveOptions.cacheObject = conflicts[i].right;
|
||||
}
|
||||
}
|
||||
saveOptions.notifierQueue = notifierQueue;
|
||||
|
||||
// Errors have to be thrown in order to roll back the transaction, so catch
|
||||
|
@ -1259,9 +1261,7 @@ Zotero.Sync.Data.Local = {
|
|||
saveOptions.skipCache = true;
|
||||
}
|
||||
|
||||
let saveResults = yield this._saveObjectFromJSON(
|
||||
obj, json, saveOptions
|
||||
);
|
||||
let saveResults = yield this._saveObjectFromJSON(obj, json, saveOptions);
|
||||
results.push(saveResults);
|
||||
if (!saveResults.processed) {
|
||||
throw saveResults.error;
|
||||
|
@ -1360,7 +1360,7 @@ Zotero.Sync.Data.Local = {
|
|||
yield this._checkAttachmentForDownload(obj, json.data.mtime, options.isNewObject);
|
||||
}
|
||||
obj.version = json.data.version;
|
||||
if (!options.saveAsChanged) {
|
||||
if (!options.saveAsUnsynced) {
|
||||
obj.synced = true;
|
||||
}
|
||||
yield obj.save({
|
||||
|
@ -1374,13 +1374,17 @@ Zotero.Sync.Data.Local = {
|
|||
return;
|
||||
}
|
||||
});
|
||||
yield this.saveCacheObject(obj.objectType, obj.libraryID, json.data);
|
||||
results.processed = true;
|
||||
|
||||
let cacheJSON = options.cacheObject ? options.cacheObject : json.data;
|
||||
yield this.saveCacheObject(obj.objectType, obj.libraryID, cacheJSON);
|
||||
// Delete older versions of the object in the cache
|
||||
yield this.deleteCacheObjectVersions(
|
||||
obj.objectType, obj.libraryID, json.key, null, json.version - 1
|
||||
obj.objectType,
|
||||
obj.libraryID,
|
||||
json.key,
|
||||
null,
|
||||
cacheJSON.version - 1
|
||||
);
|
||||
results.processed = true;
|
||||
|
||||
// Delete from sync queue
|
||||
yield this._removeObjectFromSyncQueue(obj.objectType, obj.libraryID, json.key);
|
||||
|
@ -1519,7 +1523,7 @@ Zotero.Sync.Data.Local = {
|
|||
|
||||
return {
|
||||
changes: changeset2,
|
||||
conflicts: conflicts
|
||||
conflicts
|
||||
};
|
||||
},
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue