mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-01 07:04:16 +01:00
Compare commits
2 Commits
3.1.0-desi
...
3.1.0-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
85f66f5e0c | ||
|
|
a5c980113b |
@@ -62,10 +62,6 @@ gitGraph
|
||||
commit id: "2022-12-28" tag: "2.7.8"
|
||||
checkout support/3.0
|
||||
commit id: "2023-04-12" tag: "3.0.3"
|
||||
checkout develop
|
||||
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
|
||||
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
|
||||
branch support/3.1 order: 840
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
@@ -2246,27 +2246,3 @@ interface iModuleExtension
|
||||
*/
|
||||
public function __construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* KPI logging extensibility point
|
||||
*
|
||||
* KPI Logger extension
|
||||
*/
|
||||
interface iKPILoggerExtension
|
||||
{
|
||||
/**
|
||||
* Init the statistics collected
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function InitStats();
|
||||
|
||||
/**
|
||||
* Add a new KPI to the stats
|
||||
*
|
||||
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKpiLogData
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function LogOperation($oKpiLogData);
|
||||
}
|
||||
@@ -1166,7 +1166,7 @@ HTML
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param \CMDBObjectSet $oSet
|
||||
* @param array $aExtraParams See possible values in {@see DataTableUIBlockFactory::RenderDataTable()}
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \CoreException
|
||||
@@ -4547,9 +4547,7 @@ HTML;
|
||||
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBInsert()");
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4564,16 +4562,13 @@ HTML;
|
||||
|
||||
protected function DBCloneTracked_Internal($newKey = null)
|
||||
{
|
||||
/** @var cmdbAbstractObject $oNewObj */
|
||||
$oNewObj = MetaModel::GetObject(get_class($this), parent::DBCloneTracked_Internal($newKey));
|
||||
$oNewObj = parent::DBCloneTracked_Internal($newKey);
|
||||
|
||||
// Invoke extensions after insertion (the object must exist, have an id, etc.)
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
|
||||
}
|
||||
|
||||
return $oNewObj;
|
||||
@@ -4610,9 +4605,7 @@ HTML;
|
||||
foreach (MetaModel::EnumPlugins(iApplicationObjectExtension::class) as $oExtensionInstance) {
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnDBUpdate()");
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBUpdate');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4656,9 +4649,7 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
|
||||
}
|
||||
|
||||
return parent::DBDeleteTracked_Internal($oDeletionPlan);
|
||||
@@ -4677,10 +4668,7 @@ HTML;
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$sExtensionClass = get_class($oExtensionInstance);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$bIsModified = $oExtensionInstance->OnIsModified($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified');
|
||||
if ($bIsModified) {
|
||||
if ($oExtensionInstance->OnIsModified($this)) {
|
||||
$this->LogCRUDDebug(__METHOD__, "Calling $sExtensionClass::OnIsModified() -> true");
|
||||
return true;
|
||||
} else {
|
||||
@@ -4736,9 +4724,7 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aNewIssues = $oExtensionInstance->OnCheckToWrite($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite');
|
||||
if (is_array($aNewIssues) && (count($aNewIssues) > 0)) // Some extensions return null instead of an empty array
|
||||
{
|
||||
$this->m_aCheckIssues = array_merge($this->m_aCheckIssues, $aNewIssues);
|
||||
@@ -4786,9 +4772,7 @@ HTML;
|
||||
/** @var \iApplicationObjectExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aNewIssues = $oExtensionInstance->OnCheckToDelete($this);
|
||||
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete');
|
||||
if (is_array($aNewIssues) && count($aNewIssues) > 0)
|
||||
{
|
||||
$this->m_aDeleteIssues = array_merge($this->m_aDeleteIssues, $aNewIssues);
|
||||
|
||||
@@ -918,11 +918,6 @@ class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
|
||||
if (false === $sDashboardFileSanitized) {
|
||||
throw new SecurityException('Invalid dashboard file !');
|
||||
}
|
||||
|
||||
// Search for an eventual user defined dashboard
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
@@ -934,7 +929,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
} else {
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
|
||||
$sDashboardDefinition = @file_get_contents($sDashboardFile);
|
||||
}
|
||||
|
||||
|
||||
@@ -942,7 +937,7 @@ class RuntimeDashboard extends Dashboard
|
||||
$oDashboard = new RuntimeDashboard($sDashBoardId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFileSanitized);
|
||||
$oDashboard->SetDefinitionFile($sDashboardFile);
|
||||
} else {
|
||||
$oDashboard = null;
|
||||
}
|
||||
|
||||
@@ -99,10 +99,4 @@ else
|
||||
Session::Set('itop_env', ITOP_DEFAULT_ENV);
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
try {
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
}
|
||||
catch (MySQLException $e) {
|
||||
IssueLog::Debug($e->getMessage());
|
||||
throw new MySQLException('Could not connect to the DB server', []);
|
||||
}
|
||||
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\UI\Base\iUIBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Service\Module\ModuleService;
|
||||
use ScssPhp\ScssPhp\Compiler;
|
||||
use ScssPhp\ScssPhp\OutputStyle;
|
||||
use ScssPhp\ScssPhp\ValueConverter;
|
||||
@@ -2266,7 +2265,24 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleName($iCallDepth = 0)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1);
|
||||
$sCurrentModuleName = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleName = $sModuleName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2288,7 +2304,24 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleDir($iCallDepth)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleDir($iCallDepth);
|
||||
$sCurrentModuleDir = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleDir = basename($sRootDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleDir;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2303,7 +2336,12 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleUrl()
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleUrl(1);
|
||||
$sDir = static::GetCurrentModuleDir(1);
|
||||
if ( $sDir !== '')
|
||||
{
|
||||
return static::GetAbsoluteUrlModulesRoot().'/'.$sDir;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2313,7 +2351,8 @@ SQL;
|
||||
*/
|
||||
public static function GetCurrentModuleSetting($sProperty, $defaultvalue = null)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue);
|
||||
$sModuleName = static::GetCurrentModuleName(1);
|
||||
return MetaModel::GetModuleSetting($sModuleName, $sProperty, $defaultvalue);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2322,7 +2361,12 @@ SQL;
|
||||
*/
|
||||
public static function GetCompiledModuleVersion($sModuleName)
|
||||
{
|
||||
return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName);
|
||||
$aModulesInfo = GetModulesInfo();
|
||||
if (array_key_exists($sModuleName, $aModulesInfo))
|
||||
{
|
||||
return $aModulesInfo[$sModuleName]['version'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2647,26 +2691,24 @@ SQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local path relative to the iTop installation (APPROOT or the given base path)
|
||||
* Returns the local path relative to the iTop installation of an existing file
|
||||
* Dir separator is changed to '/' for consistency among the different OS
|
||||
*
|
||||
* @param string $sAbsolutePath absolute path
|
||||
* @param string $sBasePath Base path for the resulting local path (default APPROOT)
|
||||
*
|
||||
* @return false|string The generated local path or false if absolute path is not under the base path
|
||||
* @since 3.1.1 Added base path defaulted to previous version APPROOT
|
||||
* @return false|string
|
||||
*/
|
||||
final public static function LocalPath($sAbsolutePath, string $sBasePath = APPROOT)
|
||||
final public static function LocalPath($sAbsolutePath)
|
||||
{
|
||||
$sRootPath = realpath($sBasePath);
|
||||
$sRootPath = realpath(APPROOT);
|
||||
$sFullPath = realpath($sAbsolutePath);
|
||||
if (($sFullPath === false) || !self::StartsWith($sFullPath, $sRootPath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$sLocalPath = substr($sFullPath, strlen($sRootPath.DIRECTORY_SEPARATOR));
|
||||
|
||||
return str_replace(DIRECTORY_SEPARATOR, '/', $sLocalPath);
|
||||
$sLocalPath = str_replace(DIRECTORY_SEPARATOR, '/', $sLocalPath);
|
||||
return $sLocalPath;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2858,7 +2900,7 @@ HTML;
|
||||
|
||||
// Add already loaded classes
|
||||
$aCurrentClasses = array_fill_keys(get_declared_classes(), '');
|
||||
$aClassMap = array_merge($aCurrentClasses, $aClassMap);
|
||||
$aClassMap = array_merge($aClassMap, $aCurrentClasses);
|
||||
|
||||
foreach ($aClassMap as $sPHPClass => $sPHPFile) {
|
||||
$bSkipped = false;
|
||||
@@ -2883,12 +2925,11 @@ HTML;
|
||||
$bSkipped = true; // file not found
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!$bSkipped){
|
||||
try {
|
||||
$oRefClass = new ReflectionClass($sPHPClass);
|
||||
if ($oRefClass->implementsInterface($sInterface) &&
|
||||
!$oRefClass->isInterface() && !$oRefClass->isAbstract() && !$oRefClass->isTrait()) {
|
||||
if ($oRefClass->implementsInterface($sInterface) && $oRefClass->isInstantiable()) {
|
||||
$aMatchingClasses[] = $sPHPClass;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
|
||||
@@ -45,7 +45,6 @@ define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
|
||||
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
|
||||
|
||||
$fItopStarted = microtime(true);
|
||||
$iItopInitialMemory = memory_get_usage(true);
|
||||
|
||||
if (!isset($GLOBALS['bBypassAutoload']) || $GLOBALS['bBypassAutoload'] == false) {
|
||||
require_once APPROOT.'/lib/autoload.php';
|
||||
|
||||
@@ -419,7 +419,6 @@ class MyHelpers
|
||||
//}
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,3 +523,5 @@ class Str
|
||||
return (strtolower($sString) == $sString);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -607,9 +607,8 @@ class CMDBSource
|
||||
{
|
||||
self::LogDeadLock($e, true);
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
|
||||
} finally {
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
}
|
||||
}
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
if ($oResult === false) {
|
||||
$aContext = array('query' => $sSql);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get iTop core version
|
||||
*/
|
||||
define('ITOP_VERSION', '3.1.1-dev');
|
||||
define('ITOP_VERSION', '3.1.0-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
@@ -656,22 +656,22 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_transport_smtp.allow_self_signed' => [
|
||||
'email_transport_smtp.allow_self_signed' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Allow self signed peer certificates',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'email_transport_smtp.verify_peer' => [
|
||||
),
|
||||
'email_transport_smtp.verify_peer' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Verify peer certificate',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
),
|
||||
'email_css' => [
|
||||
'type' => 'string',
|
||||
'description' => 'CSS that will override the standard stylesheet used for the notifications',
|
||||
@@ -1069,14 +1069,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'log_kpi_generate_legacy_report' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Generate the legacy KPI report (kpi.html)',
|
||||
'default' => true,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'max_linkset_output' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.',
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* This file is only here for compatibility reasons.
|
||||
* It will be removed in future iTop versions (N°6533)
|
||||
* This file is only here for compatibility issues. Will be removed in iTop 3.1.0 (N°3664)
|
||||
*
|
||||
* @deprecated 3.0.0 N°3663 Exception classes were moved to `/application/exceptions`, use autoloader instead of require !
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../approot.inc.php';
|
||||
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions and can be used directly with the autoloader');
|
||||
require_once '../approot.inc.php';
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile('Classes were moved to /application/exceptions');
|
||||
|
||||
@@ -188,8 +188,8 @@ final class ItopCounter
|
||||
|
||||
if (!$hDBLink)
|
||||
{
|
||||
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
|
||||
}
|
||||
throw new Exception("Could not connect to the DB server (host=$sDBHost, user=$sDBUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
}
|
||||
|
||||
return $hDBLink;
|
||||
}
|
||||
|
||||
@@ -1144,9 +1144,7 @@ abstract class DBObject implements iDisplay
|
||||
return; //skip!
|
||||
}
|
||||
$this->FireEventComputeValues();
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->ComputeValues();
|
||||
$oKPI->ComputeStatsForExtension($this, 'ComputeValues');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2482,6 +2480,7 @@ abstract class DBObject implements iDisplay
|
||||
{
|
||||
$this->m_aCheckIssues = array();
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
if ($bDoComputeValues) {
|
||||
$this->DoComputeValues();
|
||||
}
|
||||
@@ -2491,9 +2490,8 @@ abstract class DBObject implements iDisplay
|
||||
$this->FireEventCheckToWrite();
|
||||
$this->SetReadWrite();
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->DoCheckToWrite();
|
||||
$oKPI->ComputeStatsForExtension($this, 'DoCheckToWrite');
|
||||
$oKPI->ComputeStats('CheckToWrite', get_class($this));
|
||||
if (count($this->m_aCheckIssues) == 0)
|
||||
{
|
||||
$this->m_bCheckStatus = true;
|
||||
@@ -3116,9 +3114,7 @@ abstract class DBObject implements iDisplay
|
||||
|
||||
// Ensure the update of the values (we are accessing the data directly)
|
||||
$this->DoComputeValues();
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->OnInsert();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnInsert');
|
||||
|
||||
$this->FireEventBeforeWrite();
|
||||
|
||||
@@ -3174,9 +3170,7 @@ abstract class DBObject implements iDisplay
|
||||
$this->DBInsertSingleTable($sParentClass);
|
||||
}
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->OnObjectKeyReady();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnObjectKeyReady');
|
||||
$this->UpdateCurrentObjectInCrudStack();
|
||||
|
||||
$this->DBWriteLinks();
|
||||
@@ -3253,9 +3247,7 @@ abstract class DBObject implements iDisplay
|
||||
public function PostInsertActions(): void
|
||||
{
|
||||
$this->FireEventAfterWrite([], true);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->AfterInsert();
|
||||
$oKPI->ComputeStatsForExtension($this, 'AfterInsert');
|
||||
|
||||
// Activate any existing trigger
|
||||
$sClass = get_class($this);
|
||||
@@ -3353,9 +3345,7 @@ abstract class DBObject implements iDisplay
|
||||
try {
|
||||
$this->DoComputeValues();
|
||||
$this->ComputeStopWatchesDeadline(false);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->OnUpdate();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnUpdate');
|
||||
|
||||
$this->FireEventBeforeWrite();
|
||||
|
||||
@@ -3569,9 +3559,7 @@ abstract class DBObject implements iDisplay
|
||||
public function PostUpdateActions(array $aChanges): void
|
||||
{
|
||||
$this->FireEventAfterWrite($aChanges, false);
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->AfterUpdate();
|
||||
$oKPI->ComputeStatsForExtension($this, 'AfterUpdate');
|
||||
|
||||
// - TriggerOnObjectUpdate
|
||||
$aParams = array('class_list' => MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL));
|
||||
@@ -3798,9 +3786,7 @@ abstract class DBObject implements iDisplay
|
||||
return;
|
||||
}
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->OnDelete();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnDelete');
|
||||
|
||||
// Activate any existing trigger
|
||||
$sClass = get_class($this);
|
||||
@@ -3908,9 +3894,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
$this->FireEventAfterDelete();
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->AfterDelete();
|
||||
$oKPI->ComputeStatsForExtension($this, 'AfterDelete');
|
||||
|
||||
|
||||
$this->m_bIsInDB = false;
|
||||
|
||||
@@ -767,10 +767,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
|
||||
try
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->m_oSQLResult = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, $this->GetRealSortOrder(), $this->m_iLimitCount, $this->m_iLimitStart, false);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
} catch (MySQLException $e)
|
||||
{
|
||||
// 1116 = ER_TOO_MANY_TABLES
|
||||
@@ -850,11 +847,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), 0, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -865,42 +859,6 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBSearch $oFilter
|
||||
* @param array $aOrder
|
||||
* @param int $iLimitCount
|
||||
* @param int $iLimitStart
|
||||
* @param bool $bCount
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function GetPseudoOQL($oFilter, $aOrder, $iLimitCount, $iLimitStart, $bCount)
|
||||
{
|
||||
$sOQL = '';
|
||||
if ($bCount) {
|
||||
$sOQL .= 'COUNT ';
|
||||
}
|
||||
$sOQL .= $oFilter->ToOQL();
|
||||
|
||||
if ($iLimitCount > 0) {
|
||||
$sOQL .= ' LIMIT ';
|
||||
if ($iLimitStart > 0) {
|
||||
$sOQL .= "$iLimitStart, ";
|
||||
}
|
||||
$sOQL .= "$iLimitCount";
|
||||
}
|
||||
|
||||
if (count($aOrder) > 0) {
|
||||
$sOQL .= ' ORDER BY ';
|
||||
$aOrderBy = [];
|
||||
foreach ($aOrder as $sAttCode => $bAsc) {
|
||||
$aOrderBy[] = $sAttCode.' '.($bAsc ? 'ASC' : 'DESC');
|
||||
}
|
||||
$sOQL .= implode(', ', $aOrderBy);
|
||||
}
|
||||
return $sOQL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the count exceeds a given limit
|
||||
*
|
||||
@@ -917,11 +875,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if ($resQuery)
|
||||
{
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -932,7 +887,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount = $this->m_iNumTotalDBRows;
|
||||
@@ -957,11 +912,8 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
if (is_null($this->m_iNumTotalDBRows))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
|
||||
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
|
||||
if ($resQuery)
|
||||
{
|
||||
$aRow = CMDBSource::FetchArray($resQuery);
|
||||
@@ -972,7 +924,7 @@ class DBObjectSet implements iDBObjectSetIterator
|
||||
{
|
||||
$iCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iCount = $this->m_iNumTotalDBRows;
|
||||
|
||||
@@ -1,14 +1,27 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
use Combodo\iTop\Core\Kpi\KpiLogData;
|
||||
use Combodo\iTop\Service\Module\ModuleService;
|
||||
// Copyright (C) 2010-2023 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/>
|
||||
|
||||
|
||||
/**
|
||||
* Measures operations duration, memory usage, etc. (and some other KPIs)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class ExecutionKPI
|
||||
@@ -17,8 +30,6 @@ class ExecutionKPI
|
||||
static protected $m_bEnabled_Memory = false;
|
||||
static protected $m_bBlameCaller = false;
|
||||
static protected $m_sAllowedUser = '*';
|
||||
static protected $m_bGenerateLegacyReport = true;
|
||||
static protected $m_fSlowQueries = 0;
|
||||
|
||||
static protected $m_aStats = []; // Recurrent operations
|
||||
static protected $m_aExecData = []; // One shot operations
|
||||
@@ -75,39 +86,14 @@ class ExecutionKPI
|
||||
return false;
|
||||
}
|
||||
|
||||
static public function SetGenerateLegacyReport($bReportExtensionsOnly)
|
||||
{
|
||||
self::$m_bGenerateLegacyReport = $bReportExtensionsOnly;
|
||||
}
|
||||
|
||||
static public function SetSlowQueries($fSlowQueries)
|
||||
{
|
||||
self::$m_fSlowQueries = $fSlowQueries;
|
||||
}
|
||||
|
||||
static public function GetDescription()
|
||||
{
|
||||
$aFeatures = array();
|
||||
if (self::$m_bEnabled_Duration) $aFeatures[] = 'Duration';
|
||||
if (self::$m_bEnabled_Memory) $aFeatures[] = 'Memory usage';
|
||||
$sFeatures = 'Measures: '.implode(', ', $aFeatures);
|
||||
$sFeatures = implode(', ', $aFeatures);
|
||||
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
|
||||
$sSlowQueries = '';
|
||||
if (self::$m_fSlowQueries > 0) {
|
||||
$sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s";
|
||||
}
|
||||
|
||||
$aExtensions = [];
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$aExtensions[] = ModuleService::GetInstance()->GetModuleNameFromObject($oExtensionInstance);
|
||||
}
|
||||
$sExtensions = '';
|
||||
if (count($aExtensions) > 0) {
|
||||
$sExtensions = '. KPI Extensions: ['.implode(', ', $aExtensions).']';
|
||||
}
|
||||
|
||||
return "KPI logging is active for $sFor. $sFeatures$sSlowQueries$sExtensions";
|
||||
return "KPI logging is active for $sFor. Measures: $sFeatures";
|
||||
}
|
||||
|
||||
static public function ReportStats()
|
||||
@@ -115,28 +101,7 @@ class ExecutionKPI
|
||||
if (!self::IsEnabled()) return;
|
||||
|
||||
global $fItopStarted;
|
||||
global $iItopInitialMemory;
|
||||
$sExecId = microtime(); // id to differentiate the hrefs!
|
||||
$sRequest = $_SERVER['REQUEST_URI'].' ('.$_SERVER['REQUEST_METHOD'].')';
|
||||
if (isset($_POST['operation'])) {
|
||||
$sRequest .= ' operation: '.$_POST['operation'];
|
||||
}
|
||||
|
||||
$fStop = MyHelpers::getmicrotime();
|
||||
if (($fStop - $fItopStarted) > self::$m_fSlowQueries) {
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$oKPILogData = new KpiLogData(KpiLogData::TYPE_REQUEST, 'Page', $sRequest, $fItopStarted, $fStop, '', $iItopInitialMemory, $iCurrentMemory, $iPeakMemory);
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!self::$m_bGenerateLegacyReport) {
|
||||
return;
|
||||
}
|
||||
|
||||
$aBeginTimes = array();
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
@@ -149,9 +114,9 @@ class ExecutionKPI
|
||||
|
||||
$sHtml = "<hr/>";
|
||||
$sHtml .= "<div style=\"background-color: grey; padding: 10px;\">";
|
||||
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>";
|
||||
$sHtml .= "<h3><a name=\"".md5($sExecId)."\">KPIs</a> - ".$_SERVER['REQUEST_URI']." (".$_SERVER['REQUEST_METHOD'].")</h3>";
|
||||
$oStarted = DateTime::createFromFormat('U.u', $fItopStarted);
|
||||
$sHtml .= '<p>'.$oStarted->format('Y-m-d H:i:s.u').'</p>';
|
||||
$sHtml .= "<p>".$oStarted->format('Y-m-d H:i:s.u')."</p>";
|
||||
$sHtml .= "<p>log_kpi_user_id: ".UserRights::GetUserId()."</p>";
|
||||
$sHtml .= "<div>";
|
||||
$sHtml .= "<table border=\"1\" style=\"$sTableStyle\">";
|
||||
@@ -292,7 +257,7 @@ class ExecutionKPI
|
||||
$sTotalInter = round($fTotalInter, 3);
|
||||
$sMinInter = round($fMinInter, 3);
|
||||
$sMaxInter = round($fMaxInter, 3);
|
||||
if (($fTotalInter >= self::$m_fSlowQueries))
|
||||
if (($fTotalInter >= $fSlowQueries))
|
||||
{
|
||||
if ($bDisplayHeader)
|
||||
{
|
||||
@@ -320,19 +285,37 @@ class ExecutionKPI
|
||||
self::Report($sHtml);
|
||||
}
|
||||
|
||||
public static function InitStats()
|
||||
{
|
||||
// Invoke extensions to initialize the KPI statistics
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$oExtensionInstance->InitStats();
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->ResetCounters();
|
||||
}
|
||||
self::Push($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stack executions to remove children duration from stats
|
||||
*
|
||||
* @param \ExecutionKPI $oExecutionKPI
|
||||
*/
|
||||
private static function Push(ExecutionKPI $oExecutionKPI)
|
||||
{
|
||||
self::$m_aExecutionStack[] = $oExecutionKPI;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop current child and count its duration in its parent
|
||||
*
|
||||
* @param float|int $fChildDuration
|
||||
*/
|
||||
private static function Pop(float $fChildDuration = 0)
|
||||
{
|
||||
array_pop(self::$m_aExecutionStack);
|
||||
// Update the parent's children duration
|
||||
$oPrevExecutionKPI = end(self::$m_aExecutionStack);
|
||||
if ($oPrevExecutionKPI) {
|
||||
$oPrevExecutionKPI->m_fChildrenDuration += $fChildDuration;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the duration since startup, and reset the counter for the next measure
|
||||
//
|
||||
@@ -340,15 +323,9 @@ class ExecutionKPI
|
||||
{
|
||||
global $fItopStarted;
|
||||
|
||||
if (!self::IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$aNewEntry = null;
|
||||
|
||||
$fStarted = $this->m_fStarted;
|
||||
$fStopped = $this->m_fStarted;
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$aNewEntry = array(
|
||||
'op' => $sOperationDesc,
|
||||
@@ -359,9 +336,6 @@ class ExecutionKPI
|
||||
$this->m_fStarted = $fStopped;
|
||||
}
|
||||
|
||||
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
|
||||
$iCurrentMemory = 0;
|
||||
$iPeakMemory = 0;
|
||||
if (self::$m_bEnabled_Memory)
|
||||
{
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
@@ -371,103 +345,40 @@ class ExecutionKPI
|
||||
}
|
||||
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
|
||||
$aNewEntry['mem_end'] = $iCurrentMemory;
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
$aNewEntry['mem_peak'] = $iPeakMemory;
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
$aNewEntry['mem_peak'] = memory_get_peak_usage();
|
||||
}
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_iInitialMemory = $iCurrentMemory;
|
||||
}
|
||||
|
||||
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) {
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach(MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance)
|
||||
{
|
||||
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_REPORT,
|
||||
'Step',
|
||||
$sOperationDesc,
|
||||
$fStarted,
|
||||
$fStopped,
|
||||
$sExtension,
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory);
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($aNewEntry) && self::$m_bGenerateLegacyReport)
|
||||
if (!is_null($aNewEntry))
|
||||
{
|
||||
self::$m_aExecData[] = $aNewEntry;
|
||||
}
|
||||
$this->ResetCounters();
|
||||
}
|
||||
|
||||
public function ComputeStatsForExtension($object, $sMethod)
|
||||
{
|
||||
if (!self::IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sSignature = ModuleService::GetInstance()->GetModuleMethodSignature($object, $sMethod);
|
||||
if (utils::StartsWith($sSignature, '[')) {
|
||||
$this->ComputeStats('Extension', $sSignature);
|
||||
}
|
||||
}
|
||||
|
||||
public function ComputeStats($sOperation, $sArguments)
|
||||
{
|
||||
if (!self::IsEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fDuration = 0;
|
||||
if (self::$m_bEnabled_Duration) {
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$fDuration = $fStopped - $this->m_fStarted;
|
||||
$aCallstack = [];
|
||||
if (self::$m_bGenerateLegacyReport) {
|
||||
if (self::$m_bBlameCaller) {
|
||||
$aCallstack = MyHelpers::get_callstack(1);
|
||||
self::$m_aStats[$sOperation][$sArguments][] = [
|
||||
'time' => $fDuration,
|
||||
'callers' => $aCallstack,
|
||||
];
|
||||
} else {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = [
|
||||
'time' => $fDuration
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
|
||||
$iCurrentMemory = 0;
|
||||
$iPeakMemory = 0;
|
||||
if (self::$m_bEnabled_Memory)
|
||||
{
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
$iPeakMemory = self::memory_get_peak_usage();
|
||||
}
|
||||
|
||||
// Invoke extensions to log the KPI operation
|
||||
/** @var \iKPILoggerExtension $oExtensionInstance */
|
||||
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
|
||||
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
|
||||
$oKPILogData = new KpiLogData(
|
||||
KpiLogData::TYPE_STATS,
|
||||
$sOperation,
|
||||
$sArguments,
|
||||
$this->m_fStarted,
|
||||
$fStopped,
|
||||
$sExtension,
|
||||
$iInitialMemory,
|
||||
$iCurrentMemory,
|
||||
$iPeakMemory,
|
||||
$aCallstack);
|
||||
$oExtensionInstance->LogOperation($oKPILogData);
|
||||
}
|
||||
}
|
||||
$fSelfDuration = $fDuration - $this->m_fChildrenDuration;
|
||||
if (self::$m_bBlameCaller) {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = array(
|
||||
'time' => $fSelfDuration,
|
||||
'callers' => MyHelpers::get_callstack(1),
|
||||
);
|
||||
} else {
|
||||
self::$m_aStats[$sOperation][$sArguments][] = array(
|
||||
'time' => $fSelfDuration,
|
||||
);
|
||||
}
|
||||
}
|
||||
self::Pop($fDuration);
|
||||
}
|
||||
|
||||
protected function ResetCounters()
|
||||
@@ -497,7 +408,35 @@ class ExecutionKPI
|
||||
|
||||
static protected function memory_get_usage()
|
||||
{
|
||||
return memory_get_usage(true);
|
||||
if (function_exists('memory_get_usage'))
|
||||
{
|
||||
return memory_get_usage(true);
|
||||
}
|
||||
|
||||
// Copied from the PHP manual
|
||||
//
|
||||
//If its Windows
|
||||
//Tested on Win XP Pro SP2. Should work on Win 2003 Server too
|
||||
//Doesn't work for 2000
|
||||
//If you need it to work for 2000 look at http://us2.php.net/manual/en/function.memory-get-usage.php#54642
|
||||
if (substr(PHP_OS,0,3) == 'WIN')
|
||||
{
|
||||
$output = array();
|
||||
exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);
|
||||
|
||||
return preg_replace( '/[\D]/', '', $output[5] ) * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
//We now assume the OS is UNIX
|
||||
//Tested on Mac OS X 10.4.6 and Linux Red Hat Enterprise 4
|
||||
//This should work on most UNIX systems
|
||||
$pid = getmypid();
|
||||
exec("ps -eo%mem,rss,pid | grep $pid", $output);
|
||||
$output = explode(" ", $output[0]);
|
||||
//rss is given in 1024 byte units
|
||||
return $output[1] * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
static public function memory_get_peak_usage($bRealUsage = false)
|
||||
|
||||
@@ -6376,9 +6376,7 @@ abstract class MetaModel
|
||||
|
||||
ExecutionKPI::EnableDuration(self::$m_oConfig->Get('log_kpi_duration'));
|
||||
ExecutionKPI::EnableMemory(self::$m_oConfig->Get('log_kpi_memory'));
|
||||
ExecutionKPI::SetAllowedUser(self::$m_oConfig->Get('log_kpi_user_id'));
|
||||
ExecutionKPI::SetGenerateLegacyReport(self::$m_oConfig->Get('log_kpi_generate_legacy_report'));
|
||||
ExecutionKPI::SetSlowQueries(self::$m_oConfig->Get('log_kpi_slow_queries'));
|
||||
ExecutionKPI::SetAllowedUser(self::$m_oConfig->Get('log_kpi_user_id'));
|
||||
|
||||
self::$m_bSkipCheckToWrite = self::$m_oConfig->Get('skip_check_to_write');
|
||||
self::$m_bSkipCheckExtKeys = self::$m_oConfig->Get('skip_check_ext_keys');
|
||||
@@ -6497,7 +6495,6 @@ abstract class MetaModel
|
||||
|
||||
CMDBSource::InitFromConfig(self::$m_oConfig);
|
||||
// Later when timezone implementation is correctly done: CMDBSource::SetTimezone($sDBTimezone);
|
||||
ExecutionKPI::InitStats();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7635,7 +7632,6 @@ abstract class MetaModel
|
||||
'ModuleHandlerApiInterface',
|
||||
'iNewsroomProvider',
|
||||
'iModuleExtension',
|
||||
'iKPILoggerExtension',
|
||||
];
|
||||
foreach ($aInterfaces as $sInterface) {
|
||||
self::$m_aExtensionClassNames[$sInterface] = array();
|
||||
|
||||
@@ -257,7 +257,7 @@ class iTopMutex
|
||||
$this->hDBLink = CMDBSource::GetMysqliInstance($sServer, $sUser, $sPwd, $sSource, $bTlsEnabled, $sTlsCA, false);
|
||||
|
||||
if (!$this->hDBLink) {
|
||||
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
|
||||
throw new Exception("Could not connect to the DB server (host=$sServer, user=$sUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
}
|
||||
|
||||
// Make sure that the server variable `wait_timeout` is at least 86400 seconds for this connection,
|
||||
|
||||
@@ -121,9 +121,7 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive())
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:FAQ/Attribute:category_id+' => '',
|
||||
'Class:FAQ/Attribute:category_name' => '类别名称',
|
||||
'Class:FAQ/Attribute:category_name+' => '',
|
||||
'Class:FAQ/Attribute:error_code' => '错误编码',
|
||||
'Class:FAQ/Attribute:error_code' => '错误代码',
|
||||
'Class:FAQ/Attribute:error_code+' => '',
|
||||
'Class:FAQ/Attribute:key_words' => '关键字',
|
||||
'Class:FAQ/Attribute:key_words+' => '',
|
||||
|
||||
@@ -66,11 +66,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Incident/Attribute:status+' => '',
|
||||
'Class:Incident/Attribute:status/Value:new' => '新建',
|
||||
'Class:Incident/Attribute:status/Value:new+' => '',
|
||||
'Class:Incident/Attribute:status/Value:escalated_tto' => '已升级TTO',
|
||||
'Class:Incident/Attribute:status/Value:escalated_tto' => '已升级响应时间',
|
||||
'Class:Incident/Attribute:status/Value:escalated_tto+' => '',
|
||||
'Class:Incident/Attribute:status/Value:assigned' => '已分配',
|
||||
'Class:Incident/Attribute:status/Value:assigned+' => '',
|
||||
'Class:Incident/Attribute:status/Value:escalated_ttr' => '已升级TTR',
|
||||
'Class:Incident/Attribute:status/Value:escalated_ttr' => '已升级解决时间',
|
||||
'Class:Incident/Attribute:status/Value:escalated_ttr+' => '',
|
||||
'Class:Incident/Attribute:status/Value:waiting_for_approval' => '等待批准',
|
||||
'Class:Incident/Attribute:status/Value:waiting_for_approval+' => '',
|
||||
@@ -90,8 +90,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Incident/Attribute:impact/Value:3+' => '',
|
||||
'Class:Incident/Attribute:priority' => '优先级',
|
||||
'Class:Incident/Attribute:priority+' => '',
|
||||
'Class:Incident/Attribute:priority/Value:1' => '紧急',
|
||||
'Class:Incident/Attribute:priority/Value:1+' => '紧急',
|
||||
'Class:Incident/Attribute:priority/Value:1' => '非常高',
|
||||
'Class:Incident/Attribute:priority/Value:1+' => '非常高',
|
||||
'Class:Incident/Attribute:priority/Value:2' => '高',
|
||||
'Class:Incident/Attribute:priority/Value:2+' => '高',
|
||||
'Class:Incident/Attribute:priority/Value:3' => '中',
|
||||
@@ -100,8 +100,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Incident/Attribute:priority/Value:4+' => '低',
|
||||
'Class:Incident/Attribute:urgency' => '紧急度',
|
||||
'Class:Incident/Attribute:urgency+' => '',
|
||||
'Class:Incident/Attribute:urgency/Value:1' => '紧急',
|
||||
'Class:Incident/Attribute:urgency/Value:1+' => '紧急',
|
||||
'Class:Incident/Attribute:urgency/Value:1' => '非常高',
|
||||
'Class:Incident/Attribute:urgency/Value:1+' => '非常高',
|
||||
'Class:Incident/Attribute:urgency/Value:2' => '高',
|
||||
'Class:Incident/Attribute:urgency/Value:2+' => '高',
|
||||
'Class:Incident/Attribute:urgency/Value:3' => '中',
|
||||
@@ -136,7 +136,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Incident/Attribute:escalation_flag/Value:no+' => '否',
|
||||
'Class:Incident/Attribute:escalation_flag/Value:yes' => '是',
|
||||
'Class:Incident/Attribute:escalation_flag/Value:yes+' => '是',
|
||||
'Class:Incident/Attribute:escalation_reason' => '升级原因',
|
||||
'Class:Incident/Attribute:escalation_reason' => '热门',
|
||||
'Class:Incident/Attribute:escalation_reason+' => '',
|
||||
'Class:Incident/Attribute:assignment_date' => '分配日期',
|
||||
'Class:Incident/Attribute:assignment_date+' => '',
|
||||
@@ -146,21 +146,21 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Incident/Attribute:last_pending_date+' => '',
|
||||
'Class:Incident/Attribute:cumulatedpending' => '累计待定',
|
||||
'Class:Incident/Attribute:cumulatedpending+' => '',
|
||||
'Class:Incident/Attribute:tto' => 'TTO',
|
||||
'Class:Incident/Attribute:tto+' => '响应时间',
|
||||
'Class:Incident/Attribute:ttr' => 'TTR',
|
||||
'Class:Incident/Attribute:ttr+' => '解决时限',
|
||||
'Class:Incident/Attribute:tto_escalation_deadline' => 'TTO截止日期',
|
||||
'Class:Incident/Attribute:tto' => '响应时间',
|
||||
'Class:Incident/Attribute:tto+' => '',
|
||||
'Class:Incident/Attribute:ttr' => '解决时间',
|
||||
'Class:Incident/Attribute:ttr+' => '',
|
||||
'Class:Incident/Attribute:tto_escalation_deadline' => '响应时间截止',
|
||||
'Class:Incident/Attribute:tto_escalation_deadline+' => '',
|
||||
'Class:Incident/Attribute:sla_tto_passed' => 'SLA TTO 合格',
|
||||
'Class:Incident/Attribute:sla_tto_passed' => '超过SLA响应时间',
|
||||
'Class:Incident/Attribute:sla_tto_passed+' => '',
|
||||
'Class:Incident/Attribute:sla_tto_over' => 'SLA TTO 超时',
|
||||
'Class:Incident/Attribute:sla_tto_over' => 'SLA响应时间结束',
|
||||
'Class:Incident/Attribute:sla_tto_over+' => '',
|
||||
'Class:Incident/Attribute:ttr_escalation_deadline' => 'TTR截止日期',
|
||||
'Class:Incident/Attribute:ttr_escalation_deadline' => '解决时间截止',
|
||||
'Class:Incident/Attribute:ttr_escalation_deadline+' => '',
|
||||
'Class:Incident/Attribute:sla_ttr_passed' => 'SLA TTR 合格',
|
||||
'Class:Incident/Attribute:sla_ttr_passed' => '超过SLA解决时间',
|
||||
'Class:Incident/Attribute:sla_ttr_passed+' => '',
|
||||
'Class:Incident/Attribute:sla_ttr_over' => 'SLA TTR 超时',
|
||||
'Class:Incident/Attribute:sla_ttr_over' => 'SLA解决时间结束',
|
||||
'Class:Incident/Attribute:sla_ttr_over+' => '',
|
||||
'Class:Incident/Attribute:time_spent' => '耗时',
|
||||
'Class:Incident/Attribute:time_spent+' => '',
|
||||
@@ -182,7 +182,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Incident/Attribute:resolution_code/Value:training+' => '培训',
|
||||
'Class:Incident/Attribute:solution' => '解决方案',
|
||||
'Class:Incident/Attribute:solution+' => '',
|
||||
'Class:Incident/Attribute:pending_reason' => '待定原因',
|
||||
'Class:Incident/Attribute:pending_reason' => '待定的原因',
|
||||
'Class:Incident/Attribute:pending_reason+' => '',
|
||||
'Class:Incident/Attribute:parent_incident_id' => '父级事件',
|
||||
'Class:Incident/Attribute:parent_incident_id+' => '',
|
||||
|
||||
@@ -66,7 +66,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:KnownError/Attribute:workaround+' => '',
|
||||
'Class:KnownError/Attribute:solution' => '解决方案',
|
||||
'Class:KnownError/Attribute:solution+' => '',
|
||||
'Class:KnownError/Attribute:error_code' => '错误编码',
|
||||
'Class:KnownError/Attribute:error_code' => '错误代码',
|
||||
'Class:KnownError/Attribute:error_code+' => '',
|
||||
'Class:KnownError/Attribute:domain' => '类型',
|
||||
'Class:KnownError/Attribute:domain+' => '',
|
||||
|
||||
@@ -230,7 +230,6 @@ HTML
|
||||
$this->Set('refresh_token', $oAccessToken->getRefreshToken());
|
||||
}
|
||||
$this->Set('status', 'active');
|
||||
$this->AllowWrite();
|
||||
$this->DBUpdate();
|
||||
}
|
||||
]]></code>
|
||||
|
||||
@@ -11,7 +11,6 @@ use Combodo\iTop\Application\TwigBase\Controller\Controller;
|
||||
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
|
||||
use Dict;
|
||||
use IssueLog;
|
||||
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
use WebPage;
|
||||
@@ -66,15 +65,13 @@ class AjaxOauthClientController extends Controller
|
||||
}
|
||||
if (isset($aQuery['code'])) {
|
||||
$sCode = $aQuery['code'];
|
||||
try {
|
||||
$oAccessToken = OAuthClientProviderFactory::GetAccessTokenFromCode($oOAuthClient, $sCode);
|
||||
$oOAuthClient->SetAccessToken($oAccessToken);
|
||||
$aResult['status'] = 'success';
|
||||
}
|
||||
catch (IdentityProviderException $e) {
|
||||
$aResult['status'] = 'error';
|
||||
$aResult['error_description'] = $e->getMessage();
|
||||
}
|
||||
$oAccessToken = OAuthClientProviderFactory::GetAccessTokenFromCode($oOAuthClient, $sCode);
|
||||
|
||||
$oOAuthClient->SetAccessToken($oAccessToken);
|
||||
|
||||
|
||||
|
||||
$aResult['status'] = 'success';
|
||||
}
|
||||
} else {
|
||||
$aResult['status'] = 'error';
|
||||
|
||||
@@ -103,8 +103,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Problem/Attribute:impact/Value:3+' => '',
|
||||
'Class:Problem/Attribute:urgency' => '紧急度',
|
||||
'Class:Problem/Attribute:urgency+' => '',
|
||||
'Class:Problem/Attribute:urgency/Value:1' => '紧急',
|
||||
'Class:Problem/Attribute:urgency/Value:1+' => '紧急',
|
||||
'Class:Problem/Attribute:urgency/Value:1' => '非常高',
|
||||
'Class:Problem/Attribute:urgency/Value:1+' => '非常高',
|
||||
'Class:Problem/Attribute:urgency/Value:2' => '高',
|
||||
'Class:Problem/Attribute:urgency/Value:2+' => '高',
|
||||
'Class:Problem/Attribute:urgency/Value:3' => '中',
|
||||
@@ -113,8 +113,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:Problem/Attribute:urgency/Value:4+' => '低',
|
||||
'Class:Problem/Attribute:priority' => '优先级',
|
||||
'Class:Problem/Attribute:priority+' => '',
|
||||
'Class:Problem/Attribute:priority/Value:1' => '紧急',
|
||||
'Class:Problem/Attribute:priority/Value:1+' => '紧急',
|
||||
'Class:Problem/Attribute:priority/Value:1' => '非常高',
|
||||
'Class:Problem/Attribute:priority/Value:1+' => '非常高',
|
||||
'Class:Problem/Attribute:priority/Value:2' => '高',
|
||||
'Class:Problem/Attribute:priority/Value:2+' => '高',
|
||||
'Class:Problem/Attribute:priority/Value:3' => '中',
|
||||
|
||||
@@ -58,11 +58,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:status+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:new' => '新建',
|
||||
'Class:UserRequest/Attribute:status/Value:new+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_tto' => '已升级TTO',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_tto' => '已升级响应时间',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_tto+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:assigned' => '已分配',
|
||||
'Class:UserRequest/Attribute:status/Value:assigned+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_ttr' => '已升级TTR',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_ttr' => '已升级解决时间',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_ttr+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:waiting_for_approval' => '等待批准',
|
||||
'Class:UserRequest/Attribute:status/Value:waiting_for_approval+' => '',
|
||||
@@ -90,8 +90,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:impact/Value:3+' => '',
|
||||
'Class:UserRequest/Attribute:priority' => '优先级',
|
||||
'Class:UserRequest/Attribute:priority+' => '',
|
||||
'Class:UserRequest/Attribute:priority/Value:1' => '紧急',
|
||||
'Class:UserRequest/Attribute:priority/Value:1+' => '紧急',
|
||||
'Class:UserRequest/Attribute:priority/Value:1' => '非常高',
|
||||
'Class:UserRequest/Attribute:priority/Value:1+' => '非常高',
|
||||
'Class:UserRequest/Attribute:priority/Value:2' => '高',
|
||||
'Class:UserRequest/Attribute:priority/Value:2+' => '高',
|
||||
'Class:UserRequest/Attribute:priority/Value:3' => '中',
|
||||
@@ -100,8 +100,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:priority/Value:4+' => '低',
|
||||
'Class:UserRequest/Attribute:urgency' => '紧急度',
|
||||
'Class:UserRequest/Attribute:urgency+' => '',
|
||||
'Class:UserRequest/Attribute:urgency/Value:1' => '紧急',
|
||||
'Class:UserRequest/Attribute:urgency/Value:1+' => '紧急',
|
||||
'Class:UserRequest/Attribute:urgency/Value:1' => '非常高',
|
||||
'Class:UserRequest/Attribute:urgency/Value:1+' => '非常高',
|
||||
'Class:UserRequest/Attribute:urgency/Value:2' => '高',
|
||||
'Class:UserRequest/Attribute:urgency/Value:2+' => '高',
|
||||
'Class:UserRequest/Attribute:urgency/Value:3' => '中',
|
||||
@@ -134,7 +134,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:servicesubcategory_id+' => '',
|
||||
'Class:UserRequest/Attribute:servicesubcategory_name' => '子服务名称',
|
||||
'Class:UserRequest/Attribute:servicesubcategory_name+' => '',
|
||||
'Class:UserRequest/Attribute:escalation_flag' => '升级标签',
|
||||
'Class:UserRequest/Attribute:escalation_flag' => '是否升级',
|
||||
'Class:UserRequest/Attribute:escalation_flag+' => '',
|
||||
'Class:UserRequest/Attribute:escalation_flag/Value:no' => '否',
|
||||
'Class:UserRequest/Attribute:escalation_flag/Value:no+' => '否',
|
||||
@@ -150,30 +150,30 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:last_pending_date+' => '',
|
||||
'Class:UserRequest/Attribute:cumulatedpending' => '累计待定',
|
||||
'Class:UserRequest/Attribute:cumulatedpending+' => '',
|
||||
'Class:UserRequest/Attribute:tto' => 'TTO',
|
||||
'Class:UserRequest/Attribute:tto' => '响应时间',
|
||||
'Class:UserRequest/Attribute:tto+' => '',
|
||||
'Class:UserRequest/Attribute:ttr' => 'TTR',
|
||||
'Class:UserRequest/Attribute:ttr' => '解决时间',
|
||||
'Class:UserRequest/Attribute:ttr+' => '',
|
||||
'Class:UserRequest/Attribute:tto_escalation_deadline' => 'TTO截止日期',
|
||||
'Class:UserRequest/Attribute:tto_escalation_deadline' => '响应时间截止',
|
||||
'Class:UserRequest/Attribute:tto_escalation_deadline+' => '',
|
||||
'Class:UserRequest/Attribute:sla_tto_passed' => 'SLA TTO 合格',
|
||||
'Class:UserRequest/Attribute:sla_tto_passed' => '超过SLA响应时间',
|
||||
'Class:UserRequest/Attribute:sla_tto_passed+' => '',
|
||||
'Class:UserRequest/Attribute:sla_tto_over' => 'SLA TTO 超时',
|
||||
'Class:UserRequest/Attribute:sla_tto_over' => 'SLA响应时间超过',
|
||||
'Class:UserRequest/Attribute:sla_tto_over+' => '',
|
||||
'Class:UserRequest/Attribute:ttr_escalation_deadline' => 'TTR截止日期',
|
||||
'Class:UserRequest/Attribute:ttr_escalation_deadline' => '解决时间截止',
|
||||
'Class:UserRequest/Attribute:ttr_escalation_deadline+' => '',
|
||||
'Class:UserRequest/Attribute:sla_ttr_passed' => 'SLA TTR 合格',
|
||||
'Class:UserRequest/Attribute:sla_ttr_passed' => '超过SLA解决时间',
|
||||
'Class:UserRequest/Attribute:sla_ttr_passed+' => '',
|
||||
'Class:UserRequest/Attribute:sla_ttr_over' => 'SLA TTR 超时',
|
||||
'Class:UserRequest/Attribute:sla_ttr_over' => 'SLA解决时间超过',
|
||||
'Class:UserRequest/Attribute:sla_ttr_over+' => '',
|
||||
'Class:UserRequest/Attribute:time_spent' => '耗时',
|
||||
'Class:UserRequest/Attribute:time_spent+' => '',
|
||||
'Class:UserRequest/Attribute:resolution_code' => '解决编码',
|
||||
'Class:UserRequest/Attribute:resolution_code' => '解决代码',
|
||||
'Class:UserRequest/Attribute:resolution_code+' => '',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:assistance' => '帮助',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:assistance+' => '帮助',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed' => 'bug修复',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed+' => 'bug修复',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed' => '缺陷修复',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:bug fixed+' => '缺陷修复',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:hardware repair' => '硬件维修',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:hardware repair+' => '硬件维修',
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:other' => '其它',
|
||||
|
||||
@@ -62,11 +62,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:status+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:new' => '新建',
|
||||
'Class:UserRequest/Attribute:status/Value:new+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_tto' => '已升级TTO',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_tto' => '已升级响应时间',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_tto+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:assigned' => '已分配',
|
||||
'Class:UserRequest/Attribute:status/Value:assigned+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_ttr' => '已升级TTR',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_ttr' => '已升级解决时间',
|
||||
'Class:UserRequest/Attribute:status/Value:escalated_ttr+' => '',
|
||||
'Class:UserRequest/Attribute:status/Value:waiting_for_approval' => '等待批准',
|
||||
'Class:UserRequest/Attribute:status/Value:waiting_for_approval+' => '',
|
||||
@@ -156,21 +156,21 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:last_pending_date+' => '',
|
||||
'Class:UserRequest/Attribute:cumulatedpending' => '累计待定',
|
||||
'Class:UserRequest/Attribute:cumulatedpending+' => '',
|
||||
'Class:UserRequest/Attribute:tto' => 'TTO',
|
||||
'Class:UserRequest/Attribute:tto+' => '响应时间',
|
||||
'Class:UserRequest/Attribute:ttr' => 'TTR',
|
||||
'Class:UserRequest/Attribute:ttr+' => '解决时限',
|
||||
'Class:UserRequest/Attribute:tto_escalation_deadline' => 'TTO截止日期',
|
||||
'Class:UserRequest/Attribute:tto' => '响应时间',
|
||||
'Class:UserRequest/Attribute:tto+' => '',
|
||||
'Class:UserRequest/Attribute:ttr' => '解决时间',
|
||||
'Class:UserRequest/Attribute:ttr+' => '',
|
||||
'Class:UserRequest/Attribute:tto_escalation_deadline' => '响应时间期限',
|
||||
'Class:UserRequest/Attribute:tto_escalation_deadline+' => '',
|
||||
'Class:UserRequest/Attribute:sla_tto_passed' => 'SLA TTO 合格',
|
||||
'Class:UserRequest/Attribute:sla_tto_passed' => '超过SLA响应时间',
|
||||
'Class:UserRequest/Attribute:sla_tto_passed+' => '',
|
||||
'Class:UserRequest/Attribute:sla_tto_over' => 'SLA TTO 超时',
|
||||
'Class:UserRequest/Attribute:sla_tto_over' => 'SLA响应时间结束',
|
||||
'Class:UserRequest/Attribute:sla_tto_over+' => '',
|
||||
'Class:UserRequest/Attribute:ttr_escalation_deadline' => 'TTR截止日期',
|
||||
'Class:UserRequest/Attribute:ttr_escalation_deadline' => '解决时间期限',
|
||||
'Class:UserRequest/Attribute:ttr_escalation_deadline+' => '',
|
||||
'Class:UserRequest/Attribute:sla_ttr_passed' => 'SLA TTR 合格',
|
||||
'Class:UserRequest/Attribute:sla_ttr_passed' => '超过SLA解决时间',
|
||||
'Class:UserRequest/Attribute:sla_ttr_passed+' => '',
|
||||
'Class:UserRequest/Attribute:sla_ttr_over' => 'SLA TTR 超时',
|
||||
'Class:UserRequest/Attribute:sla_ttr_over' => 'SLA解决时间结束',
|
||||
'Class:UserRequest/Attribute:sla_ttr_over+' => '',
|
||||
'Class:UserRequest/Attribute:time_spent' => '耗时',
|
||||
'Class:UserRequest/Attribute:time_spent+' => '',
|
||||
@@ -192,7 +192,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:UserRequest/Attribute:resolution_code/Value:training+' => '培训',
|
||||
'Class:UserRequest/Attribute:solution' => '解决方案',
|
||||
'Class:UserRequest/Attribute:solution+' => '',
|
||||
'Class:UserRequest/Attribute:pending_reason' => '待定原因',
|
||||
'Class:UserRequest/Attribute:pending_reason' => '待定的原因',
|
||||
'Class:UserRequest/Attribute:pending_reason+' => '',
|
||||
'Class:UserRequest/Attribute:parent_request_id' => '父级需求',
|
||||
'Class:UserRequest/Attribute:parent_request_id+' => '',
|
||||
|
||||
@@ -389,8 +389,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:SLT/Attribute:name+' => '',
|
||||
'Class:SLT/Attribute:priority' => '优先级',
|
||||
'Class:SLT/Attribute:priority+' => '',
|
||||
'Class:SLT/Attribute:priority/Value:1' => '紧急',
|
||||
'Class:SLT/Attribute:priority/Value:1+' => '紧急',
|
||||
'Class:SLT/Attribute:priority/Value:1' => '非常高',
|
||||
'Class:SLT/Attribute:priority/Value:1+' => '非常高',
|
||||
'Class:SLT/Attribute:priority/Value:2' => '高',
|
||||
'Class:SLT/Attribute:priority/Value:2+' => '高',
|
||||
'Class:SLT/Attribute:priority/Value:3' => '中',
|
||||
@@ -403,15 +403,15 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:SLT/Attribute:request_type/Value:incident+' => '事件',
|
||||
'Class:SLT/Attribute:request_type/Value:service_request' => '服务需求',
|
||||
'Class:SLT/Attribute:request_type/Value:service_request+' => '服务需求',
|
||||
'Class:SLT/Attribute:metric' => '衡量指标',
|
||||
'Class:SLT/Attribute:metric' => '指标',
|
||||
'Class:SLT/Attribute:metric+' => '',
|
||||
'Class:SLT/Attribute:metric/Value:tto' => 'TTO',
|
||||
'Class:SLT/Attribute:metric/Value:tto' => '响应时间',
|
||||
'Class:SLT/Attribute:metric/Value:tto+' => '响应时间',
|
||||
'Class:SLT/Attribute:metric/Value:ttr' => 'TTR',
|
||||
'Class:SLT/Attribute:metric/Value:ttr+' => '解决时限',
|
||||
'Class:SLT/Attribute:metric/Value:ttr' => '解决时间',
|
||||
'Class:SLT/Attribute:metric/Value:ttr+' => '解决时间',
|
||||
'Class:SLT/Attribute:value' => '值',
|
||||
'Class:SLT/Attribute:value+' => '',
|
||||
'Class:SLT/Attribute:unit' => '度量单位',
|
||||
'Class:SLT/Attribute:unit' => '单位',
|
||||
'Class:SLT/Attribute:unit+' => '',
|
||||
'Class:SLT/Attribute:unit/Value:hours' => '小时',
|
||||
'Class:SLT/Attribute:unit/Value:hours+' => '小时',
|
||||
|
||||
@@ -362,8 +362,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:SLT/Attribute:name+' => '',
|
||||
'Class:SLT/Attribute:priority' => '优先级',
|
||||
'Class:SLT/Attribute:priority+' => '',
|
||||
'Class:SLT/Attribute:priority/Value:1' => '紧急',
|
||||
'Class:SLT/Attribute:priority/Value:1+' => '紧急',
|
||||
'Class:SLT/Attribute:priority/Value:1' => '非常高',
|
||||
'Class:SLT/Attribute:priority/Value:1+' => '非常高',
|
||||
'Class:SLT/Attribute:priority/Value:2' => '高',
|
||||
'Class:SLT/Attribute:priority/Value:2+' => '高',
|
||||
'Class:SLT/Attribute:priority/Value:3' => '中',
|
||||
@@ -376,15 +376,15 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:SLT/Attribute:request_type/Value:incident+' => '事件',
|
||||
'Class:SLT/Attribute:request_type/Value:service_request' => '服务需求',
|
||||
'Class:SLT/Attribute:request_type/Value:service_request+' => '服务需求',
|
||||
'Class:SLT/Attribute:metric' => '衡量指标',
|
||||
'Class:SLT/Attribute:metric' => '指标',
|
||||
'Class:SLT/Attribute:metric+' => '',
|
||||
'Class:SLT/Attribute:metric/Value:tto' => 'TTO',
|
||||
'Class:SLT/Attribute:metric/Value:tto' => '响应时间',
|
||||
'Class:SLT/Attribute:metric/Value:tto+' => '响应时间',
|
||||
'Class:SLT/Attribute:metric/Value:ttr' => 'TTR',
|
||||
'Class:SLT/Attribute:metric/Value:ttr+' => '解决时限',
|
||||
'Class:SLT/Attribute:metric/Value:ttr' => '解决时间',
|
||||
'Class:SLT/Attribute:metric/Value:ttr+' => '解决时间',
|
||||
'Class:SLT/Attribute:value' => '值',
|
||||
'Class:SLT/Attribute:value+' => '',
|
||||
'Class:SLT/Attribute:unit' => '度量单位',
|
||||
'Class:SLT/Attribute:unit' => '单位',
|
||||
'Class:SLT/Attribute:unit+' => '',
|
||||
'Class:SLT/Attribute:unit/Value:hours' => '小时',
|
||||
'Class:SLT/Attribute:unit/Value:hours+' => '小时',
|
||||
|
||||
@@ -251,7 +251,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:DocumentNote' => '文档笔记',
|
||||
'Class:DocumentNote+' => '',
|
||||
'Class:DocumentNote/Attribute:text' => '正文',
|
||||
'Class:DocumentNote/Attribute:text' => '文本',
|
||||
'Class:DocumentNote/Attribute:text+' => '',
|
||||
));
|
||||
|
||||
|
||||
@@ -240,9 +240,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:cmdbAbstractObject/Method:ApplyStimulus+' => 'Apply the specified stimulus to the current object',
|
||||
'Class:cmdbAbstractObject/Method:ApplyStimulus/Param:1' => 'Stimulus code',
|
||||
'Class:cmdbAbstractObject/Method:ApplyStimulus/Param:1+' => 'A valid stimulus code for the current class',
|
||||
'Class:ResponseTicketTTO/Interface:iMetricComputer' => 'TTO',
|
||||
'Class:ResponseTicketTTO/Interface:iMetricComputer' => '响应时间',
|
||||
'Class:ResponseTicketTTO/Interface:iMetricComputer+' => 'SLT 的响应时间',
|
||||
'Class:ResponseTicketTTR/Interface:iMetricComputer' => 'TTR',
|
||||
'Class:ResponseTicketTTR/Interface:iMetricComputer+' => 'SLT 的解决时限',
|
||||
'Class:ResponseTicketTTR/Interface:iMetricComputer' => '解决时间',
|
||||
'Class:ResponseTicketTTR/Interface:iMetricComputer+' => 'SLT 的解决时间',
|
||||
));
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
// Display DataTable
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'UI:Datatables:Language:Processing' => '请稍候...',
|
||||
'UI:Datatables:Language:LengthMenu' => '每页 _MENU_ 项',
|
||||
'UI:Datatables:Language:LengthMenu' => '_MENU_ 每页',
|
||||
'UI:Datatables:Language:ZeroRecords' => '未找到相关结果',
|
||||
'UI:Datatables:Language:Info' => '共 _TOTAL_ 项',
|
||||
'UI:Datatables:Language:Info' => '_TOTAL_ 项',
|
||||
'UI:Datatables:Language:InfoEmpty' => '未找到相关信息',
|
||||
'UI:Datatables:Language:EmptyTable' => '表格中暂无数据',
|
||||
'UI:Datatables:Language:Error' => '运行查询时出错',
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
// Navigation menu
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'UI:Layout:NavigationMenu:CompanyLogo:AltText' => '公司logo',
|
||||
|
||||
@@ -20,60 +20,44 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Core:DeletedObjectLabel' => '%1s (已删除)',
|
||||
'Core:DeletedObjectTip' => '对象已被删除于 %1$s (%2$s)',
|
||||
|
||||
'Core:UnknownObjectLabel' => '对象找不到 (class: %1$s, id: %2$d)',
|
||||
'Core:UnknownObjectTip' => 'The object could not be found. It may have been deleted some time ago and the log has been purged since.~~',
|
||||
|
||||
'Core:UniquenessDefaultError' => 'Uniqueness rule \'%1$s\' in error~~',
|
||||
'Core:CheckConsistencyError' => 'Consistency rules not followed: %1$s~~',
|
||||
'Core:CheckValueError' => 'Unexpected value for attribute \'%1$s\' (%2$s) : %3$s~~',
|
||||
|
||||
'Core:AttributeLinkedSet' => '对象数组',
|
||||
'Core:AttributeLinkedSet+' => 'Any kind of objects of the same class or subclass~~',
|
||||
|
||||
'Core:AttributeLinkedSetDuplicatesFound' => 'Duplicates in the \'%1$s\' field : %2$s~~',
|
||||
|
||||
'Core:AttributeDashboard' => '仪表盘',
|
||||
'Core:AttributeDashboard+' => '',
|
||||
|
||||
'Core:AttributePhoneNumber' => '电话号码',
|
||||
'Core:AttributePhoneNumber+' => '',
|
||||
|
||||
'Core:AttributeObsolescenceDate' => '报废日期',
|
||||
'Core:AttributeObsolescenceDate+' => '',
|
||||
|
||||
'Core:AttributeTagSet' => '清单',
|
||||
'Core:AttributeTagSet+' => '',
|
||||
'Core:AttributeSet:placeholder' => '请点击这里添加',
|
||||
'Core:AttributeClassAttCodeSet:ItemLabel:AttributeFromClass' => '%1$s (%2$s)~~',
|
||||
'Core:AttributeClassAttCodeSet:ItemLabel:AttributeFromOneChildClass' => '%1$s (%2$s from %3$s)~~',
|
||||
'Core:AttributeClassAttCodeSet:ItemLabel:AttributeFromSeveralChildClasses' => '%1$s (%2$s from child classes)~~',
|
||||
|
||||
'Core:AttributeCaseLog' => '日志',
|
||||
'Core:AttributeCaseLog+' => '',
|
||||
|
||||
'Core:AttributeMetaEnum' => 'Computed enum~~',
|
||||
'Core:AttributeMetaEnum+' => '~~',
|
||||
|
||||
'Core:AttributeLinkedSetIndirect' => '对象数组(N-N)',
|
||||
'Core:AttributeLinkedSetIndirect+' => 'Any kind of objects [subclass] of the same class~~',
|
||||
|
||||
'Core:AttributeInteger' => '整数',
|
||||
'Core:AttributeInteger+' => '整数值(可以为负)',
|
||||
|
||||
'Core:AttributeDecimal' => '小数',
|
||||
'Core:AttributeDecimal+' => '小数(可以为负)',
|
||||
|
||||
'Core:AttributeBoolean' => '布尔',
|
||||
'Core:AttributeBoolean+' => '',
|
||||
'Core:AttributeBoolean+' => '布尔',
|
||||
'Core:AttributeBoolean/Value:null' => '',
|
||||
'Core:AttributeBoolean/Value:yes' => '是',
|
||||
'Core:AttributeBoolean/Value:no' => '否',
|
||||
|
||||
'Core:AttributeArchiveFlag' => '是否归档',
|
||||
'Core:AttributeArchiveFlag/Value:yes' => '是',
|
||||
'Core:AttributeArchiveFlag/Value:yes+' => '此对象仅在归档模式可见',
|
||||
@@ -82,7 +66,6 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Core:AttributeArchiveFlag/Label+' => '',
|
||||
'Core:AttributeArchiveDate/Label' => '归档日期',
|
||||
'Core:AttributeArchiveDate/Label+' => '',
|
||||
|
||||
'Core:AttributeObsolescenceFlag' => '是否废弃',
|
||||
'Core:AttributeObsolescenceFlag/Value:yes' => '是',
|
||||
'Core:AttributeObsolescenceFlag/Value:yes+' => 'This object is excluded from the impact analysis, and hidden from search results~~',
|
||||
@@ -91,54 +74,38 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Core:AttributeObsolescenceFlag/Label+' => 'Computed dynamically on other attributes~~',
|
||||
'Core:AttributeObsolescenceDate/Label' => '废弃时间',
|
||||
'Core:AttributeObsolescenceDate/Label+' => 'Approximative date at which the object has been considered obsolete~~',
|
||||
|
||||
'Core:AttributeString' => '字符串',
|
||||
'Core:AttributeString+' => '字符串',
|
||||
|
||||
'Core:AttributeClass' => '类',
|
||||
'Core:AttributeClass+' => '',
|
||||
|
||||
'Core:AttributeClass+' => '类别',
|
||||
'Core:AttributeApplicationLanguage' => '用户语言',
|
||||
'Core:AttributeApplicationLanguage+' => '语言和国家地区(EN US)',
|
||||
|
||||
'Core:AttributeFinalClass' => '类 (auto)',
|
||||
'Core:AttributeFinalClass+' => 'Real class of the object (automatically created by the core)',
|
||||
|
||||
'Core:AttributePassword' => '密码',
|
||||
'Core:AttributePassword+' => '外部设备的密码',
|
||||
|
||||
'Core:AttributeEncryptedString' => '加密字符串',
|
||||
'Core:AttributeEncryptedString+' => 'String encrypted with a local key~~',
|
||||
'Core:AttributeEncryptUnknownLibrary' => '未知的加密库 (%1$s)',
|
||||
'Core:AttributeEncryptFailedToDecrypt' => '** 解密错误 **',
|
||||
|
||||
'Core:AttributeText' => '文本',
|
||||
'Core:AttributeText+' => '多行字符串',
|
||||
|
||||
'Core:AttributeHTML' => 'HTML',
|
||||
'Core:AttributeHTML+' => 'HTML字符串',
|
||||
|
||||
'Core:AttributeEmailAddress' => '邮箱地址',
|
||||
'Core:AttributeEmailAddress+' => '邮箱地址',
|
||||
|
||||
'Core:AttributeIPAddress' => 'IP地址',
|
||||
'Core:AttributeIPAddress+' => 'IP地址',
|
||||
|
||||
'Core:AttributeOQL' => 'OQL',
|
||||
'Core:AttributeOQL+' => 'Object Query Langage expression~~',
|
||||
|
||||
'Core:AttributeEnum' => 'Enum~~',
|
||||
'Core:AttributeEnum+' => 'List of predefined alphanumeric strings~~',
|
||||
|
||||
'Core:AttributeTemplateString' => '字符模板',
|
||||
'Core:AttributeTemplateString+' => '包含占位符的字符串',
|
||||
|
||||
'Core:AttributeTemplateText' => '文字模板',
|
||||
'Core:AttributeTemplateText+' => '包含占位符的文本',
|
||||
|
||||
'Core:AttributeTemplateHTML' => 'HTML模板',
|
||||
'Core:AttributeTemplateHTML+' => 'HTML containing placeholders~~',
|
||||
|
||||
'Core:AttributeDateTime' => '日期/时间',
|
||||
'Core:AttributeDateTime+' => 'Date and time (年-月-日 时:分:秒)',
|
||||
'Core:AttributeDateTime?SmartSearch' => '
|
||||
@@ -156,7 +123,6 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
<p>
|
||||
如果不写具体时间,则默认00:00:00
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDate' => '日期',
|
||||
'Core:AttributeDate+' => '日期 (年-月-日)',
|
||||
'Core:AttributeDate?SmartSearch' => '
|
||||
@@ -171,43 +137,30 @@ Operators:<br/>
|
||||
<b><</b><em>日期</em><br/>
|
||||
<b>[</b><em>日期</em>,<em>日期</em><b>]</b>
|
||||
</p>',
|
||||
|
||||
'Core:AttributeDeadline' => '截止日期',
|
||||
'Core:AttributeDeadline+' => '日期, 显示与当前的相对时间',
|
||||
|
||||
'Core:AttributeExternalKey' => '外键',
|
||||
'Core:AttributeExternalKey+' => 'External (or foreign) key~~',
|
||||
|
||||
'Core:AttributeHierarchicalKey' => 'Hierarchical Key~~',
|
||||
'Core:AttributeHierarchicalKey+' => 'External (or foreign) key to the parent~~',
|
||||
|
||||
'Core:AttributeExternalField' => '外部字段',
|
||||
'Core:AttributeExternalField+' => 'Field mapped to an external key~~',
|
||||
|
||||
'Core:AttributeURL' => 'URL',
|
||||
'Core:AttributeURL+' => 'Absolute or relative URL as a text string~~',
|
||||
|
||||
'Core:AttributeBlob' => 'Blob',
|
||||
'Core:AttributeBlob+' => '任何二进制内容(文档)',
|
||||
|
||||
'Core:AttributeOneWayPassword' => '单向密码',
|
||||
'Core:AttributeOneWayPassword+' => '单向加密(或哈希) 的密码',
|
||||
|
||||
'Core:AttributeTable' => '表',
|
||||
'Core:AttributeTable+' => '带索引的二维数组',
|
||||
|
||||
'Core:AttributePropertySet' => '属性',
|
||||
'Core:AttributePropertySet+' => 'List of untyped properties (name and value)~~',
|
||||
|
||||
'Core:AttributeFriendlyName' => '通用名称',
|
||||
'Core:AttributeFriendlyName+' => 'Attribute created automatically ; the friendly name is computed after several attributes~~',
|
||||
|
||||
'Core:FriendlyName-Label' => '全称',
|
||||
'Core:FriendlyName-Description' => '全称',
|
||||
|
||||
'Core:AttributeTag' => '标签',
|
||||
'Core:AttributeTag+' => '标签',
|
||||
|
||||
'Core:Context=REST/JSON' => 'REST',
|
||||
'Core:Context=Synchro' => '同步',
|
||||
'Core:Context=Setup' => '安装向导',
|
||||
@@ -248,10 +201,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
//
|
||||
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:CMDBChangeOp' => '变更操作跟踪',
|
||||
'Class:CMDBChangeOp+' => '某人在某时某刻对某个对象的变更操作',
|
||||
'Class:CMDBChangeOp' => '变更操作',
|
||||
'Class:CMDBChangeOp+' => '变更操作跟踪',
|
||||
'Class:CMDBChangeOp/Attribute:change' => '变更',
|
||||
'Class:CMDBChangeOp/Attribute:change+' => '',
|
||||
'Class:CMDBChangeOp/Attribute:change+' => '变更',
|
||||
'Class:CMDBChangeOp/Attribute:date' => '日期',
|
||||
'Class:CMDBChangeOp/Attribute:date+' => '变更的日期和时间',
|
||||
'Class:CMDBChangeOp/Attribute:userinfo' => '用户',
|
||||
@@ -372,9 +325,9 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:EventNotification' => '通知事件',
|
||||
'Class:EventNotification+' => 'Trace of a notification that has been sent~~',
|
||||
'Class:EventNotification/Attribute:trigger_id' => '触发器',
|
||||
'Class:EventNotification/Attribute:trigger_id+' => '用户账号',
|
||||
'Class:EventNotification/Attribute:trigger_id+' => '用户账户',
|
||||
'Class:EventNotification/Attribute:action_id' => '用户',
|
||||
'Class:EventNotification/Attribute:action_id+' => '用户账号',
|
||||
'Class:EventNotification/Attribute:action_id+' => '用户账户',
|
||||
'Class:EventNotification/Attribute:object_id' => '对象id',
|
||||
'Class:EventNotification/Attribute:object_id+' => 'object id (class defined by the trigger ?)~~',
|
||||
));
|
||||
@@ -455,8 +408,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:EventRestService/Attribute:version+' => '参数 \'版本\'',
|
||||
'Class:EventRestService/Attribute:json_input' => '输入',
|
||||
'Class:EventRestService/Attribute:json_input+' => 'Argument \'json_data\'~~',
|
||||
'Class:EventRestService/Attribute:code' => '编码',
|
||||
'Class:EventRestService/Attribute:code+' => '返回编码',
|
||||
'Class:EventRestService/Attribute:code' => '代码',
|
||||
'Class:EventRestService/Attribute:code+' => '返回代码',
|
||||
'Class:EventRestService/Attribute:json_output' => '响应',
|
||||
'Class:EventRestService/Attribute:json_output+' => 'HTTP 响应 (json)',
|
||||
'Class:EventRestService/Attribute:provider' => '提供者',
|
||||
@@ -707,7 +660,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:TriggerOnAttributeBlobDownload' => 'Trigger (on object\'s document download)~~',
|
||||
'Class:TriggerOnAttributeBlobDownload+' => 'Trigger on object\'s document field download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttributeBlobDownload/Attribute:target_attcodes' => '目标字段',
|
||||
'Class:TriggerOnAttributeBlobDownload/Attribute:target_attcodes' => 'Target fields~~',
|
||||
'Class:TriggerOnAttributeBlobDownload/Attribute:target_attcodes+' => '',
|
||||
));
|
||||
|
||||
@@ -718,7 +671,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:TriggerOnThresholdReached' => '触发器 (基于阈值)',
|
||||
'Class:TriggerOnThresholdReached+' => '当达到某个阈值时触发',
|
||||
'Class:TriggerOnThresholdReached/Attribute:stop_watch_code' => '计时',
|
||||
'Class:TriggerOnThresholdReached/Attribute:stop_watch_code' => '秒表',
|
||||
'Class:TriggerOnThresholdReached/Attribute:stop_watch_code+' => '',
|
||||
'Class:TriggerOnThresholdReached/Attribute:threshold_index' => '阈值',
|
||||
'Class:TriggerOnThresholdReached/Attribute:threshold_index+' => '',
|
||||
@@ -815,7 +768,6 @@ The hyperlink is displayed in the tooltip appearing on the “Lock” symbol of
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:administrators' => 'Administrators only',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:everybody' => 'Everybody allowed to delete such objects',
|
||||
'Class:SynchroDataSource/Attribute:user_delete_policy/Value:nobody' => 'Nobody',
|
||||
|
||||
'SynchroDataSource:Description' => '描述',
|
||||
'SynchroDataSource:Reconciliation' => 'Search & reconciliation~~',
|
||||
'SynchroDataSource:Deletion' => 'Deletion rules~~',
|
||||
@@ -1053,9 +1005,8 @@ The hyperlink is displayed in the tooltip appearing on the “Lock” symbol of
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:TagSetFieldData' => '%2$s for class %1$s~~',
|
||||
'Class:TagSetFieldData+' => '~~',
|
||||
|
||||
'Class:TagSetFieldData/Attribute:code' => '编码',
|
||||
'Class:TagSetFieldData/Attribute:code+' => '内部编码. 必须至少包含3个数字或字母',
|
||||
'Class:TagSetFieldData/Attribute:code' => '代码',
|
||||
'Class:TagSetFieldData/Attribute:code+' => '内部代码. 必须至少包含3个数字或字母',
|
||||
'Class:TagSetFieldData/Attribute:label' => '标签',
|
||||
'Class:TagSetFieldData/Attribute:label+' => '显示的标签',
|
||||
'Class:TagSetFieldData/Attribute:description' => '描述',
|
||||
@@ -1063,7 +1014,6 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:TagSetFieldData/Attribute:finalclass' => 'Tag class~~~~',
|
||||
'Class:TagSetFieldData/Attribute:obj_class' => 'Object class~~~~',
|
||||
'Class:TagSetFieldData/Attribute:obj_attcode' => 'Field code~~~~',
|
||||
|
||||
'Core:TagSetFieldData:ErrorDeleteUsedTag' => '已使用的标签无法删除',
|
||||
'Core:TagSetFieldData:ErrorDuplicateTagCodeOrLabel' => 'Tags codes or labels must be unique~~',
|
||||
'Core:TagSetFieldData:ErrorTagCodeSyntax' => 'Tags code must contain between 3 and %1$d alphanumeric characters, starting with a letter.~~',
|
||||
@@ -1189,8 +1139,6 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'Class:ResourceSystemMenu' => 'Resource System Menu~~',
|
||||
'Class:ResourceSystemMenu+' => '',
|
||||
));
|
||||
|
||||
|
||||
// Additional language entries not present in English dict
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'INTERNAL:JQuery-DatePicker:LangCode' => 'zh-CN'
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -383,7 +383,6 @@ return array(
|
||||
'Combodo\\iTop\\Core\\Email\\EmailFactory' => $baseDir . '/sources/Core/Email/EmailFactory.php',
|
||||
'Combodo\\iTop\\Core\\Email\\iEMail' => $baseDir . '/sources/Core/Email/iEMail.php',
|
||||
'Combodo\\iTop\\Core\\EventListener\\AttributeBlobEventListener' => $baseDir . '/sources/Core/EventListener/AttributeBlobEventListener.php',
|
||||
'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => $baseDir . '/sources/Core/Kpi/KpiLogData.php',
|
||||
'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => $baseDir . '/sources/Core/MetaModel/FriendlyNameType.php',
|
||||
'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => $baseDir . '/sources/Core/MetaModel/HierarchicalKey.php',
|
||||
'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php',
|
||||
@@ -462,7 +461,6 @@ return array(
|
||||
'Combodo\\iTop\\Service\\Links\\LinkSetModel' => $baseDir . '/sources/Service/Links/LinkSetModel.php',
|
||||
'Combodo\\iTop\\Service\\Links\\LinkSetRepository' => $baseDir . '/sources/Service/Links/LinkSetRepository.php',
|
||||
'Combodo\\iTop\\Service\\Links\\LinksBulkDataPostProcessor' => $baseDir . '/sources/Service/Links/LinksBulkDataPostProcessor.php',
|
||||
'Combodo\\iTop\\Service\\Module\\ModuleService' => $baseDir . '/sources/Service/Module/ModuleService.php',
|
||||
'Combodo\\iTop\\Service\\Router\\Exception\\RouteNotFoundException' => $baseDir . '/sources/Service/Router/Exception/RouteNotFoundException.php',
|
||||
'Combodo\\iTop\\Service\\Router\\Exception\\RouterException' => $baseDir . '/sources/Service/Router/Exception/RouterException.php',
|
||||
'Combodo\\iTop\\Service\\Router\\Router' => $baseDir . '/sources/Service/Router/Router.php',
|
||||
@@ -2954,7 +2952,6 @@ return array(
|
||||
'iDBObjectURLMaker' => $baseDir . '/application/applicationcontext.class.inc.php',
|
||||
'iDisplay' => $baseDir . '/core/dbobject.class.php',
|
||||
'iFieldRendererMappingsExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iKPILoggerExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iKeyboardShortcut' => $baseDir . '/sources/Application/UI/Hook/iKeyboardShortcut.php',
|
||||
'iLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php',
|
||||
'iLoginExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
|
||||
@@ -747,7 +747,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Core\\Email\\EmailFactory' => __DIR__ . '/../..' . '/sources/Core/Email/EmailFactory.php',
|
||||
'Combodo\\iTop\\Core\\Email\\iEMail' => __DIR__ . '/../..' . '/sources/Core/Email/iEMail.php',
|
||||
'Combodo\\iTop\\Core\\EventListener\\AttributeBlobEventListener' => __DIR__ . '/../..' . '/sources/Core/EventListener/AttributeBlobEventListener.php',
|
||||
'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => __DIR__ . '/../..' . '/sources/Core/Kpi/KpiLogData.php',
|
||||
'Combodo\\iTop\\Core\\MetaModel\\FriendlyNameType' => __DIR__ . '/../..' . '/sources/Core/MetaModel/FriendlyNameType.php',
|
||||
'Combodo\\iTop\\Core\\MetaModel\\HierarchicalKey' => __DIR__ . '/../..' . '/sources/Core/MetaModel/HierarchicalKey.php',
|
||||
'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
|
||||
@@ -826,7 +825,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Service\\Links\\LinkSetModel' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetModel.php',
|
||||
'Combodo\\iTop\\Service\\Links\\LinkSetRepository' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetRepository.php',
|
||||
'Combodo\\iTop\\Service\\Links\\LinksBulkDataPostProcessor' => __DIR__ . '/../..' . '/sources/Service/Links/LinksBulkDataPostProcessor.php',
|
||||
'Combodo\\iTop\\Service\\Module\\ModuleService' => __DIR__ . '/../..' . '/sources/Service/Module/ModuleService.php',
|
||||
'Combodo\\iTop\\Service\\Router\\Exception\\RouteNotFoundException' => __DIR__ . '/../..' . '/sources/Service/Router/Exception/RouteNotFoundException.php',
|
||||
'Combodo\\iTop\\Service\\Router\\Exception\\RouterException' => __DIR__ . '/../..' . '/sources/Service/Router/Exception/RouterException.php',
|
||||
'Combodo\\iTop\\Service\\Router\\Router' => __DIR__ . '/../..' . '/sources/Service/Router/Router.php',
|
||||
@@ -3318,7 +3316,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'iDBObjectURLMaker' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
|
||||
'iDisplay' => __DIR__ . '/../..' . '/core/dbobject.class.php',
|
||||
'iFieldRendererMappingsExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iKPILoggerExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iKeyboardShortcut' => __DIR__ . '/../..' . '/sources/Application/UI/Hook/iKeyboardShortcut.php',
|
||||
'iLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php',
|
||||
'iLoginExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<system.web>
|
||||
<authorization>
|
||||
<deny users="*" /> <!-- Denies all users -->
|
||||
</authorization>
|
||||
</system.web>
|
||||
<system.webServer>
|
||||
<security>
|
||||
<requestFiltering>
|
||||
<fileExtensions applyToWebDAV="false" allowUnlisted="false"></fileExtensions>
|
||||
</requestFiltering>
|
||||
<authorization>
|
||||
<deny users="*" /> <!-- Denies all users -->
|
||||
</authorization>
|
||||
</security>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
@@ -358,7 +358,6 @@ class DBBackup
|
||||
|
||||
$sPortOption = self::GetMysqliCliSingleOption('port', $this->iDBPort);
|
||||
$sTlsOptions = self::GetMysqlCliTlsOptions($this->oConfig);
|
||||
$sProtocolOption = self::GetMysqlCliTransportOption($this->sDBHost);
|
||||
|
||||
$sMysqlVersion = CMDBSource::GetDBVersion();
|
||||
$bIsMysqlSupportUtf8mb4 = (version_compare($sMysqlVersion, self::MYSQL_VERSION_WITH_UTF8MB4_IN_PROGRAMS) === -1);
|
||||
@@ -379,8 +378,8 @@ EOF;
|
||||
|
||||
// Note: opt implicitely sets lock-tables... which cancels the benefit of single-transaction!
|
||||
// skip-lock-tables compensates and allows for writes during a backup
|
||||
$sCommand = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption $sProtocolOption --user=$sUser $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables 2>&1";
|
||||
$sCommandDisplay = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption $sProtocolOption --user=xxxxx $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables";
|
||||
$sCommand = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption --user=$sUser $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables 2>&1";
|
||||
$sCommandDisplay = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption --user=xxxxx $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables";
|
||||
|
||||
// Now run the command for real
|
||||
$this->LogInfo("backup: generate data file with command: $sCommandDisplay");
|
||||
@@ -468,8 +467,8 @@ EOF;
|
||||
if ($oMysqli->connect_errno)
|
||||
{
|
||||
$sHost = is_null($this->iDBPort) ? $this->sDBHost : $this->sDBHost.' on port '.$this->iDBPort;
|
||||
throw new MySQLException('Could not connect to the DB server '.$oMysqli->connect_errno.' (mysql errno: '.$oMysqli->connect_error, array('host' => $sHost, 'user' => $sUser));
|
||||
}
|
||||
throw new BackupException("Cannot connect to the MySQL server '$sHost' (".$oMysqli->connect_errno.") ".$oMysqli->connect_error);
|
||||
}
|
||||
if (!$oMysqli->select_db($this->sDBName))
|
||||
{
|
||||
throw new BackupException("The database '$this->sDBName' does not seem to exist");
|
||||
@@ -577,28 +576,6 @@ EOF;
|
||||
return ' --'.$sCliArgName.'='.self::EscapeShellArg($sData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define if we should force a transport option
|
||||
*
|
||||
* @param string $sHost
|
||||
*
|
||||
* @return string .
|
||||
|
||||
* @since 2.7.9 3.0.4 3.1.1 N°6123
|
||||
*/
|
||||
public static function GetMysqlCliTransportOption(string $sHost)
|
||||
{
|
||||
$sTransportOptions = '';
|
||||
|
||||
/** N°6123 As we're using a --port option, if we use localhost as host,
|
||||
* MariaDB > 10.6 will implicitly change its protocol from socket to tcp and throw a warning **/
|
||||
if($sHost === 'localhost'){
|
||||
$sTransportOptions = '--protocol=tcp';
|
||||
}
|
||||
|
||||
return $sTransportOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the command to launch mysqldump (without its params)
|
||||
*/
|
||||
|
||||
@@ -2060,6 +2060,7 @@ EOF
|
||||
$this->CompileCommonProperty('display_style', $oField, $aParameters, $sModuleRelativeDir);
|
||||
$this->CompileCommonProperty('edit_mode', $oField, $aParameters, $sModuleRelativeDir);
|
||||
$this->CompileCommonProperty('filter', $oField, $aParameters, $sModuleRelativeDir);
|
||||
$this->CompileCommonProperty('allowed_values', $oField, $aParameters, $sModuleRelativeDir);
|
||||
$this->CompileCommonProperty('with_php_constraint', $oField, $aParameters, $sModuleRelativeDir, false);
|
||||
$aParameters['depends_on'] = $sDependencies;
|
||||
} elseif ($sAttType == 'AttributeLinkedSet') {
|
||||
|
||||
@@ -55,13 +55,11 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory
|
||||
public const UI_BLOCK_CLASS_NAME = DataTable::class;
|
||||
|
||||
/**
|
||||
* If inside an iTop object, you can use {@see cmdbAbstractObject::DisplaySet()}
|
||||
*
|
||||
* @api
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sListId
|
||||
* @param \DBObjectSet $oSet
|
||||
* @param array $aExtraParams See possible values in {@see self::RenderDataTable()}
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
|
||||
* @throws \ApplicationException
|
||||
@@ -86,13 +84,11 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory
|
||||
}
|
||||
|
||||
/**
|
||||
* If inside an iTop object, you can use {@see cmdbAbstractObject::DisplaySet()}
|
||||
*
|
||||
* @api
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sListId
|
||||
* @param DBObjectSet $oSet
|
||||
* @param array $aExtraParams See possible values in {@see self::RenderDataTable()}
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
|
||||
* @throws \ArchivedObjectException
|
||||
@@ -121,12 +117,7 @@ class DataTableUIBlockFactory extends AbstractUIBlockFactory
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sListId
|
||||
* @param \DBObjectSet $oSet
|
||||
* @param array $aExtraParams example keys used in this method :
|
||||
* - toolkit_menu = boolean
|
||||
* - surround_with_panel = boolean : if true adds the standard class panel (icon, title, ...)
|
||||
* - panel_title = string
|
||||
* - panel_title_is_html = boolean
|
||||
* - panel_icon = string : class icon (for example from {@see MetaModel::GetClassIcon()})
|
||||
* @param array $aExtraParams
|
||||
*
|
||||
* @return \Combodo\iTop\Application\UI\Base\Layout\UIContentBlock
|
||||
* @throws \ArchivedObjectException
|
||||
|
||||
@@ -74,7 +74,6 @@ class OAuthClientProviderFactory
|
||||
* @return AccessTokenInterface
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
|
||||
*/
|
||||
public static function GetAccessTokenFromCode(OAuthClient $oOAuthClient, $sCode)
|
||||
{
|
||||
@@ -110,7 +109,7 @@ class OAuthClientProviderFactory
|
||||
/**
|
||||
* @param \DBObject $oOAuthClient
|
||||
*
|
||||
* @return OAuthClientProviderAbstract
|
||||
* @return mixed
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Core\Kpi;
|
||||
|
||||
class KpiLogData
|
||||
{
|
||||
const TYPE_REPORT = 'report';
|
||||
const TYPE_STATS = 'stats';
|
||||
const TYPE_REQUEST = 'request';
|
||||
|
||||
/** @var string */
|
||||
public $sType;
|
||||
/** @var string */
|
||||
public $sOperation;
|
||||
/** @var string */
|
||||
public $sArguments;
|
||||
/** @var float */
|
||||
public $fStartTime;
|
||||
/** @var float */
|
||||
public $fStopTime;
|
||||
/** @var string */
|
||||
public $sExtension;
|
||||
/** @var int */
|
||||
public $iInitialMemory;
|
||||
/** @var int */
|
||||
public $iCurrentMemory;
|
||||
/** @var int */
|
||||
public $iPeakMemory;
|
||||
/** @var array */
|
||||
public $aData;
|
||||
|
||||
/**
|
||||
* @param string $sType
|
||||
* @param string $sOperation
|
||||
* @param string $sArguments
|
||||
* @param float $fStartTime
|
||||
* @param float $fStopTime
|
||||
* @param string $sExtension
|
||||
* @param int $iInitialMemory
|
||||
* @param int $iCurrentMemory
|
||||
* @param array $aData
|
||||
*/
|
||||
public function __construct($sType, $sOperation, $sArguments, $fStartTime, $fStopTime, $sExtension, $iInitialMemory = 0, $iCurrentMemory = 0, $iPeakMemory = 0, $aData = [])
|
||||
{
|
||||
$this->sType = $sType;
|
||||
$this->sOperation = $sOperation;
|
||||
$this->sArguments = @iconv(mb_detect_encoding($sArguments, mb_detect_order(), true), 'UTF-8', $sArguments);
|
||||
$this->fStartTime = $fStartTime;
|
||||
$this->fStopTime = $fStopTime;
|
||||
$this->sExtension = $sExtension;
|
||||
$this->iInitialMemory = $iInitialMemory;
|
||||
$this->iCurrentMemory = $iCurrentMemory;
|
||||
$this->iPeakMemory = $iPeakMemory;
|
||||
$this->aData = $aData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSV Header
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function GetCSVHeader()
|
||||
{
|
||||
return "Type,Operation,Arguments,StartTime,StopTime,Duration,Extension,InitialMemory,CurrentMemory,PeakMemory";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CSV line for the values
|
||||
* @return string
|
||||
*/
|
||||
public function GetCSV()
|
||||
{
|
||||
$fDuration = sprintf('%01.4f', $this->fStopTime - $this->fStartTime);
|
||||
$sType = $this->RemoveQuotes($this->sType);
|
||||
$sOperation = $this->RemoveQuotes($this->sOperation);
|
||||
$sArguments = $this->RemoveQuotes($this->sArguments);
|
||||
$sExtension = $this->RemoveQuotes($this->sExtension);
|
||||
return "\"$sType\",\"$sOperation\",\"$sArguments\",$this->fStartTime,$this->fStopTime,$fDuration,\"$sExtension\",$this->iInitialMemory,$this->iCurrentMemory,$this->iPeakMemory";
|
||||
}
|
||||
|
||||
private function RemoveQuotes(string $sEntry): string
|
||||
{
|
||||
return str_replace('"', "'", $sEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oOther
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public function Compare(KpiLogData $oOther): float
|
||||
{
|
||||
if ($oOther->fStartTime > $this->fStartTime) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public function Contains(KpiLogData $oOther): bool
|
||||
{
|
||||
if ($oOther->fStartTime < $this->fStartTime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($oOther->fStartTime > $this->fStopTime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return "$this->sType:$this->sOperation:$this->sArguments";
|
||||
}
|
||||
|
||||
public function GetUUID(): string
|
||||
{
|
||||
return sha1($this->__toString());
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2023 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Service\Module;
|
||||
|
||||
use MetaModel;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use utils;
|
||||
|
||||
class ModuleService
|
||||
{
|
||||
/** @var ModuleService */
|
||||
private static $oInstance;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public static function GetInstance(): ModuleService
|
||||
{
|
||||
if (!isset(static::$oInstance)) {
|
||||
static::$oInstance = new ModuleService();
|
||||
}
|
||||
|
||||
return static::$oInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a "signature" of the method of an extension in the form of: "[module-name] class::method()"
|
||||
*
|
||||
* @param object|string $object Object or class
|
||||
* @param string $sMethod
|
||||
*
|
||||
* @return string
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function GetModuleMethodSignature($object, string $sMethod): string
|
||||
{
|
||||
$sSignature = '';
|
||||
$oReflectionMethod = new ReflectionMethod($object, $sMethod);
|
||||
$oReflectionClass = $oReflectionMethod->getDeclaringClass();
|
||||
$sExtension = $this->GetModuleNameFromObject($oReflectionClass->getName());
|
||||
if (strlen($sExtension) !== 0) {
|
||||
$sSignature .= '['.$sExtension.'] ';
|
||||
}
|
||||
$sSignature .= $oReflectionClass->getShortName().'::'.$sMethod.'()';
|
||||
|
||||
return $sSignature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the module name from an object or class
|
||||
*
|
||||
* @param object|string $object
|
||||
*
|
||||
* @return string
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function GetModuleNameFromObject($object): string
|
||||
{
|
||||
$oReflectionClass = new ReflectionClass($object);
|
||||
$sPath = str_replace('\\', '/', $oReflectionClass->getFileName());
|
||||
$sPattern = str_replace('\\', '/', '@'.APPROOT.'env-'.utils::GetCurrentEnvironment()).'/(?<ext>.+)/@U';
|
||||
if (preg_match($sPattern, $sPath, $aMatches) !== false) {
|
||||
if (isset($aMatches['ext'])) {
|
||||
return $aMatches['ext'];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
|
||||
*
|
||||
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
*
|
||||
* @return string the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
*
|
||||
* @uses \debug_backtrace()
|
||||
*/
|
||||
public function GetCurrentModuleDir(int $iCallDepth): string
|
||||
{
|
||||
$sCurrentModuleDir = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
foreach(GetModulesInfo() as $sModuleName => $aInfo)
|
||||
{
|
||||
if ($aInfo['root_dir'] !== '')
|
||||
{
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
|
||||
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
|
||||
{
|
||||
$sCurrentModuleDir = basename($sRootDir);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sCurrentModuleDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* **Warning** : as this method uses {@see GetCurrentModuleDir} it produces hazardous results.
|
||||
* You should better uses directly {@see GetAbsoluteUrlModulesRoot} and add the module dir name yourself ! See N°4573
|
||||
*
|
||||
* @return string the base URL for all files in the current module from which this method is called
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @throws \Exception
|
||||
*
|
||||
* @uses GetCurrentModuleDir
|
||||
*/
|
||||
public function GetCurrentModuleUrl(int $iCallDepth = 0): string
|
||||
{
|
||||
$sDir = $this->GetCurrentModuleDir(1 + $iCallDepth);
|
||||
if ( $sDir !== '')
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot().'/'.$sDir;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sProperty The name of the property to retrieve
|
||||
* @param mixed $defaultValue
|
||||
*
|
||||
* @return mixed the value of a given setting for the current module
|
||||
*/
|
||||
public function GetCurrentModuleSetting(string $sProperty, $defaultValue = null)
|
||||
{
|
||||
$sModuleName = $this->GetCurrentModuleName(1);
|
||||
return MetaModel::GetModuleSetting($sModuleName, $sProperty, $defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sModuleName
|
||||
*
|
||||
* @return string|NULL compiled version of a given module, as it was seen by the compiler
|
||||
*/
|
||||
public function GetCompiledModuleVersion(string $sModuleName): ?string
|
||||
{
|
||||
$aModulesInfo = GetModulesInfo();
|
||||
if (array_key_exists($sModuleName, $aModulesInfo))
|
||||
{
|
||||
return $aModulesInfo[$sModuleName]['version'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the module containing the file where the call to this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
*
|
||||
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetCurrentModuleName(int $iCallDepth = 0): string
|
||||
{
|
||||
$sCurrentModuleName = '';
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
|
||||
|
||||
return $this->GetModuleNameFromPath($sCallerFile);
|
||||
}
|
||||
|
||||
private function GetModuleNameFromPath($sPath)
|
||||
{
|
||||
foreach (GetModulesInfo() as $sModuleName => $aInfo) {
|
||||
if ($aInfo['root_dir'] !== '') {
|
||||
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
|
||||
if (substr($sPath, 0, strlen($sRootDir)) === $sRootDir) {
|
||||
|
||||
return $sModuleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the extension code from the call stack.
|
||||
* Scan the call stack until a module is found.
|
||||
*
|
||||
* @param int $iLevelsToIgnore
|
||||
*
|
||||
* @return string module name
|
||||
*/
|
||||
public function GetModuleNameFromCallStack(int $iLevelsToIgnore = 0): string
|
||||
{
|
||||
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
|
||||
$aCallStack = array_slice($aCallStack, $iLevelsToIgnore);
|
||||
|
||||
foreach ($aCallStack as $aCallInfo) {
|
||||
$sFile = realpath(empty($aCallInfo['file']) ? '' : $aCallInfo['file']);
|
||||
|
||||
$sModuleName = $this->GetModuleNameFromPath($sFile);
|
||||
if (strlen($sModuleName) > 0) {
|
||||
return $sModuleName;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
}
|
||||
@@ -138,12 +138,24 @@ class Router
|
||||
{
|
||||
$aRoutes = [];
|
||||
$bUseCache = false === utils::IsDevelopmentEnvironment();
|
||||
$bMustWriteCache = false;
|
||||
$sCacheFilePath = $this->GetCacheFileAbsPath();
|
||||
|
||||
// Try to read from cache
|
||||
if ($bUseCache) {
|
||||
if (is_file($sCacheFilePath)) {
|
||||
$aRoutes = include $sCacheFilePath;
|
||||
$aCachedRoutes = include $sCacheFilePath;
|
||||
|
||||
// N°6618 - Protection against corrupted cache returning `1` instead of an array of routes
|
||||
if (is_array($aCachedRoutes)) {
|
||||
$aRoutes = $aCachedRoutes;
|
||||
} else {
|
||||
// Invalid cache force re-generation
|
||||
// Note that even if it is re-generated corrupted again, this protection should prevent crashes
|
||||
$bMustWriteCache = true;
|
||||
}
|
||||
} else {
|
||||
$bMustWriteCache = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,11 +192,11 @@ class Router
|
||||
}
|
||||
}
|
||||
|
||||
// Save to cache
|
||||
if ($bUseCache) {
|
||||
// Save to cache if it doesn't exist already
|
||||
if ($bMustWriteCache) {
|
||||
$sCacheContent = "<?php\n\nreturn ".var_export($aRoutes, true).";";
|
||||
SetupUtils::builddir(dirname($sCacheFilePath));
|
||||
file_put_contents($sCacheFilePath, $sCacheContent);
|
||||
file_put_contents($sCacheFilePath, $sCacheContent, LOCK_EX);
|
||||
}
|
||||
|
||||
return $aRoutes;
|
||||
|
||||
@@ -2162,9 +2162,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
// it will be deleted by the mean of a trigger too
|
||||
protected function DBDeleteSingleObject()
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->OnDelete();
|
||||
$oKPI->ComputeStatsForExtension($this, 'OnDelete');
|
||||
|
||||
if (!MetaModel::DBIsReadOnly())
|
||||
{
|
||||
|
||||
@@ -32,8 +32,6 @@ class DictionariesConsistencyTest extends ItopTestCase
|
||||
*/
|
||||
public function testDictionariesLanguage($sDictFile): void
|
||||
{
|
||||
// In iTop the language available list is dynamically made during setup, depending on the dict files found
|
||||
// Here we are using a fixed list
|
||||
$aPrefixToLanguageData = array(
|
||||
'cs' => array('CS CZ', 'Czech', 'Čeština'),
|
||||
'da' => array('DA DA', 'Danish', 'Dansk'),
|
||||
|
||||
@@ -11,16 +11,11 @@ namespace Combodo\iTop\Test\UnitTest\Module\AuthentLocal;
|
||||
use AttributeDate;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Config;
|
||||
use DBObjectSearch;
|
||||
use DBObjectSet;
|
||||
use Dict;
|
||||
use MetaModel;
|
||||
use ormLinkSet;
|
||||
use URP_UserProfile;
|
||||
use User;
|
||||
use UserLocal;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* test class for UserLocal class
|
||||
@@ -397,62 +392,5 @@ class UserLocalTest extends ItopDataTestCase
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetUserProfileList()
|
||||
{
|
||||
utils::GetConfig()->SetModuleSetting('authent-local', 'password_validation.pattern', '');
|
||||
$sAdminLogin = 'admin';
|
||||
$oExistingAdminUser = MetaModel::GetObjectByColumn(User::class, 'login', $sAdminLogin, false);
|
||||
if (\is_null($oExistingAdminUser)) {
|
||||
$sAdministratorProfileId = 1;
|
||||
$this->CreateContactlessUser($sAdminLogin, $sAdministratorProfileId);
|
||||
}
|
||||
|
||||
// By default should see all profiles
|
||||
$oProfilesSet = $this->GetAdminUserProfileList();
|
||||
$this->assertIsObject($oProfilesSet);
|
||||
$this->assertInstanceOf(ormLinkSet::class, $oProfilesSet);
|
||||
$this->assertGreaterThan(0, $oProfilesSet->Count());
|
||||
|
||||
// non admin user : seeing profiles depends on the security.hide_administrators config param value
|
||||
$sSupportAgentProfileId = 5;
|
||||
$sSupportAgentLogin = 'support_agent';
|
||||
$this->CreateContactlessUser($sSupportAgentLogin, $sSupportAgentProfileId);
|
||||
UserRights::Login($sSupportAgentLogin);
|
||||
MetaModel::GetConfig()->Set('security.hide_administrators', true);
|
||||
$oProfilesSet = $this->GetAdminUserProfileList();
|
||||
$this->assertIsObject($oProfilesSet);
|
||||
$this->assertInstanceOf(ormLinkSet::class, $oProfilesSet);
|
||||
$this->assertEquals(0, $oProfilesSet->Count());
|
||||
MetaModel::GetConfig()->Set('security.hide_administrators', false);
|
||||
$oProfilesSet = $this->GetAdminUserProfileList();
|
||||
$this->assertIsObject($oProfilesSet);
|
||||
$this->assertInstanceOf(ormLinkSet::class, $oProfilesSet);
|
||||
$this->assertGreaterThan(0, $oProfilesSet->Count());
|
||||
|
||||
// admin user : will always see profiles whatever the security.hide_administrators config param value is
|
||||
UserRights::Login($sAdminLogin);
|
||||
MetaModel::GetConfig()->Set('security.hide_administrators', true);
|
||||
$oProfilesSet = $this->GetAdminUserProfileList();
|
||||
$this->assertIsObject($oProfilesSet);
|
||||
$this->assertInstanceOf(ormLinkSet::class, $oProfilesSet);
|
||||
$this->assertGreaterThan(0, $oProfilesSet->Count());
|
||||
MetaModel::GetConfig()->Set('security.hide_administrators', false);
|
||||
$oProfilesSet = $this->GetAdminUserProfileList();
|
||||
$this->assertIsObject($oProfilesSet);
|
||||
$this->assertInstanceOf(ormLinkSet::class, $oProfilesSet);
|
||||
$this->assertGreaterThan(0, $oProfilesSet->Count());
|
||||
}
|
||||
|
||||
private function GetAdminUserProfileList(): ormLinkSet
|
||||
{
|
||||
$oSearch = new DBObjectSearch(UserLocal::class);
|
||||
$oSearch->AllowAllData();
|
||||
$oSearch->AddCondition('login', 'admin', '=');
|
||||
$oObjectSet = new DBObjectSet($oSearch);
|
||||
/** @noinspection OneTimeUseVariablesInspection */
|
||||
$oUser = $oObjectSet->Fetch();
|
||||
return $oUser->Get('profile_list');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ class BulkChangeExtKeyTest extends ItopDataTestCase {
|
||||
);
|
||||
|
||||
$this->performBulkChangeTest(
|
||||
"Invalid value for attribute",
|
||||
"invalid value for attribute",
|
||||
"Ambiguous: found 2 objects",
|
||||
null,
|
||||
$bIsRackReconKey,
|
||||
@@ -206,7 +206,8 @@ class BulkChangeExtKeyTest extends ItopDataTestCase {
|
||||
$aCsvData = [["UnexistingRackDescription"]];
|
||||
$aExtKeys = ["org_id" => ["name" => 0], "rack_id" => ["name" => 1, "description" => 3]];
|
||||
|
||||
$sSearchLinkUrl = 'UI.php?operation=search&filter='.\rawurlencode('%5B%22SELECT+%60Rack%60+FROM+Rack+AS+%60Rack%60+WHERE+%28%28%60Rack%60.%60name%60+%3D+%3Aname%29+AND+%28%60Rack%60.%60description%60+%3D+%3Adescription%29%29%22%2C%7B%22name%22%3A%22UnexistingRack%22%2C%22description%22%3A%22UnexistingRackDescription%22%7D%2C%5B%5D%5D');
|
||||
$sSearchLinkUrl = 'UI.php?operation=search&filter=%5B%22SELECT+%60Rack%60+FROM+Rack+AS+%60Rack%60+WHERE+%28%28%60Rack%60.%60name%60+%3D+%3Aname%29+AND+%28%60Rack%60.%60description%60+%3D+%3Adescription%29%29%22%2C%7B%22name%22%3A%22UnexistingRack%22%2C%22description%22%3A%22UnexistingRackDescription%22%7D%2C%5B%5D%5D'
|
||||
;
|
||||
$this->performBulkChangeTest(
|
||||
"No match for value 'UnexistingRack UnexistingRackDescription'",
|
||||
"Some possible 'Rack' value(s): RackTest1 RackTest1Desc, RackTest2 RackTest2Desc, RackTest3 RackTest3Desc...",
|
||||
@@ -237,7 +238,7 @@ class BulkChangeExtKeyTest extends ItopDataTestCase {
|
||||
public function performBulkChangeTest($sExpectedDisplayableValue, $sExpectedDescription, $oOrg, $bIsRackReconKey,
|
||||
$aAdditionalCsvData=null, $aExtKeys=null, $sSearchLinkUrl=null, $sError="Object not found") {
|
||||
if ($sSearchLinkUrl===null){
|
||||
$sSearchLinkUrl = 'UI.php?operation=search&filter='.rawurlencode('%5B%22SELECT+%60Rack%60+FROM+Rack+AS+%60Rack%60+WHERE+%28%60Rack%60.%60name%60+%3D+%3Aname%29%22%2C%7B%22name%22%3A%22UnexistingRack%22%7D%2C%5B%5D%5D');
|
||||
$sSearchLinkUrl = 'UI.php?operation=search&filter=%5B%22SELECT+%60Rack%60+FROM+Rack+AS+%60Rack%60+WHERE+%28%60Rack%60.%60name%60+%3D+%3Aname%29%22%2C%7B%22name%22%3A%22UnexistingRack%22%7D%2C%5B%5D%5D';
|
||||
}
|
||||
if (is_null($oOrg)){
|
||||
$iOrgId = $this->getTestOrgId();
|
||||
@@ -284,65 +285,60 @@ class BulkChangeExtKeyTest extends ItopDataTestCase {
|
||||
|
||||
|
||||
CMDBSource::Query('START TRANSACTION');
|
||||
try {
|
||||
//change value during the test
|
||||
$db_core_transactions_enabled=MetaModel::GetConfig()->Get('db_core_transactions_enabled');
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled',false);
|
||||
|
||||
//change value during the test
|
||||
$db_core_transactions_enabled = MetaModel::GetConfig()->Get('db_core_transactions_enabled');
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled', false);
|
||||
|
||||
$this->debug("aCsvData:" . json_encode($aCsvData[0]));
|
||||
$this->debug("aReconcilKeys:" . var_export($aReconcilKeys));
|
||||
$oBulk = new \BulkChange(
|
||||
"Server",
|
||||
$aCsvData,
|
||||
$aAttributes,
|
||||
$aExtKeys,
|
||||
$aReconcilKeys,
|
||||
null,
|
||||
null,
|
||||
"Y-m-d H:i:s", // date format
|
||||
true // localize
|
||||
);
|
||||
$this->debug("BulkChange:");
|
||||
$oChange = \CMDBObject::GetCurrentChange();
|
||||
$this->debug("GetCurrentChange:");
|
||||
$aRes = $oBulk->Process($oChange);
|
||||
$this->debug("Process:");
|
||||
static::assertNotNull($aRes);
|
||||
$this->debug("assertNotNull:");
|
||||
var_dump($aRes);
|
||||
foreach ($aRes as $aRow) {
|
||||
if (array_key_exists('__STATUS__', $aRow)) {
|
||||
$sStatus = $aRow['__STATUS__'];
|
||||
$this->debug("sStatus:" . $sStatus->GetDescription());
|
||||
$this->assertEquals($aResult["__STATUS__"], $sStatus->GetDescription());
|
||||
foreach ($aRow as $i => $oCell) {
|
||||
if ($i != "finalclass" && $i != "__STATUS__" && $i != "__ERRORS__") {
|
||||
$this->debug("i:" . $i);
|
||||
$this->debug('GetDisplayableValue:' . $oCell->GetDisplayableValue());
|
||||
if (array_key_exists($i, $aResult)) {
|
||||
$this->debug("aResult:" . var_export($aResult[$i]));
|
||||
if ($oCell instanceof \CellStatus_SearchIssue ||
|
||||
$oCell instanceof \CellStatus_Ambiguous) {
|
||||
$this->assertEquals($aResult[$i][0], $oCell->GetDisplayableValue(),
|
||||
"failure on " . get_class($oCell) . ' cell type');
|
||||
$this->assertEquals($sSearchLinkUrl, $oCell->GetSearchLinkUrl(),
|
||||
"failure on " . get_class($oCell) . ' cell type');
|
||||
$this->assertEquals($aResult[$i][1], $oCell->GetDescription(),
|
||||
"failure on " . get_class($oCell) . ' cell type');
|
||||
}
|
||||
$this->debug("aCsvData:".json_encode($aCsvData[0]));
|
||||
$this->debug("aReconcilKeys:". var_export($aReconcilKeys));
|
||||
$oBulk = new \BulkChange(
|
||||
"Server",
|
||||
$aCsvData,
|
||||
$aAttributes,
|
||||
$aExtKeys,
|
||||
$aReconcilKeys,
|
||||
null,
|
||||
null,
|
||||
"Y-m-d H:i:s", // date format
|
||||
true // localize
|
||||
);
|
||||
$this->debug("BulkChange:");
|
||||
$oChange = \CMDBObject::GetCurrentChange();
|
||||
$this->debug("GetCurrentChange:");
|
||||
$aRes = $oBulk->Process($oChange);
|
||||
$this->debug("Process:");
|
||||
static::assertNotNull($aRes);
|
||||
$this->debug("assertNotNull:");
|
||||
var_dump($aRes);
|
||||
foreach ($aRes as $aRow) {
|
||||
if (array_key_exists('__STATUS__', $aRow)) {
|
||||
$sStatus = $aRow['__STATUS__'];
|
||||
$this->debug("sStatus:".$sStatus->GetDescription());
|
||||
$this->assertEquals($aResult["__STATUS__"], $sStatus->GetDescription());
|
||||
foreach ($aRow as $i => $oCell) {
|
||||
if ($i != "finalclass" && $i != "__STATUS__" && $i != "__ERRORS__") {
|
||||
$this->debug("i:".$i);
|
||||
$this->debug('GetDisplayableValue:'.$oCell->GetDisplayableValue());
|
||||
if (array_key_exists($i,$aResult)) {
|
||||
$this->debug("aResult:".var_export($aResult[$i]));
|
||||
if ($oCell instanceof \CellStatus_SearchIssue ||
|
||||
$oCell instanceof \CellStatus_Ambiguous) {
|
||||
$this->assertEquals($aResult[$i][0], $oCell->GetDisplayableValue(),
|
||||
"failure on ".get_class($oCell).' cell type');
|
||||
$this->assertEquals($sSearchLinkUrl, $oCell->GetSearchLinkUrl(),
|
||||
"failure on ".get_class($oCell).' cell type');
|
||||
$this->assertEquals($aResult[$i][1], $oCell->GetDescription(),
|
||||
"failure on ".get_class($oCell).' cell type');
|
||||
}
|
||||
} else if ($i === "__ERRORS__") {
|
||||
$sErrors = array_key_exists("__ERRORS__", $aResult) ? $aResult["__ERRORS__"] : "";
|
||||
$this->assertEquals($sErrors, $oCell->GetDescription());
|
||||
}
|
||||
} else if ($i === "__ERRORS__") {
|
||||
$sErrors = array_key_exists("__ERRORS__", $aResult) ? $aResult["__ERRORS__"] : "";
|
||||
$this->assertEquals( $sErrors, $oCell->GetDescription());
|
||||
}
|
||||
$this->assertEquals($aResult[0], $aRow[0]->GetDisplayableValue());
|
||||
}
|
||||
$this->assertEquals( $aResult[0], $aRow[0]->GetDisplayableValue());
|
||||
}
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled', $db_core_transactions_enabled);
|
||||
} finally {
|
||||
CMDBSource::Query('ROLLBACK');
|
||||
}
|
||||
MetaModel::GetConfig()->Set('db_core_transactions_enabled',$db_core_transactions_enabled);
|
||||
}
|
||||
}
|
||||
@@ -108,33 +108,6 @@ class DBBackupTest extends ItopTestCase
|
||||
$this->assertStringEndsWith('--ssl-ca='.DBBackup::EscapeShellArg($sTestCa), $sCliArgsCapathCfg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Host is localhost, we should be forced into tcp
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetMysqlCliTransportOptionWithLocalhost()
|
||||
{
|
||||
$sHost= 'localhost';
|
||||
$sTransport = DBBackup::GetMysqlCliTransportOption($sHost);
|
||||
|
||||
$this->assertStringStartsWith('--protocol=tcp', $sTransport);
|
||||
$this->assertStringEndsWith('--protocol=tcp', $sTransport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Host is not localhost, we shouldn't be forced into tcp
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testGetMysqlCliTransportOptionWithoutLocalhost()
|
||||
{
|
||||
$sHost= '127.0.0.1';
|
||||
$sTransport = DBBackup::GetMysqlCliTransportOption($sHost);
|
||||
|
||||
$this->assertEmpty($sTransport);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider MakeNameProvider
|
||||
* @covers \DBBackup::MakeName
|
||||
|
||||
@@ -56,13 +56,6 @@ class iTopDesignFormatTest extends ItopTestCase
|
||||
|
||||
$sInputXml = $this->GetFileContent($sSamplesRelDirPath.$sXmlFileName.'.input');
|
||||
$oInputDesignFormat = static::GetItopFormatFromString($sInputXml);
|
||||
|
||||
// N°6562 Disable test for 1.7 => 3.0 conversion on PHP 8.1.21 / 8.2.8 as it is failing due to unknown reason. Cause will be investigated next week.
|
||||
if ((PHP_VERSION_ID === 80121 || PHP_VERSION_ID === 80208)
|
||||
&& $oInputDesignFormat->GetVersion() === "1.7" && $sTargetVersion === "3.0") {
|
||||
$this->markTestSkipped("Skip test for 1.7 => 3.0 conversion on PHP 8.1.21 as it is failing due to unknown reason. Cause will be investigated next week.");
|
||||
}
|
||||
|
||||
$bResult = $oInputDesignFormat->Convert($sTargetVersion);
|
||||
$aErrors = $oInputDesignFormat->GetErrors();
|
||||
$this->assertCount($iExpectedErrors, $aErrors,
|
||||
@@ -107,12 +100,6 @@ class iTopDesignFormatTest extends ItopTestCase
|
||||
$oExpectedDesignFormat = static::GetItopFormatFromString($sExpectedXml);
|
||||
$sExpectedVersion = $oExpectedDesignFormat->GetVersion();
|
||||
|
||||
// N°6562 Disable test for 1.7 => 3.0 conversion on PHP 8.1.21 / 8.2.8 as it is failing due to unknown reason. Cause will be investigated next week.
|
||||
if ((PHP_VERSION_ID === 80121 || PHP_VERSION_ID === 80208)
|
||||
&& $sInputVersion === "1.7" && $sExpectedVersion === "3.0") {
|
||||
$this->markTestSkipped("Skip test for 1.7 => 3.0 conversion on PHP 8.1.21 as it is failing due to unknown reason. Cause will be investigated next week.");
|
||||
}
|
||||
|
||||
if (version_compare($sInputVersion, $sExpectedVersion, '>=')) {
|
||||
$this->markTestSkipped("This dataset correspond to a downward conversion ($sInputVersion to $sExpectedVersion) and we want to test upwards conversions => skipping !");
|
||||
}
|
||||
|
||||
@@ -20,6 +20,16 @@ use utils;
|
||||
*/
|
||||
class RouterTest extends ItopTestCase
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->RequireOnceItopFile('setup/setuputils.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Combodo\iTop\Service\Router\Router::GenerateUrl
|
||||
* @dataProvider GenerateUrlProvider
|
||||
@@ -169,6 +179,94 @@ class RouterTest extends ItopTestCase
|
||||
$this->assertEquals($bShouldBePresent, $bIsPresent, "Route '$sRoute' was not expected amongst the available routes.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Combodo\iTop\Service\Router\Router::GetRoutes
|
||||
* @return void
|
||||
*
|
||||
* @since N°6618 Covers that the cache isn't re-generated at each call of the GetRoutes method
|
||||
*/
|
||||
public function testGetRoutesCacheGeneratedOnlyOnce(): void
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sRoutesCacheFilePath = $this->InvokeNonPublicMethod(Router::class, 'GetCacheFileAbsPath', $oRouter, []);
|
||||
|
||||
// Developer mode must be disabled for the routes cache to be used
|
||||
$oConf = utils::GetConfig();
|
||||
$mDeveloperModePreviousValue = $oConf->Get('developer_mode.enabled');
|
||||
$oConf->Set('developer_mode.enabled', false);
|
||||
|
||||
// Generate cache for first time
|
||||
$this->InvokeNonPublicMethod(Router::class, 'GetRoutes', $oRouter, []);
|
||||
|
||||
// Check that file exists and retrieve modification timestamp
|
||||
if (false === is_file($sRoutesCacheFilePath)) {
|
||||
$this->fail("Cache file was not generated ($sRoutesCacheFilePath)");
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
$iFirstModificationTimestamp = filemtime($sRoutesCacheFilePath);
|
||||
$this->debug("Initial timestamp: $iFirstModificationTimestamp");
|
||||
|
||||
// Wait for just 1s to ensure timestamps would be different is the file is re-generated
|
||||
sleep(1);
|
||||
|
||||
// Call GetRoutes() again to see if cache gets re-generated or not
|
||||
$this->InvokeNonPublicMethod(Router::class, 'GetRoutes', $oRouter, []);
|
||||
|
||||
// Check that file still exists and that modification timestamp has not changed
|
||||
if (false === is_file($sRoutesCacheFilePath)) {
|
||||
$this->fail("Cache file is no longer present, that should not happen! ($sRoutesCacheFilePath)");
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
$iSecondModificationTimestamp = filemtime($sRoutesCacheFilePath);
|
||||
$this->debug("Second timestamp: $iSecondModificationTimestamp");
|
||||
|
||||
$this->assertSame($iFirstModificationTimestamp, $iSecondModificationTimestamp, "Cache file timestamp changed, seems like cache is not working and was re-generated when it should not!");
|
||||
|
||||
// Restore previous value for following tests
|
||||
$oConf->Set('developer_mode.enabled', $mDeveloperModePreviousValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Combodo\iTop\Service\Router\Router::GetRoutes
|
||||
* @return void
|
||||
*
|
||||
* @since N°6618 Covers that the cache is re-generated correctly if corrupted
|
||||
*/
|
||||
public function testGetRoutesCacheRegeneratedCorrectlyIfCorrupted(): void
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sRoutesCacheFilePath = $this->InvokeNonPublicMethod(Router::class, 'GetCacheFileAbsPath', $oRouter, []);
|
||||
|
||||
// Developer mode must be disabled for the routes cache to be used
|
||||
$oConf = utils::GetConfig();
|
||||
$mDeveloperModePreviousValue = $oConf->Get('developer_mode.enabled');
|
||||
$oConf->Set('developer_mode.enabled', false);
|
||||
|
||||
// Generate corrupted cache manually
|
||||
$sFaultyStatement = 'return 1;';
|
||||
file_put_contents($sRoutesCacheFilePath, <<<PHP
|
||||
<?php
|
||||
|
||||
{$sFaultyStatement}
|
||||
PHP
|
||||
);
|
||||
|
||||
// Retrieve routes to access / fix cache in the process
|
||||
$aRoutes = $this->InvokeNonPublicMethod(Router::class, 'GetRoutes', $oRouter, []);
|
||||
|
||||
// Check that routes are an array
|
||||
$this->assertTrue(is_array($aRoutes));
|
||||
|
||||
// Check that file content doesn't contain `return 1`
|
||||
clearstatcache();
|
||||
$this->assertStringNotContainsString($sFaultyStatement, file_get_contents($sRoutesCacheFilePath), "Cache file still contains the faulty statement ($sFaultyStatement)");
|
||||
|
||||
// Restore previous value for following tests
|
||||
$oConf->Set('developer_mode.enabled', $mDeveloperModePreviousValue);
|
||||
}
|
||||
|
||||
public function GetRoutesProvider(): array
|
||||
{
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user