Add flags to disable retraction warnings
Separate flags for hiding the retraction altogether and for hiding citation warnings for it New functions: Zotero.Retractions.hideRetraction(item) Zotero.Retractions.shouldShowCitationWarning(item) Zotero.Retractions.disableCitationWarningsForItem(item) Addresses #1710
This commit is contained in:
parent
f49d5805cd
commit
0beddb9680
5 changed files with 126 additions and 15 deletions
|
@ -1039,7 +1039,7 @@ Zotero.Search.prototype._buildQuery = Zotero.Promise.coroutine(function* () {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retracted) {
|
if (retracted) {
|
||||||
sql += " AND (itemID IN (SELECT itemID FROM retractedItems))";
|
sql += " AND (itemID IN (SELECT itemID FROM retractedItems WHERE flag=0))";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (publications) {
|
if (publications) {
|
||||||
|
|
|
@ -28,6 +28,10 @@ Zotero.Retractions = {
|
||||||
TYPE_PMID: 'p',
|
TYPE_PMID: 'p',
|
||||||
TYPE_NAMES: ['DOI', 'PMID'],
|
TYPE_NAMES: ['DOI', 'PMID'],
|
||||||
|
|
||||||
|
FLAG_NORMAL: 0,
|
||||||
|
FLAG_HIDDEN: 1,
|
||||||
|
FLAG_NO_CITATION_WARNING: 2,
|
||||||
|
|
||||||
_prefObserverRegistered: false,
|
_prefObserverRegistered: false,
|
||||||
_initialized: false,
|
_initialized: false,
|
||||||
_version: 1,
|
_version: 1,
|
||||||
|
@ -60,13 +64,13 @@ Zotero.Retractions = {
|
||||||
|
|
||||||
// Load existing retracted items
|
// Load existing retracted items
|
||||||
var rows = await Zotero.DB.queryAsync(
|
var rows = await Zotero.DB.queryAsync(
|
||||||
"SELECT libraryID, itemID, DI.itemID IS NOT NULL AS deleted FROM items "
|
"SELECT libraryID, itemID, DI.itemID IS NOT NULL AS deleted, RI.flag FROM items "
|
||||||
+ "JOIN retractedItems USING (itemID) "
|
+ "JOIN retractedItems RI USING (itemID) "
|
||||||
+ "LEFT JOIN deletedItems DI USING (itemID)"
|
+ "LEFT JOIN deletedItems DI USING (itemID)"
|
||||||
);
|
);
|
||||||
for (let row of rows) {
|
for (let row of rows) {
|
||||||
this._retractedItems.add(row.itemID);
|
this._retractedItems.set(row.itemID, row.flag);
|
||||||
if (!row.deleted) {
|
if (!row.deleted && row.flag != this.FLAG_HIDDEN) {
|
||||||
if (!this._retractedItemsByLibrary[row.libraryID]) {
|
if (!this._retractedItemsByLibrary[row.libraryID]) {
|
||||||
this._retractedItemsByLibrary[row.libraryID] = new Set();
|
this._retractedItemsByLibrary[row.libraryID] = new Set();
|
||||||
}
|
}
|
||||||
|
@ -88,7 +92,7 @@ Zotero.Retractions = {
|
||||||
this._itemKeys = {};
|
this._itemKeys = {};
|
||||||
this._queuedItems = new Set();
|
this._queuedItems = new Set();
|
||||||
this._queuedPrefixStrings = new Set();
|
this._queuedPrefixStrings = new Set();
|
||||||
this._retractedItems = new Set();
|
this._retractedItems = new Map();
|
||||||
this._retractedItemsByLibrary = {};
|
this._retractedItemsByLibrary = {};
|
||||||
this._librariesWithRetractions = new Set();
|
this._librariesWithRetractions = new Set();
|
||||||
this._cacheVersion = null;
|
this._cacheVersion = null;
|
||||||
|
@ -99,11 +103,53 @@ Zotero.Retractions = {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Zotero.Item}
|
* If item was retracted and the retraction hasn't been hidden
|
||||||
|
*
|
||||||
|
* @param {Zotero.Item} item
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
isRetracted: function (item) {
|
isRetracted: function (item) {
|
||||||
return this._retractedItems.has(item.id);
|
var flag = this._retractedItems.get(item.id);
|
||||||
|
return flag !== undefined && flag !== this.FLAG_HIDDEN;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If item was retracted and hasn't been marked to not show citation warnings
|
||||||
|
*
|
||||||
|
* @param {Zotero.Item}
|
||||||
|
* @return {Boolean}
|
||||||
|
*/
|
||||||
|
shouldShowCitationWarning: function (item) {
|
||||||
|
return this._retractedItems.get(item.id) === this.FLAG_NORMAL;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show any future retraction warnings for this item
|
||||||
|
*
|
||||||
|
* @param {Zotero.Item} item
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
hideRetraction: async function (item) {
|
||||||
|
return this._updateItemFlag(item, this.FLAG_HIDDEN);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show future citation warnings for this item
|
||||||
|
*
|
||||||
|
* @param {Zotero.Item} item
|
||||||
|
* @return {Promise}
|
||||||
|
*/
|
||||||
|
disableCitationWarningsForItem: async function (item) {
|
||||||
|
return this._updateItemFlag(item, this.FLAG_NO_CITATION_WARNING);
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateItemFlag: async function (item, flag) {
|
||||||
|
this._retractedItems.set(item.id, flag);
|
||||||
|
await Zotero.DB.queryAsync(
|
||||||
|
"UPDATE retractedItems SET flag=? WHERE itemID=?",
|
||||||
|
[flag, item.id]
|
||||||
|
);
|
||||||
|
await Zotero.Notifier.trigger('modify', 'item', [item.id]);
|
||||||
},
|
},
|
||||||
|
|
||||||
getRetractionsFromJSON: Zotero.serial(async function (jsonItems) {
|
getRetractionsFromJSON: Zotero.serial(async function (jsonItems) {
|
||||||
|
@ -369,8 +415,9 @@ Zotero.Retractions = {
|
||||||
// handled for newly detected items in _addEntry(), which gets called by
|
// handled for newly detected items in _addEntry(), which gets called by
|
||||||
// _updateItem() above after a delay (such that the item won't yet be retracted
|
// _updateItem() above after a delay (such that the item won't yet be retracted
|
||||||
// here).
|
// here).
|
||||||
if (this._retractedItems.has(item.id)) {
|
let flag = this._retractedItems.get(item.id);
|
||||||
if (item.deleted) {
|
if (flag !== undefined) {
|
||||||
|
if (item.deleted || flag == this.FLAG_HIDDEN) {
|
||||||
await this._removeLibraryRetractedItem(item.libraryID, item.id);
|
await this._removeLibraryRetractedItem(item.libraryID, item.id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -577,7 +624,7 @@ Zotero.Retractions = {
|
||||||
// Remove existing retracted items that no longer match
|
// Remove existing retracted items that no longer match
|
||||||
var removed = 0;
|
var removed = 0;
|
||||||
if (removeExisting) {
|
if (removeExisting) {
|
||||||
for (let itemID of this._retractedItems) {
|
for (let itemID of this._retractedItems.keys()) {
|
||||||
if (!allItemIDs.has(itemID)) {
|
if (!allItemIDs.has(itemID)) {
|
||||||
let item = await Zotero.Items.getAsync(itemID);
|
let item = await Zotero.Items.getAsync(itemID);
|
||||||
await this._removeEntry(itemID, item.libraryID);
|
await this._removeEntry(itemID, item.libraryID);
|
||||||
|
@ -800,13 +847,17 @@ Zotero.Retractions = {
|
||||||
delete o.retractionDOI;
|
delete o.retractionDOI;
|
||||||
delete o.retractionPMID;
|
delete o.retractionPMID;
|
||||||
|
|
||||||
var sql = "REPLACE INTO retractedItems VALUES (?, ?)";
|
var sql = "REPLACE INTO retractedItems (itemID, data) VALUES (?, ?)";
|
||||||
await Zotero.DB.queryAsync(sql, [itemID, JSON.stringify(o)]);
|
await Zotero.DB.queryAsync(sql, [itemID, JSON.stringify(o)]);
|
||||||
|
|
||||||
var item = await Zotero.Items.getAsync(itemID);
|
var item = await Zotero.Items.getAsync(itemID);
|
||||||
var libraryID = item.libraryID;
|
var libraryID = item.libraryID;
|
||||||
this._retractedItems.add(itemID);
|
// Check whether the retraction is already hidden by the user
|
||||||
if (!item.deleted) {
|
var flag = this._retractedItems.get(itemID);
|
||||||
|
if (flag === undefined) {
|
||||||
|
this._retractedItems.set(itemID, this.FLAG_NORMAL);
|
||||||
|
}
|
||||||
|
if (!item.deleted && flag !== this.FLAG_HIDDEN) {
|
||||||
if (!this._retractedItemsByLibrary[libraryID]) {
|
if (!this._retractedItemsByLibrary[libraryID]) {
|
||||||
this._retractedItemsByLibrary[libraryID] = new Set();
|
this._retractedItemsByLibrary[libraryID] = new Set();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2518,6 +2518,10 @@ Zotero.Schema = new function(){
|
||||||
yield Zotero.DB.queryAsync("CREATE TABLE IF NOT EXISTS retractedItems (\n itemID INTEGER PRIMARY KEY,\n data TEXT,\n FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE\n);");
|
yield Zotero.DB.queryAsync("CREATE TABLE IF NOT EXISTS retractedItems (\n itemID INTEGER PRIMARY KEY,\n data TEXT,\n FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE\n);");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (i == 105) {
|
||||||
|
yield Zotero.DB.queryAsync("ALTER TABLE retractedItems ADD COLUMN flag INT DEFAULT 0");
|
||||||
|
}
|
||||||
|
|
||||||
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
|
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-- 104
|
-- 105
|
||||||
|
|
||||||
-- Copyright (c) 2009 Center for History and New Media
|
-- Copyright (c) 2009 Center for History and New Media
|
||||||
-- George Mason University, Fairfax, Virginia, USA
|
-- George Mason University, Fairfax, Virginia, USA
|
||||||
|
@ -289,6 +289,7 @@ CREATE TABLE publicationsItems (
|
||||||
CREATE TABLE retractedItems (
|
CREATE TABLE retractedItems (
|
||||||
itemID INTEGER PRIMARY KEY,
|
itemID INTEGER PRIMARY KEY,
|
||||||
data TEXT,
|
data TEXT,
|
||||||
|
flag INT DEFAULT 0,
|
||||||
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE
|
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,23 @@ describe("Retractions", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe("#shouldShowCitationWarning()", function () {
|
||||||
|
it("should return false if citation warning is hidden", async function () {
|
||||||
|
var item = await createRetractedItem();
|
||||||
|
assert.isTrue(Zotero.Retractions.shouldShowCitationWarning(item));
|
||||||
|
await Zotero.Retractions.disableCitationWarningsForItem(item);
|
||||||
|
assert.isFalse(Zotero.Retractions.shouldShowCitationWarning(item));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should return false if retraction is hidden", async function () {
|
||||||
|
var item = await createRetractedItem();
|
||||||
|
assert.isTrue(Zotero.Retractions.shouldShowCitationWarning(item));
|
||||||
|
await Zotero.Retractions.hideRetraction(item);
|
||||||
|
assert.isFalse(Zotero.Retractions.shouldShowCitationWarning(item));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("#getRetractionsFromJSON()", function () {
|
describe("#getRetractionsFromJSON()", function () {
|
||||||
it("should identify object with retracted DOI", async function () {
|
it("should identify object with retracted DOI", async function () {
|
||||||
var spy = sinon.spy(Zotero.HTTP, 'request');
|
var spy = sinon.spy(Zotero.HTTP, 'request');
|
||||||
|
@ -275,6 +292,44 @@ describe("Retractions", function() {
|
||||||
assert.equal(zp.collectionsView.selectedTreeRow.id, "L" + userLibraryID);
|
assert.equal(zp.collectionsView.selectedTreeRow.id, "L" + userLibraryID);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should hide Retracted Items collection when last retracted item is marked as hidden", async function () {
|
||||||
|
var rowID = "R" + userLibraryID;
|
||||||
|
|
||||||
|
// Create item
|
||||||
|
var item = await createRetractedItem();
|
||||||
|
assert.ok(zp.collectionsView.getRowIndexByID(rowID));
|
||||||
|
|
||||||
|
// Select Retracted Items collection
|
||||||
|
await zp.collectionsView.selectByID(rowID);
|
||||||
|
await waitForItemsLoad(win);
|
||||||
|
|
||||||
|
await Zotero.Retractions.hideRetraction(item);
|
||||||
|
|
||||||
|
await Zotero.Promise.delay(50);
|
||||||
|
// Retracted Items should be gone
|
||||||
|
assert.isFalse(zp.collectionsView.getRowIndexByID(rowID));
|
||||||
|
// And My Library should be selected
|
||||||
|
assert.equal(zp.collectionsView.selectedTreeRow.id, "L" + userLibraryID);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't hide Retracted Items collection when last retracted item is marked to not show a citation warning", async function () {
|
||||||
|
var rowID = "R" + userLibraryID;
|
||||||
|
|
||||||
|
// Create item
|
||||||
|
var item = await createRetractedItem();
|
||||||
|
assert.ok(zp.collectionsView.getRowIndexByID(rowID));
|
||||||
|
|
||||||
|
// Select Retracted Items collection
|
||||||
|
await zp.collectionsView.selectByID(rowID);
|
||||||
|
await waitForItemsLoad(win);
|
||||||
|
|
||||||
|
await Zotero.Retractions.disableCitationWarningsForItem(item);
|
||||||
|
|
||||||
|
await Zotero.Promise.delay(50);
|
||||||
|
// Should still be showing
|
||||||
|
assert.ok(zp.collectionsView.getRowIndexByID("R" + userLibraryID));
|
||||||
|
});
|
||||||
|
|
||||||
it("should show Retracted Items collection when retracted item is restored from trash", async function () {
|
it("should show Retracted Items collection when retracted item is restored from trash", async function () {
|
||||||
// Create trashed item
|
// Create trashed item
|
||||||
var item = await createRetractedItem({ deleted: true });
|
var item = await createRetractedItem({ deleted: true });
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue