upgrade
This commit is contained in:
78
plugin/vchamilo/views/editinstance.php
Normal file
78
plugin/vchamilo/views/editinstance.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
define('CHAMILO_INTERNAL', true);
|
||||
|
||||
global $plugin;
|
||||
|
||||
require_once __DIR__.'/../../../main/inc/global.inc.php';
|
||||
require_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/editinstance_form.php';
|
||||
|
||||
api_protect_admin_script();
|
||||
|
||||
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_PLUGIN_PATH).'vchamilo/js/host_form.js" type="text/javascript" language="javascript"></script>';
|
||||
|
||||
// get parameters
|
||||
$id = isset($_REQUEST['vid']) ? $_REQUEST['vid'] : '';
|
||||
$action = isset($_REQUEST['what']) ? $_REQUEST['what'] : '';
|
||||
$registeronly = isset($_REQUEST['registeronly']) ? $_REQUEST['registeronly'] : 0;
|
||||
$plugin = VChamiloPlugin::create();
|
||||
$thisurl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
|
||||
|
||||
if ($id) {
|
||||
$mode = 'update';
|
||||
} else {
|
||||
$mode = $registeronly ? 'register' : 'add';
|
||||
}
|
||||
|
||||
$vhost = (array) Virtual::getInstance($id);
|
||||
|
||||
$form = new InstanceForm($plugin, $mode, $vhost);
|
||||
|
||||
if ($data = $form->get_data()) {
|
||||
switch ($data->what) {
|
||||
case 'addinstance':
|
||||
case 'registerinstance':
|
||||
Virtual::addInstance($data);
|
||||
echo '<a class="btn btn-primary" href="'.api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php'.'">Continue</a>';
|
||||
exit;
|
||||
break;
|
||||
case 'updateinstance':
|
||||
unset($data->what);
|
||||
unset($data->submitbutton);
|
||||
unset($data->registeronly);
|
||||
unset($data->template);
|
||||
$data->lastcron = 0;
|
||||
$data->lastcrongap = 0;
|
||||
$data->croncount = 0;
|
||||
$id = $data->vid;
|
||||
unset($data->vid);
|
||||
unset($data->testconnection);
|
||||
unset($data->testdatapath);
|
||||
unset($data->vid);
|
||||
|
||||
Database::update('vchamilo', (array) $data, ['id = ?' => $id], false);
|
||||
Display::addFlash(Display::return_message(get_lang('Updated')));
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($id) {
|
||||
$vhost['vid'] = $vhost['id'];
|
||||
unset($vhost['id']);
|
||||
$form->set_data($vhost);
|
||||
} else {
|
||||
$vhost['db_host'] = 'localhost';
|
||||
$vhost['registeronly'] = $registeronly;
|
||||
$form->set_data($vhost);
|
||||
}
|
||||
|
||||
$content = $form->return_form();
|
||||
|
||||
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
|
||||
|
||||
$tpl = new Template(get_lang('Instance'), true, true, false, true, false);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
579
plugin/vchamilo/views/editinstance_form.php
Normal file
579
plugin/vchamilo/views/editinstance_form.php
Normal file
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* Class ChamiloForm.
|
||||
*/
|
||||
abstract class ChamiloForm
|
||||
{
|
||||
public $_definition_finalized;
|
||||
protected $_form;
|
||||
protected $_mode;
|
||||
protected $_cancelurl;
|
||||
protected $_customdata;
|
||||
|
||||
/**
|
||||
* ChamiloForm constructor.
|
||||
*
|
||||
* @param $mode
|
||||
* @param $returnurl
|
||||
* @param $cancelurl
|
||||
* @param $customdata
|
||||
*/
|
||||
public function __construct($mode, $returnurl, $cancelurl, $customdata = [])
|
||||
{
|
||||
global $text_dir;
|
||||
$this->_mode = $mode;
|
||||
$this->_cancelurl = $cancelurl;
|
||||
$this->_customdata = $customdata;
|
||||
|
||||
$attributes = ['style' => 'width: 60%; float: '.($text_dir == 'rtl' ? 'right;' : 'left;')];
|
||||
$this->_form = new FormValidator(
|
||||
$mode.'_instance',
|
||||
'post',
|
||||
$returnurl,
|
||||
'',
|
||||
$attributes
|
||||
);
|
||||
}
|
||||
|
||||
abstract public function definition();
|
||||
|
||||
abstract public function validation($data, $files = null);
|
||||
|
||||
public function validate()
|
||||
{
|
||||
return $this->_form->validate();
|
||||
}
|
||||
|
||||
public function display()
|
||||
{
|
||||
return $this->_form->display();
|
||||
}
|
||||
|
||||
public function definition_after_data()
|
||||
{
|
||||
}
|
||||
|
||||
public function return_form()
|
||||
{
|
||||
return $this->_form->toHtml();
|
||||
}
|
||||
|
||||
public function is_in_add_mode()
|
||||
{
|
||||
return $this->_mode == 'add';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return submitted data if properly submitted or returns NULL if validation fails or
|
||||
* if there is no submitted data.
|
||||
*
|
||||
* @param bool $slashed true means return data with addslashes applied
|
||||
*
|
||||
* @return object submitted data; NULL if not valid or not submitted
|
||||
*/
|
||||
public function get_data($slashed = true)
|
||||
{
|
||||
$cform = &$this->_form;
|
||||
|
||||
if ($this->is_submitted() and $this->is_validated()) {
|
||||
$data = $cform->exportValues(null, $slashed);
|
||||
unset($data['sesskey']); // we do not need to return sesskey
|
||||
if (empty($data)) {
|
||||
return null;
|
||||
} else {
|
||||
return (object) $data;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return submitted data without validation or NULL if there is no submitted data.
|
||||
*
|
||||
* @param bool $slashed true means return data with addslashes applied
|
||||
*
|
||||
* @return object submitted data; NULL if not submitted
|
||||
*/
|
||||
public function get_submitted_data($slashed = true)
|
||||
{
|
||||
$cform = &$this->_form;
|
||||
|
||||
if ($this->is_submitted()) {
|
||||
$data = $cform->exportValues(null, $slashed);
|
||||
unset($data['sesskey']); // we do not need to return sesskey
|
||||
if (empty($data)) {
|
||||
return null;
|
||||
} else {
|
||||
return (object) $data;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that form was submitted. Does not check validity of submitted data.
|
||||
*
|
||||
* @return bool true if form properly submitted
|
||||
*/
|
||||
public function is_submitted()
|
||||
{
|
||||
return $this->_form->isSubmitted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a cancel button has been pressed resulting in the form being submitted.
|
||||
*
|
||||
* @return bool true if a cancel button has been pressed
|
||||
*/
|
||||
public function is_cancelled()
|
||||
{
|
||||
$cform = &$this->_form;
|
||||
if ($cform->isSubmitted()) {
|
||||
foreach ($cform->_cancelButtons as $cancelbutton) {
|
||||
if (optional_param($cancelbutton, 0, PARAM_RAW)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that form data is valid.
|
||||
* You should almost always use this, rather than {@see validate_defined_fields}.
|
||||
*
|
||||
* @return bool true if form data valid
|
||||
*/
|
||||
public function is_validated()
|
||||
{
|
||||
//finalize the form definition before any processing
|
||||
if (!$this->_definition_finalized) {
|
||||
$this->_definition_finalized = true;
|
||||
$this->definition_after_data();
|
||||
}
|
||||
|
||||
return $this->validate_defined_fields();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the form.
|
||||
*
|
||||
* You almost always want to call {@see is_validated} instead of this
|
||||
* because it calls {@see definition_after_data} first, before validating the form,
|
||||
* which is what you want in 99% of cases.
|
||||
*
|
||||
* This is provided as a separate function for those special cases where
|
||||
* you want the form validated before definition_after_data is called
|
||||
* for example, to selectively add new elements depending on a no_submit_button press,
|
||||
* but only when the form is valid when the no_submit_button is pressed,
|
||||
*
|
||||
* @param bool $validateonnosubmit optional, defaults to false. The default behaviour
|
||||
* is NOT to validate the form when a no submit button has been pressed.
|
||||
* pass true here to override this behaviour
|
||||
*
|
||||
* @return bool true if form data valid
|
||||
*/
|
||||
public function validate_defined_fields($validateonnosubmit = false)
|
||||
{
|
||||
static $validated = null; // one validation is enough
|
||||
$cform = &$this->_form;
|
||||
|
||||
if ($this->no_submit_button_pressed() && empty($validateonnosubmit)) {
|
||||
return false;
|
||||
} elseif ($validated === null) {
|
||||
$internal_val = $cform->validate();
|
||||
|
||||
$files = [];
|
||||
$file_val = $this->_validate_files($files);
|
||||
if ($file_val !== true) {
|
||||
if (!empty($file_val)) {
|
||||
foreach ($file_val as $element => $msg) {
|
||||
$cform->setElementError($element, $msg);
|
||||
}
|
||||
}
|
||||
$file_val = false;
|
||||
}
|
||||
|
||||
$data = $cform->exportValues(null, true);
|
||||
$chamilo_val = $this->validation($data, $files);
|
||||
if ((is_array($chamilo_val) && count($chamilo_val) !== 0)) {
|
||||
// non-empty array means errors
|
||||
foreach ($chamilo_val as $element => $msg) {
|
||||
$cform->setElementError($element, $msg);
|
||||
}
|
||||
$chamilo_val = false;
|
||||
} else {
|
||||
// anything else means validation ok
|
||||
$chamilo_val = true;
|
||||
}
|
||||
|
||||
$validated = ($internal_val && $chamilo_val && $file_val);
|
||||
}
|
||||
|
||||
return $validated;
|
||||
}
|
||||
|
||||
public function no_submit_button_pressed()
|
||||
{
|
||||
static $nosubmit = null; // one check is enough
|
||||
|
||||
if (!is_null($nosubmit)) {
|
||||
return $nosubmit;
|
||||
}
|
||||
|
||||
$cform = &$this->_form;
|
||||
$nosubmit = false;
|
||||
if (!$this->is_submitted()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
foreach ($cform->_noSubmitButtons as $nosubmitbutton){
|
||||
if (optional_param($nosubmitbutton, 0, PARAM_RAW)){
|
||||
$nosubmit = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $nosubmit;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load in existing data as form defaults. Usually new entry defaults are stored directly in
|
||||
* form definition (new entry form); this function is used to load in data where values
|
||||
* already exist and data is being edited (edit entry form).
|
||||
*
|
||||
* @param mixed $default_values object or array of default values
|
||||
* @param bool $slashed true if magic quotes applied to data values
|
||||
*/
|
||||
public function set_data($default_values, $slashed = false)
|
||||
{
|
||||
if (is_object($default_values)) {
|
||||
$default_values = (array) $default_values;
|
||||
}
|
||||
$filter = $slashed ? 'stripslashes' : null;
|
||||
$this->_form->setDefaults($default_values, $filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method. Validates all uploaded files.
|
||||
*/
|
||||
public function _validate_files(&$files)
|
||||
{
|
||||
$files = [];
|
||||
|
||||
if (empty($_FILES)) {
|
||||
// we do not need to do any checks because no files were submitted
|
||||
// note: server side rules do not work for files - use custom verification in validate() instead
|
||||
return true;
|
||||
}
|
||||
|
||||
$errors = [];
|
||||
$mform = &$this->_form;
|
||||
|
||||
// check the files
|
||||
$status = $this->_upload_manager->preprocess_files();
|
||||
|
||||
// now check that we really want each file
|
||||
foreach ($_FILES as $elname => $file) {
|
||||
if ($mform->elementExists($elname) and $mform->getElementType($elname) == 'file') {
|
||||
$required = $mform->isElementRequired($elname);
|
||||
if (!empty($this->_upload_manager->files[$elname]['uploadlog']) &&
|
||||
empty($this->_upload_manager->files[$elname]['clear'])
|
||||
) {
|
||||
if (!$required and $file['error'] == UPLOAD_ERR_NO_FILE) {
|
||||
// file not uploaded and not required - ignore it
|
||||
continue;
|
||||
}
|
||||
$errors[$elname] = $this->_upload_manager->files[$elname]['uploadlog'];
|
||||
} elseif (!empty($this->_upload_manager->files[$elname]['clear'])) {
|
||||
$files[$elname] = $this->_upload_manager->files[$elname]['tmp_name'];
|
||||
}
|
||||
} else {
|
||||
error('Incorrect upload attempt!');
|
||||
}
|
||||
}
|
||||
|
||||
// return errors if found
|
||||
if ($status && 0 == count($errors)) {
|
||||
return true;
|
||||
} else {
|
||||
$files = [];
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class InstanceForm.
|
||||
*/
|
||||
class InstanceForm extends ChamiloForm
|
||||
{
|
||||
/** @var Plugin */
|
||||
public $_plugin;
|
||||
public $instance;
|
||||
|
||||
/**
|
||||
* InstanceForm constructor.
|
||||
*
|
||||
* @param $plugin
|
||||
* @param string $mode
|
||||
*/
|
||||
public function __construct($plugin, $mode = 'add', $instance = [])
|
||||
{
|
||||
global $_configuration;
|
||||
|
||||
$this->_plugin = $plugin;
|
||||
$returnUrl = $_configuration['root_web'].'plugin/vchamilo/views/editinstance.php';
|
||||
if ($mode == 'update') {
|
||||
$returnUrl = $_configuration['root_web'].'plugin/vchamilo/views/editinstance.php?vid='.intval($_GET['vid']);
|
||||
}
|
||||
|
||||
$cancelurl = $_configuration['root_web'].'plugin/vchamilo/views/manage.php';
|
||||
parent::__construct($mode, $returnUrl, $cancelurl);
|
||||
$this->instance = $instance;
|
||||
$this->definition();
|
||||
}
|
||||
|
||||
public function definition()
|
||||
{
|
||||
global $_configuration;
|
||||
|
||||
$form = $this->_form;
|
||||
$plugin = $this->_plugin;
|
||||
|
||||
$form->addElement('hidden', 'vid');
|
||||
$form->addElement('hidden', 'what', $this->_mode.'instance');
|
||||
$form->addElement('hidden', 'registeronly');
|
||||
|
||||
$form->addHeader($plugin->get_lang('hostdefinition'));
|
||||
$form->addText(
|
||||
'sitename',
|
||||
[
|
||||
$plugin->get_lang('sitename'),
|
||||
$plugin->get_lang('SiteNameExample'),
|
||||
]
|
||||
);
|
||||
$form->applyFilter('sitename', 'trim');
|
||||
$form->addText(
|
||||
'institution',
|
||||
[
|
||||
$plugin->get_lang('institution'),
|
||||
$plugin->get_lang('InstitutionExample'),
|
||||
]
|
||||
);
|
||||
$form->applyFilter('institution', 'trim');
|
||||
|
||||
// Host's name.
|
||||
$elementWeb = $form->addElement(
|
||||
'text',
|
||||
'root_web',
|
||||
[$this->_plugin->get_lang('rootweb'), $plugin->get_lang('RootWebExample')]
|
||||
);
|
||||
$form->applyFilter('root_web', 'trim');
|
||||
|
||||
$form->addElement(
|
||||
'text',
|
||||
'url_append',
|
||||
['url_append', $plugin->get_lang('UrlAppendExample')]
|
||||
);
|
||||
|
||||
if ($this->_mode == 'update') {
|
||||
$encryptList = Virtual::getEncryptList();
|
||||
$encryptMethod = $form->addElement(
|
||||
'select',
|
||||
'password_encryption',
|
||||
get_lang('EncryptMethodUserPass'),
|
||||
$encryptList
|
||||
);
|
||||
$encryptMethod->freeze();
|
||||
$elementWeb->freeze();
|
||||
}
|
||||
|
||||
/*
|
||||
* Database fieldset.
|
||||
*/
|
||||
$form->addElement('header', $plugin->get_lang('dbgroup'));
|
||||
|
||||
// Database host.
|
||||
$form->addElement(
|
||||
'text',
|
||||
'db_host',
|
||||
$this->_plugin->get_lang('dbhost'),
|
||||
['id' => 'id_vdbhost']
|
||||
);
|
||||
$form->applyFilter('db_host', 'trim');
|
||||
|
||||
// Database login.
|
||||
$form->addElement(
|
||||
'text',
|
||||
'db_user',
|
||||
$this->_plugin->get_lang('dbuser'),
|
||||
['id' => 'id_vdbuser']
|
||||
);
|
||||
$form->applyFilter('db_user', 'trim');
|
||||
|
||||
// Database password.
|
||||
$form->addElement(
|
||||
'password',
|
||||
'db_password',
|
||||
$this->_plugin->get_lang('dbpassword'),
|
||||
['id' => 'id_vdbpassword']
|
||||
);
|
||||
|
||||
// Database name.
|
||||
$form->addText(
|
||||
'main_database',
|
||||
[
|
||||
$plugin->get_lang('maindatabase'),
|
||||
$plugin->get_lang('DatabaseDescription'),
|
||||
]
|
||||
);
|
||||
|
||||
// Button for testing database connection.
|
||||
$form->addElement(
|
||||
'button',
|
||||
'testconnection',
|
||||
$this->_plugin->get_lang('testconnection'),
|
||||
'check',
|
||||
'default',
|
||||
'default',
|
||||
'',
|
||||
'onclick="opencnxpopup(\''.$_configuration['root_web'].'\'); return false;"'
|
||||
);
|
||||
|
||||
$form->addText('archive_url', $this->_plugin->get_lang('ArchiveUrl'));
|
||||
$form->addText('home_url', $this->_plugin->get_lang('HomeUrl'));
|
||||
$form->addText('upload_url', $this->_plugin->get_lang('UploadUrl'));
|
||||
$form->addText(
|
||||
'css_theme_folder',
|
||||
[
|
||||
$this->_plugin->get_lang('ThemeFolder'),
|
||||
$this->_plugin->get_lang('ThemeFolderExplanation'),
|
||||
],
|
||||
false
|
||||
);
|
||||
//$form->addText('course_url', $this->_plugin->get_lang('CourseUrl'));
|
||||
|
||||
/**
|
||||
* Template selection.
|
||||
*/
|
||||
if ($this->is_in_add_mode()) {
|
||||
$form->addElement('header', $this->_plugin->get_lang('templating'));
|
||||
|
||||
$templateoptions = Virtual::getAvailableTemplates();
|
||||
|
||||
// Template choice
|
||||
$form->addSelect(
|
||||
'template',
|
||||
$this->_plugin->get_lang('template'),
|
||||
$templateoptions
|
||||
);
|
||||
} else {
|
||||
if ($this->instance) {
|
||||
$form->addLabel(
|
||||
'slug',
|
||||
$this->instance['slug']
|
||||
);
|
||||
|
||||
$form->addLabel(
|
||||
'archive_real_root',
|
||||
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'archive_real_root')).
|
||||
$this->instance['slug']
|
||||
);
|
||||
|
||||
$form->addLabel(
|
||||
'course_real_root',
|
||||
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'course_real_root')).
|
||||
$this->instance['slug']
|
||||
);
|
||||
|
||||
$form->addLabel(
|
||||
'home_real_root',
|
||||
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'home_real_root')).$this->instance['slug']
|
||||
);
|
||||
|
||||
$form->addLabel(
|
||||
'upload_real_root',
|
||||
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'upload_real_root')).$this->instance['slug']
|
||||
);
|
||||
|
||||
$form->addLabel(
|
||||
$this->_plugin->get_lang('template'),
|
||||
$this->instance['template']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$form->addButtonSave(
|
||||
$this->_plugin->get_lang('savechanges'),
|
||||
'submitbutton'
|
||||
);
|
||||
|
||||
// Rules
|
||||
$form->addRule(
|
||||
'sitename',
|
||||
$this->_plugin->get_lang('sitenameinputerror'),
|
||||
'required',
|
||||
null,
|
||||
'client'
|
||||
);
|
||||
$form->addRule(
|
||||
'institution',
|
||||
$this->_plugin->get_lang('institutioninputerror'),
|
||||
'required',
|
||||
null,
|
||||
'client'
|
||||
);
|
||||
|
||||
$form->addRule(
|
||||
'root_web',
|
||||
$this->_plugin->get_lang('rootwebinputerror'),
|
||||
'required',
|
||||
null,
|
||||
'client'
|
||||
);
|
||||
$form->addRule(
|
||||
'main_database',
|
||||
$this->_plugin->get_lang('databaseinputerror'),
|
||||
'required',
|
||||
null,
|
||||
'client'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param null $files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validation($data, $files = null)
|
||||
{
|
||||
global $plugin;
|
||||
|
||||
$errors = [];
|
||||
$tablename = Database::get_main_table('vchamilo');
|
||||
$vchamilo = Database::select(
|
||||
'*',
|
||||
$tablename,
|
||||
['where' => [' root_web = ? ' => [$data['root_web']]]],
|
||||
'first'
|
||||
);
|
||||
|
||||
if ($vchamilo && isset($data['vid']) && $data['vid'] != $vchamilo['id']) {
|
||||
$errors['root_web'] = $plugin->get_lang('RootWebExists');
|
||||
}
|
||||
|
||||
if (!empty($errors)) {
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
plugin/vchamilo/views/import.php
Normal file
196
plugin/vchamilo/views/import.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../../../main/inc/global.inc.php';
|
||||
|
||||
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
|
||||
|
||||
// Security
|
||||
api_protect_admin_script();
|
||||
|
||||
Virtual::checkSettings();
|
||||
|
||||
$plugin = VChamiloPlugin::create();
|
||||
$form = new FormValidator('import', 'post', api_get_self());
|
||||
|
||||
// Database host.
|
||||
$form->addHeader(get_lang('From'));
|
||||
|
||||
$form->addText('root_web', [$plugin->get_lang('rootweb'), 'Example: http://www.chamilo.org/']);
|
||||
$form->addText('db_host', $plugin->get_lang('dbhost'));
|
||||
$form->applyFilter('db_host', 'trim');
|
||||
|
||||
// Database login.
|
||||
$form->addText('db_user', $plugin->get_lang('dbuser'));
|
||||
$form->applyFilter('db_user', 'trim');
|
||||
|
||||
// Database password.
|
||||
$form->addElement(
|
||||
'password',
|
||||
'db_password',
|
||||
$plugin->get_lang('dbpassword'),
|
||||
['id' => 'id_vdbpassword']
|
||||
);
|
||||
|
||||
// Database name.
|
||||
$form->addText('main_database', [$plugin->get_lang('maindatabase')]);
|
||||
|
||||
$form->addText(
|
||||
'configuration_file',
|
||||
[
|
||||
$plugin->get_lang('ConfigurationPath'),
|
||||
get_lang('Example').': /var/www/site/app/config/configuration.php',
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
$encryptList = Virtual::getEncryptList();
|
||||
|
||||
$form->addSelect(
|
||||
'password_encryption',
|
||||
get_lang('EncryptMethodUserPass'),
|
||||
$encryptList
|
||||
);
|
||||
|
||||
$encryptList = Virtual::getEncryptList();
|
||||
|
||||
$versionList = [
|
||||
'1.11.x',
|
||||
'1.10.x',
|
||||
'1.9.x',
|
||||
];
|
||||
|
||||
$form->addSelect(
|
||||
'version',
|
||||
$plugin->get_lang('FromVersion'),
|
||||
array_combine($versionList, $versionList)
|
||||
);
|
||||
|
||||
$form->addText(
|
||||
'course_path',
|
||||
[
|
||||
$plugin->get_lang('CoursePath'),
|
||||
get_lang('Example').': /var/www/site/virtual/var/courses',
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
$form->addText(
|
||||
'home_path',
|
||||
[
|
||||
$plugin->get_lang('HomePath'),
|
||||
get_lang('Example').': /var/www/site/virtual/var/home',
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
$form->addText(
|
||||
'upload_path',
|
||||
[
|
||||
$plugin->get_lang('UploadPath'),
|
||||
get_lang('Example').': /var/www/site/virtual/var/upload',
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
$form->addHeader(get_lang('To'));
|
||||
|
||||
$form->addText('to_db_host', $plugin->get_lang('dbhost'));
|
||||
$form->applyFilter('to_db_host', 'trim');
|
||||
|
||||
// Database login.
|
||||
$form->addText('to_db_user', $plugin->get_lang('dbuser'));
|
||||
$form->applyFilter('to_db_user', 'trim');
|
||||
|
||||
// Database password.
|
||||
$form->addElement(
|
||||
'password',
|
||||
'to_db_password',
|
||||
$plugin->get_lang('dbpassword'),
|
||||
['id' => 'id_vdbpassword']
|
||||
);
|
||||
|
||||
// Database name.
|
||||
$form->addText(
|
||||
'to_main_database',
|
||||
[
|
||||
$plugin->get_lang('maindatabase'),
|
||||
$plugin->get_lang('DatabaseDescription'),
|
||||
]
|
||||
);
|
||||
|
||||
$form->addButtonSave($plugin->get_lang('savechanges'), 'submitbutton');
|
||||
$content = $form->returnForm();
|
||||
|
||||
if ($form->validate()) {
|
||||
$values = $form->getSubmitValues();
|
||||
|
||||
$coursePath = $values['course_path'];
|
||||
$homePath = $values['home_path'];
|
||||
$confFile = $values['configuration_file'];
|
||||
$uploadPath = $values['upload_path'];
|
||||
|
||||
$isPharFile = str_starts_with(strtolower($confFile), 'phar://')
|
||||
|| str_starts_with(strtolower($coursePath), 'phar://')
|
||||
|| str_starts_with(strtolower($homePath), 'phar://')
|
||||
|| str_starts_with(strtolower($uploadPath), 'phar://');
|
||||
|
||||
if ($isPharFile) {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
$plugin->get_lang('NotAllowed'),
|
||||
'error'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$isWritable = is_dir($coursePath)
|
||||
&& is_dir($homePath)
|
||||
&& is_dir($uploadPath)
|
||||
&& file_exists($confFile)
|
||||
&& is_readable($confFile);
|
||||
|
||||
if ($isWritable) {
|
||||
$currentHost = api_get_configuration_value('db_host');
|
||||
$currentDatabase = api_get_configuration_value('main_database');
|
||||
$currentUser = api_get_configuration_value('db_user');
|
||||
$currentPassword = api_get_configuration_value('db_password');
|
||||
|
||||
if ($values['to_main_database'] !== $currentDatabase &&
|
||||
$values['to_db_user'] !== $currentUser &&
|
||||
$values['to_db_password'] !== $currentPassword
|
||||
) {
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
$plugin->get_lang('DatabaseAccessShouldBeDifferentThanMasterChamilo'),
|
||||
'warning'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$vchamilo = new stdClass();
|
||||
$vchamilo->main_database = $values['main_database'];
|
||||
$vchamilo->db_user = $values['db_user'];
|
||||
$vchamilo->db_password = $values['db_password'];
|
||||
$vchamilo->db_host = $values['db_host'];
|
||||
$vchamilo->root_web = $values['root_web'];
|
||||
$vchamilo->import_to_main_database = $values['to_main_database'];
|
||||
$vchamilo->import_to_db_user = $values['to_db_user'];
|
||||
$vchamilo->import_to_db_password = $values['to_db_password'];
|
||||
$vchamilo->import_to_db_host = $values['to_db_host'];
|
||||
$vchamilo->course_path = $values['course_path'];
|
||||
$vchamilo->home_path = $values['home_path'];
|
||||
$vchamilo->upload_path = $values['upload_path'];
|
||||
$vchamilo->password_encryption = $values['password_encryption'];
|
||||
|
||||
Virtual::importInstance($vchamilo, $values['version']);
|
||||
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = new Template(get_lang('Import'), true, true, false, true, false);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
373
plugin/vchamilo/views/manage.controller.php
Normal file
373
plugin/vchamilo/views/manage.controller.php
Normal file
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$table = Database::get_main_table('vchamilo');
|
||||
|
||||
if (!defined('CHAMILO_INTERNAL')) {
|
||||
exit('You cannot use this script this way');
|
||||
}
|
||||
|
||||
$vidlist = isset($_REQUEST['vids']) ? implode("','", array_map('intval', $_REQUEST['vids'])) : '';
|
||||
|
||||
switch ($action) {
|
||||
case 'upgrade':
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/upgrade.php?vid='.$vidlist);
|
||||
break;
|
||||
case 'import':
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/import.php');
|
||||
break;
|
||||
case 'newinstance':
|
||||
case 'instance':
|
||||
$registeronly = isset($_REQUEST['registeronly']) ? $_REQUEST['registeronly'] : 0;
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/editinstance.php?registeronly='.$registeronly);
|
||||
break;
|
||||
case 'editinstance':
|
||||
case 'updateinstance':
|
||||
$vid = $_REQUEST['vid'];
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/editinstance.php?vid='.$vid);
|
||||
break;
|
||||
case 'deleteinstances':
|
||||
case 'disableinstances':
|
||||
if (!empty($vidlist)) {
|
||||
Display::addFlash(Display::return_message("Disabling instance"));
|
||||
// Make it not visible.
|
||||
|
||||
$sql = "UPDATE $table SET visible = 0 WHERE id IN ('$vidlist')";
|
||||
Database::query($sql);
|
||||
}
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
|
||||
break;
|
||||
case 'enableinstances':
|
||||
if (!empty($vidlist)) {
|
||||
Display::addFlash(Display::return_message("Enabling instance"));
|
||||
$sql = "UPDATE $table SET visible = 1 WHERE id IN ('$vidlist') ";
|
||||
Database::query($sql);
|
||||
}
|
||||
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
|
||||
break;
|
||||
case 'fulldeleteinstances':
|
||||
$todelete = [];
|
||||
// Removes everything.
|
||||
if (empty($automation)) {
|
||||
if (!empty($vidlist)) {
|
||||
$todelete = Database::select('*', 'vchamilo', ['where' => ["id IN ('$vidlist')" => []]]);
|
||||
}
|
||||
} else {
|
||||
$todelete = Database::select(
|
||||
'*',
|
||||
'vchamilo',
|
||||
['where' => ["root_web = '{$n->root_web}' " => []]]
|
||||
);
|
||||
}
|
||||
|
||||
if ($todelete) {
|
||||
foreach ($todelete as $fooid => $instance) {
|
||||
$slug = $instance['slug'];
|
||||
|
||||
if (!empty($slug)) {
|
||||
// Remove all files and eventual symlinks
|
||||
$absalternatecourse = Virtual::getConfig('vchamilo', 'course_real_root');
|
||||
$coursedir = $absalternatecourse.$slug;
|
||||
|
||||
Display::addFlash(Display::return_message("Deleting $coursedir"));
|
||||
|
||||
removeDir($coursedir);
|
||||
|
||||
if ($absalternatehome = Virtual::getConfig('vchamilo', 'home_real_root')) {
|
||||
$homedir = $absalternatehome.'/'.$slug;
|
||||
|
||||
Display::addFlash(Display::return_message("Deleting $homedir"));
|
||||
removeDir($homedir);
|
||||
}
|
||||
|
||||
// delete archive
|
||||
if ($absalternatearchive = Virtual::getConfig('vchamilo', 'archive_real_root')) {
|
||||
$archivedir = $absalternatearchive.'/'.$slug;
|
||||
|
||||
Display::addFlash(Display::return_message("Deleting $archivedir"));
|
||||
removeDir($archivedir);
|
||||
}
|
||||
|
||||
// Delete upload
|
||||
if ($dir = Virtual::getConfig('vchamilo', 'upload_real_root')) {
|
||||
$dir = $dir.'/'.$slug;
|
||||
|
||||
Display::addFlash(Display::return_message("Deleting $dir"));
|
||||
removeDir($dir);
|
||||
}
|
||||
}
|
||||
|
||||
$sql = "DELETE FROM {$table} WHERE id = ".$instance['id'];
|
||||
Database::query($sql);
|
||||
|
||||
Display::addFlash(Display::return_message("Removing instance: ".$instance['root_web']));
|
||||
|
||||
Virtual::dropDatabase((object) $instance);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'snapshotinstance':
|
||||
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
|
||||
|
||||
$vid = isset($_REQUEST['vid']) ? $_REQUEST['vid'] : '';
|
||||
if ($vid) {
|
||||
$vhosts = Database::select('*', 'vchamilo', ['where' => ['id = ?' => $vid]]);
|
||||
$vhost = (object) array_pop($vhosts);
|
||||
} else {
|
||||
$vhost = (object) $_configuration;
|
||||
$vhost->slug = Virtual::getSlugFromUrl($vhost->root_web);
|
||||
$vhost->id = 0;
|
||||
}
|
||||
|
||||
// Parsing url for building the template name.
|
||||
$wwwroot = $vhost->root_web;
|
||||
$vchamilostep = isset($_REQUEST['step']) ? $_REQUEST['step'] : '';
|
||||
|
||||
// Make template directory (files and SQL).
|
||||
$separator = DIRECTORY_SEPARATOR;
|
||||
$dirMode = api_get_permissions_for_new_directories();
|
||||
|
||||
$backupDir = api_get_path(SYS_PATH).'plugin'.$separator.'vchamilo'.$separator.'templates'.$separator.$vhost->slug.$separator;
|
||||
|
||||
$absolute_datadir = $backupDir.'data';
|
||||
$absolute_sqldir = $backupDir.'dump.sql';
|
||||
|
||||
if (!is_dir($backupDir)) {
|
||||
$result = mkdir($backupDir, $dirMode, true);
|
||||
if ($result) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Directory created: '.$backupDir)
|
||||
);
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message("Cannot create directory: $backupDir check the folder permissions", 'error')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($vchamilostep == 0) {
|
||||
// Create directories, if necessary.
|
||||
if (!is_dir($absolute_datadir)) {
|
||||
mkdir($absolute_datadir, $dirMode, true);
|
||||
mkdir($absolute_datadir.'/home', $dirMode, true);
|
||||
}
|
||||
|
||||
if (empty($fullautomation)) {
|
||||
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
|
||||
$content = '<form name"single" action="'.$actionurl.'">';
|
||||
$content .= '<input type="hidden" name="what" value="snapshotinstance" />';
|
||||
$content .= '<input type="hidden" name="vid" value="'.$vhost->id.'" />';
|
||||
$content .= '<input type="hidden" name="step" value="1" />';
|
||||
$content .= '<input type="submit" class="btn btn-primary" name="go_btn" value="'.$plugin->get_lang('continue').'" />';
|
||||
$content .= '</form>';
|
||||
$content .= '</div>';
|
||||
|
||||
$tpl = new Template(get_lang('Snapshot'), true, true, false, true, false);
|
||||
$tpl->assign('message', '<h4>'.$plugin->get_lang('vchamilosnapshot1').'</h4>');
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
|
||||
exit;
|
||||
} else {
|
||||
// continue next step
|
||||
$vchamilostep = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($vchamilostep >= 1) {
|
||||
if ($wwwroot == $_configuration['root_web']) {
|
||||
// Make fake Vchamilo record.
|
||||
$vchamilo = Virtual::makeThis();
|
||||
$coursePath = api_get_path(SYS_COURSE_PATH);
|
||||
$homePath = api_get_path(SYS_HOME_PATH);
|
||||
$archivePath = api_get_path(SYS_ARCHIVE_PATH);
|
||||
$uploadPath = api_get_path(SYS_UPLOAD_PATH);
|
||||
} else {
|
||||
// Get Vchamilo known record.
|
||||
$vchamilo = Database::select('*', 'vchamilo', ['where' => ['root_web = ?' => [$wwwroot]]], 'first');
|
||||
$vchamilo = (object) $vchamilo;
|
||||
$coursePath = Virtual::getConfig('vchamilo', 'course_real_root');
|
||||
$homePath = Virtual::getConfig('vchamilo', 'home_real_root');
|
||||
$archivePath = Virtual::getConfig('vchamilo', 'archive_real_root');
|
||||
$uploadPath = Virtual::getConfig('vchamilo', 'upload_real_root');
|
||||
|
||||
$coursePath = $coursePath.'/'.$vchamilo->slug;
|
||||
$homePath = $homePath.'/'.$vchamilo->slug;
|
||||
$archivePath = $archivePath.'/'.$vchamilo->slug;
|
||||
$uploadPath = $uploadPath.'/'.$vchamilo->slug;
|
||||
}
|
||||
|
||||
$content = '';
|
||||
if ($vchamilostep == 1) {
|
||||
// Auto dump the databases in a master template folder.
|
||||
// this will create three files : dump.sql
|
||||
$result = Virtual::backupDatabase($vchamilo, $absolute_sqldir);
|
||||
|
||||
if (empty($fullautomation)) {
|
||||
if (!$result) {
|
||||
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
|
||||
$content .= '<p><form name"single" action="'.$actionurl.'">';
|
||||
$content .= '<input type="submit" name="go_btn" value="'.$plugin->get_lang('cancel').'" />';
|
||||
$content .= '</form></p>';
|
||||
} else {
|
||||
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
|
||||
|
||||
$message = $plugin->get_lang('vchamilosnapshot2');
|
||||
|
||||
Display::addFlash(
|
||||
Display::return_message('Database file created: '.$absolute_sqldir)
|
||||
);
|
||||
|
||||
$content .= '<form name"single" action="'.$actionurl.'">';
|
||||
$content .= '<input type="hidden" name="what" value="snapshotinstance" />';
|
||||
$content .= '<input type="hidden" name="vid" value="'.$vhost->id.'" />';
|
||||
$content .= '<input type="hidden" name="step" value="2" />';
|
||||
$content .= '<input class="btn btn-primary" type="submit" name="go_btn" value="'.$plugin->get_lang('continue').'" />';
|
||||
$content .= '</form>';
|
||||
}
|
||||
|
||||
$tpl = new Template(get_lang('Snapshot'), true, true, false, true, false);
|
||||
$tpl->assign('message', '<h4>'.$message.'</h4>');
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
Display::addFlash(Display::return_message("Copying from '$homePath' to '{$absolute_datadir}/home' "));
|
||||
copyDirTo($homePath, $absolute_datadir.'/home/', false);
|
||||
|
||||
Display::addFlash(Display::return_message("Copying from '$coursePath' to '$absolute_datadir/courses' "));
|
||||
copyDirTo($coursePath, $absolute_datadir.'/courses/', false);
|
||||
|
||||
Display::addFlash(Display::return_message("Copying from '$uploadPath' to '$absolute_datadir/upload' "));
|
||||
copyDirTo($uploadPath, $absolute_datadir.'/upload/', false);
|
||||
|
||||
// Store original hostname and some config info for further database or filestore replacements.
|
||||
$FILE = fopen($backupDir.$separator.'manifest.php', 'w');
|
||||
fwrite($FILE, '<'.'?php ');
|
||||
fwrite($FILE, "\$templatewwwroot = '".$wwwroot."';\n");
|
||||
fwrite($FILE, '?'.'>');
|
||||
fclose($FILE);
|
||||
|
||||
// Every step was SUCCESS.
|
||||
if (empty($fullautomation)) {
|
||||
Display::addFlash(
|
||||
Display::return_message(
|
||||
$plugin->get_lang('successfinishedcapture'),
|
||||
'success'
|
||||
)
|
||||
);
|
||||
|
||||
if (empty($vid)) {
|
||||
$template = Virtual::getConfig('vchamilo', 'default_template');
|
||||
if (empty($template)) {
|
||||
Display::addFlash(
|
||||
Display::return_message('Set default template as <b>'.$vhost->slug.'</b>', 'success', false)
|
||||
);
|
||||
$params = [
|
||||
'subkey' => 'vchamilo',
|
||||
'title' => 'default_template',
|
||||
'type' => 'setting',
|
||||
'category' => 'Plugins',
|
||||
'variable' => 'vchamilo_default_template',
|
||||
'selected_value' => $vhost->slug,
|
||||
'access_url_changeable' => 0,
|
||||
];
|
||||
api_set_setting_simple($params);
|
||||
} else {
|
||||
Display::addFlash(
|
||||
Display::return_message('Default template is: <b>'.$vhost->slug.'</b>', 'success', false)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
|
||||
$content .= '<form name"single" action="'.$actionurl.'">';
|
||||
$content .= '<input class="btn btn-primary" type="submit" name="go_btn" value="'.$plugin->get_lang('backtoindex').'" />';
|
||||
$content .= '</form>';
|
||||
|
||||
$tpl = new Template(get_lang('Snapshot'), true, true, false, true, false);
|
||||
$tpl->assign('message', $plugin->get_lang('vchamilosnapshot3'));
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'clearcache':
|
||||
// Removes cache directory.
|
||||
if (empty($automation)) {
|
||||
if (array_key_exists('vids', $_REQUEST)) {
|
||||
$toclear = Database::select('*', 'vchamilo', ['where' => ["id IN ('$vidlist')" => []]]);
|
||||
} else {
|
||||
$vid = isset($_REQUEST['vid']) ? $_REQUEST['vid'] : 0;
|
||||
if ($vid) {
|
||||
$vhosts = Database::select('*', 'vchamilo', ['where' => ['id = ?' => $vid]]);
|
||||
$vhost = (object) array_pop($vhosts);
|
||||
$toclear[$vhost->id] = $vhost;
|
||||
} else {
|
||||
$toclear[0] = (object) $_configuration;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$toclear = Database::select(
|
||||
'*',
|
||||
'vchamilo',
|
||||
['where' => ["root_web = '{$n->root_web}' " => []]]
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($toclear as $fooid => $instance) {
|
||||
if ($fooid == 0) {
|
||||
$templatepath = api_get_path(SYS_ARCHIVE_PATH).'twig';
|
||||
Display::addFlash(Display::return_message("Deleting master cache $templatepath \n"));
|
||||
removeDir($templatepath);
|
||||
} else {
|
||||
$coursePath = Virtual::getConfig('vchamilo', 'course_real_root');
|
||||
$homePath = Virtual::getConfig('vchamilo', 'home_real_root');
|
||||
$archivePath = Virtual::getConfig('vchamilo', 'archive_real_root');
|
||||
//$uploadPath = Virtual::getConfig('vchamilo', 'upload_real_root');
|
||||
|
||||
// Get instance archive
|
||||
$archivepath = api_get_path(SYS_ARCHIVE_PATH, (array) $instance);
|
||||
$templatepath = $archivePath.'/'.$instance['slug'].'/twig';
|
||||
Display::addFlash(Display::return_message("Deleting cache $templatepath \n"));
|
||||
removeDir($templatepath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'setconfigvalue':
|
||||
$select = '<select name="preset" onchange="setpreset(this.form, this)">';
|
||||
$settings = api_get_settings();
|
||||
foreach ($settings as $setting) {
|
||||
$select .= '<option name="'.$setting['variable'].'/'.$setting['subkey'].'">'.
|
||||
$setting['variable'].' - '.$setting['subkey'].
|
||||
'</option>';
|
||||
}
|
||||
$select .= '</select>';
|
||||
|
||||
if (empty($vidlist)) {
|
||||
api_not_allowed(true, 'No virtual chamilo selected');
|
||||
}
|
||||
|
||||
Display::display_header();
|
||||
echo '<h2>'.$plugin->get_lang('sendconfigvalue').'</h2>';
|
||||
echo '<form name="setconfigform">';
|
||||
echo '<input type="hidden" name="vidlist" value="'.$vidlist.'" />';
|
||||
echo '<input type="hidden" name="confirm" value="1" />';
|
||||
echo '<table>';
|
||||
echo '<tr><td>'.get_lang('variable').'</td><td>'.get_lang('subkey').'</td></tr>';
|
||||
echo '<tr><td><input type="text" name="variable" value="" size="30" /></td>';
|
||||
echo '<td><input type="text" name="subkey" value="" size="30" /></td></tr>';
|
||||
echo '<tr><td colspan="2">'.$select.'</td></tr>';
|
||||
echo '<tr><td colspan="2">';
|
||||
echo '<input class="btn btn-primary" type="submit" name="go_btn" value="'.$plugin->get_lang('distributevalue').'"</td></tr>';
|
||||
echo '</table>';
|
||||
echo '</form>';
|
||||
Display::display_footer();
|
||||
exit;
|
||||
break;
|
||||
}
|
||||
157
plugin/vchamilo/views/manage.php
Normal file
157
plugin/vchamilo/views/manage.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../../../main/inc/global.inc.php';
|
||||
|
||||
// Security
|
||||
api_protect_admin_script();
|
||||
Virtual::checkSettings();
|
||||
|
||||
$action = isset($_GET['what']) ? $_GET['what'] : '';
|
||||
define('CHAMILO_INTERNAL', true);
|
||||
|
||||
$plugin = VChamiloPlugin::create();
|
||||
$thisurl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
|
||||
|
||||
Virtual::requireJs('host_list.js', 'vchamilo', 'head');
|
||||
|
||||
if ($action) {
|
||||
require_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/manage.controller.php';
|
||||
}
|
||||
|
||||
$query = "SELECT * FROM vchamilo";
|
||||
$result = Database::query($query);
|
||||
$instances = [];
|
||||
while ($instance = Database::fetch_object($result)) {
|
||||
$instances[$instance->id] = $instance;
|
||||
}
|
||||
|
||||
$templates = Virtual::getAvailableTemplates();
|
||||
|
||||
if (empty($templates)) {
|
||||
$url = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php?what=snapshotinstance';
|
||||
$url = Display::url($url, $url);
|
||||
Display::addFlash(
|
||||
Display::return_message('You need to create a snapshot of master first here:'.$url, 'info', false)
|
||||
);
|
||||
}
|
||||
|
||||
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
|
||||
$column = 0;
|
||||
$row = 0;
|
||||
|
||||
// $table->set_additional_parameters($parameters);
|
||||
$headers = [
|
||||
'',
|
||||
$plugin->get_lang('sitename'),
|
||||
$plugin->get_lang('dbhost').' - '.get_lang('Database'),
|
||||
$plugin->get_lang('coursefolder'),
|
||||
$plugin->get_lang('enabled'),
|
||||
$plugin->get_lang('lastcron'),
|
||||
'',
|
||||
];
|
||||
$attrs = ['center' => 'left'];
|
||||
$table->addRow($headers, $attrs, 'th');
|
||||
|
||||
$i = 0;
|
||||
foreach ($instances as $instance) {
|
||||
$checkbox = '<input type="checkbox" class="vnodessel" name="vids[]" value="'.$instance->id.'" />';
|
||||
$sitelink = $instance->sitename;
|
||||
|
||||
if ($instance->visible) {
|
||||
$status = '<a href="'.$thisurl.'?what=disableinstances&vids[]='.$instance->id.'" >
|
||||
'.Display::returnFontAwesomeIcon('toggle-on', 2).'</a>';
|
||||
} else {
|
||||
$status = '<a href="'.$thisurl.'?what=enableinstances&vids[]='.$instance->id.'" >
|
||||
'.Display::returnFontAwesomeIcon('toggle-off', 2).'</a>';
|
||||
}
|
||||
|
||||
$cmd = ' <a href="'.$thisurl.'?what=editinstance&vid='.$instance->id.'" title="'.$plugin->get_lang('edit').'">
|
||||
'.Display::returnFontAwesomeIcon('pencil', 2).'</a>';
|
||||
$cmd .= ' <a href="'.$thisurl.'?what=snapshotinstance&vid='.$instance->id.'" title="'.$plugin->get_lang('snapshotinstance').'">
|
||||
'.Display::returnFontAwesomeIcon('camera', 2).'</a>';
|
||||
|
||||
$cmd .= '<a href="'.$thisurl.'?what=upgrade&vids[]='.$instance->id.'" title="'.$plugin->get_lang('Upgrade').'">
|
||||
'.Display::returnFontAwesomeIcon('wrench', 2).' </a>';
|
||||
|
||||
if (!$instance->visible) {
|
||||
$cmd .= '<a onclick="javascript:if(!confirm(\''.get_lang('AreYouSureToDelete').'\')) return false;" href="'.$thisurl.'?what=fulldeleteinstances&vids[]='.$instance->id.'" title="'.$plugin->get_lang('destroyinstances').'">
|
||||
'.Display::returnFontAwesomeIcon('remove', 2).' </a>';
|
||||
} else {
|
||||
$cmd .= '<a onclick="javascript:if(!confirm(\''.get_lang('AreYouSureToDelete').'\')) return false;" href="'.$thisurl.'?what=deleteinstances&vids[]='.$instance->id.'" title="'.$plugin->get_lang('deleteinstances').'">
|
||||
'.Display::returnFontAwesomeIcon('remove', 2).' </a>';
|
||||
}
|
||||
|
||||
$crondate = $instance->lastcron ? date('r', $instance->lastcron) : '';
|
||||
$data = [
|
||||
$checkbox,
|
||||
$sitelink.' '.$instance->institution.' ('.Display::url($instance->root_web, $instance->root_web, ['target' => '_blank']).')',
|
||||
$instance->db_host.' - '.$instance->main_database,
|
||||
$instance->slug,
|
||||
$status,
|
||||
$crondate,
|
||||
$cmd,
|
||||
];
|
||||
$attrs = ['center' => 'left'];
|
||||
$table->addRow($data, $attrs, 'td');
|
||||
$i++;
|
||||
}
|
||||
|
||||
$items = [
|
||||
[
|
||||
'url' => $thisurl.'?what=newinstance',
|
||||
'content' => $plugin->get_lang('newinstance'),
|
||||
],
|
||||
[
|
||||
'url' => $thisurl.'?what=import',
|
||||
'content' => $plugin->get_lang('ImportInstance'),
|
||||
],
|
||||
[
|
||||
'url' => $thisurl.'?what=snapshotinstance&vid=0',
|
||||
'content' => $plugin->get_lang('snapshotmaster'),
|
||||
],
|
||||
[
|
||||
'url' => $thisurl.'?what=clearcache&vid=0',
|
||||
'content' => $plugin->get_lang('clearmastercache'),
|
||||
],
|
||||
[
|
||||
'url' => api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/syncparams.php',
|
||||
'content' => $plugin->get_lang('sync_settings'),
|
||||
],
|
||||
[
|
||||
'url' => api_get_path(WEB_CODE_PATH).'admin/configure_plugin.php?name=vchamilo',
|
||||
'content' => get_lang('Settings'),
|
||||
],
|
||||
];
|
||||
|
||||
$content = Display::page_header('VChamilo Instances');
|
||||
|
||||
$content .= Display::actions($items);
|
||||
$content .= '<form action="'.$thisurl.'">';
|
||||
$content .= $table->toHtml();
|
||||
|
||||
$selectionoptions = ['<option value="0" selected="selected">'.$plugin->get_lang('choose').'</option>'];
|
||||
$selectionoptions[] = '<option value="deleteinstances">'.$plugin->get_lang('deleteinstances').'</option>';
|
||||
$selectionoptions[] = '<option value="enableinstances">'.$plugin->get_lang('enableinstances').'</option>';
|
||||
$selectionoptions[] = '<option value="fulldeleteinstances">'.$plugin->get_lang(
|
||||
'destroyinstances'
|
||||
).'</option>';
|
||||
$selectionoptions[] = '<option value="clearcache">'.$plugin->get_lang('clearcache').'</option>';
|
||||
$selectionoptions[] = '<option value="setconfigvalue">'.$plugin->get_lang('setconfigvalue').'</option>';
|
||||
$selectionaction = '<select name="what" onchange="this.form.submit()">'.implode('', $selectionoptions).'</select>';
|
||||
|
||||
$content .= '<div class="vchamilo-right"><div></div><div>
|
||||
<a href="javascript:selectallhosts()">'.$plugin->get_lang('selectall').'</a> -
|
||||
<a href="javascript:deselectallhosts()">'.$plugin->get_lang('selectnone').'</a> -
|
||||
- '.$plugin->get_lang('withselection').' '.$selectionaction.'</div></div>';
|
||||
|
||||
$content .= '</form>';
|
||||
|
||||
if (empty($templates)) {
|
||||
$content = '';
|
||||
}
|
||||
|
||||
$tpl = new Template(get_lang('VChamilo'), true, true, false, true, false);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
55
plugin/vchamilo/views/manage.testcnx.php
Normal file
55
plugin/vchamilo/views/manage.testcnx.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
/**
|
||||
* Tests database connection.
|
||||
*
|
||||
* @package vchamilo
|
||||
*
|
||||
* @author Moheissen Fabien (fabien.moheissen@gmail.com)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
|
||||
*/
|
||||
|
||||
// Loading configuration.
|
||||
require_once __DIR__.'/../../../main/inc/global.inc.php';
|
||||
|
||||
api_protect_admin_script();
|
||||
|
||||
global $_configuration;
|
||||
|
||||
$plugin = VChamiloPlugin::create();
|
||||
|
||||
// Retrieve parameters for database connection test.
|
||||
$dbParams = [];
|
||||
$dbParams['db_host'] = $_REQUEST['vdbhost'];
|
||||
$dbParams['db_user'] = $_REQUEST['vdblogin'];
|
||||
$dbParams['db_password'] = $_REQUEST['vdbpass'];
|
||||
$dbParams['root_sys'] = api_get_path(SYS_PATH);
|
||||
|
||||
$dbParams = [
|
||||
'driver' => 'pdo_mysql',
|
||||
'host' => $_REQUEST['vdbhost'],
|
||||
'user' => $_REQUEST['vdblogin'],
|
||||
'password' => $_REQUEST['vdbpass'],
|
||||
//'dbname' => isset($_configuration['main_database']) ? $_configuration['main_database'] : '',
|
||||
// Only relevant for pdo_sqlite, specifies the path to the SQLite database.
|
||||
//'path' => isset($_configuration['db_path']) ? $_configuration['db_path'] : '',
|
||||
// Only relevant for pdo_mysql, pdo_pgsql, and pdo_oci/oci8,
|
||||
//'port' => isset($_configuration['db_port']) ? $_configuration['db_port'] : '',
|
||||
];
|
||||
|
||||
try {
|
||||
$database = new \Database();
|
||||
$connection = $database->connect(
|
||||
$dbParams,
|
||||
$_configuration['root_sys'],
|
||||
$_configuration['root_sys'],
|
||||
true
|
||||
);
|
||||
|
||||
$list = $connection->getSchemaManager()->listDatabases();
|
||||
echo $plugin->get_lang('connectionok');
|
||||
} catch (Exception $e) {
|
||||
echo $plugin->get_lang('badconnection');
|
||||
exit();
|
||||
}
|
||||
3
plugin/vchamilo/views/manage.testdatapath.php
Normal file
3
plugin/vchamilo/views/manage.testdatapath.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
// Deprecated and vulnerable. Blanked as substitute to removal due to minor version update method.
|
||||
exit;
|
||||
132
plugin/vchamilo/views/syncparams.controller.php
Normal file
132
plugin/vchamilo/views/syncparams.controller.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
use Doctrine\DBAL\Configuration;
|
||||
use Doctrine\DBAL\DriverManager;
|
||||
|
||||
api_protect_admin_script();
|
||||
|
||||
$sql = "SELECT * FROM vchamilo";
|
||||
$result = Database::query($sql);
|
||||
$vchamilos = Database::store_result($result, 'ASSOC');
|
||||
|
||||
// propagate in all known vchamilos a setting
|
||||
switch ($action) {
|
||||
case 'syncall':
|
||||
exit;
|
||||
$keys = array_keys($_REQUEST);
|
||||
$selection = preg_grep('/sel_.*/', $keys);
|
||||
|
||||
foreach ($selection as $selkey) {
|
||||
$settingId = str_replace('sel_', '', $selkey);
|
||||
|
||||
if (!is_numeric($settingId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$value = $_REQUEST[$selkey];
|
||||
$setting = api_get_settings_params_simple(['id = ?' => $settingId]);
|
||||
|
||||
$params = [
|
||||
'title' => $setting['title'],
|
||||
'variable' => $setting['variable'],
|
||||
'subkey' => $setting['subkey'],
|
||||
'category' => $setting['category'],
|
||||
'access_url' => $setting['access_url'],
|
||||
];
|
||||
|
||||
foreach ($vchamilos as $chm) {
|
||||
$table = $chm['main_database'].".settings_current ";
|
||||
$sql = " SELECT * FROM $table
|
||||
WHERE
|
||||
variable = '{{$setting['variable']}}' AND
|
||||
access_url = '{$setting['access_url']}'
|
||||
";
|
||||
$result = Database::query($sql);
|
||||
|
||||
if (Database::num_rows($result)) {
|
||||
Database::update($table, ['selected_Value' => $value, ['id' => $settingId]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'syncthis':
|
||||
$settingId = isset($_GET['settingid']) ? (int) $_GET['settingid'] : 0;
|
||||
|
||||
if ($settingId) {
|
||||
$deleteIfEmpty = $_REQUEST['del'] ?? '';
|
||||
$value = $_REQUEST['value'];
|
||||
// Getting the local setting record.
|
||||
$setting = api_get_settings_params_simple(['id = ?' => $settingId]);
|
||||
if (empty($setting)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$params = [
|
||||
'access_url_changeable' => $setting['access_url_changeable'],
|
||||
'title' => $setting['title'],
|
||||
'variable' => $setting['variable'],
|
||||
'subkey' => $setting['subkey'],
|
||||
'category' => $setting['category'],
|
||||
'type' => $setting['type'],
|
||||
'comment' => $setting['comment'],
|
||||
'access_url' => $setting['access_url'],
|
||||
];
|
||||
|
||||
$errors = '';
|
||||
foreach ($vchamilos as $instance) {
|
||||
$table = 'settings_current';
|
||||
$config = new Configuration();
|
||||
$connectionParams = [
|
||||
'dbname' => $instance['main_database'],
|
||||
'user' => $instance['db_user'],
|
||||
'password' => $instance['db_password'],
|
||||
'host' => $instance['db_host'],
|
||||
'driver' => 'pdo_mysql',
|
||||
];
|
||||
try {
|
||||
$connection = DriverManager::getConnection($connectionParams, $config);
|
||||
|
||||
$variable = $setting['variable'];
|
||||
$subKey = $setting['subkey'];
|
||||
$category = $setting['category'];
|
||||
$accessUrl = $setting['access_url'];
|
||||
|
||||
if ($deleteIfEmpty && empty($value)) {
|
||||
$connection->delete($table, ['selected_value' => $value, 'variable' => $variable, 'access_url' => $accessUrl]);
|
||||
$case = 'delete';
|
||||
} else {
|
||||
$sql = "SELECT * FROM $table
|
||||
WHERE
|
||||
variable = '$variable' AND
|
||||
access_url = '$accessUrl'
|
||||
";
|
||||
$result = $connection->fetchAllAssociative($sql);
|
||||
|
||||
if (!empty($result)) {
|
||||
//$sql = "UPDATE $table SET selected_value = '$value' WHERE id = $settingId";
|
||||
$criteria = ['variable' => $variable];
|
||||
if (!empty($subKey)) {
|
||||
$criteria['subkey'] = $subKey;
|
||||
}
|
||||
if (!empty($category)) {
|
||||
$criteria['category'] = $category;
|
||||
}
|
||||
$connection->update($table, ['selected_value' => $value], $criteria);
|
||||
} else {
|
||||
$connection->insert($table, $params);
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
} else {
|
||||
return "Bad ID. Non numeric";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
83
plugin/vchamilo/views/syncparams.php
Normal file
83
plugin/vchamilo/views/syncparams.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
require_once __DIR__.'/../../../main/inc/global.inc.php';
|
||||
|
||||
api_protect_admin_script();
|
||||
|
||||
$action = $_GET['what'] ?? '';
|
||||
define('CHAMILO_INTERNAL', true);
|
||||
|
||||
$plugin = VChamiloPlugin::create();
|
||||
$thisUrl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
|
||||
|
||||
if ($action) {
|
||||
require_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/syncparams.controller.php';
|
||||
}
|
||||
|
||||
$settings = api_get_settings();
|
||||
|
||||
$table = new HTML_Table(['class' => 'table']);
|
||||
$column = 0;
|
||||
$row = 0;
|
||||
$headers = [
|
||||
'',
|
||||
$plugin->get_lang('variable').' ['.$plugin->get_lang('subkey').']',
|
||||
$plugin->get_lang('category'),
|
||||
$plugin->get_lang('accessurl'),
|
||||
$plugin->get_lang('value'),
|
||||
'',
|
||||
];
|
||||
$attrs = ['center' => 'left'];
|
||||
$table->addRow($headers, $attrs, 'th');
|
||||
|
||||
foreach ($settings as $param) {
|
||||
if ($param['subkey'] == 'vchamilo') {
|
||||
continue;
|
||||
}
|
||||
$check = '';
|
||||
$attrs = ['center' => 'left'];
|
||||
$syncButton = '
|
||||
<input class="btn btn-default" type="button" name="syncthis"
|
||||
value="'.$plugin->get_lang('syncthis').'" onclick="ajax_sync_setting(\''.$param['id'].'\')" />
|
||||
<span id="res_'.$param['id'].'"></span>';
|
||||
$data = [
|
||||
$check,
|
||||
isset($param['subkey']) && !empty($param['subkey']) ? $param['variable'].' ['.$param['subkey'].']' : $param['variable'],
|
||||
$param['category'],
|
||||
$param['access_url'],
|
||||
'<input type="text" disabled name="value_'.$param['id'].'"
|
||||
value="'.htmlspecialchars($param['selected_value'], ENT_COMPAT, 'UTF-8').'" />'.
|
||||
'<br />Master value: '.$param['selected_value'],
|
||||
$syncButton,
|
||||
];
|
||||
$row = $table->addRow($data, $attrs, 'td');
|
||||
$table->setRowAttributes($row, ['id' => 'row_'.$param['id']], true);
|
||||
}
|
||||
|
||||
$content = '<form name="settingsform" action="'.$thisUrl.'">';
|
||||
$content .= '<input type="hidden" name="what" value="" />';
|
||||
$content .= $table->toHtml();
|
||||
$content .= '</form>';
|
||||
|
||||
Display::addFlash(Display::return_message($plugin->get_lang('Sync your master settings to all instances.')));
|
||||
|
||||
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
|
||||
$htmlHeadXtra[] = "<script>
|
||||
function ajax_sync_setting(settingid) {
|
||||
var webUrl = '".api_get_path(WEB_PATH)."';
|
||||
var spare = $('#row_'+settingid).html();
|
||||
var formobj = document.forms['settingsform'];
|
||||
var url = webUrl + 'plugin/vchamilo/ajax/service.php?what=syncthis&settingid='+settingid+'&value='+encodeURIComponent(formobj.elements['value_'+settingid].value);
|
||||
$('#row_'+settingid).html('<td colspan=\"7\"><img src=\"'+webUrl+'plugin/vchamilo/pix/ajax_waiter.gif\" /></td>');
|
||||
$.get(url, function (data) {
|
||||
$('#row_'+settingid).html(spare);
|
||||
$('#res_'+settingid).html(data);
|
||||
});
|
||||
}
|
||||
</script>";
|
||||
|
||||
$tpl = new Template($plugin->get_lang('SyncSettings'), true, true, false, true, false);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
65
plugin/vchamilo/views/upgrade.php
Normal file
65
plugin/vchamilo/views/upgrade.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/* For licensing terms, see /license.txt */
|
||||
|
||||
$cidReset = true;
|
||||
|
||||
require_once __DIR__.'/../../../main/inc/global.inc.php';
|
||||
|
||||
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
|
||||
|
||||
// Security
|
||||
api_protect_admin_script();
|
||||
Virtual::checkSettings();
|
||||
|
||||
$plugin = VChamiloPlugin::create();
|
||||
|
||||
$id = isset($_REQUEST['vid']) ? (int) $_REQUEST['vid'] : 0;
|
||||
|
||||
$instance = Virtual::getInstance($id);
|
||||
$canBeUpgraded = Virtual::canBeUpgraded($instance);
|
||||
|
||||
$form = new FormValidator('upgrade', 'post', api_get_self().'?vid='.$id);
|
||||
// Database host.
|
||||
$form->addHeader(get_lang('Upgrade'));
|
||||
|
||||
$form->addText('root_web', $plugin->get_lang('rootweb'));
|
||||
$form->addText('db_host', $plugin->get_lang('dbhost'));
|
||||
$form->addText('db_user', $plugin->get_lang('dbuser'));
|
||||
$form->addText('main_database', [$plugin->get_lang('maindatabase')]);
|
||||
|
||||
$form->setDefaults((array) $instance);
|
||||
if ($canBeUpgraded) {
|
||||
$form->addLabel(get_lang('From'), $canBeUpgraded);
|
||||
$form->addLabel(get_lang('To'), api_get_setting('chamilo_database_version'));
|
||||
$form->addButtonSave(get_lang('Upgrade'));
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('NothingToUpgrade')));
|
||||
}
|
||||
|
||||
$form->freeze();
|
||||
$content = $form->returnForm();
|
||||
|
||||
if ($form->validate() && $canBeUpgraded) {
|
||||
$values = $form->getSubmitValues();
|
||||
|
||||
require_once api_get_path(SYS_CODE_PATH).'install/install.lib.php';
|
||||
|
||||
$manager = Virtual::getConnectionFromInstance($instance, true);
|
||||
if ($manager) {
|
||||
ob_start();
|
||||
$result = migrateSwitch($canBeUpgraded, $manager, false);
|
||||
$data = ob_get_clean();
|
||||
if ($result) {
|
||||
Display::addFlash(Display::return_message(get_lang('Upgraded')));
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('Error')));
|
||||
}
|
||||
$content = $data;
|
||||
} else {
|
||||
Display::addFlash(Display::return_message(get_lang('Error')));
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = new Template(get_lang('Upgrade'), true, true, false, true, false);
|
||||
$tpl->assign('content', $content);
|
||||
$tpl->display_one_col_template();
|
||||
Reference in New Issue
Block a user