Don't clear the hidden flag when refreshing retractions data

_addEntry() wrote the row with REPLACE INTO, listing only itemID and
data, so flag reverted to its default of 0. It's called for every match
on every update, not just new ones, so a retraction the user had hidden
came back as soon as the list changed and Zotero restarted.
This commit is contained in:
Dan Stillman 2026-09-04 15:07:15 -04:00
parent 53bcd30a5f
commit e88b7ee10f
2 changed files with 57 additions and 1 deletions

View file

@ -911,7 +911,9 @@ Zotero.Retractions = {
delete o.retractionDOI;
delete o.retractionPMID;
var sql = "REPLACE INTO retractedItems (itemID, data) VALUES (?, ?)";
// Leave the flag alone, so a hidden retraction stays hidden across refreshes
var sql = "INSERT INTO retractedItems (itemID, data) VALUES (?, ?) "
+ "ON CONFLICT(itemID) DO UPDATE SET data=excluded.data";
await Zotero.DB.queryAsync(sql, [itemID, JSON.stringify(o)]);
var item = await Zotero.Items.getAsync(itemID);

View file

@ -257,6 +257,60 @@ describe("Retractions", function () {
Zotero.Retractions._version = version;
}
});
it("should keep a hidden retraction hidden across an update", async function () {
var doi = '10.1234/defgh';
var hash = Zotero.Utilities.Internal.sha1(doi);
var line = Zotero.Retractions.TYPE_DOI + hash.substr(0, 5) + ' 12345\n';
var etags = ['first', 'second'];
server.respond(function (req) {
if (req.method == 'GET' && req.url == baseURL + 'list') {
req.respond(
200,
{ 'Content-Type': 'text/plain', 'ETag': etags.shift() || 'second' },
line
);
}
else if (req.method == 'POST' && req.url == baseURL + 'search') {
req.respond(
200,
{ 'Content-Type': 'application/json' },
JSON.stringify([
{
doi: hash,
retractionDOI: '10.1234/efghi',
date: '2019-01-02',
reasons: ["Error in Data"],
urls: []
}
])
);
}
});
await Zotero.Retractions.updateFromServer();
let promise = waitForItemEvent('refresh');
let item = createUnsavedDataObject('item', { itemType: 'journalArticle' });
item.setField('DOI', doi);
await item.saveTx();
await promise;
assert.isTrue(Zotero.Retractions.isRetracted(item));
await Zotero.Retractions.hideRetraction(item);
assert.isFalse(Zotero.Retractions.isRetracted(item));
// The stored flag is what survives a restart, so it has to outlast an update
await Zotero.Retractions.updateFromServer();
assert.isFalse(Zotero.Retractions.isRetracted(item));
assert.equal(
await Zotero.DB.valueQueryAsync(
"SELECT flag FROM retractedItems WHERE itemID=?", item.id
),
Zotero.Retractions.FLAG_HIDDEN
);
});
});