Merge pull request #3067 from tnajdek/2925-direct-login-fx-102
Port Mendeley Import fixes & improvements from master branch
This commit is contained in:
commit
16ef1c476e
19 changed files with 989 additions and 85 deletions
|
@ -444,10 +444,13 @@ var Zotero_File_Interface = new function() {
|
||||||
|
|
||||||
var translation;
|
var translation;
|
||||||
|
|
||||||
if (options.mendeleyCode) {
|
if (options.mendeleyAuth || options.mendeleyCode) {
|
||||||
translation = yield _getMendeleyTranslation();
|
translation = yield _getMendeleyTranslation();
|
||||||
translation.createNewCollection = createNewCollection;
|
translation.createNewCollection = createNewCollection;
|
||||||
|
translation.mendeleyAuth = options.mendeleyAuth;
|
||||||
translation.mendeleyCode = options.mendeleyCode;
|
translation.mendeleyCode = options.mendeleyCode;
|
||||||
|
translation.newItemsOnly = options.newItemsOnly;
|
||||||
|
translation.relinkOnly = options.relinkOnly;
|
||||||
}
|
}
|
||||||
else if (options.folder) {
|
else if (options.folder) {
|
||||||
Components.utils.import("chrome://zotero/content/import/folderImport.js");
|
Components.utils.import("chrome://zotero/content/import/folderImport.js");
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
***** BEGIN LICENSE BLOCK *****
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
Copyright © 2022 Corporation for Digital Scholarship
|
Copyright © 2023 Corporation for Digital Scholarship
|
||||||
Vienna, Virginia, USA
|
Vienna, Virginia, USA
|
||||||
https://www.zotero.org
|
https://www.zotero.org
|
||||||
|
|
||||||
|
@ -22,23 +22,30 @@
|
||||||
|
|
||||||
***** END LICENSE BLOCK *****
|
***** END LICENSE BLOCK *****
|
||||||
*/
|
*/
|
||||||
|
/* eslint camelcase: ["error", {allow: ["Zotero_File_Interface", "Zotero_Import_Wizard"]} ] */
|
||||||
|
/* global Zotero_File_Interface: false, mendeleyAPIUtils: false */
|
||||||
|
|
||||||
import FilePicker from 'zotero/filePicker';
|
import FilePicker from 'zotero/filePicker';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import ProgressQueueTable from 'components/progressQueueTable';
|
import ProgressQueueTable from 'components/progressQueueTable';
|
||||||
|
|
||||||
/* eslint camelcase: ["error", {allow: ["Zotero_File_Interface", "Zotero_Import_Wizard"]} ] */
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
/* global Zotero_File_Interface: false */
|
Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/mendeleyAPIUtils.js");
|
||||||
|
const { directAuth } = mendeleyAPIUtils;
|
||||||
|
|
||||||
|
|
||||||
const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
wizard: null,
|
|
||||||
folder: null,
|
|
||||||
file: null,
|
file: null,
|
||||||
mendeleyCode: null,
|
folder: null,
|
||||||
|
isZotfileInstalled: false,
|
||||||
libraryID: null,
|
libraryID: null,
|
||||||
|
mendeleyAuth: null,
|
||||||
|
mendeleyCode: null,
|
||||||
|
mendeleyHasPreviouslyImported: false,
|
||||||
|
mendeleyImporterVersion: 0,
|
||||||
translation: null,
|
translation: null,
|
||||||
|
wizard: null,
|
||||||
|
|
||||||
async getShouldCreateCollection() {
|
async getShouldCreateCollection() {
|
||||||
const sql = "SELECT ROWID FROM collections WHERE libraryID=?1 "
|
const sql = "SELECT ROWID FROM collections WHERE libraryID=?1 "
|
||||||
|
@ -54,18 +61,29 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
},
|
},
|
||||||
|
|
||||||
async init() {
|
async init() {
|
||||||
const { mendeleyCode, libraryID } = window.arguments[0].wrappedJSObject ?? {};
|
const { mendeleyCode, libraryID, pageID, relinkOnly } = window.arguments[0].wrappedJSObject ?? {};
|
||||||
|
|
||||||
this.libraryID = libraryID;
|
this.libraryID = libraryID;
|
||||||
this.mendeleyCode = mendeleyCode;
|
|
||||||
|
const predicateID = Zotero.RelationPredicates.getID('mendeleyDB:documentUUID');
|
||||||
|
if (predicateID) {
|
||||||
|
const relSQL = 'SELECT ROWID FROM itemRelations WHERE predicateID = ? LIMIT 1';
|
||||||
|
this.mendeleyHasPreviouslyImported = !!(await Zotero.DB.valueQueryAsync(relSQL, predicateID));
|
||||||
|
}
|
||||||
|
|
||||||
|
const extensions = await Zotero.getInstalledExtensions();
|
||||||
|
this.isZotfileInstalled = !!extensions.find(extName => extName.match(/^ZotFile((?!disabled).)*$/));
|
||||||
|
this.mendeleyImporterVersion = parseInt((await Zotero.DB.valueQueryAsync("SELECT value FROM settings WHERE setting='mendeleyImport' AND key='version'")) || 0);
|
||||||
|
|
||||||
this.wizard = document.getElementById('import-wizard');
|
this.wizard = document.getElementById('import-wizard');
|
||||||
this.wizard.getPageById('page-start')
|
this.wizard.getPageById('page-start')
|
||||||
.addEventListener('pageadvanced', this.onImportSourceAdvance.bind(this));
|
.addEventListener('pageadvanced', this.onImportSourceAdvance.bind(this));
|
||||||
|
this.wizard.getPageById('page-mendeley-online-intro')
|
||||||
|
.addEventListener('pageshow', this.onMendeleyOnlineShow.bind(this));
|
||||||
this.wizard.getPageById('page-mendeley-online-intro')
|
this.wizard.getPageById('page-mendeley-online-intro')
|
||||||
.addEventListener('pagerewound', this.goToStart.bind(this));
|
.addEventListener('pagerewound', this.goToStart.bind(this));
|
||||||
this.wizard.getPageById('page-mendeley-online-intro')
|
this.wizard.getPageById('page-mendeley-online-intro')
|
||||||
.addEventListener('pageadvanced', this.openMendeleyAuthWindow.bind(this));
|
.addEventListener('pageadvanced', this.onMendeleyOnlineAdvance.bind(this));
|
||||||
this.wizard.getPageById('page-options')
|
this.wizard.getPageById('page-options')
|
||||||
.addEventListener('pageshow', this.onOptionsPageShow.bind(this));
|
.addEventListener('pageshow', this.onOptionsPageShow.bind(this));
|
||||||
this.wizard.getPageById('page-options')
|
this.wizard.getPageById('page-options')
|
||||||
|
@ -79,10 +97,10 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
document.getElementById('import-other').checked = ev.currentTarget.value.length > 0;
|
document.getElementById('import-other').checked = ev.currentTarget.value.length > 0;
|
||||||
});
|
});
|
||||||
document
|
document
|
||||||
.querySelector('#page-done-error-mendeley > a')
|
.querySelector('a')
|
||||||
.addEventListener('click', this.onURLInteract.bind(this));
|
.addEventListener('click', this.onURLInteract.bind(this));
|
||||||
document
|
document
|
||||||
.querySelector('#page-done-error-mendeley > a')
|
.querySelector('a')
|
||||||
.addEventListener('keydown', this.onURLInteract.bind(this));
|
.addEventListener('keydown', this.onURLInteract.bind(this));
|
||||||
document
|
document
|
||||||
.querySelector('#page-done-error > button')
|
.querySelector('#page-done-error > button')
|
||||||
|
@ -90,6 +108,12 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
document
|
document
|
||||||
.querySelector('#page-done-error > button')
|
.querySelector('#page-done-error > button')
|
||||||
.addEventListener('keydown', this.onReportErrorInteract.bind(this));
|
.addEventListener('keydown', this.onReportErrorInteract.bind(this));
|
||||||
|
document
|
||||||
|
.getElementById('mendeley-username').addEventListener('keyup', this.onMendeleyAuthKeyUp.bind(this));
|
||||||
|
document
|
||||||
|
.getElementById('mendeley-password').addEventListener('keyup', this.onMendeleyAuthKeyUp.bind(this));
|
||||||
|
document
|
||||||
|
.getElementById('relink-only-checkbox').addEventListener('command', this.onRelinkOnlyChange.bind(this));
|
||||||
|
|
||||||
this.wizard.addEventListener('pageshow', this.updateFocus.bind(this));
|
this.wizard.addEventListener('pageshow', this.updateFocus.bind(this));
|
||||||
this.wizard.addEventListener('wizardcancel', this.onCancel.bind(this));
|
this.wizard.addEventListener('wizardcancel', this.onCancel.bind(this));
|
||||||
|
@ -101,7 +125,17 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
this.wizard.shadowRoot
|
this.wizard.shadowRoot
|
||||||
.querySelector('.wizard-header-label').style.fontSize = '16px';
|
.querySelector('.wizard-header-label').style.fontSize = '16px';
|
||||||
|
|
||||||
if (mendeleyCode) {
|
if (relinkOnly) {
|
||||||
|
document.getElementById('relink-only-checkbox').checked = true;
|
||||||
|
this.onRelinkOnlyChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageID) {
|
||||||
|
this.wizard.goTo(pageID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mendeleyCode && Zotero.Prefs.get("import.mendeleyUseOAuth")) {
|
||||||
|
this.mendeleyCode = mendeleyCode;
|
||||||
this.wizard.goTo('page-options');
|
this.wizard.goTo('page-options');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -194,6 +228,50 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
this.wizard.goTo('page-options');
|
this.wizard.goTo('page-options');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async onMendeleyOnlineShow() {
|
||||||
|
document.getElementById('import-online-intro').l10nId = Zotero.Prefs.get("import.mendeleyUseOAuth")
|
||||||
|
? 'import-online-intro'
|
||||||
|
: 'import-online-form-intro';
|
||||||
|
document.getElementById('mendeley-login').style.display = Zotero.Prefs.get("import.mendeleyUseOAuth") ? 'none' : '';
|
||||||
|
document.getElementById('mendeley-online-login-feedback').style.display = 'none';
|
||||||
|
|
||||||
|
// If we use oAuth, form doesn't show and we can advance, otherwise need to fill-in form first so disable
|
||||||
|
this.wizard.canAdvance = Zotero.Prefs.get("import.mendeleyUseOAuth");
|
||||||
|
},
|
||||||
|
|
||||||
|
async onMendeleyOnlineAdvance(ev) {
|
||||||
|
ev.preventDefault();
|
||||||
|
|
||||||
|
if (Zotero.Prefs.get("import.mendeleyUseOAuth")) {
|
||||||
|
this.openMendeleyAuthWindow();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const userNameEl = document.getElementById('mendeley-username');
|
||||||
|
const passwordEl = document.getElementById('mendeley-password');
|
||||||
|
userNameEl.disabled = true;
|
||||||
|
passwordEl.disabled = true;
|
||||||
|
try {
|
||||||
|
this.mendeleyAuth = await directAuth(userNameEl.value, passwordEl.value);
|
||||||
|
this.wizard.goTo('page-options');
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
const feedbackEl = document.getElementById('mendeley-online-login-feedback');
|
||||||
|
feedbackEl.style.display = '';
|
||||||
|
this.wizard.canAdvance = false; // change to either of the inputs will reset thi
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
userNameEl.disabled = false;
|
||||||
|
passwordEl.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onMendeleyAuthKeyUp() {
|
||||||
|
document.getElementById('mendeley-online-login-feedback').style.display = 'none';
|
||||||
|
this.wizard.canAdvance = document.getElementById('mendeley-username').value.length > 0
|
||||||
|
&& document.getElementById('mendeley-password').value.length > 0;
|
||||||
|
},
|
||||||
|
|
||||||
async onImportSourceAdvance(ev) {
|
async onImportSourceAdvance(ev) {
|
||||||
const selectedMode = document.getElementById('import-source-group').selectedItem.value;
|
const selectedMode = document.getElementById('import-source-group').selectedItem.value;
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
|
@ -211,6 +289,13 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
case 'mendeleyOnline':
|
case 'mendeleyOnline':
|
||||||
this.file = null;
|
this.file = null;
|
||||||
this.folder = null;
|
this.folder = null;
|
||||||
|
if (this.isZotfileInstalled) {
|
||||||
|
this.skipToDonePage(
|
||||||
|
'general-error',
|
||||||
|
['import-online-blocked-by-plugin', { plugin: 'ZotFile' }]
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.wizard.goTo('page-mendeley-online-intro');
|
this.wizard.goTo('page-mendeley-online-intro');
|
||||||
this.wizard.canRewind = true;
|
this.wizard.canRewind = true;
|
||||||
break;
|
break;
|
||||||
|
@ -226,13 +311,17 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
onOptionsPageShow() {
|
onOptionsPageShow() {
|
||||||
document.getElementById('page-options-folder-import').style.display = this.folder ? 'block' : 'none';
|
document.getElementById('page-options-folder-import').style.display = this.folder ? 'block' : 'none';
|
||||||
document.getElementById('page-options-file-handling').style.display = this.mendeleyCode ? 'none' : 'block';
|
document.getElementById('page-options-file-handling').style.display = (this.mendeleyCode || this.mendeleyAuth) ? 'none' : 'block';
|
||||||
|
const hideExtraMendeleyOptions = !this.mendeleyHasPreviouslyImported || !(this.mendeleyAuth || this.mendeleyCode);
|
||||||
|
document.getElementById('page-options-mendeley').style.display = hideExtraMendeleyOptions ? 'none' : 'block';
|
||||||
|
document.getElementById('page-options-relink-only').style.display = (hideExtraMendeleyOptions || this.mendeleyImporterVersion > 0) ? 'none' : null;
|
||||||
|
if (hideExtraMendeleyOptions) {
|
||||||
|
document.getElementById('new-items-only-checkbox').checked = false;
|
||||||
|
}
|
||||||
this.wizard.canRewind = false;
|
this.wizard.canRewind = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
openMendeleyAuthWindow(ev) {
|
openMendeleyAuthWindow() {
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
const arg = Components.classes["@mozilla.org/supports-string;1"]
|
const arg = Components.classes["@mozilla.org/supports-string;1"]
|
||||||
.createInstance(Components.interfaces.nsISupportsString);
|
.createInstance(Components.interfaces.nsISupportsString);
|
||||||
arg.data = 'mendeleyImport';
|
arg.data = 'mendeleyImport';
|
||||||
|
@ -279,6 +368,16 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRelinkOnlyChange() {
|
||||||
|
if (document.getElementById('relink-only-checkbox').checked) {
|
||||||
|
document.getElementById('new-items-only-checkbox').checked = true;
|
||||||
|
document.getElementById('create-collection').checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('new-items-only-checkbox').disabled = document.getElementById('relink-only-checkbox').checked;
|
||||||
|
document.getElementById('create-collection').disabled = document.getElementById('relink-only-checkbox').checked;
|
||||||
|
},
|
||||||
|
|
||||||
onURLInteract(ev) {
|
onURLInteract(ev) {
|
||||||
if (ev.type === 'click' || (ev.type === 'keydown' && ev.key === ' ')) {
|
if (ev.type === 'click' || (ev.type === 'keydown' && ev.key === ' ')) {
|
||||||
Zotero.launchURL(ev.currentTarget.getAttribute('href'));
|
Zotero.launchURL(ev.currentTarget.getAttribute('href'));
|
||||||
|
@ -317,6 +416,8 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
const fileTypes = document.getElementById('import-other').checked
|
const fileTypes = document.getElementById('import-other').checked
|
||||||
? document.getElementById('other-files').value
|
? document.getElementById('other-files').value
|
||||||
: null;
|
: null;
|
||||||
|
const newItemsOnly = document.getElementById('new-items-only-checkbox').checked;
|
||||||
|
const relinkOnly = document.getElementById('relink-only-checkbox').checked;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await Zotero_File_Interface.importFile({
|
const result = await Zotero_File_Interface.importFile({
|
||||||
|
@ -325,10 +426,13 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
fileTypes,
|
fileTypes,
|
||||||
folder: this.folder,
|
folder: this.folder,
|
||||||
linkFiles,
|
linkFiles,
|
||||||
|
mendeleyAuth: this.mendeleyAuth,
|
||||||
mendeleyCode: this.mendeleyCode,
|
mendeleyCode: this.mendeleyCode,
|
||||||
mimeTypes,
|
mimeTypes,
|
||||||
|
newItemsOnly,
|
||||||
onBeforeImport: this.onBeforeImport.bind(this),
|
onBeforeImport: this.onBeforeImport.bind(this),
|
||||||
recreateStructure
|
recreateStructure,
|
||||||
|
relinkOnly
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cancelled by user or due to error
|
// Cancelled by user or due to error
|
||||||
|
@ -338,19 +442,22 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars
|
||||||
}
|
}
|
||||||
|
|
||||||
const numItems = this.translation.newItems.length;
|
const numItems = this.translation.newItems.length;
|
||||||
|
const numRelinked = this.translation.numRelinked;
|
||||||
this.skipToDonePage(
|
this.skipToDonePage(
|
||||||
'file-interface-import-complete',
|
'file-interface-import-complete',
|
||||||
['file-interface-items-were-imported', { numItems }]
|
document.getElementById('relink-only-checkbox').checked
|
||||||
|
? ['file-interface-items-were-relinked', { numRelinked }]
|
||||||
|
: ['file-interface-items-were-imported', { numItems }]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.message == 'Encrypted Mendeley database') {
|
if (e.message == 'Encrypted Mendeley database') {
|
||||||
this.skipToDonePage('general.error', [], false, true);
|
this.skipToDonePage('general-error', [], false, true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const translatorLabel = this.translation?.translator?.[0]?.label;
|
const translatorLabel = this.translation?.translator?.[0]?.label;
|
||||||
this.skipToDonePage(
|
this.skipToDonePage(
|
||||||
'general.error',
|
'general-error',
|
||||||
translatorLabel
|
translatorLabel
|
||||||
? ['file-interface-import-error-translator', { translator: translatorLabel }]
|
? ['file-interface-import-error-translator', { translator: translatorLabel }]
|
||||||
: 'file-interface-import-error',
|
: 'file-interface-import-error',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||||
<?xml-stylesheet href="chrome://zotero-platform/content/zotero-react-client.css"?>
|
<?xml-stylesheet href="chrome://zotero-platform/content/zotero.css"?>
|
||||||
|
|
||||||
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
<!DOCTYPE window SYSTEM "chrome://zotero/locale/zotero.dtd">
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
data-header-label-id="import-online-intro-title"
|
data-header-label-id="import-online-intro-title"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
id="import-online-intro"
|
||||||
class="mendeley-online-intro"
|
class="mendeley-online-intro"
|
||||||
data-l10n-id="import-online-intro"
|
data-l10n-id="import-online-intro"
|
||||||
data-l10n-args='{"targetAppOnline": "Mendeley Reference Manager", "targetApp": "Mendeley"}'></div>
|
data-l10n-args='{"targetAppOnline": "Mendeley Reference Manager", "targetApp": "Mendeley"}'></div>
|
||||||
|
@ -37,11 +38,26 @@
|
||||||
class="mendeley-online-intro"
|
class="mendeley-online-intro"
|
||||||
data-l10n-id="import-online-intro2"
|
data-l10n-id="import-online-intro2"
|
||||||
data-l10n-args='{"targetApp": "Mendeley"}'></div>
|
data-l10n-args='{"targetApp": "Mendeley"}'></div>
|
||||||
|
<fieldset id="mendeley-login">
|
||||||
|
<div class="field">
|
||||||
|
<html:label for="mendeley-username" data-l10n-id="import-mendeley-username" />
|
||||||
|
<html:input type="text" id="mendeley-username" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<html:label for="mendeley-password" data-l10n-id="import-mendeley-password" />
|
||||||
|
<html:input type="password" id="mendeley-password" />
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<div id="mendeley-online-login-feedback" data-l10n-id="import-online-wrong-credentials" />
|
||||||
</wizardpage>
|
</wizardpage>
|
||||||
<wizardpage
|
<wizardpage
|
||||||
pageid="page-options"
|
pageid="page-options"
|
||||||
data-header-label-id="import-options"
|
data-header-label-id="import-options"
|
||||||
>
|
>
|
||||||
|
<div class="options-group" id="page-options-relink-only">
|
||||||
|
<checkbox id="relink-only-checkbox" data-l10n-id="import-online-relink-only" native="true" />
|
||||||
|
<html:a data-l10n-id="import-online-relink-kb" href="https://www.zotero.org/support/kb/mendeley_import#using_mendeley_citations" />
|
||||||
|
</div>
|
||||||
<div class="options-group" id="page-options-common">
|
<div class="options-group" id="page-options-common">
|
||||||
<checkbox native="true" id="create-collection" data-l10n-id="import-create-collection" />
|
<checkbox native="true" id="create-collection" data-l10n-id="import-create-collection" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,6 +82,9 @@
|
||||||
</radiogroup>
|
</radiogroup>
|
||||||
<div class="page-options-file-handling-description" data-l10n-id="import-fileHandling-description"></div>
|
<div class="page-options-file-handling-description" data-l10n-id="import-fileHandling-description"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="options-group" id="page-options-mendeley">
|
||||||
|
<checkbox native="true" id="new-items-only-checkbox" data-l10n-id="import-online-new" checked="true" />
|
||||||
|
</div>
|
||||||
</wizardpage>
|
</wizardpage>
|
||||||
<wizardpage pageid="page-progress" data-header-label-id="import-importing">
|
<wizardpage pageid="page-progress" data-header-label-id="import-importing">
|
||||||
<html:progress id="import-progress" max="100" value="0" />
|
<html:progress id="import-progress" max="100" value="0" />
|
||||||
|
|
|
@ -1,22 +1,67 @@
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
var mendeleyAPIUtils = (function () {
|
var mendeleyAPIUtils = (function () {
|
||||||
const OAUTH_URL = 'https://www.zotero.org/utils/mendeley/oauth';
|
const ZOTERO_OAUTH_URL = 'https://www.zotero.org/utils/mendeley/oauth';
|
||||||
|
const OAUTH_URL = 'https://api.mendeley.com/oauth/token';
|
||||||
const MENDELEY_API_URL = 'https://api.mendeley.com';
|
const MENDELEY_API_URL = 'https://api.mendeley.com';
|
||||||
|
const CLIENT_ID = '6';
|
||||||
|
const CLIENT_NOT_VERY_SECRET = 'JtSAMzFdwC6RAED3RMZU';
|
||||||
|
const USER_AGENT = 'Mendeley Desktop/1.18';
|
||||||
|
|
||||||
const getTokens = async (codeOrRefreshToken, isRefresh = false) => {
|
const getTokens = async (url, bodyProps, headers = {}, options = {}) => {
|
||||||
const options = {
|
const body = Object.entries(bodyProps)
|
||||||
body: isRefresh
|
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
|
||||||
? `grant_type=refresh_token&refresh_token=${codeOrRefreshToken}`
|
.join('&');
|
||||||
: `grant_type=authorization_code&code=${codeOrRefreshToken}`,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const response = await Zotero.HTTP.request('POST', OAUTH_URL, options);
|
|
||||||
|
|
||||||
|
headers = { ...headers, 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||||
|
|
||||||
|
if (!Zotero.Prefs.get('import.mendeleyUseOAuth')) {
|
||||||
|
headers['User-Agent'] = USER_AGENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
options = { ...options, body, headers, timeout: 30000 };
|
||||||
|
const response = await Zotero.HTTP.request('POST', url, options);
|
||||||
return JSON.parse(response.responseText);
|
return JSON.parse(response.responseText);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const directAuth = async (username, password, headers = {}, options = {}) => {
|
||||||
|
const bodyProps = {
|
||||||
|
client_id: CLIENT_ID, // eslint-disable-line camelcase
|
||||||
|
client_secret: CLIENT_NOT_VERY_SECRET, // eslint-disable-line camelcase
|
||||||
|
grant_type: 'password', // eslint-disable-line camelcase
|
||||||
|
password,
|
||||||
|
scope: 'all',
|
||||||
|
username
|
||||||
|
};
|
||||||
|
|
||||||
|
return getTokens(OAUTH_URL, bodyProps, headers, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const codeAuth = async (code, headers = {}, options = {}) => {
|
||||||
|
const bodyProps = {
|
||||||
|
grant_type: 'authorization_code', // eslint-disable-line camelcase
|
||||||
|
code,
|
||||||
|
};
|
||||||
|
|
||||||
|
return getTokens(ZOTERO_OAUTH_URL, bodyProps, headers, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshAuth = async (refreshToken, headers = {}, options = {}) => {
|
||||||
|
const bodyProps = {
|
||||||
|
grant_type: 'refresh_token', // eslint-disable-line camelcase
|
||||||
|
refresh_token: refreshToken, // eslint-disable-line camelcase
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!Zotero.Prefs.get('import.mendeleyUseOAuth')) {
|
||||||
|
bodyProps.client_id = CLIENT_ID; // eslint-disable-line camelcase
|
||||||
|
bodyProps.client_secret = CLIENT_NOT_VERY_SECRET; // eslint-disable-line camelcase
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTokens(
|
||||||
|
Zotero.Prefs.get('import.mendeleyUseOAuth') ? ZOTERO_OAUTH_URL : OAUTH_URL,
|
||||||
|
bodyProps, headers, options
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const getNextLinkFromResponse = (response) => {
|
const getNextLinkFromResponse = (response) => {
|
||||||
let next = null;
|
let next = null;
|
||||||
let links = response.getResponseHeader('link');
|
let links = response.getResponseHeader('link');
|
||||||
|
@ -42,7 +87,7 @@ const apiFetchUrl = async (tokens, url, headers = {}, options = {}) => {
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
if (e.status === 401 || e.status === 403) {
|
if (e.status === 401 || e.status === 403) {
|
||||||
const newTokens = await getTokens(tokens.refresh_token, true);
|
const newTokens = await refreshAuth(tokens.refresh_token);
|
||||||
// update tokens in the tokens object and in the header for next request
|
// update tokens in the tokens object and in the header for next request
|
||||||
tokens.access_token = newTokens.access_token; // eslint-disable-line camelcase
|
tokens.access_token = newTokens.access_token; // eslint-disable-line camelcase
|
||||||
tokens.refresh_token = newTokens.refresh_token; // eslint-disable-line camelcase
|
tokens.refresh_token = newTokens.refresh_token; // eslint-disable-line camelcase
|
||||||
|
@ -81,6 +126,5 @@ const getAll = async (tokens, endPoint, params = {}, headers = {}, options = {},
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return { codeAuth, directAuth, getNextLinkFromResponse, apiFetch, apiFetchUrl, get, getAll };
|
||||||
return { getNextLinkFromResponse, getTokens, apiFetch, apiFetchUrl, get, getAll };
|
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -9,8 +9,9 @@ Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/men
|
||||||
Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/mendeleyAPIUtils.js");
|
Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/mendeleyAPIUtils.js");
|
||||||
Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/mendeleySchemaMap.js");
|
Services.scriptloader.loadSubScript("chrome://zotero/content/import/mendeley/mendeleySchemaMap.js");
|
||||||
|
|
||||||
|
const importerVersion = 1;
|
||||||
const { apiTypeToDBType, apiFieldToDBField } = mendeleyOnlineMappings;
|
const { apiTypeToDBType, apiFieldToDBField } = mendeleyOnlineMappings;
|
||||||
const { apiFetch, get, getAll, getTokens } = mendeleyAPIUtils;
|
const { apiFetch, codeAuth, get, getAll } = mendeleyAPIUtils;
|
||||||
|
|
||||||
const colorMap = new Map();
|
const colorMap = new Map();
|
||||||
colorMap.set('rgb(255, 245, 173)', '#ffd400');
|
colorMap.set('rgb(255, 245, 173)', '#ffd400');
|
||||||
|
@ -28,7 +29,11 @@ var Zotero_Import_Mendeley = function () {
|
||||||
this.createNewCollection = null;
|
this.createNewCollection = null;
|
||||||
this.linkFiles = null;
|
this.linkFiles = null;
|
||||||
this.newItems = [];
|
this.newItems = [];
|
||||||
this.mendeleyCode = null;
|
this.newCollections = [];
|
||||||
|
this.mendeleyAuth = null;
|
||||||
|
this.newItemsOnly = false;
|
||||||
|
this.relinkOnly = false;
|
||||||
|
this.numRelinked = 0;
|
||||||
|
|
||||||
this._tokens = null;
|
this._tokens = null;
|
||||||
this._db = null;
|
this._db = null;
|
||||||
|
@ -89,13 +94,15 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) {
|
||||||
skipSelect: true,
|
skipSelect: true,
|
||||||
...(options.saveOptions || {})
|
...(options.saveOptions || {})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.newItemsOnly = this.newItemsOnly || this.relinkOnly;
|
||||||
|
|
||||||
const libraryID = options.libraryID || Zotero.Libraries.userLibraryID;
|
const libraryID = options.libraryID || Zotero.Libraries.userLibraryID;
|
||||||
const { key: rootCollectionKey } = options.collections
|
const { key: rootCollectionKey } = options.collections
|
||||||
? Zotero.Collections.getLibraryAndKeyFromID(options.collections[0])
|
? Zotero.Collections.getLibraryAndKeyFromID(options.collections[0])
|
||||||
: {};
|
: {};
|
||||||
|
|
||||||
Zotero.debug(`Begining Mendeley import at ${this._started}. libraryID: ${libraryID}, linkFiles: ${this.linkFiles}, rootCollectionKey: ${rootCollectionKey}`);
|
Zotero.debug(`Begining Mendeley import at ${this._started}. libraryID: ${libraryID}, linkFiles: ${this.linkFiles}, rootCollectionKey: ${rootCollectionKey}, newItemsOnly: ${this.newItemsOnly}, relinkOnly: ${this.relinkOnly}`);
|
||||||
|
|
||||||
// TODO: Get appropriate version based on schema version
|
// TODO: Get appropriate version based on schema version
|
||||||
const mapVersion = 83;
|
const mapVersion = 83;
|
||||||
|
@ -115,8 +122,11 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) {
|
||||||
throw new Error("Not a valid Mendeley database");
|
throw new Error("Not a valid Mendeley database");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.mendeleyCode) {
|
if (this.mendeleyAuth) {
|
||||||
this._tokens = await getTokens(this.mendeleyCode);
|
this._tokens = this.mendeleyAuth;
|
||||||
|
}
|
||||||
|
else if (this.mendeleyCode) {
|
||||||
|
this._tokens = await codeAuth(this.mendeleyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._file && !this._tokens) {
|
if (!this._file && !this._tokens) {
|
||||||
|
@ -129,14 +139,17 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) {
|
||||||
this._progressMax = 50;
|
this._progressMax = 50;
|
||||||
this._itemDone();
|
this._itemDone();
|
||||||
|
|
||||||
const folders = this._tokens
|
let folderKeys = new Map();
|
||||||
? await this._getFoldersAPI(mendeleyGroupID)
|
if (!this.relinkOnly) {
|
||||||
: await this._getFoldersDB(mendeleyGroupID);
|
const folders = this._tokens
|
||||||
|
? await this._getFoldersAPI(mendeleyGroupID)
|
||||||
|
: await this._getFoldersDB(mendeleyGroupID);
|
||||||
|
|
||||||
const collectionJSON = this._foldersToAPIJSON(folders, rootCollectionKey);
|
const collectionJSON = this._foldersToAPIJSON(folders, rootCollectionKey);
|
||||||
const folderKeys = this._getFolderKeys(collectionJSON);
|
folderKeys = this._getFolderKeys(collectionJSON);
|
||||||
|
|
||||||
await this._saveCollections(libraryID, collectionJSON, folderKeys);
|
await this._saveCollections(libraryID, collectionJSON, folderKeys);
|
||||||
|
}
|
||||||
|
|
||||||
this._interruptChecker(true);
|
this._interruptChecker(true);
|
||||||
//
|
//
|
||||||
|
@ -169,13 +182,15 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) {
|
||||||
|
|
||||||
this._interruptChecker(true);
|
this._interruptChecker(true);
|
||||||
|
|
||||||
let collections = this._tokens
|
// eslint-disable-next-line multiline-ternary
|
||||||
|
let collections = this.relinkOnly ? new Map() : this._tokens
|
||||||
? await this._getDocumentCollectionsAPI(documents, rootCollectionKey, folderKeys)
|
? await this._getDocumentCollectionsAPI(documents, rootCollectionKey, folderKeys)
|
||||||
: await this._getDocumentCollectionsDB(mendeleyGroupID, documents, rootCollectionKey, folderKeys);
|
: await this._getDocumentCollectionsDB(mendeleyGroupID, documents, rootCollectionKey, folderKeys);
|
||||||
|
|
||||||
this._interruptChecker(true);
|
this._interruptChecker(true);
|
||||||
|
|
||||||
let files = this._tokens
|
// eslint-disable-next-line multiline-ternary
|
||||||
|
let files = this.relinkOnly ? new Map() : this._tokens
|
||||||
? await this._getDocumentFilesAPI(documents)
|
? await this._getDocumentFilesAPI(documents)
|
||||||
: await this._getDocumentFilesDB(mendeleyGroupID);
|
: await this._getDocumentFilesDB(mendeleyGroupID);
|
||||||
|
|
||||||
|
@ -303,9 +318,16 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) {
|
||||||
annotations.get(document.id)
|
annotations.get(document.id)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.newItems.push(Zotero.Items.get(documentIDMap.get(document.id)));
|
|
||||||
this._interruptChecker(true);
|
this._interruptChecker(true);
|
||||||
}
|
}
|
||||||
|
if (this.newItemsOnly && rootCollectionKey && this.newItems.length === 0) {
|
||||||
|
Zotero.debug(`Mendeley Import detected no new items, removing import collection containing ${this.newCollections.length} collections created during the import`);
|
||||||
|
const rootCollection = await Zotero.Collections.getAsync(options.collections[0]);
|
||||||
|
await rootCollection.eraseTx(this._saveOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Zotero.DB.queryAsync("REPLACE INTO settings VALUES ('mendeleyImport', 'version', ?)", importerVersion);
|
||||||
|
|
||||||
Zotero.debug(`Completed Mendeley import in ${Math.round((Date.now() - this._started) / 1000)}s. (Started: ${this._started})`);
|
Zotero.debug(`Completed Mendeley import in ${Math.round((Date.now() - this._started) / 1000)}s. (Started: ${this._started})`);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
@ -480,6 +502,7 @@ Zotero_Import_Mendeley.prototype._saveCollections = async function (libraryID, j
|
||||||
collection.key = collectionJSON.key;
|
collection.key = collectionJSON.key;
|
||||||
await collection.loadPrimaryData();
|
await collection.loadPrimaryData();
|
||||||
}
|
}
|
||||||
|
this.newCollections.push(collection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove external ids before saving
|
// Remove external ids before saving
|
||||||
|
@ -541,11 +564,19 @@ Zotero_Import_Mendeley.prototype._getDocumentsAPI = async function (groupID) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (await getAll(this._tokens, 'documents', params, headers, {}, this._interruptChecker)).map(d => ({
|
return (await getAll(this._tokens, 'documents', params, headers, {}, this._interruptChecker)).map((d) => {
|
||||||
...d,
|
const processedDocument = { ...d, remoteUuid: d.id };
|
||||||
uuid: d.id,
|
|
||||||
remoteUuid: d.id
|
try {
|
||||||
}));
|
const clientData = JSON.parse(d.client_data);
|
||||||
|
processedDocument.uuid = clientData.desktop_id ? clientData.desktop_id : d.id;
|
||||||
|
}
|
||||||
|
catch (_) {
|
||||||
|
processedDocument.uuid = d.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return processedDocument;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -607,7 +638,12 @@ Zotero_Import_Mendeley.prototype._getDocumentCreatorsAPI = async function (docum
|
||||||
const authors = (doc.authors || []).map(c => this._makeCreator('author', c.first_name, c.last_name));
|
const authors = (doc.authors || []).map(c => this._makeCreator('author', c.first_name, c.last_name));
|
||||||
const editors = (doc.editors || []).map(c => this._makeCreator('editor', c.first_name, c.last_name));
|
const editors = (doc.editors || []).map(c => this._makeCreator('editor', c.first_name, c.last_name));
|
||||||
const translators = (doc.translators || []).map(c => this._makeCreator('translator', c.first_name, c.last_name));
|
const translators = (doc.translators || []).map(c => this._makeCreator('translator', c.first_name, c.last_name));
|
||||||
map.set(doc.id, [...authors, ...editors, ...translators]);
|
const creators = [...authors, ...editors, ...translators];
|
||||||
|
const validCreators = creators.filter(c => c.name || c.firstName || c.lastName);
|
||||||
|
if (creators.length !== validCreators.length) {
|
||||||
|
Zotero.debug(`Discarding ${creators.length - validCreators.length} invalid creators for document ${doc.id}`);
|
||||||
|
}
|
||||||
|
map.set(doc.id, validCreators);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
};
|
};
|
||||||
|
@ -646,7 +682,10 @@ Zotero_Import_Mendeley.prototype._getDocumentTagsDB = async function (groupID) {
|
||||||
Zotero_Import_Mendeley.prototype._getDocumentTagsAPI = async function (documents) {
|
Zotero_Import_Mendeley.prototype._getDocumentTagsAPI = async function (documents) {
|
||||||
var map = new Map();
|
var map = new Map();
|
||||||
for (let doc of documents) {
|
for (let doc of documents) {
|
||||||
const tags = [...(doc.tags || []).map(tag => ({ tag, type: 0 })), ...(doc.keywords || []).map(tag => ({ tag, type: 1 }))];
|
const tags = [
|
||||||
|
...(doc.tags || []).map(tag => ({ tag, type: 0 })),
|
||||||
|
...(doc.keywords || []).map(tag => ({ tag, type: 1 }))
|
||||||
|
].filter(t => t.tag && t.tag.trim());
|
||||||
map.set(doc.id, tags);
|
map.set(doc.id, tags);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
|
@ -1279,16 +1318,19 @@ Zotero_Import_Mendeley.prototype._saveItems = async function (libraryID, json) {
|
||||||
var lastExistingParentItem;
|
var lastExistingParentItem;
|
||||||
for (let i = 0; i < json.length; i++) {
|
for (let i = 0; i < json.length; i++) {
|
||||||
let itemJSON = json[i];
|
let itemJSON = json[i];
|
||||||
|
let isMappedToExisting = false;
|
||||||
|
|
||||||
// Check if the item has been previously imported
|
// Check if the item has been previously imported
|
||||||
let item = await this._findExistingItem(libraryID, itemJSON, lastExistingParentItem);
|
let item = await this._findExistingItem(libraryID, itemJSON, lastExistingParentItem);
|
||||||
if (item) {
|
if (item) {
|
||||||
|
isMappedToExisting = true;
|
||||||
if (item.isRegularItem()) {
|
if (item.isRegularItem()) {
|
||||||
lastExistingParentItem = item;
|
lastExistingParentItem = item;
|
||||||
|
|
||||||
// Update any child items to point to the existing item's key instead of the
|
// Update any child items to point to the existing item's key instead of the
|
||||||
// new generated one
|
// new generated one
|
||||||
this._updateParentKeys('item', json, i + 1, itemJSON.key, item.key);
|
this._updateParentKeys('item', json, i + 1, itemJSON.key, item.key);
|
||||||
|
this.numRelinked++;
|
||||||
|
|
||||||
// Leave item in any collections it's in
|
// Leave item in any collections it's in
|
||||||
itemJSON.collections = item.getCollections()
|
itemJSON.collections = item.getCollections()
|
||||||
|
@ -1306,12 +1348,33 @@ Zotero_Import_Mendeley.prototype._saveItems = async function (libraryID, json) {
|
||||||
await item.loadPrimaryData();
|
await item.loadPrimaryData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.relinkOnly && !isMappedToExisting) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove external id before save
|
// Remove external id before save
|
||||||
let toSave = Object.assign({}, itemJSON);
|
let toSave = Object.assign({}, itemJSON);
|
||||||
delete toSave.documentID;
|
delete toSave.documentID;
|
||||||
|
|
||||||
item.fromJSON(toSave);
|
if ((this.newItemsOnly && !isMappedToExisting) || !this.newItemsOnly) {
|
||||||
|
if (isMappedToExisting) {
|
||||||
|
// dateAdded shouldn't change on an updated item. See #2881
|
||||||
|
delete toSave.dateAdded;
|
||||||
|
}
|
||||||
|
item.fromJSON(toSave);
|
||||||
|
this.newItems.push(item);
|
||||||
|
}
|
||||||
|
else if (isMappedToExisting && toSave.relations) {
|
||||||
|
const predicate = 'mendeleyDB:documentUUID';
|
||||||
|
const existingRels = item.getRelationsByPredicate(predicate);
|
||||||
|
const newRel = toSave.relations[predicate];
|
||||||
|
if (existingRels.length && newRel && existingRels[0] !== newRel) {
|
||||||
|
Zotero.debug(`Migrating relation ${predicate} for existing item ${item.key} from ${existingRels[0]} to ${newRel}`);
|
||||||
|
item.removeRelation(predicate, existingRels[0]);
|
||||||
|
item.addRelation(predicate, newRel);
|
||||||
|
}
|
||||||
|
}
|
||||||
await item.saveTx({
|
await item.saveTx({
|
||||||
skipDateModifiedUpdate: true,
|
skipDateModifiedUpdate: true,
|
||||||
...this._saveOptions
|
...this._saveOptions
|
||||||
|
|
|
@ -28,6 +28,7 @@ var mendeleyOnlineMappings = {
|
||||||
arxiv: 'arxivId',
|
arxiv: 'arxivId',
|
||||||
accessed: 'dateAccessed',
|
accessed: 'dateAccessed',
|
||||||
authors: false, // all author types handled separately
|
authors: false, // all author types handled separately
|
||||||
|
client_data: false, // desktop_id extraction handled separately
|
||||||
citation_key: 'citationKey',
|
citation_key: 'citationKey',
|
||||||
created: 'added',
|
created: 'added',
|
||||||
edition: 'edition',
|
edition: 'edition',
|
||||||
|
|
|
@ -2655,11 +2655,49 @@ Zotero.Integration.URIMap.prototype.getZoteroItemForURIs = async function (uris)
|
||||||
replacer = await Zotero.Relations.getByPredicateAndObject(
|
replacer = await Zotero.Relations.getByPredicateAndObject(
|
||||||
'item', 'mendeleyDB:documentUUID', m[1]
|
'item', 'mendeleyDB:documentUUID', m[1]
|
||||||
);
|
);
|
||||||
if (replacer.length && !replacer[0].deleted) {
|
if (replacer.length) {
|
||||||
zoteroItem = replacer[0];
|
if (!replacer[0].deleted) {
|
||||||
break;
|
zoteroItem = replacer[0];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// If not blocked by user having pressed skip in this session,
|
||||||
|
// or user having checked the checkbox to not be prompted about this,
|
||||||
|
// or user having imported their library with the new version of importer
|
||||||
|
else if (!(this.session.dontPromptForMendeley
|
||||||
|
|| Zotero.Prefs.get('integration.dontPromptMendeleyImport')
|
||||||
|
|| await Zotero.DB.valueQueryAsync("SELECT value FROM settings WHERE setting='mendeleyImport' AND key='version'")
|
||||||
|
)) {
|
||||||
|
// Prompt user to (re)import their mendeley database which might make us recognize
|
||||||
|
// these items
|
||||||
|
let checkbox = {};
|
||||||
|
let result = Zotero.Prompt.confirm({
|
||||||
|
title: Zotero.getString('integration.mendeleyImport.title'),
|
||||||
|
text: Zotero.getString('integration.mendeleyImport.description', [Zotero.appName]),
|
||||||
|
button0: Zotero.getString('integration.mendeleyImport.openImporter'),
|
||||||
|
button1: Zotero.getString('general.skip'),
|
||||||
|
checkLabel: Zotero.getString('general.dontAskAgain'),
|
||||||
|
checkbox
|
||||||
|
});
|
||||||
|
if (result === 0) {
|
||||||
|
setTimeout(
|
||||||
|
() => Zotero.getMainWindow().Zotero_File_Interface.showImportWizard(
|
||||||
|
{
|
||||||
|
pageID: 'page-mendeley-online-intro',
|
||||||
|
relinkOnly: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
throw new Zotero.Exception.UserCancelled("Importing mendeley citations");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.session.dontPromptForMendeley = true;
|
||||||
|
}
|
||||||
|
if (checkbox.value) {
|
||||||
|
Zotero.Prefs.set('integration.dontPromptMendeleyImport', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
87
chrome/content/zotero/xpcom/prompt.js
Normal file
87
chrome/content/zotero/xpcom/prompt.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright © 2022 Corporation for Digital Scholarship
|
||||||
|
Vienna, Virginia, USA
|
||||||
|
http://zotero.org
|
||||||
|
|
||||||
|
This file is part of Zotero.
|
||||||
|
|
||||||
|
Zotero is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Zotero is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||||
|
|
||||||
|
Zotero.Prompt = {
|
||||||
|
BUTTON_TITLE_OK: Services.prompt.BUTTON_TITLE_OK,
|
||||||
|
BUTTON_TITLE_CANCEL: Services.prompt.BUTTON_TITLE_CANCEL,
|
||||||
|
BUTTON_TITLE_YES: Services.prompt.BUTTON_TITLE_YES,
|
||||||
|
BUTTON_TITLE_NO: Services.prompt.BUTTON_TITLE_NO,
|
||||||
|
BUTTON_TITLE_SAVE: Services.prompt.BUTTON_TITLE_SAVE,
|
||||||
|
BUTTON_TITLE_DONT_SAVE: Services.prompt.BUTTON_TITLE_DONT_SAVE,
|
||||||
|
BUTTON_TITLE_REVERT: Services.prompt.BUTTON_TITLE_REVERT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around XPCOM's Services.prompt.confirmEx()
|
||||||
|
* but with a friendlier interface.
|
||||||
|
*
|
||||||
|
* Button text can use special static variables from
|
||||||
|
* Zotero.Prompt
|
||||||
|
*
|
||||||
|
* @param options
|
||||||
|
* - {mozIDOMWindowProxy} window - The parent window or null.
|
||||||
|
* - {String} title - Text to appear in the title of the dialog.
|
||||||
|
* - {String} text - Text to appear in the body of the dialog.
|
||||||
|
* - {String|Number} button0 - Button 0 text
|
||||||
|
* - {String|Number} button1 - Button 1 text
|
||||||
|
* - {String|Number} button2 - Button 2 text
|
||||||
|
* - {String} checkLabel - Text to appear with the checkbox.
|
||||||
|
* - {Object} checkbox - Contains the initial checked state of the
|
||||||
|
* checkbox when this method is called and the final checked
|
||||||
|
* state after this method returns. Either {} or { value: true/false }.
|
||||||
|
* - {Number} defaultButton - The index of default button. 0 by default
|
||||||
|
* - {Boolean} delayButtons - Make the buttons initially disabled and enable them after some period
|
||||||
|
* so that the user doesn't click through the dialog without reading it.
|
||||||
|
* @returns {Number} The index of the button pressed.
|
||||||
|
*/
|
||||||
|
confirm(options = {}) {
|
||||||
|
let { window: win, title, text, button0, button1, button2, checkLabel, checkbox, defaultButton, delayButtons } = options;
|
||||||
|
if (!win) win = null;
|
||||||
|
if (!title) throw new Error('`title` is required');
|
||||||
|
if (!text) throw new Error('`text` is required');
|
||||||
|
if (!button0 && !button1 && !button2) {
|
||||||
|
throw new Error('At least one button is required');
|
||||||
|
}
|
||||||
|
if (checkLabel && (!checkbox || typeof checkbox != 'object')) {
|
||||||
|
throw new Error('`checkLabel` provided without `checkbox` option');
|
||||||
|
}
|
||||||
|
let flags = delayButtons ? Services.prompt.BUTTON_DELAY_ENABLE : 0;
|
||||||
|
if (typeof button0 == 'number') flags += Services.prompt.BUTTON_POS_0 * button0;
|
||||||
|
else if (typeof button0 == 'string') flags += Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING;
|
||||||
|
if (typeof button1 == 'number') flags += Services.prompt.BUTTON_POS_1 * button1;
|
||||||
|
else if (typeof button1 == 'string') flags += Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_IS_STRING;
|
||||||
|
if (typeof button2 == 'number') flags += Services.prompt.BUTTON_POS_2 * button2;
|
||||||
|
else if (typeof button2 == 'string') flags += Services.prompt.BUTTON_POS_2 * Services.prompt.BUTTON_TITLE_IS_STRING;
|
||||||
|
if (defaultButton) flags += defaultButton == 1 ? Services.prompt.BUTTON_POS_1_DEFAULT : Services.prompt.BUTTON_POS_2_DEFAULT;
|
||||||
|
return Services.prompt.confirmEx(
|
||||||
|
win, title, text, flags,
|
||||||
|
typeof button0 == 'number' ? null : button0,
|
||||||
|
typeof button1 == 'number' ? null : button1,
|
||||||
|
typeof button2 == 'number' ? null : button2,
|
||||||
|
checkLabel, checkbox
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
|
@ -15,6 +15,7 @@
|
||||||
<!ENTITY zotero.general.advancedOptions.label "Advanced Options">
|
<!ENTITY zotero.general.advancedOptions.label "Advanced Options">
|
||||||
<!ENTITY zotero.general.tools "Tools">
|
<!ENTITY zotero.general.tools "Tools">
|
||||||
<!ENTITY zotero.general.more "More">
|
<!ENTITY zotero.general.more "More">
|
||||||
|
<!ENTITY zotero.general.moreInformation "More Information">
|
||||||
<!ENTITY zotero.general.loading "Loading…">
|
<!ENTITY zotero.general.loading "Loading…">
|
||||||
<!ENTITY zotero.general.close "Close">
|
<!ENTITY zotero.general.close "Close">
|
||||||
<!ENTITY zotero.general.minimize "Minimize">
|
<!ENTITY zotero.general.minimize "Minimize">
|
||||||
|
@ -188,6 +189,7 @@
|
||||||
<!ENTITY zotero.import.size "Size">
|
<!ENTITY zotero.import.size "Size">
|
||||||
<!ENTITY zotero.import.createCollection "Place imported collections and items into new collection">
|
<!ENTITY zotero.import.createCollection "Place imported collections and items into new collection">
|
||||||
<!ENTITY zotero.import.fileHandling "File Handling">
|
<!ENTITY zotero.import.fileHandling "File Handling">
|
||||||
|
<!ENTITY zotero.import.online.newItemsOnly "Download new items only; don’t update previously imported items">
|
||||||
|
|
||||||
<!ENTITY zotero.exportOptions.title "Export…">
|
<!ENTITY zotero.exportOptions.title "Export…">
|
||||||
<!ENTITY zotero.exportOptions.format.label "Format:">
|
<!ENTITY zotero.exportOptions.format.label "Format:">
|
||||||
|
|
|
@ -38,25 +38,38 @@ import-file-handling-store =
|
||||||
import-file-handling-link =
|
import-file-handling-link =
|
||||||
.label = Link to files in original location
|
.label = Link to files in original location
|
||||||
import-fileHandling-description = Linked files cannot be synced by { -app-name }.
|
import-fileHandling-description = Linked files cannot be synced by { -app-name }.
|
||||||
|
import-online-new =
|
||||||
|
.label = Download new items only; don’t update previously imported items
|
||||||
|
import-mendeley-username = Username
|
||||||
|
import-mendeley-password = Password
|
||||||
|
|
||||||
general-error = Error
|
general-error = Error
|
||||||
file-interface-import-error = An error occurred while trying to import the selected file. Please ensure that the file is valid and try again.
|
file-interface-import-error = An error occurred while trying to import the selected file. Please ensure that the file is valid and try again.
|
||||||
file-interface-import-complete = Import Complete
|
file-interface-import-complete = Import Complete
|
||||||
file-interface-items-were-imported = { $numItems ->
|
file-interface-items-were-imported = { $numItems ->
|
||||||
[one] item was imported
|
[0] No items were imported
|
||||||
|
[one] One item was imported
|
||||||
*[other] { $numItems } items were imported
|
*[other] { $numItems } items were imported
|
||||||
}
|
}
|
||||||
|
file-interface-items-were-relinked = { $numRelinked ->
|
||||||
|
[0] No items were relinked
|
||||||
|
[one] One item was relinked
|
||||||
|
*[other] { $numRelinked } items were relinked
|
||||||
|
}
|
||||||
|
|
||||||
import-mendeley-encrypted = The selected Mendeley database cannot be read, likely because it is encrypted.
|
import-mendeley-encrypted = The selected Mendeley database cannot be read, likely because it is encrypted.
|
||||||
See <a data-l10n-name="mendeley-import-kb">How do I import a Mendeley library into Zotero?</a> for more information.
|
See <a data-l10n-name="mendeley-import-kb">How do I import a Mendeley library into Zotero?</a> for more information.
|
||||||
|
|
||||||
file-interface-import-error-translator = An error occurred importing the selected file with “{ $translator }”. Please ensure that the file is valid and try again.
|
file-interface-import-error-translator = An error occurred importing the selected file with “{ $translator }”. Please ensure that the file is valid and try again.
|
||||||
|
|
||||||
# Variables:
|
|
||||||
# $targetAppOnline (String)
|
|
||||||
# $targetApp (String)
|
|
||||||
import-online-intro=In the next step you will be asked to log in to { $targetAppOnline } and grant { -app-name } access. This is necessary to import your { $targetApp } library into { -app-name }.
|
import-online-intro=In the next step you will be asked to log in to { $targetAppOnline } and grant { -app-name } access. This is necessary to import your { $targetApp } library into { -app-name }.
|
||||||
import-online-intro2={ -app-name } will never see or store your { $targetApp } password.
|
import-online-intro2={ -app-name } will never see or store your { $targetApp } password.
|
||||||
|
import-online-form-intro = Please enter your credentials to log in to { $targetAppOnline }. This is necessary to import your { $targetApp } library into { -app-name }.
|
||||||
|
import-online-wrong-credentials = Login to { $targetApp } failed. Please re-enter credentials and try again.
|
||||||
|
import-online-blocked-by-plugin = The import cannot continue with { $plugin } installed. Please disable this plugin and try again.
|
||||||
|
import-online-relink-only =
|
||||||
|
.label = Relink Mendeley Desktop citations
|
||||||
|
import-online-relink-kb = More Information
|
||||||
|
|
||||||
report-error =
|
report-error =
|
||||||
.label = Report Error…
|
.label = Report Error…
|
||||||
|
|
|
@ -73,6 +73,7 @@ general.tryLater = Try Later
|
||||||
general.showDirectory = Show Directory
|
general.showDirectory = Show Directory
|
||||||
general.showInLibrary = Show in Library
|
general.showInLibrary = Show in Library
|
||||||
general.continue = Continue
|
general.continue = Continue
|
||||||
|
general.skip = Skip
|
||||||
general.copy = Copy
|
general.copy = Copy
|
||||||
general.copyToClipboard = Copy to Clipboard
|
general.copyToClipboard = Copy to Clipboard
|
||||||
general.cancel = Cancel
|
general.cancel = Cancel
|
||||||
|
@ -93,6 +94,8 @@ general.loading = Loading…
|
||||||
general.richText = Rich Text
|
general.richText = Rich Text
|
||||||
general.clearSelection = Clear Selection
|
general.clearSelection = Clear Selection
|
||||||
general.insert = Insert
|
general.insert = Insert
|
||||||
|
general.username = Username
|
||||||
|
general.password = Password
|
||||||
|
|
||||||
general.yellow = Yellow
|
general.yellow = Yellow
|
||||||
general.red = Red
|
general.red = Red
|
||||||
|
@ -796,6 +799,7 @@ dragAndDrop.filesNotFound = The following files were not found and could not be
|
||||||
fileInterface.importing = Importing…
|
fileInterface.importing = Importing…
|
||||||
fileInterface.importComplete = Import Complete
|
fileInterface.importComplete = Import Complete
|
||||||
fileInterface.itemsWereImported = %1$S item was imported;%1$S items were imported
|
fileInterface.itemsWereImported = %1$S item was imported;%1$S items were imported
|
||||||
|
fileInterface.itemsWereRelinked = %1$S item was relinked;%1$S items were relinked
|
||||||
fileInterface.itemsExported = Exporting items…
|
fileInterface.itemsExported = Exporting items…
|
||||||
fileInterface.import = Import
|
fileInterface.import = Import
|
||||||
fileInterface.chooseAppDatabaseToImport = Choose the %S database to import
|
fileInterface.chooseAppDatabaseToImport = Choose the %S database to import
|
||||||
|
@ -990,6 +994,9 @@ integration.exportDocument.description1 = Zotero will convert citations in the d
|
||||||
integration.exportDocument.description2 = You should make a backup of the document before proceeding.
|
integration.exportDocument.description2 = You should make a backup of the document before proceeding.
|
||||||
integration.importInstructions = The Zotero citations in this document have been converted to a format that can be safely transferred between word processors. Open this document in a supported word processor and press Refresh in the Zotero plugin to continue working with the citations.
|
integration.importInstructions = The Zotero citations in this document have been converted to a format that can be safely transferred between word processors. Open this document in a supported word processor and press Refresh in the Zotero plugin to continue working with the citations.
|
||||||
integration.upgradeTemplate = The %S plugin for %S is outdated. Reinstall the plugin from Preferences → Cite → Word Processors.
|
integration.upgradeTemplate = The %S plugin for %S is outdated. Reinstall the plugin from Preferences → Cite → Word Processors.
|
||||||
|
integration.mendeleyImport.title = Missing Mendeley Data
|
||||||
|
integration.mendeleyImport.description = %1$S detected that the document you are citing with contains Mendeley citations. %1$S will be able to manage these citations if you import your Mendeley database.
|
||||||
|
integration.mendeleyImport.openImporter = Open Mendeley Importer...
|
||||||
|
|
||||||
styles.install.title = Install Style
|
styles.install.title = Install Style
|
||||||
styles.install.unexpectedError = An unexpected error occurred while installing "%1$S"
|
styles.install.unexpectedError = An unexpected error occurred while installing "%1$S"
|
||||||
|
|
|
@ -53,6 +53,7 @@ const xpcomFilesAll = [
|
||||||
'mimeTypeHandler',
|
'mimeTypeHandler',
|
||||||
'pdfWorker/manager',
|
'pdfWorker/manager',
|
||||||
'ipc',
|
'ipc',
|
||||||
|
'prompt',
|
||||||
'profile',
|
'profile',
|
||||||
'progressWindow',
|
'progressWindow',
|
||||||
'proxy',
|
'proxy',
|
||||||
|
|
|
@ -135,6 +135,7 @@ pref("extensions.zotero.integration.autoRegenerate", -1); // -1 = ask; 0 = no; 1
|
||||||
pref("extensions.zotero.integration.useClassicAddCitationDialog", false);
|
pref("extensions.zotero.integration.useClassicAddCitationDialog", false);
|
||||||
pref("extensions.zotero.integration.keepAddCitationDialogRaised", false);
|
pref("extensions.zotero.integration.keepAddCitationDialogRaised", false);
|
||||||
pref("extensions.zotero.integration.upgradeTemplateDelayedOn", 0);
|
pref("extensions.zotero.integration.upgradeTemplateDelayedOn", 0);
|
||||||
|
pref("extensions.zotero.integration.dontPromptMendeleyImport", false);
|
||||||
|
|
||||||
// Connector settings
|
// Connector settings
|
||||||
pref("extensions.zotero.httpServer.enabled", true);
|
pref("extensions.zotero.httpServer.enabled", true);
|
||||||
|
|
|
@ -42,6 +42,10 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[disabled="true"] .checkbox-label {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
#other-files {
|
#other-files {
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
|
@ -88,6 +92,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#page-options-relink-only {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin: 4px 1em 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.page-options-file-handling-description {
|
.page-options-file-handling-description {
|
||||||
margin-top: .6em;
|
margin-top: .6em;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
|
@ -106,6 +118,46 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#mendeley-login {
|
||||||
|
padding: 1.5em 1em 0;
|
||||||
|
font-size: 13px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
.field {
|
||||||
|
display: flex;
|
||||||
|
max-width: 300px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field+.field {
|
||||||
|
margin-top: .5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
flex: 0 0 90px;
|
||||||
|
width: 90px;
|
||||||
|
margin-right: 8px;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#mendeley-online-login-feedback {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-top: 1.3em;
|
||||||
|
color: red;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
#import-progress {
|
#import-progress {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
97
test/tests/data/mendeleyMock/items-bad-data.json
Normal file
97
test/tests/data/mendeleyMock/items-bad-data.json
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2023-03-07T13:30:46.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "b7b1023f-5072-4608-8fd5-87b045b77887",
|
||||||
|
"client_data": "{\"desktop_id\":\"9c03fca4-ee5b-435e-abdd-fb6d7d11cd02\"}",
|
||||||
|
"last_modified": "2023-03-07T13:30:46.025Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"source": "something wrong",
|
||||||
|
"identifiers": {
|
||||||
|
"doi": "10.1111",
|
||||||
|
"pmid": "PMID: 11111111",
|
||||||
|
"arxiv": "1111.2222"
|
||||||
|
},
|
||||||
|
"starred": false,
|
||||||
|
"title": "This one has no authors",
|
||||||
|
"type": "journal",
|
||||||
|
"folder_uuids": [
|
||||||
|
"8d2f262d-49b3-4dfc-8968-0bb71bcd92ea"
|
||||||
|
],
|
||||||
|
"year": 1987
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2023-03-07T13:30:46.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "a15698a9-6214-4fac-81c5-5ac62b2d06b5",
|
||||||
|
"client_data": "{\"desktop_id\":\"fd86e48e-1931-4282-b72d-78c535b0398c\"}",
|
||||||
|
"last_modified": "2023-03-07T13:30:46.025Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"source": "something wrong",
|
||||||
|
"identifiers":
|
||||||
|
{
|
||||||
|
"doi": "10.1111",
|
||||||
|
"pmid": "PMID: 11111111",
|
||||||
|
"arxiv": "1111.2222"
|
||||||
|
},
|
||||||
|
"starred": false,
|
||||||
|
"title": "This one has empty authors",
|
||||||
|
"authors":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"first_name": "",
|
||||||
|
"last_name": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "journal",
|
||||||
|
"folder_uuids": [
|
||||||
|
"8d2f262d-49b3-4dfc-8968-0bb71bcd92ea"
|
||||||
|
],
|
||||||
|
"year": 1987
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2023-03-07T13:30:46.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "49426b47-d9ff-4ab6-ba2c-54e3608f56b8",
|
||||||
|
"client_data": "{\"desktop_id\":\"c7ec2737-044a-493b-9d94-d7f67be68765\"}",
|
||||||
|
"last_modified": "2023-03-07T13:30:46.025Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"source": "something wrong",
|
||||||
|
"identifiers": {
|
||||||
|
"doi": "10.1111",
|
||||||
|
"pmid": "PMID: 11111111",
|
||||||
|
"arxiv": "1111.2222"
|
||||||
|
},
|
||||||
|
"starred": false,
|
||||||
|
"tags": ["", ""],
|
||||||
|
"keywords": [],
|
||||||
|
"title": "This one has empty tags and keywords",
|
||||||
|
"type": "journal",
|
||||||
|
"folder_uuids": [
|
||||||
|
"8d2f262d-49b3-4dfc-8968-0bb71bcd92ea"
|
||||||
|
],
|
||||||
|
"year": 1987
|
||||||
|
}
|
||||||
|
]
|
88
test/tests/data/mendeleyMock/items-simple-no-desktop-id.json
Normal file
88
test/tests/data/mendeleyMock/items-simple-no-desktop-id.json
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2021-11-02T09:54:28.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "7fea3cb3-f97d-3f16-8fad-f59caaa71688",
|
||||||
|
"last_modified": "2021-11-02T12:26:30.025Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"source": "lorem ipsum",
|
||||||
|
"identifiers":
|
||||||
|
{
|
||||||
|
"doi": "10.1111",
|
||||||
|
"pmid": "PMID: 11111111",
|
||||||
|
"arxiv": "1111.2222"
|
||||||
|
},
|
||||||
|
"starred": false,
|
||||||
|
"title": "Foo Bar",
|
||||||
|
"authors":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"first_name": "Tom",
|
||||||
|
"last_name": "Najdek"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"first_name": "Lorem",
|
||||||
|
"last_name": "Ipsum"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "journal",
|
||||||
|
"folder_uuids": [
|
||||||
|
"8d2f262d-49b3-4dfc-8968-0bb71bcd92ea"
|
||||||
|
],
|
||||||
|
"year": 1987
|
||||||
|
}, {
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2021-11-04T11:53:10.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef",
|
||||||
|
"last_modified": "2021-11-04T11:53:10.353Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"starred": false,
|
||||||
|
"title": "Sample Report",
|
||||||
|
"type": "report",
|
||||||
|
"year": 2002
|
||||||
|
}, {
|
||||||
|
"title": "Item with PDF",
|
||||||
|
"type": "journal",
|
||||||
|
"year": 2005,
|
||||||
|
"source": "Zotero",
|
||||||
|
"pages": "1-11",
|
||||||
|
"websites":
|
||||||
|
[
|
||||||
|
"https://zotero.org"
|
||||||
|
],
|
||||||
|
"id": "c54b0c6f-c4ce-4706-8742-bc7d032df862",
|
||||||
|
"created": "2021-11-09T10:26:15.201Z",
|
||||||
|
"file_attached": true,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"last_modified": "2021-11-09T10:26:16.303Z",
|
||||||
|
"read": false,
|
||||||
|
"starred": false,
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"hidden": false,
|
||||||
|
"private_publication": false,
|
||||||
|
"abstract": "Lorem Ipsum. Nostrud elit ullamco laborum cillum.",
|
||||||
|
"files":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "19fb5e5b-1a39-4851-b513-d48441a670e1",
|
||||||
|
"document_id": "c54b0c6f-c4ce-4706-8742-bc7d032df862",
|
||||||
|
"mime_type": "application/pdf",
|
||||||
|
"file_name": "item.pdf",
|
||||||
|
"size": 123456,
|
||||||
|
"created": "2021-11-09T10:26:16.292Z",
|
||||||
|
"filehash": "cc22c6611277df346ff8dc7386ba3880b2bafa15"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -6,6 +6,7 @@
|
||||||
"file_attached": false,
|
"file_attached": false,
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"id": "7fea3cb3-f97d-3f16-8fad-f59caaa71688",
|
"id": "7fea3cb3-f97d-3f16-8fad-f59caaa71688",
|
||||||
|
"client_data": "{\"desktop_id\":\"b5f57b1a-f083-486c-aec7-5d5edd366dd2\"}",
|
||||||
"last_modified": "2021-11-02T12:26:30.025Z",
|
"last_modified": "2021-11-02T12:26:30.025Z",
|
||||||
"private_publication": false,
|
"private_publication": false,
|
||||||
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
@ -42,6 +43,7 @@
|
||||||
"file_attached": false,
|
"file_attached": false,
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"id": "07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef",
|
"id": "07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef",
|
||||||
|
"client_data": "{\"desktop_id\":\"616ec6d1-8d23-4414-8b6e-7bb129677577\"}",
|
||||||
"last_modified": "2021-11-04T11:53:10.353Z",
|
"last_modified": "2021-11-04T11:53:10.353Z",
|
||||||
"private_publication": false,
|
"private_publication": false,
|
||||||
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
@ -61,6 +63,7 @@
|
||||||
"https://zotero.org"
|
"https://zotero.org"
|
||||||
],
|
],
|
||||||
"id": "c54b0c6f-c4ce-4706-8742-bc7d032df862",
|
"id": "c54b0c6f-c4ce-4706-8742-bc7d032df862",
|
||||||
|
"client_data": "{\"desktop_id\":\"3630a4bf-d97e-46c4-8611-61ec50f840c6\"}",
|
||||||
"created": "2021-11-09T10:26:15.201Z",
|
"created": "2021-11-09T10:26:15.201Z",
|
||||||
"file_attached": true,
|
"file_attached": true,
|
||||||
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
@ -84,5 +87,30 @@
|
||||||
"filehash": "cc22c6611277df346ff8dc7386ba3880b2bafa15"
|
"filehash": "cc22c6611277df346ff8dc7386ba3880b2bafa15"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2021-11-04T11:53:10.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "cda0c150-bc85-4312-af2c-61a29b179595",
|
||||||
|
"client_data": "{\"desktop_id\":\"4308d8ec-e8ea-43fb-9d38-4e6628f7c10a\"}",
|
||||||
|
"last_modified": "2021-11-04T11:53:10.353Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"starred": false,
|
||||||
|
"tags": [
|
||||||
|
"tag1",
|
||||||
|
"tag2"
|
||||||
|
],
|
||||||
|
"keywords": [
|
||||||
|
"keyword1",
|
||||||
|
"keyword2"
|
||||||
|
],
|
||||||
|
"title": "Has tags",
|
||||||
|
"type": "report",
|
||||||
|
"year": 2002
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -2,10 +2,11 @@
|
||||||
{
|
{
|
||||||
"authored": false,
|
"authored": false,
|
||||||
"confirmed": true,
|
"confirmed": true,
|
||||||
"created": "2021-11-04T11:53:10.353Z",
|
"created": "2021-12-05T12:00:00.000Z",
|
||||||
"file_attached": false,
|
"file_attached": false,
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"id": "07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef",
|
"id": "07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef",
|
||||||
|
"client_data": "{\"desktop_id\":\"616ec6d1-8d23-4414-8b6e-7bb129677577\"}",
|
||||||
"last_modified": "2021-11-05T11:53:10.353Z",
|
"last_modified": "2021-11-05T11:53:10.353Z",
|
||||||
"private_publication": false,
|
"private_publication": false,
|
||||||
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
@ -15,5 +16,23 @@
|
||||||
"type": "journal",
|
"type": "journal",
|
||||||
"source": "lorem ipsum",
|
"source": "lorem ipsum",
|
||||||
"year": 2002
|
"year": 2002
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"authored": false,
|
||||||
|
"confirmed": true,
|
||||||
|
"created": "2021-11-05T12:33:18.353Z",
|
||||||
|
"file_attached": false,
|
||||||
|
"hidden": false,
|
||||||
|
"id": "31a8251f-88b0-497b-9d30-1b2516771057",
|
||||||
|
"client_data": "{\"desktop_id\":\"86e56a00-5ae5-4fe8-a977-9298a03b16d6\"}",
|
||||||
|
"last_modified": "2021-11-05T12:33:18.353Z",
|
||||||
|
"private_publication": false,
|
||||||
|
"profile_id": "8dbf0832-8723-4c48-b532-20c0b7f6e01a",
|
||||||
|
"read": false,
|
||||||
|
"starred": true,
|
||||||
|
"title": "Completely new item",
|
||||||
|
"type": "book",
|
||||||
|
"source": "lorem ipsum",
|
||||||
|
"year": 1999
|
||||||
}
|
}
|
||||||
]
|
]
|
|
@ -1,12 +1,17 @@
|
||||||
/* global setHTTPResponse:false, sinon: false, Zotero_Import_Mendeley: false, HttpServer: false */
|
/* global setHTTPResponse:false, sinon: false, Zotero_Import_Mendeley: false, HttpServer: false */
|
||||||
|
|
||||||
describe('Zotero_Import_Mendeley', function () {
|
describe('Zotero_Import_Mendeley', function () {
|
||||||
var server, importer, httpd, httpdURL;
|
var server, httpd, httpdURL, importers;
|
||||||
|
|
||||||
|
const getImporter = () => {
|
||||||
|
const importer = new Zotero_Import_Mendeley();
|
||||||
|
importer.mendeleyAuth = { access_token: 'access_token', refresh_token: 'refresh_token' };// eslint-disable-line camelcase
|
||||||
|
importers.push(importer);
|
||||||
|
return importer;
|
||||||
|
};
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
Components.utils.import('chrome://zotero/content/import/mendeley/mendeleyImport.js');
|
Components.utils.import('chrome://zotero/content/import/mendeley/mendeleyImport.js');
|
||||||
importer = new Zotero_Import_Mendeley();
|
|
||||||
importer.mendeleyCode = 'CODE';
|
|
||||||
|
|
||||||
// real http server is used to deliver an empty pdf so that annotations can be processed during import
|
// real http server is used to deliver an empty pdf so that annotations can be processed during import
|
||||||
Components.utils.import("resource://zotero-unit/httpd.js");
|
Components.utils.import("resource://zotero-unit/httpd.js");
|
||||||
|
@ -25,12 +30,15 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
importers = [];
|
||||||
Zotero.HTTP.mock = sinon.FakeXMLHttpRequest;
|
Zotero.HTTP.mock = sinon.FakeXMLHttpRequest;
|
||||||
server = sinon.fakeServer.create();
|
server = sinon.fakeServer.create({
|
||||||
|
unsafeHeadersEnabled: false
|
||||||
|
});
|
||||||
server.autoRespond = true;
|
server.autoRespond = true;
|
||||||
setHTTPResponse(server, 'https://www.zotero.org/', {
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
url: `utils/mendeley/oauth`,
|
url: `oauth/token`,
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: {},
|
headers: {},
|
||||||
json: {
|
json: {
|
||||||
|
@ -127,12 +135,21 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(async () => {
|
||||||
|
await Promise.all(
|
||||||
|
importers
|
||||||
|
.map(importer => ([
|
||||||
|
Zotero.Items.erase(Array.from(new Set(importer.newItems)).map(i => i.id)),
|
||||||
|
Zotero.Collections.erase(Array.from(new Set(importer.newCollections)).map(c => c.id))
|
||||||
|
]))
|
||||||
|
.reduce((prev, a) => ([...prev, ...a]), []) // .flat() in >= FF62
|
||||||
|
);
|
||||||
Zotero.HTTP.mock = null;
|
Zotero.HTTP.mock = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#import', () => {
|
describe('#import', () => {
|
||||||
it("should import collections, items, attachments & annotations", async () => {
|
it("should import collections, items, attachments & annotations", async () => {
|
||||||
|
const importer = getImporter();
|
||||||
await importer.translate({
|
await importer.translate({
|
||||||
libraryID: Zotero.Libraries.userLibraryID,
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
collections: null,
|
collections: null,
|
||||||
|
@ -140,17 +157,17 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
const journal = (await Zotero.Relations
|
const journal = (await Zotero.Relations
|
||||||
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '7fea3cb3-f97d-3f16-8fad-f59caaa71688'))
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', 'b5f57b1a-f083-486c-aec7-5d5edd366dd2'))
|
||||||
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
.shift();
|
.shift();
|
||||||
|
|
||||||
const report = (await Zotero.Relations
|
const report = (await Zotero.Relations
|
||||||
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef'))
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '616ec6d1-8d23-4414-8b6e-7bb129677577'))
|
||||||
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
.shift();
|
.shift();
|
||||||
|
|
||||||
const withpdf = (await Zotero.Relations
|
const withpdf = (await Zotero.Relations
|
||||||
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', 'c54b0c6f-c4ce-4706-8742-bc7d032df862'))
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '3630a4bf-d97e-46c4-8611-61ec50f840c6'))
|
||||||
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
.shift();
|
.shift();
|
||||||
|
|
||||||
|
@ -159,10 +176,19 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
.shift();
|
.shift();
|
||||||
|
|
||||||
|
const withTags = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '4308d8ec-e8ea-43fb-9d38-4e6628f7c10a'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
|
||||||
|
assert.equal(journal.getRelations()['mendeleyDB:remoteDocumentUUID'], '7fea3cb3-f97d-3f16-8fad-f59caaa71688');
|
||||||
assert.equal(journal.getField('title'), 'Foo Bar');
|
assert.equal(journal.getField('title'), 'Foo Bar');
|
||||||
assert.equal(journal.itemTypeID, Zotero.ItemTypes.getID('journalArticle'));
|
assert.equal(journal.itemTypeID, Zotero.ItemTypes.getID('journalArticle'));
|
||||||
|
assert.equal(report.getRelations()['mendeleyDB:remoteDocumentUUID'], '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef');
|
||||||
assert.equal(report.getField('title'), 'Sample Report');
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('report'));
|
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('report'));
|
||||||
|
assert.equal(withpdf.getRelations()['mendeleyDB:remoteDocumentUUID'], 'c54b0c6f-c4ce-4706-8742-bc7d032df862');
|
||||||
assert.equal(withpdf.getField('title'), 'Item with PDF');
|
assert.equal(withpdf.getField('title'), 'Item with PDF');
|
||||||
assert.equal(withpdf.itemTypeID, Zotero.ItemTypes.getID('journalArticle'));
|
assert.equal(withpdf.itemTypeID, Zotero.ItemTypes.getID('journalArticle'));
|
||||||
|
|
||||||
|
@ -176,6 +202,17 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
assert.equal(journal.getField('DOI'), '10.1111');
|
assert.equal(journal.getField('DOI'), '10.1111');
|
||||||
assert.sameMembers(journal.getField('extra').split('\n'), ['PMID: 11111111', 'arXiv: 1111.2222']);
|
assert.sameMembers(journal.getField('extra').split('\n'), ['PMID: 11111111', 'arXiv: 1111.2222']);
|
||||||
|
|
||||||
|
// tags
|
||||||
|
assert.equal(withTags.getTags().length, 4);
|
||||||
|
assert.sameMembers(
|
||||||
|
withTags.getTags().filter(t => t.type === 1).map(t => t.tag),
|
||||||
|
['keyword1', 'keyword2']
|
||||||
|
);
|
||||||
|
assert.sameMembers(
|
||||||
|
withTags.getTags().filter(t => !t.type).map(t => t.tag),
|
||||||
|
['tag1', 'tag2']
|
||||||
|
);
|
||||||
|
|
||||||
// attachment & annotations
|
// attachment & annotations
|
||||||
assert.lengthOf(withpdf.getAttachments(), 1);
|
assert.lengthOf(withpdf.getAttachments(), 1);
|
||||||
assert.equal(pdf.parentID, withpdf.id);
|
assert.equal(pdf.parentID, withpdf.id);
|
||||||
|
@ -237,22 +274,23 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
assert.equal(parentCollection.name, 'folder1');
|
assert.equal(parentCollection.name, 'folder1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update previously imported item", async () => {
|
it("should update previously imported item, based on config", async () => {
|
||||||
const importer = new Zotero_Import_Mendeley();
|
const importer1 = getImporter();
|
||||||
importer.mendeleyCode = 'CODE';
|
await importer1.translate({
|
||||||
await importer.translate({
|
|
||||||
libraryID: Zotero.Libraries.userLibraryID,
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
collections: null,
|
collections: null,
|
||||||
linkFiles: false,
|
linkFiles: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const report = (await Zotero.Relations
|
const report = (await Zotero.Relations
|
||||||
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef'))
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '616ec6d1-8d23-4414-8b6e-7bb129677577'))
|
||||||
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
.shift();
|
.shift();
|
||||||
|
|
||||||
|
|
||||||
assert.equal(report.getField('title'), 'Sample Report');
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
assert.equal(report.getField('year'), '2002');
|
assert.equal(report.getField('year'), '2002');
|
||||||
|
assert.equal(report.getField('dateAdded'), '2021-11-04 11:53:10');
|
||||||
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('report'));
|
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('report'));
|
||||||
assert.lengthOf(report.getTags(), 0);
|
assert.lengthOf(report.getTags(), 0);
|
||||||
|
|
||||||
|
@ -266,7 +304,9 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
await importer.translate({
|
const importer2 = getImporter();
|
||||||
|
importer2.newItemsOnly = false;
|
||||||
|
await importer2.translate({
|
||||||
libraryID: Zotero.Libraries.userLibraryID,
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
collections: null,
|
collections: null,
|
||||||
linkFiles: false,
|
linkFiles: false,
|
||||||
|
@ -276,6 +316,200 @@ describe('Zotero_Import_Mendeley', function () {
|
||||||
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('journalArticle'));
|
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('journalArticle'));
|
||||||
assert.equal(report.getField('year'), '2002');
|
assert.equal(report.getField('year'), '2002');
|
||||||
assert.sameMembers(report.getTags().map(t => t.tag), ['\u2605']);
|
assert.sameMembers(report.getTags().map(t => t.tag), ['\u2605']);
|
||||||
|
// dateAdded shouldn't change on an updated item. See #2881
|
||||||
|
assert.equal(report.getField('dateAdded'), '2021-11-04 11:53:10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("shouldn't update previously imported item, based on config", async () => {
|
||||||
|
const importer1 = getImporter();
|
||||||
|
await importer1.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const report = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '616ec6d1-8d23-4414-8b6e-7bb129677577'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
const noNewItemHere = await Zotero.Relations.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '86e56a00-5ae5-4fe8-a977-9298a03b16d6');
|
||||||
|
|
||||||
|
|
||||||
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
|
assert.equal(report.getField('year'), '2002');
|
||||||
|
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('report'));
|
||||||
|
assert.lengthOf(report.getTags(), 0);
|
||||||
|
assert.lengthOf(noNewItemHere, 0);
|
||||||
|
|
||||||
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
|
method: 'GET',
|
||||||
|
url: `documents?view=all&limit=500`,
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
json: JSON.parse(
|
||||||
|
await Zotero.File.getContentsFromURLAsync('resource://zotero-unit-tests/data/mendeleyMock/items-updated.json')
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
const importer2 = getImporter();
|
||||||
|
importer2.newItemsOnly = true;
|
||||||
|
await importer2.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
|
assert.equal(report.itemTypeID, Zotero.ItemTypes.getID('report'));
|
||||||
|
assert.equal(report.getField('year'), '2002');
|
||||||
|
assert.lengthOf(report.getTags(), 0);
|
||||||
|
|
||||||
|
const newItem = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '86e56a00-5ae5-4fe8-a977-9298a03b16d6'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
assert.equal(newItem.getField('title'), 'Completely new item');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should correct IDs if available on subsequent import", async () => {
|
||||||
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
|
method: 'GET',
|
||||||
|
url: `documents?view=all&limit=500`,
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
json: JSON.parse(
|
||||||
|
await Zotero.File.getContentsFromURLAsync('resource://zotero-unit-tests/data/mendeleyMock/items-simple-no-desktop-id.json')
|
||||||
|
)
|
||||||
|
});
|
||||||
|
const importer = getImporter();
|
||||||
|
importer.newItemsOnly = true;
|
||||||
|
await importer.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const report = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:remoteDocumentUUID', '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
|
assert.equal(report.getRelations()['mendeleyDB:documentUUID'], '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef');
|
||||||
|
|
||||||
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
|
method: 'GET',
|
||||||
|
url: `documents?view=all&limit=500`,
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
json: JSON.parse(
|
||||||
|
await Zotero.File.getContentsFromURLAsync('resource://zotero-unit-tests/data/mendeleyMock/items-simple.json')
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
await importer.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
|
assert.equal(report.getRelations()['mendeleyDB:documentUUID'], '616ec6d1-8d23-4414-8b6e-7bb129677577');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should only correct IDs and not add new items if \"relinkOnly\" is configured", async () => {
|
||||||
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
|
method: 'GET',
|
||||||
|
url: `documents?view=all&limit=500`,
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
json: JSON.parse(
|
||||||
|
await Zotero.File.getContentsFromURLAsync('resource://zotero-unit-tests/data/mendeleyMock/items-simple-no-desktop-id.json')
|
||||||
|
)
|
||||||
|
});
|
||||||
|
const importer1 = getImporter();
|
||||||
|
await importer1.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const report = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:remoteDocumentUUID', '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
|
assert.equal(report.getRelations()['mendeleyDB:documentUUID'], '07a74c26-28d1-4d9f-a60d-3f3bc5ef76ef');
|
||||||
|
|
||||||
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
|
method: 'GET',
|
||||||
|
url: `documents?view=all&limit=500`,
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
json: JSON.parse(
|
||||||
|
await Zotero.File.getContentsFromURLAsync('resource://zotero-unit-tests/data/mendeleyMock/items-updated.json')
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
const importer2 = getImporter();
|
||||||
|
importer2.relinkOnly = true;
|
||||||
|
await importer2.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(report.getField('title'), 'Sample Report');
|
||||||
|
assert.equal(report.getRelations()['mendeleyDB:documentUUID'], '616ec6d1-8d23-4414-8b6e-7bb129677577');
|
||||||
|
|
||||||
|
const noNewItemHere = await Zotero.Relations.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '86e56a00-5ae5-4fe8-a977-9298a03b16d6');
|
||||||
|
assert.lengthOf(noNewItemHere, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty creators and tags", async () => {
|
||||||
|
setHTTPResponse(server, 'https://api.mendeley.com/', {
|
||||||
|
method: 'GET',
|
||||||
|
url: `documents?view=all&limit=500`,
|
||||||
|
status: 200,
|
||||||
|
headers: {},
|
||||||
|
json: JSON.parse(
|
||||||
|
await Zotero.File.getContentsFromURLAsync('resource://zotero-unit-tests/data/mendeleyMock/items-bad-data.json')
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
const importer = getImporter();
|
||||||
|
await importer.translate({
|
||||||
|
libraryID: Zotero.Libraries.userLibraryID,
|
||||||
|
collections: null,
|
||||||
|
linkFiles: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const journalNoAuthors = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', '9c03fca4-ee5b-435e-abdd-fb6d7d11cd02'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
assert.equal(journalNoAuthors.getField('title'), 'This one has no authors');
|
||||||
|
assert.equal(journalNoAuthors.getCreators().length, 0);
|
||||||
|
|
||||||
|
const journalEmptyAuthors = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', 'fd86e48e-1931-4282-b72d-78c535b0398c'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
assert.equal(journalEmptyAuthors.getField('title'), 'This one has empty authors');
|
||||||
|
assert.equal(journalEmptyAuthors.getCreators().length, 0);
|
||||||
|
|
||||||
|
const journalEmptyTags = (await Zotero.Relations
|
||||||
|
.getByPredicateAndObject('item', 'mendeleyDB:documentUUID', 'c7ec2737-044a-493b-9d94-d7f67be68765'))
|
||||||
|
.filter(item => item.libraryID == Zotero.Libraries.userLibraryID && !item.deleted)
|
||||||
|
.shift();
|
||||||
|
|
||||||
|
assert.equal(journalEmptyTags.getField('title'), 'This one has empty tags and keywords');
|
||||||
|
assert.equal(journalEmptyTags.getTags().length, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue