mirror of
https://github.com/Combodo/iTop.git
synced 2026-04-23 10:38:45 +02:00
Fix files using CrLf, convert them to Lf to have the whole repo using Lf
Warn your git config (core.autocrlf = input or true)
This commit is contained in:
@@ -1,208 +1,208 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Does load data from XML files (currently used in the setup only)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* This page is called to perform "asynchronously" the setup actions
|
||||
* parameters
|
||||
* 'operation': one of 'compile_data_model', 'update_db_schema', 'after_db_creation', 'file'
|
||||
*
|
||||
* if 'operation' == 'update_db_schema':
|
||||
* 'mode': install | upgrade
|
||||
*
|
||||
* if 'operation' == 'after_db_creation':
|
||||
* 'mode': install | upgrade
|
||||
*
|
||||
* if 'operation' == 'file':
|
||||
* 'file': string Name of the file to load
|
||||
* 'session_status': string 'start', 'continue' or 'end'
|
||||
* 'percent': integer 0..100 the percentage of completion once the file has been loaded
|
||||
*/
|
||||
define('SAFE_MINIMUM_MEMORY', 64*1024*1024);
|
||||
require_once('../approot.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
|
||||
ini_set('max_execution_time', max(3600, ini_get('max_execution_time'))); // Under Windows SQL/backup operations are part of the timeout and require extra time
|
||||
date_default_timezone_set('Europe/Paris'); // Just to avoid a warning if the timezone is not set in php.ini
|
||||
|
||||
$sMemoryLimit = trim(ini_get('memory_limit'));
|
||||
if (empty($sMemoryLimit))
|
||||
{
|
||||
// On some PHP installations, memory_limit does not exist as a PHP setting!
|
||||
// (encountered on a 5.2.0 under Windows)
|
||||
// In that case, ini_set will not work, let's keep track of this and proceed with the data load
|
||||
SetupPage::log_info("No memory limit has been defined in this instance of PHP");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check that the limit will allow us to load the data
|
||||
//
|
||||
$iMemoryLimit = utils::ConvertToBytes($sMemoryLimit);
|
||||
if ($iMemoryLimit < SAFE_MINIMUM_MEMORY)
|
||||
{
|
||||
if (ini_set('memory_limit', SAFE_MINIMUM_MEMORY) === FALSE)
|
||||
{
|
||||
SetupPage::log_error("memory_limit is too small: $iMemoryLimit and can not be increased by the script itself.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_info("memory_limit increased from $iMemoryLimit to ".SAFE_MINIMUM_MEMORY.".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
define('PHP_FATAL_ERROR_TAG', 'phpfatalerror');
|
||||
|
||||
|
||||
/**
|
||||
* Handler for register_shutdown_function, to catch PHP errors
|
||||
*/
|
||||
function ShutdownCallback()
|
||||
{
|
||||
$error = error_get_last();
|
||||
$bIsErrorToReport = (($error !== null) && ($error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR)));
|
||||
if (!$bIsErrorToReport)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$errno = $error["type"];
|
||||
$errfile = $error["file"];
|
||||
$errline = $error["line"];
|
||||
$errstr = $error["message"];
|
||||
$sLogMessage = "PHP error occured : msg=$errstr, no=$errno, file=$errfile, line=$errline";
|
||||
SetupPage::log_error("Setup error: $sLogMessage");
|
||||
echo '<'.PHP_FATAL_ERROR_TAG.'>'.$sLogMessage.'</'.PHP_FATAL_ERROR_TAG.'>';
|
||||
}
|
||||
|
||||
|
||||
function FatalErrorCatcher($sOutput)
|
||||
{
|
||||
if (preg_match('|<'.PHP_FATAL_ERROR_TAG.'>.*</'.PHP_FATAL_ERROR_TAG.'>|s', $sOutput, $aMatches))
|
||||
{
|
||||
header("HTTP/1.0 500 Internal server error.");
|
||||
$errors = '';
|
||||
foreach ($aMatches as $sMatch)
|
||||
{
|
||||
$errors .= strip_tags($sMatch)."\n";
|
||||
}
|
||||
$sOutput = "$errors\n";
|
||||
// Logging to a file does not work if the whole memory is exhausted...
|
||||
//SetupPage::log_error("Fatal error - in $__FILE__ , $errors");
|
||||
}
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
//Define some bogus, invalid HTML tags that no sane
|
||||
//person would ever put in an actual document and tell
|
||||
//PHP to delimit fatal error warnings with them.
|
||||
ini_set('error_prepend_string', '<'.PHP_FATAL_ERROR_TAG.'>');
|
||||
ini_set('error_append_string', '</'.PHP_FATAL_ERROR_TAG.'>');
|
||||
|
||||
// callback on errors to log
|
||||
register_shutdown_function('ShutdownCallback');
|
||||
// Starts the capture of the ouput, and sets a filter to capture the fatal errors.
|
||||
ob_start('FatalErrorCatcher'); // Start capturing the output, and pass it through the fatal error catcher
|
||||
|
||||
require_once(APPROOT.'/core/config.class.inc.php');
|
||||
require_once(APPROOT.'/core/log.class.inc.php');
|
||||
require_once(APPROOT.'/core/kpi.class.inc.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
require_once('./xmldataloader.class.inc.php');
|
||||
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
|
||||
|
||||
|
||||
// Never cache this page
|
||||
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
||||
header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
$sOperation = Utils::ReadParam('operation', '');
|
||||
try
|
||||
{
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'async_action':
|
||||
ini_set('max_execution_time', max(240, ini_get('max_execution_time')));
|
||||
// While running the setup it is desirable to see any error that may happen
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
|
||||
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
|
||||
|
||||
$sClass = utils::ReadParam('step_class', '');
|
||||
$sState = utils::ReadParam('step_state', '');
|
||||
$sActionCode = utils::ReadParam('code', '');
|
||||
$aParams = utils::ReadParam('params', array(), false, 'raw_data');
|
||||
$oPage = new ajax_page('');
|
||||
$oDummyController = new WizardController('');
|
||||
if (is_subclass_of($sClass, 'WizardStep'))
|
||||
{
|
||||
/** @var WizardStep $oStep */
|
||||
$oStep = new $sClass($oDummyController, $sState);
|
||||
$sConfigFile = utils::GetConfigFilePath();
|
||||
if (file_exists($sConfigFile) && !is_writable($sConfigFile) && $oStep->RequiresWritableConfig())
|
||||
{
|
||||
$oPage->error("<b>Error:</b> the configuration file '".$sConfigFile."' already exists and cannot be overwritten.");
|
||||
$oPage->p("The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '<b>".realpath($sConfigFile)."</b>' can be modified by the web server.");
|
||||
$oPage->output();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStep->AsyncAction($oPage, $sActionCode, $aParams);
|
||||
}
|
||||
}
|
||||
$oPage->output();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw(new Exception("Error unsupported operation '$sOperation'"));
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
header("HTTP/1.0 500 Internal server error.");
|
||||
echo "<p>An error happened while processing the installation:</p>\n";
|
||||
echo '<p>'.$e."</p>\n";
|
||||
SetupPage::log_error("An error happened while processing the installation: ".$e);
|
||||
}
|
||||
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
if ($sOperation == 'file')
|
||||
{
|
||||
SetupPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
}
|
||||
<?php
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Does load data from XML files (currently used in the setup only)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2018 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* This page is called to perform "asynchronously" the setup actions
|
||||
* parameters
|
||||
* 'operation': one of 'compile_data_model', 'update_db_schema', 'after_db_creation', 'file'
|
||||
*
|
||||
* if 'operation' == 'update_db_schema':
|
||||
* 'mode': install | upgrade
|
||||
*
|
||||
* if 'operation' == 'after_db_creation':
|
||||
* 'mode': install | upgrade
|
||||
*
|
||||
* if 'operation' == 'file':
|
||||
* 'file': string Name of the file to load
|
||||
* 'session_status': string 'start', 'continue' or 'end'
|
||||
* 'percent': integer 0..100 the percentage of completion once the file has been loaded
|
||||
*/
|
||||
define('SAFE_MINIMUM_MEMORY', 64*1024*1024);
|
||||
require_once('../approot.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
|
||||
ini_set('max_execution_time', max(3600, ini_get('max_execution_time'))); // Under Windows SQL/backup operations are part of the timeout and require extra time
|
||||
date_default_timezone_set('Europe/Paris'); // Just to avoid a warning if the timezone is not set in php.ini
|
||||
|
||||
$sMemoryLimit = trim(ini_get('memory_limit'));
|
||||
if (empty($sMemoryLimit))
|
||||
{
|
||||
// On some PHP installations, memory_limit does not exist as a PHP setting!
|
||||
// (encountered on a 5.2.0 under Windows)
|
||||
// In that case, ini_set will not work, let's keep track of this and proceed with the data load
|
||||
SetupPage::log_info("No memory limit has been defined in this instance of PHP");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check that the limit will allow us to load the data
|
||||
//
|
||||
$iMemoryLimit = utils::ConvertToBytes($sMemoryLimit);
|
||||
if ($iMemoryLimit < SAFE_MINIMUM_MEMORY)
|
||||
{
|
||||
if (ini_set('memory_limit', SAFE_MINIMUM_MEMORY) === FALSE)
|
||||
{
|
||||
SetupPage::log_error("memory_limit is too small: $iMemoryLimit and can not be increased by the script itself.");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_info("memory_limit increased from $iMemoryLimit to ".SAFE_MINIMUM_MEMORY.".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
define('PHP_FATAL_ERROR_TAG', 'phpfatalerror');
|
||||
|
||||
|
||||
/**
|
||||
* Handler for register_shutdown_function, to catch PHP errors
|
||||
*/
|
||||
function ShutdownCallback()
|
||||
{
|
||||
$error = error_get_last();
|
||||
$bIsErrorToReport = (($error !== null) && ($error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR)));
|
||||
if (!$bIsErrorToReport)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$errno = $error["type"];
|
||||
$errfile = $error["file"];
|
||||
$errline = $error["line"];
|
||||
$errstr = $error["message"];
|
||||
$sLogMessage = "PHP error occured : msg=$errstr, no=$errno, file=$errfile, line=$errline";
|
||||
SetupPage::log_error("Setup error: $sLogMessage");
|
||||
echo '<'.PHP_FATAL_ERROR_TAG.'>'.$sLogMessage.'</'.PHP_FATAL_ERROR_TAG.'>';
|
||||
}
|
||||
|
||||
|
||||
function FatalErrorCatcher($sOutput)
|
||||
{
|
||||
if (preg_match('|<'.PHP_FATAL_ERROR_TAG.'>.*</'.PHP_FATAL_ERROR_TAG.'>|s', $sOutput, $aMatches))
|
||||
{
|
||||
header("HTTP/1.0 500 Internal server error.");
|
||||
$errors = '';
|
||||
foreach ($aMatches as $sMatch)
|
||||
{
|
||||
$errors .= strip_tags($sMatch)."\n";
|
||||
}
|
||||
$sOutput = "$errors\n";
|
||||
// Logging to a file does not work if the whole memory is exhausted...
|
||||
//SetupPage::log_error("Fatal error - in $__FILE__ , $errors");
|
||||
}
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
//Define some bogus, invalid HTML tags that no sane
|
||||
//person would ever put in an actual document and tell
|
||||
//PHP to delimit fatal error warnings with them.
|
||||
ini_set('error_prepend_string', '<'.PHP_FATAL_ERROR_TAG.'>');
|
||||
ini_set('error_append_string', '</'.PHP_FATAL_ERROR_TAG.'>');
|
||||
|
||||
// callback on errors to log
|
||||
register_shutdown_function('ShutdownCallback');
|
||||
// Starts the capture of the ouput, and sets a filter to capture the fatal errors.
|
||||
ob_start('FatalErrorCatcher'); // Start capturing the output, and pass it through the fatal error catcher
|
||||
|
||||
require_once(APPROOT.'/core/config.class.inc.php');
|
||||
require_once(APPROOT.'/core/log.class.inc.php');
|
||||
require_once(APPROOT.'/core/kpi.class.inc.php');
|
||||
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
|
||||
require_once('./xmldataloader.class.inc.php');
|
||||
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
|
||||
|
||||
|
||||
// Never cache this page
|
||||
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
||||
header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
$sOperation = Utils::ReadParam('operation', '');
|
||||
try
|
||||
{
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'async_action':
|
||||
ini_set('max_execution_time', max(240, ini_get('max_execution_time')));
|
||||
// While running the setup it is desirable to see any error that may happen
|
||||
ini_set('display_errors', true);
|
||||
ini_set('display_startup_errors', true);
|
||||
|
||||
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
|
||||
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
|
||||
|
||||
$sClass = utils::ReadParam('step_class', '');
|
||||
$sState = utils::ReadParam('step_state', '');
|
||||
$sActionCode = utils::ReadParam('code', '');
|
||||
$aParams = utils::ReadParam('params', array(), false, 'raw_data');
|
||||
$oPage = new ajax_page('');
|
||||
$oDummyController = new WizardController('');
|
||||
if (is_subclass_of($sClass, 'WizardStep'))
|
||||
{
|
||||
/** @var WizardStep $oStep */
|
||||
$oStep = new $sClass($oDummyController, $sState);
|
||||
$sConfigFile = utils::GetConfigFilePath();
|
||||
if (file_exists($sConfigFile) && !is_writable($sConfigFile) && $oStep->RequiresWritableConfig())
|
||||
{
|
||||
$oPage->error("<b>Error:</b> the configuration file '".$sConfigFile."' already exists and cannot be overwritten.");
|
||||
$oPage->p("The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '<b>".realpath($sConfigFile)."</b>' can be modified by the web server.");
|
||||
$oPage->output();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStep->AsyncAction($oPage, $sActionCode, $aParams);
|
||||
}
|
||||
}
|
||||
$oPage->output();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw(new Exception("Error unsupported operation '$sOperation'"));
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
header("HTTP/1.0 500 Internal server error.");
|
||||
echo "<p>An error happened while processing the installation:</p>\n";
|
||||
echo '<p>'.$e."</p>\n";
|
||||
SetupPage::log_error("An error happened while processing the installation: ".$e);
|
||||
}
|
||||
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
if ($sOperation == 'file')
|
||||
{
|
||||
SetupPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,285 +1,285 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Emailing: helper for the admins to troubleshoot email issues
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Wizard to configure and initialize the iTop application
|
||||
*/
|
||||
require_once('../approot.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/email.class.inc.php');
|
||||
require_once('./setuppage.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
|
||||
|
||||
$sOperation = Utils::ReadParam('operation', 'step1');
|
||||
$oP = new SetupPage('iTop email test utility');
|
||||
|
||||
|
||||
/**
|
||||
* Helper to check server setting required to send an email
|
||||
*/
|
||||
function CheckEmailSetting($oP)
|
||||
{
|
||||
$bRet = true;
|
||||
|
||||
if (function_exists('php_ini_loaded_file')) // PHP >= 5.2.4
|
||||
{
|
||||
$sPhpIniFile = php_ini_loaded_file();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPhpIniFile = 'php.ini';
|
||||
}
|
||||
|
||||
$sTransport = MetaModel::GetConfig()->Get('email_transport');
|
||||
switch($sTransport)
|
||||
{
|
||||
case 'PHPMail':
|
||||
$oP->info("iTop is configured to use PHP's <a style=\"background:transparent;padding:0;color:#000;text-decoration:underline;\" href=\"http://www.php.net/manual/en/function.mail.php\" target=\"_blank\">mail</a> function to send emails.");
|
||||
$bIsWindows = (array_key_exists('WINDIR', $_SERVER) || array_key_exists('windir', $_SERVER));
|
||||
if ($bIsWindows)
|
||||
{
|
||||
$sSmtpServer = ini_get('SMTP');
|
||||
if (empty($sSmtpServer))
|
||||
{
|
||||
$oP->error("The SMTP server is not defined. Please add the 'SMTP' directive into $sPhpIniFile");
|
||||
$bRet = false;
|
||||
}
|
||||
else if (strcasecmp($sSmtpServer, 'localhost') == 0)
|
||||
{
|
||||
$oP->warning("Your SMTP server is configured to 'localhost'. You might want to set or change the 'SMTP' directive into $sPhpIniFile");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->info("Your SMTP server: <strong>$sSmtpServer</strong>. To change this value, modify the 'SMTP' directive into $sPhpIniFile");
|
||||
}
|
||||
|
||||
$iSmtpPort = (int) ini_get('smtp_port');
|
||||
if (empty($iSmtpPort))
|
||||
{
|
||||
$oP->info("The SMTP port is not defined. Please add the 'smtp_port' directive into $sPhpIniFile");
|
||||
$bRet = false;
|
||||
}
|
||||
else if ($iSmtpPort == 25)
|
||||
{
|
||||
$oP->info("Your SMTP port is configured to the default value: 25. You might want to set or change the 'smtp_port' directive into $sPhpIniFile");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->info("Your SMTP port is configured to $iSmtpPort. You might want to set or change the 'smtp_port' directive into $sPhpIniFile");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a windows system
|
||||
$sSendMail = ini_get('sendmail_path');
|
||||
if (empty($sSendMail))
|
||||
{
|
||||
$oP->error("The command to send mail is not defined. Please add the 'sendmail_path' directive into $sPhpIniFile. A recommended setting is <em>sendmail_path=sendmail -t -i</em>");
|
||||
$bRet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->info("The command to send mail is: <strong>$sSendMail</strong>. To change this value, modify the 'sendmail_path' directive into $sPhpIniFile");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SMTP':
|
||||
$oP->info("iTop is configured to use the <b>SMTP</b> transport.");
|
||||
$sHost = MetaModel::GetConfig()->Get('email_transport_smtp.host');
|
||||
$sPort = MetaModel::GetConfig()->Get('email_transport_smtp.port');
|
||||
$sEncryption = MetaModel::GetConfig()->Get('email_transport_smtp.encryption');
|
||||
$sDisplayEncryption = empty($sEncryption) ? '<em>no encryption</em> ' : $sEncryption;
|
||||
$sUserName = MetaModel::GetConfig()->Get('email_transport_smtp.username');
|
||||
$sDisplayUserName = empty($sUserName) ? '<em>no user</em> ' : $sUserName;
|
||||
$sPassword = MetaModel::GetConfig()->Get('email_transport_smtp.password');
|
||||
$sDisplayPassword = empty($sPassword) ? '<em>no password</em> ' : str_repeat('*', strlen($sPassword));
|
||||
$oP->info("SMTP configuration (from config-itop.php): host: $sHost, port: $sPort, user: $sDisplayUserName, password: $sDisplayPassword, encryption: $sDisplayEncryption.");
|
||||
if (($sHost == 'localhost') && ($sPort == '25') && ($sUserName == '') && ($sPassword == '') )
|
||||
{
|
||||
$oP->warning("The default settings may not be suitable for your environment. You may want to ajust these values by editing iTop's configuration file (".APPROOT."conf/production/config-itop.php).");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Null':
|
||||
$oP->warning("iTop is configured to use the <b>Null</b> transport: emails sending will have no effect.");
|
||||
$bRet = false;
|
||||
break;
|
||||
|
||||
case 'LogFile':
|
||||
$oP->warning("iTop is configured to use the <b>LogFile</b> transport: emails will <em>not</em> be sent but logged to the file: '".APPROOT."/log/mail.log'.");
|
||||
$bRet = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
$oP->error("Unknown transport '$sTransport' configured.");
|
||||
$bRet = false;
|
||||
}
|
||||
if ($bRet)
|
||||
{
|
||||
$oP->ok("PHP settings are ok to proceed with a test of the email");
|
||||
}
|
||||
$bConfigAsync = MetaModel::GetConfig()->Get('email_asynchronous');
|
||||
if ($bConfigAsync)
|
||||
{
|
||||
$oP->warning("iTop is configured to send emails <em>asynchronously</em>. Make sure that cron.php is scheduled to run in the background, otherwise regular emails will <em>not</em> be sent. For the purpose of this test, the email will be sent <em>synchronously</em>.");
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the form for the first step of the test wizard
|
||||
* which consists in a basic check of the configuration and display of a form for testing
|
||||
*/
|
||||
function DisplayStep1(SetupPage $oP)
|
||||
{
|
||||
$sNextOperation = 'step2';
|
||||
$oP->add("<h1>iTop email test</h1>\n");
|
||||
$oP->add("<h2>Checking prerequisites</h2>\n");
|
||||
if (CheckEmailSetting($oP))
|
||||
{
|
||||
$sRedStar = '<span class="hilite">*</span>';
|
||||
$oP->add("<h2>Try to send an email</h2>\n");
|
||||
$oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Sending an email...', 10)\">\n");
|
||||
// Form goes here
|
||||
$oP->add("<fieldset><legend>Test recipient</legend>\n");
|
||||
$aForm = array();
|
||||
$aForm[] = array(
|
||||
'label' => "To$sRedStar:",
|
||||
'input' => "<input id=\"to\" type=\"text\" name=\"to\" value=\"\">",
|
||||
'help' => ' email address (e.g. john.foo@worldcompany.com)',
|
||||
);
|
||||
$aForm[] = array(
|
||||
'label' => "From:",
|
||||
'input' => "<input id=\"from\" type=\"text\" name=\"from\" value=\"\">",
|
||||
'help' => ' defaults to the configuration param "email_default_sender_address" or "To" field.',
|
||||
);
|
||||
$oP->form($aForm);
|
||||
$oP->add("</fieldset>\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
|
||||
$oP->add("<div>\n");
|
||||
$oP->add("<button style=\"float:left\" type=\"button\" onclick=\"window.location.reload()\">Refresh</button>\n");
|
||||
$oP->add("<button style=\"float:right\" type=\"submit\">Next >></button>\n");
|
||||
$oP->add("<div style=\"clear:both;\"></div>\n");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("</form>\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the form for the second step of the configuration wizard
|
||||
* which consists in sending an email, which maybe a problem under Windows
|
||||
*/
|
||||
function DisplayStep2(SetupPage $oP, $sFrom, $sTo)
|
||||
{
|
||||
//$sNextOperation = 'step3';
|
||||
$oP->add("<h1>iTop configuration wizard</h1>\n");
|
||||
$oP->add("<h2>Step 2: send an email</h2>\n");
|
||||
$oP->add("<p>Sending an email to '".htmlentities($sTo, ENT_QUOTES, 'utf-8')."'... (From: '".htmlentities($sFrom, ENT_QUOTES, 'utf-8')."')</p>\n");
|
||||
$oP->add("<form method=\"post\">\n");
|
||||
|
||||
$oEmail = new Email();
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetSubject("Test iTop");
|
||||
$oEmail->SetBody("<p>Hello,</p><p>The email function is now working fine.</p><p>You may now be able to use the notification function.</p><p>iTop</p>");
|
||||
$iRes = $oEmail->Send($aIssues, true /* force synchronous exec */);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
$sTransport = MetaModel::GetConfig()->Get('email_transport');
|
||||
if ($sTransport == 'LogFile')
|
||||
{
|
||||
$oP->ok("The email has been logged into the file ".APPROOT."/log/mail.log.");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->ok("The email has been sent, check your inbox for the incoming mail...");
|
||||
}
|
||||
$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
|
||||
break;
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
$oP->ok("Email queued");
|
||||
$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
|
||||
break;
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
foreach ($aIssues as $sError)
|
||||
{
|
||||
$oP->error(htmlentities($sError, ENT_QUOTES, 'utf-8'));
|
||||
}
|
||||
$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
|
||||
// #@# Init default timezone -> do not get a notice... to be improved !!!
|
||||
// duplicated from 'attributedef.class.inc.php', needed here because mail() does
|
||||
// generate a notice
|
||||
date_default_timezone_set('Europe/Paris');
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'step1':
|
||||
DisplayStep1($oP);
|
||||
break;
|
||||
|
||||
case 'step2':
|
||||
$oP->no_cache();
|
||||
$sTo = Utils::ReadParam('to', '', false, 'raw_data');
|
||||
$sFrom = Utils::ReadParam('from', '', false, 'raw_data');
|
||||
DisplayStep2($oP, $sFrom, $sTo);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oP->error("Error: unsupported operation '$sOperation'");
|
||||
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oP->error("Error: '".htmlentities($e->getMessage(), ENT_QUOTES, 'utf-8')."'");
|
||||
}
|
||||
catch(CoreException $e)
|
||||
{
|
||||
$oP->error("Error: '".$e->getHtmlDesc()."'");
|
||||
}
|
||||
$oP->output();
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Emailing: helper for the admins to troubleshoot email issues
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Wizard to configure and initialize the iTop application
|
||||
*/
|
||||
require_once('../approot.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/core/email.class.inc.php');
|
||||
require_once('./setuppage.class.inc.php');
|
||||
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
|
||||
|
||||
$sOperation = Utils::ReadParam('operation', 'step1');
|
||||
$oP = new SetupPage('iTop email test utility');
|
||||
|
||||
|
||||
/**
|
||||
* Helper to check server setting required to send an email
|
||||
*/
|
||||
function CheckEmailSetting($oP)
|
||||
{
|
||||
$bRet = true;
|
||||
|
||||
if (function_exists('php_ini_loaded_file')) // PHP >= 5.2.4
|
||||
{
|
||||
$sPhpIniFile = php_ini_loaded_file();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPhpIniFile = 'php.ini';
|
||||
}
|
||||
|
||||
$sTransport = MetaModel::GetConfig()->Get('email_transport');
|
||||
switch($sTransport)
|
||||
{
|
||||
case 'PHPMail':
|
||||
$oP->info("iTop is configured to use PHP's <a style=\"background:transparent;padding:0;color:#000;text-decoration:underline;\" href=\"http://www.php.net/manual/en/function.mail.php\" target=\"_blank\">mail</a> function to send emails.");
|
||||
$bIsWindows = (array_key_exists('WINDIR', $_SERVER) || array_key_exists('windir', $_SERVER));
|
||||
if ($bIsWindows)
|
||||
{
|
||||
$sSmtpServer = ini_get('SMTP');
|
||||
if (empty($sSmtpServer))
|
||||
{
|
||||
$oP->error("The SMTP server is not defined. Please add the 'SMTP' directive into $sPhpIniFile");
|
||||
$bRet = false;
|
||||
}
|
||||
else if (strcasecmp($sSmtpServer, 'localhost') == 0)
|
||||
{
|
||||
$oP->warning("Your SMTP server is configured to 'localhost'. You might want to set or change the 'SMTP' directive into $sPhpIniFile");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->info("Your SMTP server: <strong>$sSmtpServer</strong>. To change this value, modify the 'SMTP' directive into $sPhpIniFile");
|
||||
}
|
||||
|
||||
$iSmtpPort = (int) ini_get('smtp_port');
|
||||
if (empty($iSmtpPort))
|
||||
{
|
||||
$oP->info("The SMTP port is not defined. Please add the 'smtp_port' directive into $sPhpIniFile");
|
||||
$bRet = false;
|
||||
}
|
||||
else if ($iSmtpPort == 25)
|
||||
{
|
||||
$oP->info("Your SMTP port is configured to the default value: 25. You might want to set or change the 'smtp_port' directive into $sPhpIniFile");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->info("Your SMTP port is configured to $iSmtpPort. You might want to set or change the 'smtp_port' directive into $sPhpIniFile");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a windows system
|
||||
$sSendMail = ini_get('sendmail_path');
|
||||
if (empty($sSendMail))
|
||||
{
|
||||
$oP->error("The command to send mail is not defined. Please add the 'sendmail_path' directive into $sPhpIniFile. A recommended setting is <em>sendmail_path=sendmail -t -i</em>");
|
||||
$bRet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->info("The command to send mail is: <strong>$sSendMail</strong>. To change this value, modify the 'sendmail_path' directive into $sPhpIniFile");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SMTP':
|
||||
$oP->info("iTop is configured to use the <b>SMTP</b> transport.");
|
||||
$sHost = MetaModel::GetConfig()->Get('email_transport_smtp.host');
|
||||
$sPort = MetaModel::GetConfig()->Get('email_transport_smtp.port');
|
||||
$sEncryption = MetaModel::GetConfig()->Get('email_transport_smtp.encryption');
|
||||
$sDisplayEncryption = empty($sEncryption) ? '<em>no encryption</em> ' : $sEncryption;
|
||||
$sUserName = MetaModel::GetConfig()->Get('email_transport_smtp.username');
|
||||
$sDisplayUserName = empty($sUserName) ? '<em>no user</em> ' : $sUserName;
|
||||
$sPassword = MetaModel::GetConfig()->Get('email_transport_smtp.password');
|
||||
$sDisplayPassword = empty($sPassword) ? '<em>no password</em> ' : str_repeat('*', strlen($sPassword));
|
||||
$oP->info("SMTP configuration (from config-itop.php): host: $sHost, port: $sPort, user: $sDisplayUserName, password: $sDisplayPassword, encryption: $sDisplayEncryption.");
|
||||
if (($sHost == 'localhost') && ($sPort == '25') && ($sUserName == '') && ($sPassword == '') )
|
||||
{
|
||||
$oP->warning("The default settings may not be suitable for your environment. You may want to ajust these values by editing iTop's configuration file (".APPROOT."conf/production/config-itop.php).");
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Null':
|
||||
$oP->warning("iTop is configured to use the <b>Null</b> transport: emails sending will have no effect.");
|
||||
$bRet = false;
|
||||
break;
|
||||
|
||||
case 'LogFile':
|
||||
$oP->warning("iTop is configured to use the <b>LogFile</b> transport: emails will <em>not</em> be sent but logged to the file: '".APPROOT."/log/mail.log'.");
|
||||
$bRet = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
$oP->error("Unknown transport '$sTransport' configured.");
|
||||
$bRet = false;
|
||||
}
|
||||
if ($bRet)
|
||||
{
|
||||
$oP->ok("PHP settings are ok to proceed with a test of the email");
|
||||
}
|
||||
$bConfigAsync = MetaModel::GetConfig()->Get('email_asynchronous');
|
||||
if ($bConfigAsync)
|
||||
{
|
||||
$oP->warning("iTop is configured to send emails <em>asynchronously</em>. Make sure that cron.php is scheduled to run in the background, otherwise regular emails will <em>not</em> be sent. For the purpose of this test, the email will be sent <em>synchronously</em>.");
|
||||
}
|
||||
|
||||
return $bRet;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the form for the first step of the test wizard
|
||||
* which consists in a basic check of the configuration and display of a form for testing
|
||||
*/
|
||||
function DisplayStep1(SetupPage $oP)
|
||||
{
|
||||
$sNextOperation = 'step2';
|
||||
$oP->add("<h1>iTop email test</h1>\n");
|
||||
$oP->add("<h2>Checking prerequisites</h2>\n");
|
||||
if (CheckEmailSetting($oP))
|
||||
{
|
||||
$sRedStar = '<span class="hilite">*</span>';
|
||||
$oP->add("<h2>Try to send an email</h2>\n");
|
||||
$oP->add("<form method=\"post\" onSubmit=\"return DoSubmit('Sending an email...', 10)\">\n");
|
||||
// Form goes here
|
||||
$oP->add("<fieldset><legend>Test recipient</legend>\n");
|
||||
$aForm = array();
|
||||
$aForm[] = array(
|
||||
'label' => "To$sRedStar:",
|
||||
'input' => "<input id=\"to\" type=\"text\" name=\"to\" value=\"\">",
|
||||
'help' => ' email address (e.g. john.foo@worldcompany.com)',
|
||||
);
|
||||
$aForm[] = array(
|
||||
'label' => "From:",
|
||||
'input' => "<input id=\"from\" type=\"text\" name=\"from\" value=\"\">",
|
||||
'help' => ' defaults to the configuration param "email_default_sender_address" or "To" field.',
|
||||
);
|
||||
$oP->form($aForm);
|
||||
$oP->add("</fieldset>\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"$sNextOperation\">\n");
|
||||
$oP->add("<div>\n");
|
||||
$oP->add("<button style=\"float:left\" type=\"button\" onclick=\"window.location.reload()\">Refresh</button>\n");
|
||||
$oP->add("<button style=\"float:right\" type=\"submit\">Next >></button>\n");
|
||||
$oP->add("<div style=\"clear:both;\"></div>\n");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("</form>\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the form for the second step of the configuration wizard
|
||||
* which consists in sending an email, which maybe a problem under Windows
|
||||
*/
|
||||
function DisplayStep2(SetupPage $oP, $sFrom, $sTo)
|
||||
{
|
||||
//$sNextOperation = 'step3';
|
||||
$oP->add("<h1>iTop configuration wizard</h1>\n");
|
||||
$oP->add("<h2>Step 2: send an email</h2>\n");
|
||||
$oP->add("<p>Sending an email to '".htmlentities($sTo, ENT_QUOTES, 'utf-8')."'... (From: '".htmlentities($sFrom, ENT_QUOTES, 'utf-8')."')</p>\n");
|
||||
$oP->add("<form method=\"post\">\n");
|
||||
|
||||
$oEmail = new Email();
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetSubject("Test iTop");
|
||||
$oEmail->SetBody("<p>Hello,</p><p>The email function is now working fine.</p><p>You may now be able to use the notification function.</p><p>iTop</p>");
|
||||
$iRes = $oEmail->Send($aIssues, true /* force synchronous exec */);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
$sTransport = MetaModel::GetConfig()->Get('email_transport');
|
||||
if ($sTransport == 'LogFile')
|
||||
{
|
||||
$oP->ok("The email has been logged into the file ".APPROOT."/log/mail.log.");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->ok("The email has been sent, check your inbox for the incoming mail...");
|
||||
}
|
||||
$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
|
||||
break;
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
$oP->ok("Email queued");
|
||||
$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
|
||||
break;
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
foreach ($aIssues as $sError)
|
||||
{
|
||||
$oP->error(htmlentities($sError, ENT_QUOTES, 'utf-8'));
|
||||
}
|
||||
$oP->add("<button onClick=\"window.history.back();\"><< Back</button>\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
|
||||
// #@# Init default timezone -> do not get a notice... to be improved !!!
|
||||
// duplicated from 'attributedef.class.inc.php', needed here because mail() does
|
||||
// generate a notice
|
||||
date_default_timezone_set('Europe/Paris');
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
switch($sOperation)
|
||||
{
|
||||
case 'step1':
|
||||
DisplayStep1($oP);
|
||||
break;
|
||||
|
||||
case 'step2':
|
||||
$oP->no_cache();
|
||||
$sTo = Utils::ReadParam('to', '', false, 'raw_data');
|
||||
$sFrom = Utils::ReadParam('from', '', false, 'raw_data');
|
||||
DisplayStep2($oP, $sFrom, $sTo);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oP->error("Error: unsupported operation '$sOperation'");
|
||||
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oP->error("Error: '".htmlentities($e->getMessage(), ENT_QUOTES, 'utf-8')."'");
|
||||
}
|
||||
catch(CoreException $e)
|
||||
{
|
||||
$oP->error("Error: '".$e->getHtmlDesc()."'");
|
||||
}
|
||||
$oP->output();
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,102 +1,102 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class ModuleInstallation to record the installed modules
|
||||
* Log of module installations
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ModuleInstallation extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_module_install",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("installed", array("allowed_values"=>null, "sql"=>"installed", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("comment", array("allowed_values"=>null, "sql"=>"comment", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("parent_id", array("targetclass"=>"ModuleInstallation", "jointype"=> "", "allowed_values"=>null, "sql"=>"parent_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'version', 'installed', 'comment', 'parent_id')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name', 'version', 'installed', 'parent_id')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persistent class ExtensionInstallation to record the installed extensions
|
||||
* Log of extensions installations
|
||||
*
|
||||
* @copyright Copyright (C) 2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ExtensionInstallation extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_extension_install",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("code", array("allowed_values"=>null, "sql"=>"code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("label", array("allowed_values"=>null, "sql"=>"label", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source", array("allowed_values"=>null, "sql"=>"source", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("installed", array("allowed_values"=>null, "sql"=>"installed", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('standard_search', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed in the search form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Persistent class ModuleInstallation to record the installed modules
|
||||
* Log of module installations
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ModuleInstallation extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_module_install",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("installed", array("allowed_values"=>null, "sql"=>"installed", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("comment", array("allowed_values"=>null, "sql"=>"comment", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("parent_id", array("targetclass"=>"ModuleInstallation", "jointype"=> "", "allowed_values"=>null, "sql"=>"parent_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'version', 'installed', 'comment', 'parent_id')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('name', 'version', 'installed', 'parent_id')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persistent class ExtensionInstallation to record the installed extensions
|
||||
* Log of extensions installations
|
||||
*
|
||||
* @copyright Copyright (C) 2017 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ExtensionInstallation extends cmdbAbstractObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core,view_in_gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_extension_install",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeString("code", array("allowed_values"=>null, "sql"=>"code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("label", array("allowed_values"=>null, "sql"=>"label", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("source", array("allowed_values"=>null, "sql"=>"source", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("installed", array("allowed_values"=>null, "sql"=>"installed", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('standard_search', array('code', 'label', 'version', 'installed', 'source')); // Attributes to be displayed in the search form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,227 +1,227 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
require_once(APPROOT.'setup/setuppage.class.inc.php');
|
||||
|
||||
/**
|
||||
* Class ModuleInstaller
|
||||
* Defines the API to implement module specific actions during the setup
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called at the end of the setup of the database (profiles and admin accounts created), but before the data load
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseSetup(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called at the end of the data load
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDataLoad(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to complete the renaming of a class
|
||||
* The renaming is made in the datamodel definition, but the name has to be changed in the DB as well
|
||||
* Must be called after DB update, i.e within an implementation of AfterDatabaseCreation()
|
||||
*
|
||||
* @param string $sFrom Original name (already INVALID in the current datamodel)
|
||||
* @param string $sTo New name (valid in the current datamodel)
|
||||
* @return void
|
||||
*/
|
||||
public static function RenameClassInDB($sFrom, $sTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!MetaModel::IsStandaloneClass($sTo))
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass($sTo);
|
||||
$sTableName = MetaModel::DBGetTable($sRootClass);
|
||||
$sFinalClassCol = MetaModel::DBGetClassField($sRootClass);
|
||||
$sRepair = "UPDATE `$sTableName` SET `$sFinalClassCol` = '$sTo' WHERE `$sFinalClassCol` = BINARY '$sFrom'";
|
||||
CMDBSource::Query($sRepair);
|
||||
$iAffectedRows = CMDBSource::AffectedRows();
|
||||
SetupPage::log_info("Renaming class in DB - final class from '$sFrom' to '$sTo': $iAffectedRows rows affected");
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupPage::log_warning("Failed to rename class in DB - final class from '$sFrom' to '$sTo'. Reason: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to modify an enum value
|
||||
* The change is made in the datamodel definition, but the value has to be changed in the DB as well
|
||||
* Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation()
|
||||
* This helper does change ONE value at a time
|
||||
*
|
||||
* @param string $sClass A valid class name
|
||||
* @param string $sAttCode The enum attribute code
|
||||
* @param string $sFrom Original value (already INVALID in the current datamodel)
|
||||
* @param string $sTo New value (valid in the current datamodel)
|
||||
* @return void
|
||||
*/
|
||||
public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - from '$sFrom' to '$sTo' failed. Reason '$sAttCode' is not a valid attribute of the class '$sClass'.");
|
||||
return;
|
||||
}
|
||||
$sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode);
|
||||
$sTableName = MetaModel::DBGetTable($sOriginClass);
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeEnum)
|
||||
{
|
||||
$oValDef = $oAttDef->GetValuesDef();
|
||||
if ($oValDef)
|
||||
{
|
||||
$aNewValues = array_keys($oValDef->GetValues(array(), ""));
|
||||
if (in_array($sTo, $aNewValues))
|
||||
{
|
||||
$sEnumCol = $oAttDef->Get("sql");
|
||||
$aFields = CMDBSource::QueryToArray("SHOW COLUMNS FROM `$sTableName` WHERE Field = '$sEnumCol'");
|
||||
if (isset($aFields[0]['Type']))
|
||||
{
|
||||
$sColType = $aFields[0]['Type'];
|
||||
// Note: the parsing should rely on str_getcsv (requires PHP 5.3) to cope with escaped string
|
||||
if (preg_match("/^enum\(\'(.*)\'\)$/", $sColType, $aMatches))
|
||||
{
|
||||
$aCurrentValues = explode("','", $aMatches[1]);
|
||||
}
|
||||
}
|
||||
if (!in_array($sFrom, $aNewValues))
|
||||
{
|
||||
if (!in_array($sTo, $aCurrentValues)) // if not already transformed!
|
||||
{
|
||||
$sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL';
|
||||
|
||||
if (strtolower($sTo) == strtolower($sFrom))
|
||||
{
|
||||
SetupPage::log_info("Changing enum in DB - $sClass::$sAttCode from '$sFrom' to '$sTo' (just a change in the case)");
|
||||
$aTargetValues = array();
|
||||
foreach ($aCurrentValues as $sValue)
|
||||
{
|
||||
if ($sValue == $sFrom)
|
||||
{
|
||||
$sValue = $sTo;
|
||||
}
|
||||
$aTargetValues[] = $sValue;
|
||||
}
|
||||
$sColumnDefinition = "ENUM(".implode(",", CMDBSource::Quote($aTargetValues)).") $sNullSpec";
|
||||
$sRepair = "ALTER TABLE `$sTableName` MODIFY `$sEnumCol` $sColumnDefinition";
|
||||
CMDBSource::Query($sRepair);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1st - Allow both values in the column definition
|
||||
//
|
||||
SetupPage::log_info("Changing enum in DB - $sClass::$sAttCode from '$sFrom' to '$sTo'");
|
||||
$aAllValues = $aCurrentValues;
|
||||
$aAllValues[] = $sTo;
|
||||
$sColumnDefinition = "ENUM(".implode(",", CMDBSource::Quote($aAllValues)).") $sNullSpec";
|
||||
$sRepair = "ALTER TABLE `$sTableName` MODIFY `$sEnumCol` $sColumnDefinition";
|
||||
CMDBSource::Query($sRepair);
|
||||
|
||||
// 2nd - Change the old value into the new value
|
||||
//
|
||||
$sRepair = "UPDATE `$sTableName` SET `$sEnumCol` = '$sTo' WHERE `$sEnumCol` = BINARY '$sFrom'";
|
||||
CMDBSource::Query($sRepair);
|
||||
$iAffectedRows = CMDBSource::AffectedRows();
|
||||
SetupPage::log_info("Changing enum in DB - $iAffectedRows rows updated");
|
||||
|
||||
// 3rd - Remove the useless value from the column definition
|
||||
//
|
||||
$aTargetValues = array();
|
||||
foreach ($aCurrentValues as $sValue)
|
||||
{
|
||||
if ($sValue == $sFrom)
|
||||
{
|
||||
$sValue = $sTo;
|
||||
}
|
||||
$aTargetValues[] = $sValue;
|
||||
}
|
||||
$sColumnDefinition = "ENUM(".implode(",", CMDBSource::Quote($aTargetValues)).") $sNullSpec";
|
||||
$sRepair = "ALTER TABLE `$sTableName` MODIFY `$sEnumCol` $sColumnDefinition";
|
||||
CMDBSource::Query($sRepair);
|
||||
SetupPage::log_info("Changing enum in DB - removed useless value '$sFrom'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - '$sFrom' is still a valid value (".implode(', ', $aNewValues).")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - '$sTo' is not a known value (".implode(', ', $aNewValues).")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - '$sTo' failed. Reason ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
<?php
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
require_once(APPROOT.'setup/setuppage.class.inc.php');
|
||||
|
||||
/**
|
||||
* Class ModuleInstaller
|
||||
* Defines the API to implement module specific actions during the setup
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called at the end of the setup of the database (profiles and admin accounts created), but before the data load
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseSetup(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called at the end of the data load
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string Previous version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDataLoad(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to complete the renaming of a class
|
||||
* The renaming is made in the datamodel definition, but the name has to be changed in the DB as well
|
||||
* Must be called after DB update, i.e within an implementation of AfterDatabaseCreation()
|
||||
*
|
||||
* @param string $sFrom Original name (already INVALID in the current datamodel)
|
||||
* @param string $sTo New name (valid in the current datamodel)
|
||||
* @return void
|
||||
*/
|
||||
public static function RenameClassInDB($sFrom, $sTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!MetaModel::IsStandaloneClass($sTo))
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass($sTo);
|
||||
$sTableName = MetaModel::DBGetTable($sRootClass);
|
||||
$sFinalClassCol = MetaModel::DBGetClassField($sRootClass);
|
||||
$sRepair = "UPDATE `$sTableName` SET `$sFinalClassCol` = '$sTo' WHERE `$sFinalClassCol` = BINARY '$sFrom'";
|
||||
CMDBSource::Query($sRepair);
|
||||
$iAffectedRows = CMDBSource::AffectedRows();
|
||||
SetupPage::log_info("Renaming class in DB - final class from '$sFrom' to '$sTo': $iAffectedRows rows affected");
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupPage::log_warning("Failed to rename class in DB - final class from '$sFrom' to '$sTo'. Reason: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to modify an enum value
|
||||
* The change is made in the datamodel definition, but the value has to be changed in the DB as well
|
||||
* Must be called BEFORE DB update, i.e within an implementation of BeforeDatabaseCreation()
|
||||
* This helper does change ONE value at a time
|
||||
*
|
||||
* @param string $sClass A valid class name
|
||||
* @param string $sAttCode The enum attribute code
|
||||
* @param string $sFrom Original value (already INVALID in the current datamodel)
|
||||
* @param string $sTo New value (valid in the current datamodel)
|
||||
* @return void
|
||||
*/
|
||||
public static function RenameEnumValueInDB($sClass, $sAttCode, $sFrom, $sTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - from '$sFrom' to '$sTo' failed. Reason '$sAttCode' is not a valid attribute of the class '$sClass'.");
|
||||
return;
|
||||
}
|
||||
$sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sAttCode);
|
||||
$sTableName = MetaModel::DBGetTable($sOriginClass);
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeEnum)
|
||||
{
|
||||
$oValDef = $oAttDef->GetValuesDef();
|
||||
if ($oValDef)
|
||||
{
|
||||
$aNewValues = array_keys($oValDef->GetValues(array(), ""));
|
||||
if (in_array($sTo, $aNewValues))
|
||||
{
|
||||
$sEnumCol = $oAttDef->Get("sql");
|
||||
$aFields = CMDBSource::QueryToArray("SHOW COLUMNS FROM `$sTableName` WHERE Field = '$sEnumCol'");
|
||||
if (isset($aFields[0]['Type']))
|
||||
{
|
||||
$sColType = $aFields[0]['Type'];
|
||||
// Note: the parsing should rely on str_getcsv (requires PHP 5.3) to cope with escaped string
|
||||
if (preg_match("/^enum\(\'(.*)\'\)$/", $sColType, $aMatches))
|
||||
{
|
||||
$aCurrentValues = explode("','", $aMatches[1]);
|
||||
}
|
||||
}
|
||||
if (!in_array($sFrom, $aNewValues))
|
||||
{
|
||||
if (!in_array($sTo, $aCurrentValues)) // if not already transformed!
|
||||
{
|
||||
$sNullSpec = $oAttDef->IsNullAllowed() ? 'NULL' : 'NOT NULL';
|
||||
|
||||
if (strtolower($sTo) == strtolower($sFrom))
|
||||
{
|
||||
SetupPage::log_info("Changing enum in DB - $sClass::$sAttCode from '$sFrom' to '$sTo' (just a change in the case)");
|
||||
$aTargetValues = array();
|
||||
foreach ($aCurrentValues as $sValue)
|
||||
{
|
||||
if ($sValue == $sFrom)
|
||||
{
|
||||
$sValue = $sTo;
|
||||
}
|
||||
$aTargetValues[] = $sValue;
|
||||
}
|
||||
$sColumnDefinition = "ENUM(".implode(",", CMDBSource::Quote($aTargetValues)).") $sNullSpec";
|
||||
$sRepair = "ALTER TABLE `$sTableName` MODIFY `$sEnumCol` $sColumnDefinition";
|
||||
CMDBSource::Query($sRepair);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1st - Allow both values in the column definition
|
||||
//
|
||||
SetupPage::log_info("Changing enum in DB - $sClass::$sAttCode from '$sFrom' to '$sTo'");
|
||||
$aAllValues = $aCurrentValues;
|
||||
$aAllValues[] = $sTo;
|
||||
$sColumnDefinition = "ENUM(".implode(",", CMDBSource::Quote($aAllValues)).") $sNullSpec";
|
||||
$sRepair = "ALTER TABLE `$sTableName` MODIFY `$sEnumCol` $sColumnDefinition";
|
||||
CMDBSource::Query($sRepair);
|
||||
|
||||
// 2nd - Change the old value into the new value
|
||||
//
|
||||
$sRepair = "UPDATE `$sTableName` SET `$sEnumCol` = '$sTo' WHERE `$sEnumCol` = BINARY '$sFrom'";
|
||||
CMDBSource::Query($sRepair);
|
||||
$iAffectedRows = CMDBSource::AffectedRows();
|
||||
SetupPage::log_info("Changing enum in DB - $iAffectedRows rows updated");
|
||||
|
||||
// 3rd - Remove the useless value from the column definition
|
||||
//
|
||||
$aTargetValues = array();
|
||||
foreach ($aCurrentValues as $sValue)
|
||||
{
|
||||
if ($sValue == $sFrom)
|
||||
{
|
||||
$sValue = $sTo;
|
||||
}
|
||||
$aTargetValues[] = $sValue;
|
||||
}
|
||||
$sColumnDefinition = "ENUM(".implode(",", CMDBSource::Quote($aTargetValues)).") $sNullSpec";
|
||||
$sRepair = "ALTER TABLE `$sTableName` MODIFY `$sEnumCol` $sColumnDefinition";
|
||||
CMDBSource::Query($sRepair);
|
||||
SetupPage::log_info("Changing enum in DB - removed useless value '$sFrom'");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - '$sFrom' is still a valid value (".implode(', ', $aNewValues).")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - '$sTo' is not a known value (".implode(', ', $aNewValues).")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupPage::log_warning("Changing enum in DB - $sClass::$sAttCode - '$sTo' failed. Reason ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,305 +1,305 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Web page used for the setup
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
require_once(APPROOT."setup/modulediscovery.class.inc.php");
|
||||
require_once(APPROOT."setup/runtimeenv.class.inc.php");
|
||||
|
||||
define('INSTALL_LOG_FILE', APPROOT.'/log/setup.log');
|
||||
|
||||
class SetupPage extends NiceWebPage
|
||||
{
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../setup/setup.js");
|
||||
$this->add_style("
|
||||
body {
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 10pt;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#header {
|
||||
width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 50px;
|
||||
padding: 20px;
|
||||
background: #f6f6f1;
|
||||
height: 54px;
|
||||
border-top: 1px solid #000;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
}
|
||||
#header img {
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
margin-right: 20px;
|
||||
}
|
||||
#header h1 {
|
||||
vertical-align: middle;
|
||||
height: 54px;
|
||||
noline-height: 54px;
|
||||
margin: 0;
|
||||
}
|
||||
#setup {
|
||||
width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #555555;
|
||||
font-size: 16pt;
|
||||
}
|
||||
h2 {
|
||||
color: #000;
|
||||
font-size: 14pt;
|
||||
}
|
||||
h3 {
|
||||
color: #1C94C4;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
.next {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
.v-spacer {
|
||||
padding-top: 1em;
|
||||
}
|
||||
button {
|
||||
margin-top: 1em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
p.info {
|
||||
padding-left: 50px;
|
||||
background: url(../images/info-mid.png) no-repeat left -5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
p.ok {
|
||||
padding-left: 50px;
|
||||
background: url(../images/clean-mid.png) no-repeat left -8px;
|
||||
min-height: 48px;
|
||||
}
|
||||
p.warning {
|
||||
padding-left: 50px;
|
||||
background: url(../images/messagebox_warning-mid.png) no-repeat left -5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
p.error {
|
||||
padding-left: 50px;
|
||||
background: url(../images/stop-mid.png) no-repeat left -5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
td.label {
|
||||
text-align: left;
|
||||
}
|
||||
label.read-only {
|
||||
color: #666;
|
||||
cursor: text;
|
||||
}
|
||||
td.input {
|
||||
text-align: left;
|
||||
}
|
||||
table.formTable {
|
||||
border: 0;
|
||||
cellpadding: 2px;
|
||||
cellspacing: 0;
|
||||
}
|
||||
.wizlabel, .wizinput {
|
||||
color: #000;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.wizhelp {
|
||||
color: #333;
|
||||
font-size: 8pt;
|
||||
}
|
||||
#progress {
|
||||
border:1px solid #000000;
|
||||
width: 180px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
margin: 5px;
|
||||
}
|
||||
h3.clickable {
|
||||
background: url(../images/plus.gif) no-repeat left;
|
||||
padding-left:16px;
|
||||
cursor: hand;
|
||||
}
|
||||
h3.clickable.open {
|
||||
background: url(../images/minus.gif) no-repeat left;
|
||||
padding-left:16px;
|
||||
cursor: hand;
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden because the application is not fully loaded when the setup is being run
|
||||
*/
|
||||
public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '../';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden because the application is not fully loaded when the setup is being run
|
||||
*/
|
||||
public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return $this->GetAbsoluteUrlAppRoot().utils::GetCurrentEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden because the application is not fully loaded when the setup is being run
|
||||
*/
|
||||
function GetApplicationContext()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function info($sText)
|
||||
{
|
||||
$this->add("<p class=\"info\">$sText</p>\n");
|
||||
$this->log_info($sText);
|
||||
}
|
||||
|
||||
public function ok($sText)
|
||||
{
|
||||
$this->add("<p class=\"ok\">$sText</p>\n");
|
||||
$this->log_ok($sText);
|
||||
}
|
||||
|
||||
public function warning($sText)
|
||||
{
|
||||
$this->add("<p class=\"warning\">$sText</p>\n");
|
||||
$this->log_warning($sText);
|
||||
}
|
||||
|
||||
public function error($sText)
|
||||
{
|
||||
$this->add("<p class=\"error\">$sText</p>\n");
|
||||
$this->log_error($sText);
|
||||
}
|
||||
|
||||
public function form($aData)
|
||||
{
|
||||
$this->add("<table class=\"formTable\">\n");
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
$this->add("<tr>\n");
|
||||
if (isset($aRow['label']) && isset($aRow['input']) && isset($aRow['help']))
|
||||
{
|
||||
$this->add("<td class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
$this->add("<td class=\"wizinput\">{$aRow['input']}</td>\n");
|
||||
$this->add("<td class=\"wizhelp\">{$aRow['help']}</td>\n");
|
||||
}
|
||||
else if (isset($aRow['label']) && isset($aRow['help']))
|
||||
{
|
||||
$this->add("<td colspan=\"2\" class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
$this->add("<td class=\"wizhelp\">{$aRow['help']}</td>\n");
|
||||
}
|
||||
else if (isset($aRow['label']) && isset($aRow['input']))
|
||||
{
|
||||
$this->add("<td class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
$this->add("<td colspan=\"2\" class=\"wizinput\">{$aRow['input']}</td>\n");
|
||||
}
|
||||
else if (isset($aRow['label']))
|
||||
{
|
||||
$this->add("<td colspan=\"3\" class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
}
|
||||
$this->add("</tr>\n");
|
||||
}
|
||||
$this->add("</table>\n");
|
||||
}
|
||||
|
||||
public function collapsible($sId, $sTitle, $aItems, $bOpen = true)
|
||||
{
|
||||
$this->add("<h3 class=\"clickable open\" id=\"{$sId}\">$sTitle</h3>");
|
||||
$this->p('<ul id="'.$sId.'_list">');
|
||||
foreach($aItems as $sItem)
|
||||
{
|
||||
$this->p("<li>$sItem</li>\n");
|
||||
}
|
||||
$this->p('</ul>');
|
||||
$this->add_ready_script("$('#{$sId}').click( function() { $(this).toggleClass('open'); $('#{$sId}_list').toggle();} );\n");
|
||||
if (!$bOpen)
|
||||
{
|
||||
$this->add_ready_script("$('#{$sId}').toggleClass('open'); $('#{$sId}_list').toggle();\n");
|
||||
}
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$this->s_content = "<div id=\"header\"><h1><a href=\"http://www.combodo.com/itop\" target=\"_blank\"><img title=\"iTop by Combodo\" src=\"../images/itop-logo.png?t=".utils::GetCacheBusterTimestamp()."\"></a> ".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n</div><div id=\"setup\">{$this->s_content}\n</div>\n";
|
||||
return parent::output();
|
||||
}
|
||||
|
||||
public static function log_error($sText)
|
||||
{
|
||||
self::log("Error - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_warning($sText)
|
||||
{
|
||||
self::log("Warning - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_info($sText)
|
||||
{
|
||||
self::log("Info - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_ok($sText)
|
||||
{
|
||||
self::log("Ok - ".$sText);
|
||||
}
|
||||
|
||||
public static function log($sText)
|
||||
{
|
||||
$hLogFile = @fopen(INSTALL_LOG_FILE, 'a');
|
||||
if ($hLogFile !== false)
|
||||
{
|
||||
$sDate = date('Y-m-d H:i:s');
|
||||
fwrite($hLogFile, "$sDate - $sText\n");
|
||||
fclose($hLogFile);
|
||||
}
|
||||
}
|
||||
} // End of class
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Web page used for the setup
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
require_once(APPROOT."setup/modulediscovery.class.inc.php");
|
||||
require_once(APPROOT."setup/runtimeenv.class.inc.php");
|
||||
|
||||
define('INSTALL_LOG_FILE', APPROOT.'/log/setup.log');
|
||||
|
||||
class SetupPage extends NiceWebPage
|
||||
{
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../setup/setup.js");
|
||||
$this->add_style("
|
||||
body {
|
||||
background-color: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 10pt;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#header {
|
||||
width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 50px;
|
||||
padding: 20px;
|
||||
background: #f6f6f1;
|
||||
height: 54px;
|
||||
border-top: 1px solid #000;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
}
|
||||
#header img {
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
margin-right: 20px;
|
||||
}
|
||||
#header h1 {
|
||||
vertical-align: middle;
|
||||
height: 54px;
|
||||
noline-height: 54px;
|
||||
margin: 0;
|
||||
}
|
||||
#setup {
|
||||
width: 600px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #555555;
|
||||
font-size: 16pt;
|
||||
}
|
||||
h2 {
|
||||
color: #000;
|
||||
font-size: 14pt;
|
||||
}
|
||||
h3 {
|
||||
color: #1C94C4;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
.next {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
.v-spacer {
|
||||
padding-top: 1em;
|
||||
}
|
||||
button {
|
||||
margin-top: 1em;
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
p.info {
|
||||
padding-left: 50px;
|
||||
background: url(../images/info-mid.png) no-repeat left -5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
p.ok {
|
||||
padding-left: 50px;
|
||||
background: url(../images/clean-mid.png) no-repeat left -8px;
|
||||
min-height: 48px;
|
||||
}
|
||||
p.warning {
|
||||
padding-left: 50px;
|
||||
background: url(../images/messagebox_warning-mid.png) no-repeat left -5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
p.error {
|
||||
padding-left: 50px;
|
||||
background: url(../images/stop-mid.png) no-repeat left -5px;
|
||||
min-height: 48px;
|
||||
}
|
||||
td.label {
|
||||
text-align: left;
|
||||
}
|
||||
label.read-only {
|
||||
color: #666;
|
||||
cursor: text;
|
||||
}
|
||||
td.input {
|
||||
text-align: left;
|
||||
}
|
||||
table.formTable {
|
||||
border: 0;
|
||||
cellpadding: 2px;
|
||||
cellspacing: 0;
|
||||
}
|
||||
.wizlabel, .wizinput {
|
||||
color: #000;
|
||||
font-size: 10pt;
|
||||
}
|
||||
.wizhelp {
|
||||
color: #333;
|
||||
font-size: 8pt;
|
||||
}
|
||||
#progress {
|
||||
border:1px solid #000000;
|
||||
width: 180px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
margin: 5px;
|
||||
}
|
||||
h3.clickable {
|
||||
background: url(../images/plus.gif) no-repeat left;
|
||||
padding-left:16px;
|
||||
cursor: hand;
|
||||
}
|
||||
h3.clickable.open {
|
||||
background: url(../images/minus.gif) no-repeat left;
|
||||
padding-left:16px;
|
||||
cursor: hand;
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden because the application is not fully loaded when the setup is being run
|
||||
*/
|
||||
public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '../';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden because the application is not fully loaded when the setup is being run
|
||||
*/
|
||||
public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return $this->GetAbsoluteUrlAppRoot().utils::GetCurrentEnvironment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriden because the application is not fully loaded when the setup is being run
|
||||
*/
|
||||
function GetApplicationContext()
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function info($sText)
|
||||
{
|
||||
$this->add("<p class=\"info\">$sText</p>\n");
|
||||
$this->log_info($sText);
|
||||
}
|
||||
|
||||
public function ok($sText)
|
||||
{
|
||||
$this->add("<p class=\"ok\">$sText</p>\n");
|
||||
$this->log_ok($sText);
|
||||
}
|
||||
|
||||
public function warning($sText)
|
||||
{
|
||||
$this->add("<p class=\"warning\">$sText</p>\n");
|
||||
$this->log_warning($sText);
|
||||
}
|
||||
|
||||
public function error($sText)
|
||||
{
|
||||
$this->add("<p class=\"error\">$sText</p>\n");
|
||||
$this->log_error($sText);
|
||||
}
|
||||
|
||||
public function form($aData)
|
||||
{
|
||||
$this->add("<table class=\"formTable\">\n");
|
||||
foreach($aData as $aRow)
|
||||
{
|
||||
$this->add("<tr>\n");
|
||||
if (isset($aRow['label']) && isset($aRow['input']) && isset($aRow['help']))
|
||||
{
|
||||
$this->add("<td class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
$this->add("<td class=\"wizinput\">{$aRow['input']}</td>\n");
|
||||
$this->add("<td class=\"wizhelp\">{$aRow['help']}</td>\n");
|
||||
}
|
||||
else if (isset($aRow['label']) && isset($aRow['help']))
|
||||
{
|
||||
$this->add("<td colspan=\"2\" class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
$this->add("<td class=\"wizhelp\">{$aRow['help']}</td>\n");
|
||||
}
|
||||
else if (isset($aRow['label']) && isset($aRow['input']))
|
||||
{
|
||||
$this->add("<td class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
$this->add("<td colspan=\"2\" class=\"wizinput\">{$aRow['input']}</td>\n");
|
||||
}
|
||||
else if (isset($aRow['label']))
|
||||
{
|
||||
$this->add("<td colspan=\"3\" class=\"wizlabel\">{$aRow['label']}</td>\n");
|
||||
}
|
||||
$this->add("</tr>\n");
|
||||
}
|
||||
$this->add("</table>\n");
|
||||
}
|
||||
|
||||
public function collapsible($sId, $sTitle, $aItems, $bOpen = true)
|
||||
{
|
||||
$this->add("<h3 class=\"clickable open\" id=\"{$sId}\">$sTitle</h3>");
|
||||
$this->p('<ul id="'.$sId.'_list">');
|
||||
foreach($aItems as $sItem)
|
||||
{
|
||||
$this->p("<li>$sItem</li>\n");
|
||||
}
|
||||
$this->p('</ul>');
|
||||
$this->add_ready_script("$('#{$sId}').click( function() { $(this).toggleClass('open'); $('#{$sId}_list').toggle();} );\n");
|
||||
if (!$bOpen)
|
||||
{
|
||||
$this->add_ready_script("$('#{$sId}').toggleClass('open'); $('#{$sId}_list').toggle();\n");
|
||||
}
|
||||
}
|
||||
|
||||
public function output()
|
||||
{
|
||||
$this->s_content = "<div id=\"header\"><h1><a href=\"http://www.combodo.com/itop\" target=\"_blank\"><img title=\"iTop by Combodo\" src=\"../images/itop-logo.png?t=".utils::GetCacheBusterTimestamp()."\"></a> ".htmlentities($this->s_title, ENT_QUOTES, 'UTF-8')."</h1>\n</div><div id=\"setup\">{$this->s_content}\n</div>\n";
|
||||
return parent::output();
|
||||
}
|
||||
|
||||
public static function log_error($sText)
|
||||
{
|
||||
self::log("Error - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_warning($sText)
|
||||
{
|
||||
self::log("Warning - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_info($sText)
|
||||
{
|
||||
self::log("Info - ".$sText);
|
||||
}
|
||||
|
||||
public static function log_ok($sText)
|
||||
{
|
||||
self::log("Ok - ".$sText);
|
||||
}
|
||||
|
||||
public static function log($sText)
|
||||
{
|
||||
$hLogFile = @fopen(INSTALL_LOG_FILE, 'a');
|
||||
if ($hLogFile !== false)
|
||||
{
|
||||
$sDate = date('Y-m-d H:i:s');
|
||||
fwrite($hLogFile, "$sDate - $sText\n");
|
||||
fclose($hLogFile);
|
||||
}
|
||||
}
|
||||
} // End of class
|
||||
|
||||
4724
setup/tar.php
4724
setup/tar.php
File diff suppressed because it is too large
Load Diff
@@ -1,449 +1,449 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Load XML data from a set of files
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
define ('KEYS_CACHE_FILE', APPROOT.'data/keyscache.tmp');
|
||||
/**
|
||||
* Class to load sets of objects from XML files into the database
|
||||
* XML files can be produced by the 'export' web service or by any other means
|
||||
* Here is a simple example:
|
||||
* $oLoader = new XMLDataLoader('../itop-config.php');
|
||||
* $oLoader->StartSession();
|
||||
* $oLoader->LoadFile('./organizations.xml');
|
||||
* $oLoader->LoadFile('./locations.xml');
|
||||
* $oLoader->EndSession();
|
||||
*/
|
||||
class XMLDataLoader
|
||||
{
|
||||
protected $m_aKeys;
|
||||
protected $m_aObjectsCache;
|
||||
protected $m_bSessionActive;
|
||||
protected $m_oChange;
|
||||
protected $m_sCacheFileName;
|
||||
|
||||
protected $m_aErrors;
|
||||
protected $m_aWarnings;
|
||||
protected $m_iCountCreated;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->m_aKeys = array();
|
||||
$this->m_aObjectsCache = array();
|
||||
$this->m_oChange = null;
|
||||
$this->m_sCacheFileName = KEYS_CACHE_FILE;
|
||||
$this->LoadKeysCache();
|
||||
$this->m_bSessionActive = true;
|
||||
$this->m_aErrors = array();
|
||||
$this->m_aWarnings = array();
|
||||
$this->m_iCountCreated = 0;
|
||||
}
|
||||
|
||||
public function StartSession($oChange)
|
||||
{
|
||||
// Do cleanup any existing cache file (shall not be necessary unless a setup was interrupted abruptely)
|
||||
$this->ClearKeysCache();
|
||||
|
||||
$this->m_oChange = $oChange;
|
||||
$this->m_bSessionActive = true;
|
||||
}
|
||||
|
||||
public function EndSession($bStrict = false)
|
||||
{
|
||||
$this->ResolveExternalKeys();
|
||||
$this->m_bSessionActive = false;
|
||||
|
||||
if (count($this->m_aErrors) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
elseif ($bStrict && count($this->m_aWarnings) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetErrors()
|
||||
{
|
||||
return $this->m_aErrors;
|
||||
}
|
||||
|
||||
public function GetWarnings()
|
||||
{
|
||||
return $this->m_aWarnings;
|
||||
}
|
||||
|
||||
public function GetCountCreated()
|
||||
{
|
||||
return $this->m_iCountCreated;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// Stopping in the middle of a session, let's save the context information
|
||||
if ($this->m_bSessionActive)
|
||||
{
|
||||
$this->SaveKeysCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->ClearKeysCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the keys & object cache in a file
|
||||
*/
|
||||
protected function SaveKeysCache()
|
||||
{
|
||||
if (!is_dir(APPROOT.'data'))
|
||||
{
|
||||
mkdir(APPROOT.'data');
|
||||
}
|
||||
$hFile = @fopen($this->m_sCacheFileName, 'w');
|
||||
if ($hFile !== false)
|
||||
{
|
||||
$sData = serialize( array('keys' => $this->m_aKeys,
|
||||
'objects' => $this->m_aObjectsCache,
|
||||
'change' => $this->m_oChange,
|
||||
'errors' => $this->m_aErrors,
|
||||
'warnings' => $this->m_aWarnings,
|
||||
));
|
||||
fwrite($hFile, $sData);
|
||||
fclose($hFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot write to file: '{$this->m_sCacheFileName}'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the keys & object cache from the tmp file
|
||||
*/
|
||||
protected function LoadKeysCache()
|
||||
{
|
||||
$sFileContent = @file_get_contents($this->m_sCacheFileName);
|
||||
if (!empty($sFileContent))
|
||||
{
|
||||
$aCache = unserialize($sFileContent);
|
||||
$this->m_aKeys = $aCache['keys'];
|
||||
$this->m_aObjectsCache = $aCache['objects'];
|
||||
$this->m_oChange = $aCache['change'];
|
||||
$this->m_aErrors = $aCache['errors'];
|
||||
$this->m_aWarnings = $aCache['warnings'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the tmp file used to store the keys cache
|
||||
*/
|
||||
protected function ClearKeysCache()
|
||||
{
|
||||
if(is_file($this->m_sCacheFileName))
|
||||
{
|
||||
unlink($this->m_sCacheFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "<p>Hm, it looks like the file does not exist!!!</p>";
|
||||
}
|
||||
$this->m_aKeys = array();
|
||||
$this->m_aObjectsCache = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to load the objects from a standard XML file into the database
|
||||
* @param $sFilePath string The full path to the XML file to load
|
||||
* @param $bUpdateKeyCacheOnly bool Set to true to *just* update the keys cache but not reload the objects
|
||||
*/
|
||||
function LoadFile($sFilePath, $bUpdateKeyCacheOnly = false)
|
||||
{
|
||||
global $aKeys;
|
||||
|
||||
$oXml = simplexml_load_file($sFilePath);
|
||||
|
||||
$aReplicas = array();
|
||||
foreach($oXml as $sClass => $oXmlObj)
|
||||
{
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
SetupPage::log_error("Unknown class - $sClass");
|
||||
throw(new Exception("Unknown class - $sClass"));
|
||||
}
|
||||
|
||||
$iSrcId = (integer)$oXmlObj['id']; // Mandatory to cast
|
||||
|
||||
// Import algorithm
|
||||
// Here enumerate all the attributes of the object
|
||||
// for all attribute that is neither an external field
|
||||
// not an external key, assign it
|
||||
// Store all external keys for further reference
|
||||
// Create the object an store the correspondance between its newly created Id
|
||||
// and its original Id
|
||||
// Once all the objects have been created re-assign all the external keys to
|
||||
// their actual Ids
|
||||
$iExistingId = $this->GetObjectKey($sClass, $iSrcId);
|
||||
if ($iExistingId != 0)
|
||||
{
|
||||
$oTargetObj = MetaModel::GetObject($sClass, $iExistingId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTargetObj = MetaModel::NewObject($sClass);
|
||||
}
|
||||
foreach($oXmlObj as $sAttCode => $oSubNode)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$sMsg = "Unknown attribute code - $sClass/$sAttCode";
|
||||
continue; // ignore silently...
|
||||
//SetupPage::log_error($sMsg);
|
||||
//throw(new Exception($sMsg));
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar()))
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
if (substr(trim($oSubNode), 0, 6) == 'SELECT')
|
||||
{
|
||||
$sQuery = trim($oSubNode);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sQuery));
|
||||
$iMatches = $oSet->Count();
|
||||
if ($iMatches == 1)
|
||||
{
|
||||
$oFoundObject = $oSet->Fetch();
|
||||
$iExtKey = $oFoundObject->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sMsg = "Ext key not reconcilied - $sClass/$iSrcId - $sAttCode: '".$sQuery."' - found $iMatches matche(s)";
|
||||
SetupPage::log_error($sMsg);
|
||||
$this->m_aErrors[] = $sMsg;
|
||||
$iExtKey = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iDstObj = (integer)($oSubNode);
|
||||
// Attempt to find the object in the list of loaded objects
|
||||
$iExtKey = $this->GetObjectKey($oAttDef->GetTargetClass(), $iDstObj);
|
||||
if ($iExtKey == 0)
|
||||
{
|
||||
$iExtKey = -$iDstObj; // Convention: Unresolved keys are stored as negative !
|
||||
$oTargetObj->RegisterAsDirty();
|
||||
}
|
||||
// here we allow external keys to be invalid because we will resolve them later on...
|
||||
}
|
||||
//$oTargetObj->CheckValue($sAttCode, $iExtKey);
|
||||
$oTargetObj->Set($sAttCode, $iExtKey);
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeBlob)
|
||||
{
|
||||
$sMimeType = (string) $oSubNode->mimetype;
|
||||
$sFileName = (string) $oSubNode->filename;
|
||||
$data = base64_decode((string) $oSubNode->data);
|
||||
$oDoc = new ormDocument($data, $sMimeType, $sFileName);
|
||||
$oTargetObj->Set($sAttCode, $oDoc);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = (string)$oSubNode;
|
||||
|
||||
if ($value == '')
|
||||
{
|
||||
$value = $oAttDef->GetNullValue();
|
||||
}
|
||||
|
||||
$res = $oTargetObj->CheckValue($sAttCode, $value);
|
||||
if ($res !== true)
|
||||
{
|
||||
// $res contains the error description
|
||||
$sMsg = "Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oSubNode."' ; $res";
|
||||
SetupPage::log_error($sMsg);
|
||||
$this->m_aErrors[] = $sMsg;
|
||||
}
|
||||
$oTargetObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->StoreObject($sClass, $oTargetObj, $iSrcId, $bUpdateKeyCacheOnly, $bUpdateKeyCacheOnly);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new ID of an object in the database given its original ID
|
||||
* This may fail (return 0) if the object has not yet been created in the database
|
||||
* This is why the order of the import may be important
|
||||
*/
|
||||
protected function GetObjectKey($sClass, $iSrcId)
|
||||
{
|
||||
if (isset($this->m_aKeys[$sClass]) && isset($this->m_aKeys[$sClass][$iSrcId]))
|
||||
{
|
||||
return $this->m_aKeys[$sClass][$iSrcId];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an object in the database and remember the mapping
|
||||
* between its original ID and the newly created ID in the database
|
||||
*/
|
||||
protected function StoreObject($sClass, $oTargetObj, $iSrcId, $bSearch = false, $bUpdateKeyCacheOnly = false)
|
||||
{
|
||||
$iObjId = 0;
|
||||
try
|
||||
{
|
||||
if ($bSearch)
|
||||
{
|
||||
// Check if the object does not already exist, based on its usual reconciliation keys...
|
||||
$aReconciliationKeys = MetaModel::GetReconcKeys($sClass);
|
||||
if (count($aReconciliationKeys) > 0)
|
||||
{
|
||||
// Some reconciliation keys have been defined, use them to search for the object
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$iConditionsCount = 0;
|
||||
foreach($aReconciliationKeys as $sAttCode)
|
||||
{
|
||||
if ($oTargetObj->Get($sAttCode) != '')
|
||||
{
|
||||
$oSearch->AddCondition($sAttCode, $oTargetObj->Get($sAttCode), '=');
|
||||
$iConditionsCount++;
|
||||
}
|
||||
}
|
||||
if ($iConditionsCount > 0) // Search only if there are some valid conditions...
|
||||
{
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
if ($oSet->count() == 1)
|
||||
{
|
||||
// The object already exists, reuse it
|
||||
$oExistingObject = $oSet->Fetch();
|
||||
$iObjId = $oExistingObject->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($iObjId == 0)
|
||||
{
|
||||
if($oTargetObj->IsNew())
|
||||
{
|
||||
if (!$bUpdateKeyCacheOnly)
|
||||
{
|
||||
$iObjId = $oTargetObj->DBInsertNoReload();
|
||||
$this->m_iCountCreated++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iObjId = $oTargetObj->GetKey();
|
||||
if (!$bUpdateKeyCacheOnly)
|
||||
{
|
||||
$oTargetObj->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupPage::log_error("An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage());
|
||||
$this->m_aErrors[] = "An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage();
|
||||
}
|
||||
$aParentClasses = MetaModel::EnumParentClasses($sClass);
|
||||
$aParentClasses[] = $sClass;
|
||||
foreach($aParentClasses as $sObjClass)
|
||||
{
|
||||
$this->m_aKeys[$sObjClass][$iSrcId] = $iObjId;
|
||||
}
|
||||
$this->m_aObjectsCache[$sClass][$iObjId] = $oTargetObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an external key to its (newly created) value
|
||||
*/
|
||||
|
||||
protected function ResolveExternalKeys()
|
||||
{
|
||||
foreach($this->m_aObjectsCache as $sClass => $oObjList)
|
||||
{
|
||||
foreach($oObjList as $oTargetObj)
|
||||
{
|
||||
$bChanged = false;
|
||||
$sClass = get_class($oTargetObj);
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if ( ($oAttDef->IsExternalKey()) && ($oTargetObj->Get($sAttCode) < 0) ) // Convention unresolved key = negative
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iTempKey = $oTargetObj->Get($sAttCode);
|
||||
|
||||
$iExtKey = $this->GetObjectKey($sTargetClass, -$iTempKey);
|
||||
if ($iExtKey == 0)
|
||||
{
|
||||
$sMsg = "unresolved extkey in $sClass::".$oTargetObj->GetKey()."(".$oTargetObj->GetName().")::$sAttCode=$sTargetClass::$iTempKey";
|
||||
SetupPage::log_warning($sMsg);
|
||||
$this->m_aWarnings[] = $sMsg;
|
||||
//echo "<pre>aKeys[".$sTargetClass."]:\n";
|
||||
//print_r($this->m_aKeys[$sTargetClass]);
|
||||
//echo "</pre>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$bChanged = true;
|
||||
$oTargetObj->Set($sAttCode, $iExtKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($bChanged)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (is_subclass_of($oTargetObj, 'CMDBObject'))
|
||||
{
|
||||
$oTargetObj->DBUpdateTracked($this->m_oChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTargetObj->DBUpdate();
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->m_aErrors[] = "The object changes could not be tracked - $sClass/$iExtKey - ".$e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop 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 Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Load XML data from a set of files
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
define ('KEYS_CACHE_FILE', APPROOT.'data/keyscache.tmp');
|
||||
/**
|
||||
* Class to load sets of objects from XML files into the database
|
||||
* XML files can be produced by the 'export' web service or by any other means
|
||||
* Here is a simple example:
|
||||
* $oLoader = new XMLDataLoader('../itop-config.php');
|
||||
* $oLoader->StartSession();
|
||||
* $oLoader->LoadFile('./organizations.xml');
|
||||
* $oLoader->LoadFile('./locations.xml');
|
||||
* $oLoader->EndSession();
|
||||
*/
|
||||
class XMLDataLoader
|
||||
{
|
||||
protected $m_aKeys;
|
||||
protected $m_aObjectsCache;
|
||||
protected $m_bSessionActive;
|
||||
protected $m_oChange;
|
||||
protected $m_sCacheFileName;
|
||||
|
||||
protected $m_aErrors;
|
||||
protected $m_aWarnings;
|
||||
protected $m_iCountCreated;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->m_aKeys = array();
|
||||
$this->m_aObjectsCache = array();
|
||||
$this->m_oChange = null;
|
||||
$this->m_sCacheFileName = KEYS_CACHE_FILE;
|
||||
$this->LoadKeysCache();
|
||||
$this->m_bSessionActive = true;
|
||||
$this->m_aErrors = array();
|
||||
$this->m_aWarnings = array();
|
||||
$this->m_iCountCreated = 0;
|
||||
}
|
||||
|
||||
public function StartSession($oChange)
|
||||
{
|
||||
// Do cleanup any existing cache file (shall not be necessary unless a setup was interrupted abruptely)
|
||||
$this->ClearKeysCache();
|
||||
|
||||
$this->m_oChange = $oChange;
|
||||
$this->m_bSessionActive = true;
|
||||
}
|
||||
|
||||
public function EndSession($bStrict = false)
|
||||
{
|
||||
$this->ResolveExternalKeys();
|
||||
$this->m_bSessionActive = false;
|
||||
|
||||
if (count($this->m_aErrors) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
elseif ($bStrict && count($this->m_aWarnings) > 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetErrors()
|
||||
{
|
||||
return $this->m_aErrors;
|
||||
}
|
||||
|
||||
public function GetWarnings()
|
||||
{
|
||||
return $this->m_aWarnings;
|
||||
}
|
||||
|
||||
public function GetCountCreated()
|
||||
{
|
||||
return $this->m_iCountCreated;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// Stopping in the middle of a session, let's save the context information
|
||||
if ($this->m_bSessionActive)
|
||||
{
|
||||
$this->SaveKeysCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->ClearKeysCache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the keys & object cache in a file
|
||||
*/
|
||||
protected function SaveKeysCache()
|
||||
{
|
||||
if (!is_dir(APPROOT.'data'))
|
||||
{
|
||||
mkdir(APPROOT.'data');
|
||||
}
|
||||
$hFile = @fopen($this->m_sCacheFileName, 'w');
|
||||
if ($hFile !== false)
|
||||
{
|
||||
$sData = serialize( array('keys' => $this->m_aKeys,
|
||||
'objects' => $this->m_aObjectsCache,
|
||||
'change' => $this->m_oChange,
|
||||
'errors' => $this->m_aErrors,
|
||||
'warnings' => $this->m_aWarnings,
|
||||
));
|
||||
fwrite($hFile, $sData);
|
||||
fclose($hFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Cannot write to file: '{$this->m_sCacheFileName}'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the keys & object cache from the tmp file
|
||||
*/
|
||||
protected function LoadKeysCache()
|
||||
{
|
||||
$sFileContent = @file_get_contents($this->m_sCacheFileName);
|
||||
if (!empty($sFileContent))
|
||||
{
|
||||
$aCache = unserialize($sFileContent);
|
||||
$this->m_aKeys = $aCache['keys'];
|
||||
$this->m_aObjectsCache = $aCache['objects'];
|
||||
$this->m_oChange = $aCache['change'];
|
||||
$this->m_aErrors = $aCache['errors'];
|
||||
$this->m_aWarnings = $aCache['warnings'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the tmp file used to store the keys cache
|
||||
*/
|
||||
protected function ClearKeysCache()
|
||||
{
|
||||
if(is_file($this->m_sCacheFileName))
|
||||
{
|
||||
unlink($this->m_sCacheFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "<p>Hm, it looks like the file does not exist!!!</p>";
|
||||
}
|
||||
$this->m_aKeys = array();
|
||||
$this->m_aObjectsCache = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to load the objects from a standard XML file into the database
|
||||
* @param $sFilePath string The full path to the XML file to load
|
||||
* @param $bUpdateKeyCacheOnly bool Set to true to *just* update the keys cache but not reload the objects
|
||||
*/
|
||||
function LoadFile($sFilePath, $bUpdateKeyCacheOnly = false)
|
||||
{
|
||||
global $aKeys;
|
||||
|
||||
$oXml = simplexml_load_file($sFilePath);
|
||||
|
||||
$aReplicas = array();
|
||||
foreach($oXml as $sClass => $oXmlObj)
|
||||
{
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
SetupPage::log_error("Unknown class - $sClass");
|
||||
throw(new Exception("Unknown class - $sClass"));
|
||||
}
|
||||
|
||||
$iSrcId = (integer)$oXmlObj['id']; // Mandatory to cast
|
||||
|
||||
// Import algorithm
|
||||
// Here enumerate all the attributes of the object
|
||||
// for all attribute that is neither an external field
|
||||
// not an external key, assign it
|
||||
// Store all external keys for further reference
|
||||
// Create the object an store the correspondance between its newly created Id
|
||||
// and its original Id
|
||||
// Once all the objects have been created re-assign all the external keys to
|
||||
// their actual Ids
|
||||
$iExistingId = $this->GetObjectKey($sClass, $iSrcId);
|
||||
if ($iExistingId != 0)
|
||||
{
|
||||
$oTargetObj = MetaModel::GetObject($sClass, $iExistingId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTargetObj = MetaModel::NewObject($sClass);
|
||||
}
|
||||
foreach($oXmlObj as $sAttCode => $oSubNode)
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$sMsg = "Unknown attribute code - $sClass/$sAttCode";
|
||||
continue; // ignore silently...
|
||||
//SetupPage::log_error($sMsg);
|
||||
//throw(new Exception($sMsg));
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if (($oAttDef->IsWritable()) && ($oAttDef->IsScalar()))
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
if (substr(trim($oSubNode), 0, 6) == 'SELECT')
|
||||
{
|
||||
$sQuery = trim($oSubNode);
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sQuery));
|
||||
$iMatches = $oSet->Count();
|
||||
if ($iMatches == 1)
|
||||
{
|
||||
$oFoundObject = $oSet->Fetch();
|
||||
$iExtKey = $oFoundObject->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
$sMsg = "Ext key not reconcilied - $sClass/$iSrcId - $sAttCode: '".$sQuery."' - found $iMatches matche(s)";
|
||||
SetupPage::log_error($sMsg);
|
||||
$this->m_aErrors[] = $sMsg;
|
||||
$iExtKey = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iDstObj = (integer)($oSubNode);
|
||||
// Attempt to find the object in the list of loaded objects
|
||||
$iExtKey = $this->GetObjectKey($oAttDef->GetTargetClass(), $iDstObj);
|
||||
if ($iExtKey == 0)
|
||||
{
|
||||
$iExtKey = -$iDstObj; // Convention: Unresolved keys are stored as negative !
|
||||
$oTargetObj->RegisterAsDirty();
|
||||
}
|
||||
// here we allow external keys to be invalid because we will resolve them later on...
|
||||
}
|
||||
//$oTargetObj->CheckValue($sAttCode, $iExtKey);
|
||||
$oTargetObj->Set($sAttCode, $iExtKey);
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeBlob)
|
||||
{
|
||||
$sMimeType = (string) $oSubNode->mimetype;
|
||||
$sFileName = (string) $oSubNode->filename;
|
||||
$data = base64_decode((string) $oSubNode->data);
|
||||
$oDoc = new ormDocument($data, $sMimeType, $sFileName);
|
||||
$oTargetObj->Set($sAttCode, $oDoc);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = (string)$oSubNode;
|
||||
|
||||
if ($value == '')
|
||||
{
|
||||
$value = $oAttDef->GetNullValue();
|
||||
}
|
||||
|
||||
$res = $oTargetObj->CheckValue($sAttCode, $value);
|
||||
if ($res !== true)
|
||||
{
|
||||
// $res contains the error description
|
||||
$sMsg = "Value not allowed - $sClass/$iSrcId - $sAttCode: '".$oSubNode."' ; $res";
|
||||
SetupPage::log_error($sMsg);
|
||||
$this->m_aErrors[] = $sMsg;
|
||||
}
|
||||
$oTargetObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->StoreObject($sClass, $oTargetObj, $iSrcId, $bUpdateKeyCacheOnly, $bUpdateKeyCacheOnly);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new ID of an object in the database given its original ID
|
||||
* This may fail (return 0) if the object has not yet been created in the database
|
||||
* This is why the order of the import may be important
|
||||
*/
|
||||
protected function GetObjectKey($sClass, $iSrcId)
|
||||
{
|
||||
if (isset($this->m_aKeys[$sClass]) && isset($this->m_aKeys[$sClass][$iSrcId]))
|
||||
{
|
||||
return $this->m_aKeys[$sClass][$iSrcId];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an object in the database and remember the mapping
|
||||
* between its original ID and the newly created ID in the database
|
||||
*/
|
||||
protected function StoreObject($sClass, $oTargetObj, $iSrcId, $bSearch = false, $bUpdateKeyCacheOnly = false)
|
||||
{
|
||||
$iObjId = 0;
|
||||
try
|
||||
{
|
||||
if ($bSearch)
|
||||
{
|
||||
// Check if the object does not already exist, based on its usual reconciliation keys...
|
||||
$aReconciliationKeys = MetaModel::GetReconcKeys($sClass);
|
||||
if (count($aReconciliationKeys) > 0)
|
||||
{
|
||||
// Some reconciliation keys have been defined, use them to search for the object
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$iConditionsCount = 0;
|
||||
foreach($aReconciliationKeys as $sAttCode)
|
||||
{
|
||||
if ($oTargetObj->Get($sAttCode) != '')
|
||||
{
|
||||
$oSearch->AddCondition($sAttCode, $oTargetObj->Get($sAttCode), '=');
|
||||
$iConditionsCount++;
|
||||
}
|
||||
}
|
||||
if ($iConditionsCount > 0) // Search only if there are some valid conditions...
|
||||
{
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
if ($oSet->count() == 1)
|
||||
{
|
||||
// The object already exists, reuse it
|
||||
$oExistingObject = $oSet->Fetch();
|
||||
$iObjId = $oExistingObject->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($iObjId == 0)
|
||||
{
|
||||
if($oTargetObj->IsNew())
|
||||
{
|
||||
if (!$bUpdateKeyCacheOnly)
|
||||
{
|
||||
$iObjId = $oTargetObj->DBInsertNoReload();
|
||||
$this->m_iCountCreated++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iObjId = $oTargetObj->GetKey();
|
||||
if (!$bUpdateKeyCacheOnly)
|
||||
{
|
||||
$oTargetObj->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
SetupPage::log_error("An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage());
|
||||
$this->m_aErrors[] = "An object could not be recorded - $sClass/$iSrcId - ".$e->getMessage();
|
||||
}
|
||||
$aParentClasses = MetaModel::EnumParentClasses($sClass);
|
||||
$aParentClasses[] = $sClass;
|
||||
foreach($aParentClasses as $sObjClass)
|
||||
{
|
||||
$this->m_aKeys[$sObjClass][$iSrcId] = $iObjId;
|
||||
}
|
||||
$this->m_aObjectsCache[$sClass][$iObjId] = $oTargetObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps an external key to its (newly created) value
|
||||
*/
|
||||
|
||||
protected function ResolveExternalKeys()
|
||||
{
|
||||
foreach($this->m_aObjectsCache as $sClass => $oObjList)
|
||||
{
|
||||
foreach($oObjList as $oTargetObj)
|
||||
{
|
||||
$bChanged = false;
|
||||
$sClass = get_class($oTargetObj);
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if ( ($oAttDef->IsExternalKey()) && ($oTargetObj->Get($sAttCode) < 0) ) // Convention unresolved key = negative
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iTempKey = $oTargetObj->Get($sAttCode);
|
||||
|
||||
$iExtKey = $this->GetObjectKey($sTargetClass, -$iTempKey);
|
||||
if ($iExtKey == 0)
|
||||
{
|
||||
$sMsg = "unresolved extkey in $sClass::".$oTargetObj->GetKey()."(".$oTargetObj->GetName().")::$sAttCode=$sTargetClass::$iTempKey";
|
||||
SetupPage::log_warning($sMsg);
|
||||
$this->m_aWarnings[] = $sMsg;
|
||||
//echo "<pre>aKeys[".$sTargetClass."]:\n";
|
||||
//print_r($this->m_aKeys[$sTargetClass]);
|
||||
//echo "</pre>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$bChanged = true;
|
||||
$oTargetObj->Set($sAttCode, $iExtKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($bChanged)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (is_subclass_of($oTargetObj, 'CMDBObject'))
|
||||
{
|
||||
$oTargetObj->DBUpdateTracked($this->m_oChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oTargetObj->DBUpdate();
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->m_aErrors[] = "The object changes could not be tracked - $sClass/$iExtKey - ".$e->getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user