Fix missing creators not being removed in item.fromJSON()

Apparently there's been a bug for years where removing a creator
remotely hasn't caused it to be removed locally via sync...

https://forums.zotero.org/discussion/94910/desktop-app-not-correctly-syncing
This commit is contained in:
Dan Stillman 2022-03-09 02:37:15 -05:00
parent 326d3425db
commit c7ece79f79
4 changed files with 92 additions and 5 deletions

View file

@ -1112,12 +1112,12 @@ Zotero.Item.prototype.setCreator = function (orderIndex, data, options = {}) {
* @param {Object[]} data - An array of creator data in internal or API JSON format
*/
Zotero.Item.prototype.setCreators = function (data, options = {}) {
// If empty array, clear all existing creators
if (!data.length) {
while (this.hasCreatorAt(0)) {
this.removeCreator(0);
// Clear existing creators beyond the number of provided ones
var numCreators = this.numCreators();
if (data.length < numCreators) {
while (this.hasCreatorAt(data.length)) {
this.removeCreator(data.length);
}
return;
}
for (let i = 0; i < data.length; i++) {

View file

@ -453,6 +453,9 @@ function createUnsavedDataObject(objectType, params = {}) {
if (params.title !== undefined || params.setTitle) {
obj.setField('title', params.title !== undefined ? params.title : Zotero.Utilities.randomString());
}
if (params.creators !== undefined) {
obj.setCreators(params.creators);
}
if (params.collections !== undefined) {
obj.setCollections(params.collections);
}

View file

@ -2267,6 +2267,38 @@ describe("Zotero.Item", function () {
assert.strictEqual(item.getField('accessDate'), '');
});
it("should remove missing creators and change existing", function () {
var item = new Zotero.Item('book');
item.setCreators(
[
{
name: "A",
creatorType: "author"
},
{
name: "B",
creatorType: "author"
},
{
name: "C",
creatorType: "author"
}
]
);
var json = item.toJSON();
// Remove creators, which should cause them to be cleared in fromJSON()
var newCreators = [
{
name: "D",
creatorType: "author"
}
];
json.creators = newCreators;
item.fromJSON(json);
assert.sameDeepMembers(item.getCreatorsJSON(), newCreators);
});
it("should remove item from collection if 'collections' property not provided", function* () {
var collection = yield createDataObject('collection');
// Create standalone attachment in collection

View file

@ -747,6 +747,58 @@ describe("Zotero.Sync.Data.Local", function() {
assert.propertyVal(cacheJSON.data, "name", changedName);
});
it("should remove creators that were removed remotely and change existing", async function () {
var libraryID = Zotero.Libraries.userLibraryID;
let item = await createDataObject(
'item',
{
version: 5,
creators: [
{
name: "A",
creatorType: "author"
},
{
name: "B",
creatorType: "author"
},
{
name: "C",
creatorType: "author"
}
]
}
);
let data = item.toJSON();
await Zotero.Sync.Data.Local.saveCacheObjects('item', libraryID, [data]);
var newCreators = [
{
name: "D",
creatorType: "author"
}
];
// Create remote version with removed creators
data.version = 10;
data.creators = newCreators;
let json = {
key: item.key,
version: 10,
data
};
await Zotero.Sync.Data.Local.processObjectsFromJSON(
'item', libraryID, [json], { stopOnError: true }
);
assert.equal(item.version, 10);
var creatorJSON = item.getCreatorsJSON();
assert.sameDeepMembers(creatorJSON, newCreators);
// Sync cache should match remote
var cacheJSON = await Zotero.Sync.Data.Local.getCacheObject('item', libraryID, data.key, data.version);
assert.sameDeepMembers(cacheJSON.data.creators, newCreators);
});
it("should delete older versions in sync cache after processing", function* () {
var libraryID = Zotero.Libraries.userLibraryID;