Mobrovac has submitted this change and it was merged. Change subject: Make zotero.js an object ......................................................................
Make zotero.js an object Convert zotero.js to ZoteroService.js object. Modify CitoidService.js to point to an instance of a ZoteroService object. Bug: T78389 Change-Id: I48158fc037277ee688ef35ab0db688a46aaf54d7 --- M lib/CitoidService.js R lib/ZoteroService.js M server.js 3 files changed, 90 insertions(+), 112 deletions(-) Approvals: Mobrovac: Looks good to me, approved diff --git a/lib/CitoidService.js b/lib/CitoidService.js index 72b9334..73711dd 100644 --- a/lib/CitoidService.js +++ b/lib/CitoidService.js @@ -3,15 +3,13 @@ */ /* Import Modules */ -var crypto = require('crypto'), - urlParse = require('url'), +var urlParse = require('url'), util = require('util'); /* Import Local Modules */ var unshorten = require('./unshorten.js'), scrape = require('./scrape.js'), - zoteroWebRequest = require('./zotero.js').zoteroWebRequest, - zoteroExportRequest = require('./zotero.js').zoteroExportRequest, + ZoteroService = require('./ZoteroService.js'), pubMedRequest = require('./pubMedRequest.js'); /** @@ -22,28 +20,23 @@ function CitoidService(CitoidConfig, logger){ this.CitoidConfig = CitoidConfig; this.log = logger; - this.zoteroURL = util.format('http://%s:%s/%s', + this.zoteroURL = util.format('http://%s:%s/', CitoidConfig.zoteroInterface, CitoidConfig.zoteroPort.toString()); + this.zoteroService = new ZoteroService(this.zoteroURL, logger); } /** * Requests to the citoid service * @param {String} searchTerm searchTerm metadata is being requested about - * @param {Object} opts zoteroWebRequest options object + * @param {Object} format export format * @param {Function} callback callback (error, statusCode, body) */ CitoidService.prototype.request = function(searchTerm, format, callback){ - var citoidService = this, - sessionID = crypto.randomBytes(20).toString('hex'), //required zotero- not terribly important for this to be secure - opts = { - zoteroURL:citoidService.zoteroURL, - sessionID:sessionID, - format:format - }; + var citoidService = this; citoidService.distinguish(searchTerm, function(extractedID, runnerFunction){ - runnerFunction(extractedID, opts, function(error, responseCode, body){ + runnerFunction(extractedID, format, function(error, responseCode, body){ callback(error, responseCode, body); }); }); @@ -52,17 +45,20 @@ /** * Request citation metadata from a URL * @param {String} requestedURL URL metadata is being requested about - * @param {Object} opts zoteroWebRequest options object + * @param {Object} format requested export format * @param {Function} callback callback (error, statusCode, body) */ -CitoidService.prototype.requestFromURL = function (requestedURL, opts, callback){ - var log = this.log; - zoteroWebRequest(requestedURL, opts, function(error, response, body){ +CitoidService.prototype.requestFromURL = function (requestedURL, format, callback){ + var self = this, + log = self.log, + zoteroWebRequest = this.zoteroService.zoteroWebRequest.bind(this.zoteroService); + + zoteroWebRequest(requestedURL, format, function(error, response, body){ log.info("Zotero request made for: " + requestedURL); if (error) { log.error(error); log.info("Falling back on native scraper."); - scrapeHelper(requestedURL, opts, callback); + self.scrapeHelper(requestedURL, format, callback); } else if (response) { //501 indicates no translator available //this is common- can indicate shortened url @@ -76,18 +72,18 @@ unshorten(requestedURL, function(detected, expandedURL) { if (detected) { log.info("Redirect detected to "+ expandedURL); - zoteroWebRequest(expandedURL, opts, function(error, response, body){ + zoteroWebRequest(expandedURL, format, function(error, response, body){ if (response && !error && response.statusCode === 200){ log.info("Successfully retrieved and translated body from Zotero"); callback(null, 200, body); } else { log.info("No Zotero response available; falling back on native scraper."); - scrapeHelper(requestedURL, opts, callback); + self.scrapeHelper(requestedURL, format, callback); } }); } else { log.info("No redirect detected; falling back on native scraper."); - scrapeHelper(requestedURL, opts, callback); + self.scrapeHelper(requestedURL, format, callback); } }); } else if (response.statusCode === 200){ @@ -96,11 +92,11 @@ } else { //other response codes such as 500, 300 log.info("Falling back on native scraper."); - scrapeHelper(requestedURL, opts, callback); + self.scrapeHelper(requestedURL, format, callback); } } else { log.info("Falling back on native scraper."); - scrapeHelper(requestedURL, opts, callback); + self.scrapeHelper(requestedURL, format, callback); } }); }; @@ -108,29 +104,29 @@ /** * Request citation metadata from a DOI * @param {String} requestedDOI DOI pointing to URL metadata is being requested about - * @param {Object} opts zoteroWebRequest options object + * @param {Object} format requested export format * @param {Function} callback callback (error, statusCode, body) */ -CitoidService.prototype.requestFromDOI = function (requestedDOI, opts, callback){ +CitoidService.prototype.requestFromDOI = function (requestedDOI, format, callback){ var doiLink = 'http://dx.doi.org/'+ requestedDOI; //TODO: optimise this (can skip some steps in requestFromURL) - this.requestFromURL(doiLink, opts, callback); + this.requestFromURL(doiLink, format, callback); }; /** * Request citation metadata from a PubMed identifier. Supports PMID, PMCID, Manuscript ID and versioned identifiers * @param {String} requestedPubMedID PubMed identifier for which metadata is being requested. PMCID identifiers must begin with 'PMC' - * @param {Object} opts zoteroWebRequest options object + * @param {Object} format requested export format * @param {Function} callback callback (error, statusCode, body) */ -CitoidService.prototype.requestFromPubMedID = function(requestedPubMedID, opts, callback){ +CitoidService.prototype.requestFromPubMedID = function(requestedPubMedID, format, callback){ pubMedRequest(requestedPubMedID, function(error, obj){ if(error){ callback(error, null, null); } else { var doi = obj.records[0].doi; this.log.info("Got DOI " + doi); - this.requestFromDOI(doi, opts, callback); + this.requestFromDOI(doi, format, callback); } }); }; @@ -180,15 +176,16 @@ * sends response to Zotero if it's a format Zotero can convert to. * Currently only exports bibtex. * @param {String} url requested URL - * @param {Object} opts request options object + * @param {Object} format requested export format * @param {Function} callback callback(error, responseCode, citation) */ -function scrapeHelper(url, opts, callback) { - if (opts.format === 'bibtex') { +CitoidService.prototype.scrapeHelper = function(url, format, callback) { + var zoteroExportRequest = this.zoteroService.zoteroExportRequest.bind(this.zoteroService); + if (format === 'bibtex') { scrape(url, function(error, responseCode, citation) { - zoteroExportRequest(citation[0], opts, function(err, resCode, body) { + zoteroExportRequest(citation[0], format, function(err, resCode, body) { if (resCode !== 200){ - body = "Unable to serve this format at this time"; + body = "Unable to serve "+ format +" format at this time"; resCode = 404; // 404 error if cannot translate into alternate format } else if (responseCode !== 200){ resCode = 520; // 520 error if the scraper couldn't scrape from url @@ -199,8 +196,6 @@ } else { scrape(url, callback); } -} +}; -module.exports = { - CitoidService: CitoidService, -}; \ No newline at end of file +module.exports = CitoidService; diff --git a/lib/zotero.js b/lib/ZoteroService.js similarity index 75% rename from lib/zotero.js rename to lib/ZoteroService.js index 16fbbf2..0cc4a0c 100644 --- a/lib/zotero.js +++ b/lib/ZoteroService.js @@ -6,31 +6,41 @@ */ /* Import Modules */ -var request = require('request'), - async = require('async'), - util = require('util'), +var async = require('async'), + crypto = require('crypto'), + request = require('request'), pubMedRequest = require('./pubMedRequest.js'); + +function ZoteroService(zoteroURL, logger){ + this.log = logger; + this.baseURL = zoteroURL; + this.webURL = zoteroURL + 'web'; + this.exportURL = zoteroURL + 'export'; +} /** * Requests to Zotero server endpoint /web * @param {String} requestedURL url being requested - * @param {Object} opts options for request + * @param {Object} format options for request * @param {Function} callback callback(error, response, body) */ -var zoteroWebRequest = function(requestedURL, opts, callback){ - var options = { - url: util.format(opts.zoteroURL, 'web'), +ZoteroService.prototype.zoteroWebRequest = function(requestedURL, format, callback){ + + var zoteroService = this, + sessionID = crypto.randomBytes(20).toString('hex'), + options = { + url: this.webURL, method: 'POST', json: { "url": requestedURL, - "sessionid": opts.sessionID + "sessionid": sessionID } }; request(options, function (error, response, body) { if (!error && response.statusCode === 200) { - selectFormatFcn(opts.format, function(convert){ - convert(requestedURL, opts, body, function(modifiedBody){ + zoteroService.selectFormatFcn(format, function(convert){ + convert(requestedURL, format, body, function(modifiedBody){ callback(error, response, modifiedBody); }); }); @@ -44,15 +54,15 @@ /** * Request to Zotero server endpoint /export * @param {Object} citation Zotero JSON citation to be converted - * @param {Object} opts options for request + * @param {Object} format options for request * @param {Function} callback callback(error, responseCode, body) */ -var zoteroExportRequest = function(citation, opts, callback){ +ZoteroService.prototype.zoteroExportRequest = function(citation, format, callback){ var options = { - url: util.format(opts.zoteroURL, 'export'), + url: this.exportURL, method: 'POST', body: JSON.stringify([citation]), - qs: {format: opts.format}, + qs: {format: format}, headers: { 'content-type': 'application/json' } @@ -72,14 +82,15 @@ * @param {String} format string describing format * @param {Function} callback callback(desiredFunctionHere) */ -var selectFormatFcn = function (format, callback){ - var formatFcns = { - 'mwDeprecated':convertToMWDeprecatedAsync, - 'mediawiki':convertToMediawikiAsync, - 'zotero':convertToZoteroAsync, - 'bibtex':convertToBibtexAsync +ZoteroService.prototype.selectFormatFcn = function (format, callback){ + var self = this, + formatFcns = { + 'mwDeprecated':self.convertToMWDeprecatedAsync, + 'mediawiki':self.convertToMediawikiAsync, + 'zotero':self.convertToZoteroAsync, + 'bibtex':self.convertToBibtexAsync }; - callback(formatFcns[format]); + callback(formatFcns[format].bind(self)); }; /* Specific Conversion Methods */ @@ -87,11 +98,11 @@ /** * Takes Zotero output and standardises it * @param {String} url URL provided by user - * @param {Object} opts opts object for Zotero requests + * @param {Object} format requested format * @param {Array} body Array of citation objects * @param {Function} callback callback(arrayOfCitationObjs) */ -var convertToZoteroAsync = function (url, opts, body, callback){ +ZoteroService.prototype.convertToZoteroAsync = function(url, format, body, callback){ var citation = body[0]; if (citation instanceof Array){ citation = citation[0]; @@ -112,12 +123,13 @@ /** * Takes Zotero output, standardises, and exports to BibTex * @param {String} url URL provided by user - * @param {Object} opts opts object for Zotero requests + * @param {Object} format requested format * @param {Array} body Array of citation objects * @param {Function} callback callback(arrayOfCitationObjs) */ -var convertToBibtexAsync = function(url, opts, body, callback){ - var citation = body[0]; +ZoteroService.prototype.convertToBibtexAsync = function(url, format, body, callback){ + var zoteroService = this, + citation = body[0]; if (citation instanceof Array) { citation = citation[0]; } @@ -129,23 +141,22 @@ fixURL, //must go directly after unnamed function that hands it url fixAccessDate, function(citation, cb){ - zoteroExportRequest(citation, opts, function(error, responseCode, body){ + zoteroService.zoteroExportRequest(citation, format, function(error, responseCode, body){ cb(error, body); }); }], function (err, citation) { callback(citation); }); - }; /** * Takes Zotero output and converts to 'mediawiki' format * @param {String} url URL provided by user - * @param {Object} opts opts object for Zotero requests + * @param {Object} format requested format * @param {Array} body Array of citation objects * @param {Function} callback callback(arrayOfCitationObjs) */ -var convertToMediawikiAsync = function (url, opts, body, callback){ +ZoteroService.prototype.convertToMediawikiAsync = function(url, format, body, callback){ var citation = body[0]; if (citation instanceof Array){ citation = citation[0]; @@ -164,17 +175,16 @@ ], function (err, citation) { callback([citation]); }); - }; /** * Takes Zotero output and converts to 'mwDeprecated' format * @param {String} url URL provided by user - * @param {Object} opts opts object for Zotero requests + * @param {Object} format requested format * @param {Array} body Array of citation objects * @param {Function} callback callback(arrayOfCitationObjs) */ -var convertToMWDeprecatedAsync = function (url, opts, body, callback){ +ZoteroService.prototype.convertToMWDeprecatedAsync = function(url, format, body, callback){ var zotCreators, creatorFieldName, creatorTypeCount = {}, citation = body[0]; @@ -226,7 +236,7 @@ * @param {Object} citation citation object * @param {Function} callback callback on citation object */ -var replaceCreators = function(citation, callback){ + function replaceCreators(citation, callback){ if (citation.creators) { var creatorArray, creatorFieldName, zotCreators = citation.creators; @@ -245,14 +255,14 @@ delete citation.creators; //remove creators field } callback(null, citation); -}; +} /** * Add PMID and PMCID fields from the extra field or through DOI lookup * @param {Object} citation citation object to add PMID * @param {Function} callback callback (error, citation) */ -var addPubMedIdentifiers = function(citation, callback){ +function addPubMedIdentifiers(citation, callback){ if (citation.extra) { //get pmid from extra fields var extraFields = citation.extra.split('\n'); @@ -281,7 +291,7 @@ } else { callback(null, citation); } -}; +} /** * Add URL provided by user if none in Zotero response @@ -289,31 +299,31 @@ * @param {Object} citation citation object to add PMID * @param {Function} callback callback (error, citation) */ -var fixURL = function(url, citation, callback){ +function fixURL(url, citation, callback){ if (!citation.url){ citation.url = url; } callback(null, citation); -}; +} /** * Replace Zotero output of CURRENT_TIMESTAMP with ISO time * @param {Object} citation citation object * @param {Function} callback callback on citation object */ -var fixAccessDate = function(citation, callback){ +function fixAccessDate(citation, callback){ if (!citation.accessDate || (citation.accessDate === "CURRENT_TIMESTAMP")){ citation.accessDate = (new Date()).toISOString().substring(0, 10); } callback(null, citation); -}; +} /** * Convert String of ISSNs into an Array of ISSNs * @param {Object} citation citation object * @param {Function} callback callback on citation object */ -var fixISSN = function(citation, callback){ +function fixISSN(citation, callback){ var match, i, reISSN, issn = citation.ISSN; @@ -332,14 +342,14 @@ } } callback(null, citation); -}; +} /** * Convert String of ISBNs into an Array of ISBNs * @param {Object} citation citation object * @param {Function} callback callback on citation object */ -var fixISBN = function(citation, callback){ +function fixISBN(citation, callback){ var match, i, reISBN, isbn = citation.ISBN; @@ -358,35 +368,8 @@ } } callback(null, citation); -}; - -/* Test response alterations without having to use server */ -var testJSON = function(){ - var sampleBody = require("../test_files/4_input.json"); - console.log("before:"); - console.log(JSON.stringify(sampleBody)); - console.log("after:"); - selectFormatFcn("mwDeprecated", function(convert){ - convert("http://example.com", null, sampleBody, function(modifiedBody){ - console.log(JSON.stringify(modifiedBody)); - }); - }); - - //test PMID lookup - addPubMedIdentifiers({"DOI": "10.1371/journal.pcbi.1002947"}, function (error, modifiedCitation){ - console.log("Test lookup of PMID by DOI: PMID=" + modifiedCitation.PMID + ", PMCID=" + modifiedCitation.PMCID); - console.log("Expected: PMID=23555203, PMCID=PMC3605911"); - }); -}; - -/* Test methods in main */ -if (require.main === module) { - testJSON(); } /* Exports */ -module.exports = { - zoteroWebRequest: zoteroWebRequest, - zoteroExportRequest: zoteroExportRequest -}; +module.exports = ZoteroService; diff --git a/server.js b/server.js index b364eac..72aa82f 100644 --- a/server.js +++ b/server.js @@ -17,7 +17,7 @@ argv = opts.argv; /* Import Local Modules */ -var CitoidService = require('./lib/CitoidService.js').CitoidService; +var CitoidService = require('./lib/CitoidService.js'); /* Import Local Settings */ var settingsFile = path.resolve(process.cwd(), argv.c), -- To view, visit https://gerrit.wikimedia.org/r/192197 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I48158fc037277ee688ef35ab0db688a46aaf54d7 Gerrit-PatchSet: 16 Gerrit-Project: mediawiki/services/citoid Gerrit-Branch: master Gerrit-Owner: Mvolz <mv...@wikimedia.org> Gerrit-Reviewer: Jforrester <jforres...@wikimedia.org> Gerrit-Reviewer: Mobrovac <mobro...@wikimedia.org> Gerrit-Reviewer: Mvolz <mv...@wikimedia.org> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits