/** * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; under version 2 * of the License (non-upgradable). * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2018-2019 (original work) Open Assessment Technologies SA ; */ /** * Test runner proxy for the QTI item previewer * * @author Jean-Sébastien Conan */ define([ 'jquery', 'lodash', 'i18n', 'core/promiseQueue', 'core/request', 'taoQtiTestPreviewer/previewer/config/item' ], function($, _, __, promiseQueue, coreRequest, configFactory) { 'use strict'; /** * QTI proxy definition * Related to remote services calls * @type {Object} */ return { name : 'qtiItemPreviewerProxy', /** * Installs the proxy */ install : function install(){ var self = this; /** * A promise queue to ensure requests run sequentially */ this.queue = promiseQueue(); /** * Some parameters needs special handling... * @param {Object} actionParams - the input parameters * @returns {Object} output parameters */ this.prepareParams = function prepareParams(actionParams){ //some parameters need to be JSON.stringified var stringifyParams = ['itemState', 'itemResponse']; if(_.isPlainObject(actionParams)){ return _.mapValues(actionParams, function(value, key){ if(_.contains(stringifyParams, key)){ return JSON.stringify(value); } return value; }); } return actionParams; }; /** * Proxy request function. Returns a promise * Applied options: asynchronous call, JSON data, no cache * @param {String} url * @param {Object} [reqParams] * @param {String} [contentType] - to force the content type * @param {Boolean} [noToken] - to disable the token * @returns {Promise} */ this.request = function request(url, reqParams, contentType, noToken) { return coreRequest({ url: url, data: self.prepareParams(reqParams), method: reqParams ? 'POST' : 'GET', contentType: contentType, noToken: noToken, background: false, sequential: true, timeout: self.configStorage.getTimeout() }) .then(function(response) { self.setOnline(); if (response && response.success) { return Promise.resolve(response); } else { return Promise.reject(response); } }) .catch(function(error) { if (error.data && self.isConnectivityError(error.data)) { self.setOffline('request'); } return Promise.reject(error); }); }; }, /** * Initializes the proxy * @param {Object} config - The config provided to the proxy factory * @param {String} config.testDefinition - The URI of the test * @param {String} config.testCompilation - The URI of the compiled delivery * @param {String} config.serviceCallId - The URI of the service call * @param {Object} [params] - Some optional parameters to join to the call * @returns {Promise} - Returns a promise. The proxy will be fully initialized on resolve. * Any error will be provided if rejected. */ init: function init(config, params) { // store config in a dedicated configStorage this.configStorage = configFactory(config || {}); // request for initialization return this.request( this.configStorage.getTestActionUrl('init'), params, void 0, true ); }, /** * Uninstalls the proxy * @returns {Promise} - Returns a promise. The proxy will be fully uninstalled on resolve. * Any error will be provided if rejected. */ destroy: function destroy() { // no request, just a resources cleaning this.configStorage = null; this.queue = null; // the method must return a promise return Promise.resolve(); }, /** * Calls an action related to the test * @param {String} action - The name of the action to call * @param {Object} [params] - Some optional parameters to join to the call * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve. * Any error will be provided if rejected. */ callTestAction: function callTestAction(action, params) { return this.request(this.configStorage.getTestActionUrl(action), params); }, /** * Calls an action related to a particular item * @param {String} itemIdentifier - The identifier of the item for which call the action * @param {String} action - The name of the action to call * @param {Object} [params] - Some optional parameters to join to the call * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve. * Any error will be provided if rejected. */ callItemAction: function callItemAction(itemIdentifier, action, params) { return this.request(this.configStorage.getItemActionUrl(itemIdentifier, action), params); }, /** * Gets an item definition by its identifier, also gets its current state * @param {String} itemIdentifier - The identifier of the item to get * @param {Object} [params] - additional parameters * @returns {Promise} - Returns a promise. The item data will be provided on resolve. * Any error will be provided if rejected. */ getItem: function getItem(itemIdentifier, params) { return this.request( this.configStorage.getItemActionUrl(itemIdentifier, 'getItem'), params, void 0, true ); }, /** * Submits the state and the response of a particular item * @param {String} itemIdentifier - The identifier of the item to update * @param {Object} state - The state to submit * @param {Object} response - The response object to submit * @param {Object} [params] - Some optional parameters to join to the call * @returns {Promise} - Returns a promise. The result of the request will be provided on resolve. * Any error will be provided if rejected. */ submitItem: function submitItem(itemIdentifier, state, response, params) { var body = _.merge({ itemState: state, itemResponse: response }, params || {}); return this.request( this.configStorage.getItemActionUrl(itemIdentifier, 'submitItem'), body, void 0, true ); } }; });