tao-test/app/tao/install/js/api.js

808 lines
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg (under the project TAO & TAO2);
* 2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung (under the project TAO-TRANSFER);
* 2009-2012 (update and modification) Public Research Centre Henri Tudor (under the project TAO-SUSTAIN & TAO-DEV);
*
*/
define(['jquery'], function($){
/**
* TaoInstall API interface.
*/
function TaoInstall (){
this.url = 'api.php';
this.feedbackUrl = 'http://forge.taotesting.com/support/installation/';
this.templatePrefix = 'tpl_';
this.templateSuffix = '.html';
this.frameId = null;
this.frame = null;
this.currentTemplateId = null;
this.nextable = false;
this.onNextable = function() {};
this.onUnnextable = function() {};
this.registeredElements = [];
this.helpMessages = {};
this.data = {};
}
/**
* Changes the current template by giving its ID.
*/
TaoInstall.prototype.setTemplate = function (templateId){
if (templateId != this.currentTemplateId){
// If it is not the first template displayed...
if (this.frame != null){
// We unregister any element bound with
// the API.
this.clearRegisteredElements();
// We remove any help message in the store.
this.clearHelp();
// It is not nextable anymore.
this.nextable = false;
// Event heandlers are reset.
this.onNextable = function() {};
this.onUnnextable = function() {};
// We remove the frame handling the last
// template.
$('#mainFrame').remove();
this.frame = null;
}
this.frame = document.createElement('iframe');
$(this.frame).attr('id', this.frameId)
.attr('scrolling', 'no')
.attr('frameborder', 0);
this.currentTemplateId = templateId;
// We initialize the API and handlers for DOM injection.
this.init();
// We set the frame content.
var frameSrc = this.templatePrefix + this.currentTemplateId + this.templateSuffix;
$(this.frame).attr('src', frameSrc);
$('body').append(this.frame);
}
};
/**
* Check if the server-side can talk JSON.
*/
TaoInstall.prototype.sync = function(callback){
// Check if we can discuss using JSON and receive information
// from the server about the installation to perform.
var data = "type=Sync";
var options = {data: data,
type: 'GET',
dataType: 'json'};
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data)})
.fail(function(jqxhr){callback(jqxhr.status)});
};
/**
* Check the configuration on the server-side.
*/
TaoInstall.prototype.checkConfiguration = function(checks, callback){
if (checks != null){
// We send the checks to perform.
var data = {type: 'CheckPHPConfig',
value: checks};
var options = {data: JSON.stringify(data),
type: 'POST',
dataType: 'json'};
}
else{
// The checks to perform are chosen by the server-side.
var data = {type: 'CheckPHPConfig'};
if (typeof this.data['extensions'] !== 'undefined') {
data['extensions'] = this.data['extensions'];
}
var options = {data: data, type: 'GET', dataType: 'json'};
}
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data)})
.fail(function(jqxhr){callback(jqxhr.status)});
};
/**
* Check the database connection on the server-side
*/
TaoInstall.prototype.checkDatabaseConnection = function(check, callback){
check.password = this.nullToEmptyString(check.password);
var data = {type: 'CheckDatabaseConnection',
value: check};
var options = {data: JSON.stringify(data),
type: 'POST',
dataType: 'json'};
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data);})
.fail(function(jqxhr){callback(jqxhr.status);});
};
/**
* Check a filesystem component on the server-side
*/
TaoInstall.prototype.checkFileSystemComponent = function(check, callback){
var data = {
type: 'CheckFileSystemComponent',
value: check
};
var options = {
data: JSON.stringify(data),
type: 'POST',
dataType: 'json'
};
$.ajax(this.url, options)
.done(function(data, textStatus, jqxhr){callback(jqxhr.status, data);})
.fail(function(jqxhr){callback(jqxhr.status);});
};
/**
* Check if password match current security rules
*/
TaoInstall.prototype.сheckPasswordСonformity = function(check, callback){
check.password = this.nullToEmptyString(check.password);
var config = {"name": "PasswordConformity", "extension": "tao",'id':'xxx'};
var data = {
type: 'CheckCustom',
value: $.extend(check, config)
};
var options = {data: JSON.stringify(data),
type: 'POST',
dataType: 'json'};
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data);})
.fail(function(jqxhr){callback(jqxhr.status);});
};
/**
* Check if the AllowOverride directive is set to All
*/
/*TaoInstall.prototype.сheckAllowOverride = function(check, callback){
var config = {"name": "AllowOverride", "extension": "tao",'id':'xxx'};
var data = {
type: 'CheckCustom',
value: $.extend(check, config)
};
var options = {data: JSON.stringify(data),
type: 'POST',
dataType: 'json'};
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data);})
.fail(function(jqxhr){callback(jqxhr.status);});
};*/
/**
* Check connection to TAO Forge
*/
/*TaoInstall.prototype.checkTAOForgeConnection = function(check, callback){
check.password = this.nullToEmptyString(check.password);
var data = {type: 'CheckTAOForgeConnection',
value: check};
var options = {data: JSON.stringify(data),
type: 'POST',
dataType: 'json'};
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data)})
.fail(function(jqxhr){callback(jqxhr.status)});
};*/
TaoInstall.prototype.install = function(inputs, callback){
inputs.db_pass = this.nullToEmptyString(inputs.db_pass);
var data = {type: 'Install',
value: inputs,
timeout: 300000}; // 5 minutes max.
var options = {data: JSON.stringify(data),
type: 'POST',
dataType: 'json'};
$.ajax(this.url, options).done(function(data, textStatus, jqxhr){callback(jqxhr.status, data)})
.fail(function(jqxhr){callback(jqxhr.status)});
};
/**
* Indicates if the current template is 'nextable' or not.
*/
TaoInstall.prototype.isNextable = function(){
return this.nextable;
};
/**
* Tell the API that the current template is 'nextable'.
*/
TaoInstall.prototype.setNextable = function(value){
this.nextable = value;
if (value == true){
this.onNextable();
}
else{
this.onUnnextable();
}
};
/**
* Register a tao-input element for validation.
*/
TaoInstall.prototype.register = function(element){
if ($(element).hasClass('tao-input') && typeof(element.isValid) == 'function'){
this.registeredElements.push(element);
}
else {
throw "Tao Install API Error: only 'tao-input' elements with an 'isValid' function are registrable. Element '" + $element.attr('id') + "' is not registrable.";
}
};
/**
* Unregister a particular tao-input element.
*/
TaoInstall.prototype.unregister = function(element){
for (i in this.registeredElements){
if (this.registeredElements[i] == element){
delete this.registeredElements[i];
}
}
};
/**
* Unregister all registered tao-input elements.
*/
TaoInstall.prototype.clearRegisteredElements = function(){
this.registeredElements = [];
};
/**
* Notify the API that tao-input elements were added, modified, removed...
* and that the registered elements can be checked again.
*/
TaoInstall.prototype.stateChange = function(){
this.checkRegisteredElements();
this.storeDataForRegisteredElements();
};
/**
* Add an help message in the help store identified by a given key.
*
* @param {Object} key
* @param {Object} message
*/
TaoInstall.prototype.addHelp = function(key, message){
this.helpMessages[key] = message;
};
/**
* Remove an help message identified in the help store by a given key.
*
* @param {Object} key
*/
TaoInstall.prototype.removeHelp = function(key){
if (typeof(this.helpMessages[key]) != 'undefined'){
delete this.helpMessages[key];
}
};
/**
* Reinitialize the help store. Messages contained
* by the help store before calling this method will be lost.
*/
TaoInstall.prototype.clearHelp = function(){
this.helpMessages = {};
};
/**
* Get an help message from the help store for a given key.
* Returns null if no message is bound for the given key.
*
* @param {Object} key
*/
TaoInstall.prototype.getHelp = function(key){
if (typeof(this.helpMessages[key]) != 'undefined'){
return this.helpMessages[key];
}
else{
return null;
}
};
/**
* Add a piece of data associated to a given key in the data store.
* If some data was already associated with this key, it will be overriden
* by the new one.
* @param {String} key
* @param {Object} data
*/
TaoInstall.prototype.addData = function(key, data){
this.data[key] = data;
};
/**
* Remove a pice of data associated to in a given key in the data store.
* If no data is bound to the provided key, nothing happens.
* @param {String} key
*/
TaoInstall.prototype.removeData = function(key){
if (typeof(this.data[key]) != 'undefined'){
delete this.data[key];
}
};
/**
* Get an 'isValid' validation method for an input that will be registered
* by the API.
*
* @param {Object} element The Input HTML element for which you want a validator.
* @param {Object} options Validation options (integer -> min, max; string -> length, ...)
* @return {function}
*/
TaoInstall.prototype.getValidator = function(element, options){
var $element = $(element);
var api = this;
// Mandatory field by default.
$element.prop('tao-mandatory', true);
switch ($element.prop('tagName').toLowerCase()){
case 'input':
case 'textarea':
if ($element.prop('tagName').toLowerCase() == 'textarea' ||
$element.attr('type') == 'text' ||
$element.attr('type') == 'password' ||
$element.attr('type') == 'hidden'){
var firstValueFunction = function () { return $element.val() != $element[0].firstValue || !mandatory; };
if (typeof(options) != 'undefined'){
var mandatory = (typeof(options.mandatory) == 'undefined') ? true : options.mandatory;
$element.prop('tao-mandatory', mandatory);
if (typeof(options.dataType) != 'undefined'){
switch (options.dataType){
case 'regexp':
var reg = new RegExp(options.pattern);
element.isValid = function(){ return firstValueFunction() && reg.test($element.val()); };
break;
case 'server':
element.isValid = function(){
jQuery.post('/', {data: $element.val()}, function () {
console.log('asd');
displayTaoError('asdasd');
return false;
});
};
break;
case 'url':
var reg = new RegExp("(http|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?");
element.isValid = function(){ return firstValueFunction() && reg.test($element.val()); };
break;
case 'dbname':
var reg = new RegExp("^[\-a-zA-Z0-9_]{3,63}$");
element.isValid = function(){ return firstValueFunction() && reg.test($element.val()); };
break;
case 'dbhost':
var reg = new RegExp("[a-zA-Z0-9]{3,}(?::[0-9]{1,5})*");
element.isValid = function(){ return firstValueFunction() && reg.test($element.val()); };
break;
case 'host':
var reg = new RegExp("(https?:\/\/)(www\.)?([a-zA-Z0-9\-.\/_]){3,}(:[0-9]{1,5})?");
element.isValid = function(){ return firstValueFunction() && reg.test($element.val()); };
break;
case 'email':
element.isValid = function(){
var reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/i;
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
return firstValueFunction() && reg.test($element.val());
}
}
break;
case 'string':
var sameAsFunction = function(){ var value = ($element[0].getData() != null) ? $element[0].getData() : ''; return api.getRegisteredElement(options.sameAs).getData() == value; };
if (typeof(options.min) == 'undefined' && typeof(options.max) == 'undefined'){
// no min, no max.
if (typeof(options.sameAs) == 'undefined'){
element.isValid = function(){
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
return firstValueFunction();
}
};
}
else{
element.isValid = function(){
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
return firstValueFunction() && sameAsFunction();
}
};
}
}
else if (typeof(options.min) == 'undefined'){
// max only.
if (typeof(options.sameAs) == 'undefined'){
element.isValid = function() {
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
var value = ($element[0].getData() != null) ? $element[0].getData() : '';
return firstValueFunction() && value.length <= options.max;
}
};
}
else{
element.isValid = function() {
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
var value = ($element[0].getData() != null) ? $element[0].getData() : '';
return firstValueFunction && value.length <= options.max && sameAsFunction();
}
};
}
}
else if (typeof(options.max) == 'undefined'){
// min only.
if (typeof(options.sameAs) == 'undefined'){
element.isValid = function() { var value = ($element[0].getData() != null) ? $element[0].getData() : ''; return firstValueFunction() && value.length >= options.min; };
}
else{
element.isValid = function() {
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
var value = ($element[0].getData() != null) ? $element[0].getData() : '';
return firstValueFunction() && value.length >= options.min && sameAsFunction();
}
};
}
}
else{
// min and max.
if (typeof(options.sameAs) == 'undefined'){
element.isValid = function() {
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
var value = ($element[0].getData() != null) ? $element[0].getData() : '';
return firstValueFunction() && value.length >= options.min && value.length <= options.max;
}
};
}
else{
element.isValid = function() {
if (mandatory == false && $element[0].getData() == null){
return true;
}
else{
var value = ($element[0].getData() != null) ? $element[0].getData() : '';
return firstValueFunction() && value.length >= options.min && value.length <= options.max && sameAsFunction();
}
};
}
}
break;
}
}
}
else{
var mandatory = true;
element.isValid = function(){ return firstValueFunction() && $element.val().length > 0; };
}
}
else if ($element.attr('type') == 'checkbox' || $element.attr('type') == 'radio'){
element.isValid = function(){ return true; };
}
break;
case 'select':
element.isValid = function() { return true; };
break;
default:
throw "No support for element with id '" + $element.attr('id') + "'.";
break;
}
};
/**
* Get a 'getData' validation method for an input that will be registered
* by the API.
* @param {Object} element The Input HTML element for which you want a data getter.
* @return {function}
*/
TaoInstall.prototype.getDataGetter = function(element){
$element = $(element);
switch ($element.prop('tagName').toLowerCase()){
case 'input':
case 'textarea':
if ($element.prop('tagName').toLowerCase() == 'textarea' || $element.attr('type') == 'text' || $element.attr('type') == 'password'){
element.getData = function(){ return (this.value != this.firstValue) ? ((this.value == '') ? null : this.value) : null; };
}
else if ($element.attr('type') == 'hidden') {
element.getData = function(){ return this.value; };
}
else if ($element.attr('type') == 'checkbox'){
element.getData = function(){ return element.checked; };
}
break;
case 'select':
element.getData = function(){ return this.options[this.selectedIndex].value; };
break;
default:
throw "No support for element with id '" + $element.attr('id') + "'.";
break;
}
};
TaoInstall.prototype.getDataSetter = function(element){
$element = $(element);
var api = this;
switch ($element.prop('tagName').toLowerCase()){
case 'input':
case 'textarea':
if ($element.prop('tagName').toLowerCase() == 'textarea' || $element.attr('type') == 'text' || $element.attr('type') == 'password' || $element.attr('type') == 'hidden'){
element.setData = function(data) { this.value = data; };
}
else if ($element.attr('type') == 'checkbox'){
element.setData = function(data) { $(this).prop('checked', !!data); };
}
break;
case 'select':
element.setData = function(data) {
var count = this.options.length;
for (i = 0; i < count; i++){
if (this.options[i].value == data){
this.options[i].selected = true;
break;
}
}
};
break;
default:
throw "No support for element with id '" + $element.attr('id') + "'.";
break;
}
};
/**
* Clear the data store.
*/
TaoInstall.prototype.clearData = function(){
this.data = {};
};
/**
* Get a piece of data associated to the provided key in the data
* store. If no data is bound to the key, null is returned.
* @param {String} key;
*/
TaoInstall.prototype.getData = function(key){
if (typeof(this.data[key]) != 'undefined'){
// type
return this.data[key];
}
else {
return null;
}
};
/**
* Popuplate registered inputs of the currently displayed template with
* data stored in the data store. If keys of the store matches
* an input id, this input will be populated.
* @return {Array} A set of element that were successfully populated.
*/
TaoInstall.prototype.populate = function(){
var populated = [];
for (i in this.registeredElements){
var element = this.registeredElements[i];
if (typeof(element.setData) == 'function' && this.getData(element.id) != null){
element.setData(this.getData(element.id));
populated.push(element);
}
}
// If something was populated, it means a state change might occur.
this.stateChange();
return populated;
};
/**
* Invoke this method to redirect the end user to a specific URL.
* @param {String} A Uniform Resource Locator.
*/
TaoInstall.prototype.redirect = function(url) {
window.location.href = url;
};
// ----------- Private methods
TaoInstall.prototype.init = function(){
var self = this;
this.frame.onload = function(){
self.inject();
};
};
TaoInstall.prototype.inject = function(){
var doc = this.getDocument();
doc.install = this;
// Trigger the onLoad method of the API client to bootstrap
// the template logic.
if (doc.onLoad)
{
doc.onLoad();
}
};
TaoInstall.prototype.checkRegisteredElements = function(){
var validity = true;
for (i in this.registeredElements){
var $registeredElement = $(this.registeredElements[i]);
if (!$registeredElement[0].isValid()){
validity = false;
// The field is not valid.
// If it is not mandatory and that we have no value,
// we cannot consider it as 'invalid'.
if (typeof($registeredElement[0].onInvalid) == 'function'){
$registeredElement[0].onInvalid();
}
}
else{
// The field is valid.
// If not mandatory and empty, we call onValidButEmpty otherwise
// we call onValid.
if ($registeredElement.prop('tao-mandatory') == false &&
$registeredElement[0].getData() == null &&
typeof($registeredElement[0].onValidButEmpty) == 'function'){
$registeredElement[0].onValidButEmpty();
}
else if(typeof($registeredElement[0].onValid) == 'function') {
$registeredElement[0].onValid();
}
}
}
this.setNextable(validity);
};
TaoInstall.prototype.storeDataForRegisteredElements = function(){
for (i in this.registeredElements){
var element = this.registeredElements[i];
if (typeof(element.getData) == 'function'){
this.addData(element.id, element.getData());
}
}
};
TaoInstall.prototype.getDocument = function(){
var doc = (this.frame.contentWindow || this.frame.contentDocument);
return doc;
};
TaoInstall.prototype.getRegisteredElement = function(id){
for (i in this.registeredElements){
var element = this.registeredElements[i];
if (element.id == id){
return element;
}
}
return null;
};
TaoInstall.prototype.nullToEmptyString = function(value){
if (typeof(value) == 'undefined' || value == null){
value = '';
}
return value;
};
TaoInstall.prototype.getExpectedRightsAsString = function(expectedRights){
var tokens = [];
for (var i = 0; i < expectedRights.length; i++){
if (expectedRights.charAt(i) == 'r'){
tokens.push('readable');
} else if (expectedRights.charAt(i) == 'w'){
tokens.push('writable');
} else{
tokens.push('executable');
}
}
return tokens.join(', ');
};
TaoInstall.prototype.getCurrentRightsAsString = function(report){
var tokens = [];
if (report.value.isWritable == true){
tokens.push('writable');
} else if (report.value.isReadable == true){
tokens.push('readable');
} else{
tokens.push('executable');
}
return tokens.join(', ');
};
return TaoInstall;
});