Add mechanism for showing dialog with notice from repo
- Messages are shown once a day by default (within the same session for id-less messages) - Messages with an `id` attribute include a checkbox to not show again for 30 days - If an `infoURL` attribute is provided, a "More Information" button is shown that launches that URL - If `title` is provided, it's used for the dialog title. Otherwise "Warning" is shown.
This commit is contained in:
parent
ba7d0a18aa
commit
2459614f04
2 changed files with 261 additions and 0 deletions
|
@ -53,6 +53,7 @@ Zotero.Schema = new function(){
|
|||
var _nextRepositoryUpdate;
|
||||
var _remoteUpdateInProgress = false;
|
||||
var _localUpdateInProgress = false;
|
||||
var _hiddenNoticesWithoutIDs = new Map();
|
||||
|
||||
var self = this;
|
||||
|
||||
|
@ -2364,6 +2365,8 @@ Zotero.Schema = new function(){
|
|||
var translatorUpdates = xmlhttp.responseXML.getElementsByTagName('translator');
|
||||
var styleUpdates = xmlhttp.responseXML.getElementsByTagName('style');
|
||||
|
||||
_showRepositoryMessage(xmlhttp.responseXML);
|
||||
|
||||
if (!translatorUpdates.length && !styleUpdates.length){
|
||||
await Zotero.DB.executeTransaction(function* (conn) {
|
||||
// Store the timestamp provided by the server
|
||||
|
@ -2415,6 +2418,111 @@ Zotero.Schema = new function(){
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show dialog if repo returns a message
|
||||
*/
|
||||
function _showRepositoryMessage(responseXML) {
|
||||
try {
|
||||
var messageElem = responseXML.querySelector('message');
|
||||
if (!messageElem || !messageElem.textContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hiddenNotices = Zotero.Prefs.get('hiddenNotices') || '{}';
|
||||
try {
|
||||
hiddenNotices = JSON.parse(hiddenNotices);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
hiddenNotices = {};
|
||||
}
|
||||
|
||||
let id = messageElem.getAttribute('id');
|
||||
let title = messageElem.getAttribute('title');
|
||||
let text = messageElem.textContent;
|
||||
let url = messageElem.getAttribute('infoURL');
|
||||
let now = Math.round(Date.now() / 1000);
|
||||
let thirtyDays = 86400 * 30;
|
||||
|
||||
if (id) {
|
||||
if (hiddenNotices[id] && hiddenNotices[id] > now) {
|
||||
Zotero.debug("Not showing hidden notice " + id, 2);
|
||||
Zotero.debug(text, 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Zotero.debug("CHECKING");
|
||||
let exp = _hiddenNoticesWithoutIDs.get(text);
|
||||
Zotero.debug(exp);
|
||||
Zotero.debug(now);
|
||||
if (exp && exp > now) {
|
||||
Zotero.debug("Not showing hidden notice", 2);
|
||||
Zotero.debug(text, 2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
Zotero.debug(text, 2);
|
||||
|
||||
var ps = Services.prompt;
|
||||
var buttonFlags = ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK
|
||||
+ ps.BUTTON_POS_1 * ps.BUTTON_TITLE_IS_STRING;
|
||||
var checkState = {};
|
||||
var index = ps.confirmEx(
|
||||
null,
|
||||
title || Zotero.getString('general.warning'),
|
||||
text,
|
||||
buttonFlags,
|
||||
"",
|
||||
// Show "More Information" button if repo includes a URL
|
||||
url ? Zotero.getString('general.moreInformation') : "",
|
||||
"",
|
||||
// Show "Don't show again for 30 days" if repo includes an id
|
||||
id ? Zotero.getString('general.dontShowAgainFor', 30, 30) : null,
|
||||
checkState
|
||||
);
|
||||
|
||||
if (index == 1) {
|
||||
setTimeout(function () {
|
||||
Zotero.launchURL(url);
|
||||
}, 1);
|
||||
}
|
||||
// Handle "Don't show again for 30 days" checkbox
|
||||
if (id) {
|
||||
if (checkState.value) {
|
||||
hiddenNotices[id] = now + thirtyDays;
|
||||
}
|
||||
// If not checked, still don't show again for a day
|
||||
else {
|
||||
hiddenNotices[id] = now + 86400;
|
||||
}
|
||||
// Remove expired hidden notices
|
||||
for (let i in hiddenNotices) {
|
||||
if (hiddenNotices[i] < now) {
|
||||
delete hiddenNotices[i];
|
||||
}
|
||||
}
|
||||
if (Object.keys(hiddenNotices).length) {
|
||||
Zotero.Prefs.set('hiddenNotices', JSON.stringify(hiddenNotices));
|
||||
}
|
||||
else {
|
||||
Zotero.Prefs.clear('hiddenNotices');
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Don't show id-less messages again for a day
|
||||
_hiddenNoticesWithoutIDs.set(text, now + 86400);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.logError(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the interval between repository queries
|
||||
*
|
||||
|
|
|
@ -240,6 +240,159 @@ describe("Zotero.Schema", function() {
|
|||
});
|
||||
|
||||
|
||||
describe("Repository Check", function () {
|
||||
describe("Notices", function () {
|
||||
var win;
|
||||
var server;
|
||||
|
||||
before(async function () {
|
||||
win = await loadZoteroPane();
|
||||
});
|
||||
|
||||
beforeEach(function () {
|
||||
Zotero.HTTP.mock = sinon.FakeXMLHttpRequest;
|
||||
server = sinon.fakeServer.create();
|
||||
server.autoRespond = true;
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
Zotero.Prefs.clear('hiddenNotices');
|
||||
});
|
||||
|
||||
after(function () {
|
||||
win.close();
|
||||
Zotero.HTTP.mock = null;
|
||||
});
|
||||
|
||||
function createResponseWithMessage(message) {
|
||||
server.respond(function (req) {
|
||||
if (req.method != "POST" || !req.url.includes('/repo/updated')) {
|
||||
return;
|
||||
}
|
||||
req.respond(
|
||||
200,
|
||||
{
|
||||
"Content-Type": "application/xml"
|
||||
},
|
||||
'<xml>'
|
||||
+ '<currentTime>1630219842</currentTime>'
|
||||
+ message
|
||||
+ '</xml>'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
it("should show dialog if repo returns a message", async function () {
|
||||
createResponseWithMessage(
|
||||
`<message infoURL="https://example.com">This is a warning</message>`
|
||||
);
|
||||
|
||||
var promise = waitForDialog(function (dialog) {
|
||||
var html = dialog.document.documentElement.outerHTML;
|
||||
assert.include(html, "This is a warning");
|
||||
});
|
||||
await Zotero.Schema.updateFromRepository(3);
|
||||
await promise;
|
||||
|
||||
// Don't show id-less message again for a day
|
||||
var spy = sinon.spy(Zotero, 'debug');
|
||||
await Zotero.Schema.updateFromRepository(3);
|
||||
assert.notEqual(spy.args.findIndex(x => {
|
||||
return typeof x[0] == 'string' && x[0].startsWith("Not showing hidden");
|
||||
}), -1);
|
||||
spy.restore();
|
||||
});
|
||||
|
||||
it("shouldn't show message with id again for 1 day even if not hidden", async function () {
|
||||
var id = Zotero.Utilities.randomString();
|
||||
createResponseWithMessage(
|
||||
`<message id="${id}" infoURL="https://example.com">This is a warning</message>`
|
||||
);
|
||||
|
||||
var promise = waitForDialog();
|
||||
await Zotero.Schema.updateFromRepository(3);
|
||||
await promise;
|
||||
|
||||
// Make sure notice is hidden for 1 day
|
||||
var hiddenNotices;
|
||||
var tries = 0;
|
||||
var ttl = 86400;
|
||||
while (tries < 100) {
|
||||
tries++;
|
||||
hiddenNotices = Zotero.Prefs.get('hiddenNotices');
|
||||
if (!hiddenNotices) {
|
||||
await Zotero.Promise.delay(10);
|
||||
continue;
|
||||
}
|
||||
hiddenNotices = JSON.parse(hiddenNotices);
|
||||
assert.property(hiddenNotices, id);
|
||||
assert.approximately(hiddenNotices[id], Math.round(Date.now() / 1000) + ttl, 10);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it("shouldn't show message with id again for 30 days", async function () {
|
||||
var id = Zotero.Utilities.randomString();
|
||||
createResponseWithMessage(
|
||||
`<message id="${id}" infoURL="https://example.com">This is a warning</message>`
|
||||
);
|
||||
|
||||
var promise = waitForDialog(function (dialog) {
|
||||
var doc = dialog.document;
|
||||
var innerHTML = doc.documentElement.innerHTML;
|
||||
assert.include(innerHTML, "This is a warning");
|
||||
assert.include(innerHTML, Zotero.getString('general.dontShowAgainFor', 30, 30));
|
||||
// Check "Don't show again"
|
||||
doc.getElementById('checkbox').click();
|
||||
});
|
||||
await Zotero.Schema.updateFromRepository(3);
|
||||
await promise;
|
||||
|
||||
// Make sure notice is hidden for 30 days
|
||||
var hiddenNotices;
|
||||
var tries = 0;
|
||||
var ttl = 30 * 86400;
|
||||
while (tries < 100) {
|
||||
tries++;
|
||||
hiddenNotices = Zotero.Prefs.get('hiddenNotices');
|
||||
if (!hiddenNotices) {
|
||||
await Zotero.Promise.delay(10);
|
||||
continue;
|
||||
}
|
||||
hiddenNotices = JSON.parse(hiddenNotices);
|
||||
assert.property(hiddenNotices, id);
|
||||
assert.approximately(hiddenNotices[id], Math.round(Date.now() / 1000) + ttl, 10);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it("shouldn't show message with id if before expiration", async function () {
|
||||
var id = Zotero.Utilities.randomString();
|
||||
createResponseWithMessage(
|
||||
`<message id="${id}" infoURL="https://example.com">This is a warning</message>`
|
||||
);
|
||||
|
||||
// Set expiration for 30 days from now
|
||||
var ttl = 30 * 86400;
|
||||
Zotero.Prefs.set(
|
||||
'hiddenNotices',
|
||||
JSON.stringify({
|
||||
[id]: Math.round(Date.now() / 1000) + ttl
|
||||
})
|
||||
);
|
||||
|
||||
// Message should be hidden
|
||||
var spy = sinon.spy(Zotero, 'debug');
|
||||
await Zotero.Schema.updateFromRepository(3);
|
||||
assert.notEqual(spy.args.findIndex(x => {
|
||||
return typeof x[0] == 'string' && x[0].startsWith("Not showing hidden");
|
||||
}), -1);
|
||||
spy.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe("#integrityCheck()", function () {
|
||||
before(function* () {
|
||||
yield resetDB({
|
||||
|
|
Loading…
Reference in a new issue