From 197d8d1f3b9bc768bf6c2e4138ad419762c21f7e Mon Sep 17 00:00:00 2001 From: Tom Najdek Date: Thu, 15 Dec 2022 19:35:29 +0100 Subject: [PATCH] Add option to Mendeley importer to relink items New option only appears if importer version is < 1 or not present. It will: * Skip fetching collections and attachments * Skip any new items * Update relations on existing items --- chrome/content/zotero/fileInterface.js | 1 + chrome/content/zotero/import/importWizard.js | 19 ++++++- .../content/zotero/import/importWizard.xhtml | 3 ++ .../zotero/import/mendeley/mendeleyImport.js | 30 +++++++---- chrome/locale/en-US/zotero/zotero.ftl | 2 + scss/components/_import-wizard.scss | 4 ++ test/tests/mendeleyImportTest.js | 51 +++++++++++++++++++ 7 files changed, 99 insertions(+), 11 deletions(-) diff --git a/chrome/content/zotero/fileInterface.js b/chrome/content/zotero/fileInterface.js index 5caba74f60..9afe469e9b 100644 --- a/chrome/content/zotero/fileInterface.js +++ b/chrome/content/zotero/fileInterface.js @@ -450,6 +450,7 @@ var Zotero_File_Interface = new function() { translation.mendeleyAuth = options.mendeleyAuth; translation.mendeleyCode = options.mendeleyCode; translation.newItemsOnly = options.newItemsOnly; + translation.relinkOnly = options.relinkOnly; } else if (options.folder) { Components.utils.import("chrome://zotero/content/import/folderImport.js"); diff --git a/chrome/content/zotero/import/importWizard.js b/chrome/content/zotero/import/importWizard.js index 0b4ab7af4b..eeac19fdc8 100644 --- a/chrome/content/zotero/import/importWizard.js +++ b/chrome/content/zotero/import/importWizard.js @@ -43,6 +43,7 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars mendeleyAuth: null, mendeleyCode: null, mendeleyHasPreviouslyImported: false, + mendeleyImporterVersion: 0, translation: null, wizard: null, @@ -72,6 +73,7 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars 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.getPageById('page-start') @@ -110,6 +112,8 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars .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('wizardcancel', this.onCancel.bind(this)); @@ -301,6 +305,7 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars 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; } @@ -354,6 +359,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) { if (ev.type === 'click' || (ev.type === 'keydown' && ev.key === ' ')) { Zotero.launchURL(ev.currentTarget.getAttribute('href')); @@ -393,6 +408,7 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars ? document.getElementById('other-files').value : null; const newItemsOnly = document.getElementById('new-items-only-checkbox').checked; + const relinkOnly = document.getElementById('relink-only-checkbox').checked; try { const result = await Zotero_File_Interface.importFile({ @@ -406,7 +422,8 @@ const Zotero_Import_Wizard = { // eslint-disable-line no-unused-vars mimeTypes, newItemsOnly, onBeforeImport: this.onBeforeImport.bind(this), - recreateStructure + recreateStructure, + relinkOnly }); // Cancelled by user or due to error diff --git a/chrome/content/zotero/import/importWizard.xhtml b/chrome/content/zotero/import/importWizard.xhtml index f912f57dc9..836bd172e9 100644 --- a/chrome/content/zotero/import/importWizard.xhtml +++ b/chrome/content/zotero/import/importWizard.xhtml @@ -54,6 +54,9 @@ pageid="page-options" data-header-label-id="import-options" > +
diff --git a/chrome/content/zotero/import/mendeley/mendeleyImport.js b/chrome/content/zotero/import/mendeley/mendeleyImport.js index 532416289c..4703808de2 100644 --- a/chrome/content/zotero/import/mendeley/mendeleyImport.js +++ b/chrome/content/zotero/import/mendeley/mendeleyImport.js @@ -32,6 +32,7 @@ var Zotero_Import_Mendeley = function () { this.newCollections = []; this.mendeleyAuth = null; this.newItemsOnly = false; + this.relinkOnly = false; this._tokens = null; this._db = null; @@ -92,13 +93,15 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) { skipSelect: true, ...(options.saveOptions || {}) }; + + this.newItemsOnly = this.newItemsOnly || this.relinkOnly; const libraryID = options.libraryID || Zotero.Libraries.userLibraryID; const { key: rootCollectionKey } = options.collections ? 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 const mapVersion = 83; @@ -135,14 +138,17 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) { this._progressMax = 50; this._itemDone(); - const folders = this._tokens - ? await this._getFoldersAPI(mendeleyGroupID) - : await this._getFoldersDB(mendeleyGroupID); + let folderKeys = new Map(); + if(!this.relinkOnly) { + const folders = this._tokens + ? await this._getFoldersAPI(mendeleyGroupID) + : await this._getFoldersDB(mendeleyGroupID); - const collectionJSON = this._foldersToAPIJSON(folders, rootCollectionKey); - const folderKeys = this._getFolderKeys(collectionJSON); + const collectionJSON = this._foldersToAPIJSON(folders, rootCollectionKey); + folderKeys = this._getFolderKeys(collectionJSON); - await this._saveCollections(libraryID, collectionJSON, folderKeys); + await this._saveCollections(libraryID, collectionJSON, folderKeys); + } this._interruptChecker(true); // @@ -175,13 +181,13 @@ Zotero_Import_Mendeley.prototype.translate = async function (options = {}) { this._interruptChecker(true); - let collections = this._tokens + let collections = this.relinkOnly ? new Map() : this._tokens ? await this._getDocumentCollectionsAPI(documents, rootCollectionKey, folderKeys) : await this._getDocumentCollectionsDB(mendeleyGroupID, documents, rootCollectionKey, folderKeys); this._interruptChecker(true); - - let files = this._tokens + + let files = this.relinkOnly ? new Map() : this._tokens ? await this._getDocumentFilesAPI(documents) : await this._getDocumentFilesDB(mendeleyGroupID); @@ -1330,6 +1336,10 @@ Zotero_Import_Mendeley.prototype._saveItems = async function (libraryID, json) { await item.loadPrimaryData(); } } + + if(this.relinkOnly && !isMappedToExisting) { + continue; + } // Remove external id before save let toSave = Object.assign({}, itemJSON); diff --git a/chrome/locale/en-US/zotero/zotero.ftl b/chrome/locale/en-US/zotero/zotero.ftl index 2316d11b62..e5b6130670 100644 --- a/chrome/locale/en-US/zotero/zotero.ftl +++ b/chrome/locale/en-US/zotero/zotero.ftl @@ -61,6 +61,8 @@ import-online-intro2={ -app-name } will never see or store your { $targetApp } p 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 report-error = .label = Report Error… diff --git a/scss/components/_import-wizard.scss b/scss/components/_import-wizard.scss index 3794c3bd99..13f9466082 100644 --- a/scss/components/_import-wizard.scss +++ b/scss/components/_import-wizard.scss @@ -42,6 +42,10 @@ margin: 0; } + [disabled="true"] .checkbox-label { + opacity: .5; + } + #other-files { margin-left: -1px; width: 400px; diff --git a/test/tests/mendeleyImportTest.js b/test/tests/mendeleyImportTest.js index d176806ff0..8c257cf9af 100644 --- a/test/tests/mendeleyImportTest.js +++ b/test/tests/mendeleyImportTest.js @@ -402,5 +402,56 @@ describe('Zotero_Import_Mendeley', function () { 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); + + }); }); });