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

808 lines
31 KiB
JavaScript
Raw Normal View History

2022-08-29 20:14:13 +02:00
/*
* 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;
});