Merge pull request #1091 from adomasven/fix/connector-translation-support

Fixes overriden Zotero object in connector sandboxes
This commit is contained in:
Dan Stillman 2016-09-20 14:18:07 -04:00 committed by GitHub
commit dc0bb68f04
10 changed files with 103 additions and 48 deletions

View File

@ -24,8 +24,9 @@
*/ */
const NUM_CONCURRENT_TESTS = 6; const NUM_CONCURRENT_TESTS = 6;
const TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"];
const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Mismatch", "Issues"]; const TABLE_COLUMNS = ["Translator", "Supported", "Status", "Pending", "Succeeded", "Failed", "Mismatch", "Issues"];
// Not using const to prevent const collisions in connectors
var TRANSLATOR_TYPES = ["Web", "Import", "Export", "Search"];
var translatorTables = {}, var translatorTables = {},
translatorTestViews = {}, translatorTestViews = {},
translatorTestViewsToRun = {}, translatorTestViewsToRun = {},

View File

@ -36,7 +36,7 @@ try {
var Zotero; var Zotero;
} }
Zotero_TranslatorTesters = new function() { var Zotero_TranslatorTesters = new function() {
const TEST_TYPES = ["web", "import", "export", "search"]; const TEST_TYPES = ["web", "import", "export", "search"];
var collectedResults = {}; var collectedResults = {};
@ -190,7 +190,7 @@ Zotero_TranslatorTesters = new function() {
* @param {Function} [debugCallback] A function to call to write debug output. If not present, * @param {Function} [debugCallback] A function to call to write debug output. If not present,
* Zotero.debug will be used. * Zotero.debug will be used.
*/ */
Zotero_TranslatorTester = function(translator, type, debugCallback) { var Zotero_TranslatorTester = function(translator, type, debugCallback) {
this.type = type; this.type = type;
this.translator = translator; this.translator = translator;
this.output = ""; this.output = "";

View File

@ -56,7 +56,7 @@ Zotero.Repo = new function() {
* Get translator code from repository * Get translator code from repository
* @param {String} translatorID ID of the translator to retrieve code for * @param {String} translatorID ID of the translator to retrieve code for
*/ */
this.getTranslatorCode = Zotero.Promise.method(function (translatorID) { this.getTranslatorCode = Zotero.Promise.method(function (translatorID, debugMode) {
var deferred = Zotero.Promise.defer(); var deferred = Zotero.Promise.defer();
// try standalone // try standalone
@ -72,6 +72,11 @@ Zotero.Repo = new function() {
); );
return; return;
} }
// Don't fetch from repo in debug mode
if (debugMode) {
deferred.resolve([false, Zotero.Repo.SOURCE_ZOTERO_STANDALONE]);
return;
}
// then try repo // then try repo

View File

@ -130,7 +130,9 @@ Zotero.Translators = new function() {
if(!_initialized) Zotero.Translators.init() if(!_initialized) Zotero.Translators.init()
var translators = _cache[type].slice(0); var translators = _cache[type].slice(0);
var codeGetter = new Zotero.Translators.CodeGetter(translators, debugMode); var codeGetter = new Zotero.Translators.CodeGetter(translators, debugMode);
return codeGetter.getAll(); return codeGetter.getAll().then(function() {
return translators;
});;
}); });
/** /**
@ -326,24 +328,36 @@ Zotero.Translators = new function() {
Zotero.Translators.CodeGetter = function(translators, debugMode) { Zotero.Translators.CodeGetter = function(translators, debugMode) {
this._translators = translators; this._translators = translators;
this._debugMode = debugMode; this._debugMode = debugMode;
} this._concurrency = 1;
};
Zotero.Translators.CodeGetter.prototype.getAll = Zotero.Promise.method(function () { Zotero.Translators.CodeGetter.prototype.getCodeFor = Zotero.Promise.method(function(i) {
var translators = []; let translator = this._translators[i];
for (let translator of this._translators) { // retrieve code if no code and translator is supported locally
// retrieve code if no code and translator is supported locally if((translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER && !translator.hasOwnProperty("code"))
if((translator.runMode === Zotero.Translator.RUN_MODE_IN_BROWSER && !translator.hasOwnProperty("code")) // or if debug mode is enabled (even if unsupported locally)
// or if debug mode is enabled (even if unsupported locally) || (this._debugMode && (!translator.hasOwnProperty("code")
|| (this._debugMode && (!translator.hasOwnProperty("code") // or if in debug mode and the code we have came from the repo (which doesn't
// or if in debug mode and the code we have came from the repo (which doesn't // include test cases)
// include test cases) || (Zotero.Repo && translator.codeSource === Zotero.Repo.SOURCE_REPO)))) {
|| (Zotero.Repo && translator.codeSource === Zotero.Repo.SOURCE_REPO)))) { // get code
// get next translator return translator.getCode();
translators.push(translator.getCode()); }
});
Zotero.Translators.CodeGetter.prototype.getAll = function () {
var codes = [];
// Chain promises with some level of concurrency. If unchained, fires
// off hundreds of xhttprequests on connectors and crashes the extension
for (let i = 0; i < this._translators.length; i++) {
if (i < this._concurrency) {
codes.push(this.getCodeFor(i));
} else {
codes.push(codes[i-this._concurrency].then(() => this.getCodeFor(i)));
} }
} }
return Zotero.Promise.all(translators); return Promise.all(codes);
}); };
var TRANSLATOR_REQUIRED_PROPERTIES = ["translatorID", "translatorType", "label", "creator", "target", var TRANSLATOR_REQUIRED_PROPERTIES = ["translatorID", "translatorType", "label", "creator", "target",
"priority", "lastUpdated"]; "priority", "lastUpdated"];
@ -428,8 +442,8 @@ Zotero.Translator.prototype.init = function(info) {
* *
* @return {Promise<String|false>} - Promise for translator code or false if none * @return {Promise<String|false>} - Promise for translator code or false if none
*/ */
Zotero.Translator.prototype.getCode = function () { Zotero.Translator.prototype.getCode = function (debugMode) {
return Zotero.Repo.getTranslatorCode(this.translatorID) return Zotero.Repo.getTranslatorCode(this.translatorID, debugMode)
.then(function (args) { .then(function (args) {
var code = args[0]; var code = args[0];
var source = args[1]; var source = args[1];

View File

@ -618,7 +618,9 @@ Zotero.Server.Connector.GetTranslatorCode.prototype = {
*/ */
"init":function(postData, sendResponseCallback) { "init":function(postData, sendResponseCallback) {
var translator = Zotero.Translators.get(postData.translatorID); var translator = Zotero.Translators.get(postData.translatorID);
sendResponseCallback(200, "application/javascript", translator.code); translator.getCode().then(function(code) {
sendResponseCallback(200, "application/javascript", code);
});
} }
} }

View File

@ -1264,7 +1264,7 @@ Zotero.Translate.Base.prototype = {
// Zotero.Translators.get() returns a promise in the connectors, but we don't expect it to // Zotero.Translators.get() returns a promise in the connectors, but we don't expect it to
// otherwise // otherwise
if (!this.isConnector && this.translator[0].then) { if (!Zotero.isConnector && this.translator[0].then) {
throw new Error("Translator should not be a promise in non-connector mode"); throw new Error("Translator should not be a promise in non-connector mode");
} }
@ -1741,9 +1741,12 @@ Zotero.Translate.Base.prototype = {
this._sandboxManager = new Zotero.Translate.SandboxManager(this._sandboxLocation); this._sandboxManager = new Zotero.Translate.SandboxManager(this._sandboxLocation);
} }
const createArrays = "['creators', 'notes', 'tags', 'seeAlso', 'attachments']"; const createArrays = "['creators', 'notes', 'tags', 'seeAlso', 'attachments']";
var src = "var Zotero = {};"+ var src = "";
"Zotero.Item = function (itemType) {"+ if (Zotero.isFx && !Zotero.isBookmarklet) {
"const createArrays = "+createArrays+";"+ src = "var Zotero = {};";
}
src += "Zotero.Item = function (itemType) {"+
"var createArrays = "+createArrays+";"+
"this.itemType = itemType;"+ "this.itemType = itemType;"+
"for(var i=0, n=createArrays.length; i<n; i++) {"+ "for(var i=0, n=createArrays.length; i<n; i++) {"+
"this[createArrays[i]] = [];"+ "this[createArrays[i]] = [];"+

View File

@ -26,7 +26,7 @@
"use strict"; "use strict";
// Enumeration of types of translators // Enumeration of types of translators
const TRANSLATOR_TYPES = {"import":1, "export":2, "web":4, "search":8}; var TRANSLATOR_TYPES = {"import":1, "export":2, "web":4, "search":8};
/** /**
* Singleton to handle loading and caching of translators * Singleton to handle loading and caching of translators

View File

@ -753,6 +753,28 @@ var generateTranslatorExportData = Zotero.Promise.coroutine(function* generateTr
return translatorExportData; return translatorExportData;
}); });
/**
* Build a dummy translator that can be passed to Zotero.Translate
*/
function buildDummyTranslator(translatorType, code) {
let info = {
"translatorID":"dummy-translator",
"translatorType":1, // import
"label":"Dummy Translator",
"creator":"Simon Kornblith",
"target":"",
"priority":100,
"browserSupport":"g",
"inRepository":false,
"lastUpdated":"0000-00-00 00:00:00",
};
let translator = new Zotero.Translator(info);
translator.code = code;
return translator;
}
/** /**
* Imports an attachment from a test file. * Imports an attachment from a test file.
* @param {string} filename - The filename to import (in data directory) * @param {string} filename - The filename to import (in data directory)

View File

@ -33,6 +33,34 @@ describe("Connector Server", function () {
after(function () { after(function () {
win.close(); win.close();
}); });
describe('/connector/getTranslatorCode', function() {
it('should respond with translator code', function* () {
var code = 'function detectWeb() {}\nfunction doImport() {}';
var translator = buildDummyTranslator(4, code);
sinon.stub(Zotero.Translators, 'get').returns(translator);
var response = yield Zotero.HTTP.request(
'POST',
connectorServerPath + "/connector/getTranslatorCode",
{
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
translatorID: "dummy-translator",
})
}
);
assert.isTrue(Zotero.Translators.get.calledWith('dummy-translator'));
assert.equal(response.response, code);
Zotero.Translators.get.restore();
})
});
describe("/connector/saveItems", function () { describe("/connector/saveItems", function () {
// TODO: Test cookies // TODO: Test cookies

View File

@ -1,26 +1,6 @@
new function() { new function() {
Components.utils.import("resource://gre/modules/osfile.jsm"); Components.utils.import("resource://gre/modules/osfile.jsm");
/**
* Build a dummy translator that can be passed to Zotero.Translate
*/
function buildDummyTranslator(translatorType, code) {
let info = {
"translatorID":"dummy-translator",
"translatorType":1, // import
"label":"Dummy Translator",
"creator":"Simon Kornblith",
"target":"",
"priority":100,
"browserSupport":"g",
"inRepository":false,
"lastUpdated":"0000-00-00 00:00:00",
};
let translator = new Zotero.Translator(info);
translator.code = code;
return translator;
}
/** /**
* Create a new translator that saves the specified items * Create a new translator that saves the specified items
* @param {String} translatorType - "import" or "web" * @param {String} translatorType - "import" or "web"