Compare commits
1 Commits
support/2.
...
2.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a55e337757 |
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -563,9 +563,71 @@ exit;
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
|
||||
}
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oListExpr = ListExpression::FromScalars($aUserOrgs);
|
||||
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
|
||||
if (self::HasSharing())
|
||||
{
|
||||
if (($sAttCode == 'id') && isset($aSettings['bSearchMode']) && $aSettings['bSearchMode'])
|
||||
{
|
||||
// Querying organizations (or derived)
|
||||
// and the expected list of organizations will be used as a search criteria
|
||||
// Therefore the query can also return organization having objects shared with the allowed organizations
|
||||
//
|
||||
// 1) build the list of organizations sharing something with the allowed organizations
|
||||
// Organization <== sharing_org_id == SharedObject having org_id IN {user orgs}
|
||||
$oShareSearch = new DBObjectSearch('SharedObject');
|
||||
$oOrgField = new FieldExpression('org_id', 'SharedObject');
|
||||
$oShareSearch->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
|
||||
$oSearchSharers = new DBObjectSearch('Organization');
|
||||
$oSearchSharers->AllowAllData();
|
||||
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
|
||||
$aSharers = array();
|
||||
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
|
||||
{
|
||||
$aSharers[] = $aRow['id'];
|
||||
}
|
||||
// 2) Enlarge the overall results: ... OR id IN(id1, id2, id3)
|
||||
if (count($aSharers) > 0)
|
||||
{
|
||||
$oSharersList = ListExpression::FromScalars($aSharers);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oExpression, 'IN', $oSharersList));
|
||||
}
|
||||
}
|
||||
|
||||
$aShareProperties = SharedObject::GetSharedClassProperties($sClass);
|
||||
if ($aShareProperties)
|
||||
{
|
||||
$sShareClass = $aShareProperties['share_class'];
|
||||
$sShareAttCode = $aShareProperties['attcode'];
|
||||
|
||||
$oSearchShares = new DBObjectSearch($sShareClass);
|
||||
$oSearchShares->AllowAllData();
|
||||
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
$oOrgField = new FieldExpression('org_id', $sShareClass);
|
||||
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
$aShared = array();
|
||||
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
|
||||
{
|
||||
$aShared[] = $aRow[$sShareAttCode];
|
||||
}
|
||||
if (count($aShared) > 0)
|
||||
{
|
||||
$oObjId = new FieldExpression('id', $sClass);
|
||||
$oSharedIdList = ListExpression::FromScalars($aShared);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList));
|
||||
}
|
||||
}
|
||||
} // if HasSharing
|
||||
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
||||
public function GetProfileActionGrant($iProfile, $sClass, $sAction)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -430,7 +430,7 @@ class URP_ActionGrant extends UserRightsBaseClass
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
@@ -467,7 +467,7 @@ class URP_StimulusGrant extends UserRightsBaseClass
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
@@ -503,7 +503,7 @@ class URP_AttributeGrant extends UserRightsBaseClass
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("actiongrantid", array("targetclass"=>"URP_ActionGrant", "jointype"=> "", "allowed_values"=>null, "sql"=>"actiongrantid", "is_null_allowed"=>false, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("actiongrantid", array("targetclass"=>"URP_ActionGrant", "jointype"=> "", "allowed_values"=>null, "sql"=>"actiongrantid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
@@ -822,7 +822,70 @@ exit;
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->MakeSelectFilter($sClass, $aUserOrgs, $aSettings, $sAttCode);
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oListExpr = ListExpression::FromScalars($aUserOrgs);
|
||||
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
|
||||
if (self::HasSharing())
|
||||
{
|
||||
if (($sAttCode == 'id') && isset($aSettings['bSearchMode']) && $aSettings['bSearchMode'])
|
||||
{
|
||||
// Querying organizations (or derived)
|
||||
// and the expected list of organizations will be used as a search criteria
|
||||
// Therefore the query can also return organization having objects shared with the allowed organizations
|
||||
//
|
||||
// 1) build the list of organizations sharing something with the allowed organizations
|
||||
// Organization <== sharing_org_id == SharedObject having org_id IN {user orgs}
|
||||
$oShareSearch = new DBObjectSearch('SharedObject');
|
||||
$oOrgField = new FieldExpression('org_id', 'SharedObject');
|
||||
$oShareSearch->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
|
||||
$oSearchSharers = new DBObjectSearch('Organization');
|
||||
$oSearchSharers->AllowAllData();
|
||||
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
|
||||
$aSharers = array();
|
||||
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
|
||||
{
|
||||
$aSharers[] = $aRow['id'];
|
||||
}
|
||||
// 2) Enlarge the overall results: ... OR id IN(id1, id2, id3)
|
||||
if (count($aSharers) > 0)
|
||||
{
|
||||
$oSharersList = ListExpression::FromScalars($aSharers);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oExpression, 'IN', $oSharersList));
|
||||
}
|
||||
}
|
||||
|
||||
$aShareProperties = SharedObject::GetSharedClassProperties($sClass);
|
||||
if ($aShareProperties)
|
||||
{
|
||||
$sShareClass = $aShareProperties['share_class'];
|
||||
$sShareAttCode = $aShareProperties['attcode'];
|
||||
|
||||
$oSearchShares = new DBObjectSearch($sShareClass);
|
||||
$oSearchShares->AllowAllData();
|
||||
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
$oOrgField = new FieldExpression('org_id', $sShareClass);
|
||||
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
$aShared = array();
|
||||
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
|
||||
{
|
||||
$aShared[] = $aRow[$sShareAttCode];
|
||||
}
|
||||
if (count($aShared) > 0)
|
||||
{
|
||||
$oObjId = new FieldExpression('id', $sClass);
|
||||
$oSharedIdList = ListExpression::FromScalars($aShared);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList));
|
||||
}
|
||||
}
|
||||
} // if HasSharing
|
||||
|
||||
return $oFilter;
|
||||
}
|
||||
|
||||
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
||||
|
||||
@@ -124,20 +124,7 @@ class ajax_page extends WebPage
|
||||
<<<EOF
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
// Ugly patch for a change in the behavior of jQuery UI:
|
||||
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
|
||||
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
|
||||
// is taken into account and causes "local" tabs to be considered as Ajax
|
||||
// unless their URL is equal to the URL of the page...
|
||||
if ($('base').length > 0)
|
||||
{
|
||||
$('div[id^=tabbedContent] > ul > li > a').each(function() {
|
||||
var sHash = location.hash;
|
||||
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
|
||||
$(this).attr("href", sCleanLocation+$(this).attr("href"));
|
||||
});
|
||||
}
|
||||
|
||||
if ($.bbq)
|
||||
{
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
@@ -187,7 +174,7 @@ EOF
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<li><a href=\"#tab_{$sPrefix}{$sTabContainerName}$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
|
||||
$sTabs .= "<li><a href=\"#tab_{$sPrefix}$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</ul>\n";
|
||||
@@ -195,7 +182,7 @@ EOF
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<div id=\"tab_{$sPrefix}{$sTabContainerName}$i\">".$sTabContent."</div>\n";
|
||||
$sTabs .= "<div id=\"tab_{$sPrefix}$i\">".$sTabContent."</div>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</div>\n<!-- end of tabs-->\n";
|
||||
|
||||
@@ -31,7 +31,6 @@ require_once(APPROOT.'/application/sqlblock.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.category.class.inc.php');
|
||||
require_once(APPROOT.'/application/audit.rule.class.inc.php');
|
||||
require_once(APPROOT.'/application/query.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
|
||||
//require_once(APPROOT.'/application/menunode.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
|
||||
@@ -450,8 +450,7 @@ class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
/** @ignore */
|
||||
public function GetMenuItem()
|
||||
{
|
||||
// Note: the semicolumn is a must here!
|
||||
return array ('label' => $this->GetLabel(), 'onclick' => $this->sJSCode.'; return false;', 'url' => '#');
|
||||
return array ('label' => $this->GetLabel(), 'onclick' => $this->sJSCode, 'url' => '#');
|
||||
}
|
||||
|
||||
/** @ignore */
|
||||
@@ -581,14 +580,6 @@ class RestResult
|
||||
* Result: the input structure is not a valid JSON string
|
||||
*/
|
||||
const INVALID_JSON = 4;
|
||||
/**
|
||||
* Result: the parameter 'auth_user' is missing, authentication aborted
|
||||
*/
|
||||
const MISSING_AUTH_USER = 5;
|
||||
/**
|
||||
* Result: the parameter 'auth_pwd' is missing, authentication aborted
|
||||
*/
|
||||
const MISSING_AUTH_PWD = 6;
|
||||
/**
|
||||
* Result: no operation is available for the specified version
|
||||
*/
|
||||
@@ -768,7 +759,7 @@ class RestUtils
|
||||
foreach ($oCriteria as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||
$oSearch->AddCondition($sAttCode, $realValue);
|
||||
$aCriteriaReport[] = "$sAttCode: $value ($realValue)";
|
||||
}
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
@@ -791,12 +782,11 @@ class RestUtils
|
||||
*
|
||||
* @param string $sClass Name of the class
|
||||
* @param mixed $key Either search criteria (substructure), or an object or an OQL string.
|
||||
* @param bool $bAllowNullValue Allow the cases such as key = 0 or key = {null} and return null then
|
||||
* @return DBObject The object found
|
||||
* @throws Exception If the input structure is not valid or it could not find exactly one object
|
||||
* @api
|
||||
*/
|
||||
public static function FindObjectFromKey($sClass, $key, $bAllowNullValue = false)
|
||||
public static function FindObjectFromKey($sClass, $key)
|
||||
{
|
||||
if (is_object($key))
|
||||
{
|
||||
@@ -804,17 +794,10 @@ class RestUtils
|
||||
}
|
||||
elseif (is_numeric($key))
|
||||
{
|
||||
if ($bAllowNullValue && ($key == 0))
|
||||
$res = MetaModel::GetObject($sClass, $key, false);
|
||||
if (is_null($res))
|
||||
{
|
||||
$res = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$res = MetaModel::GetObject($sClass, $key, false);
|
||||
if (is_null($res))
|
||||
{
|
||||
throw new Exception("Invalid object $sClass::$key");
|
||||
}
|
||||
throw new Exception("Invalid object $sClass::$key");
|
||||
}
|
||||
}
|
||||
elseif (is_string($key))
|
||||
@@ -865,7 +848,7 @@ class RestUtils
|
||||
foreach ($key as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||
$oSearch->AddCondition($sAttCode, $realValue);
|
||||
}
|
||||
}
|
||||
elseif (is_numeric($key))
|
||||
@@ -908,8 +891,8 @@ class RestUtils
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeExternalKey)
|
||||
{
|
||||
$oExtKeyObject = self::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
|
||||
$value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
|
||||
$oExtKeyObject = self::FindObjectFromKey($oAttDef->GetTargetClass(), $value);
|
||||
$value = $oExtKeyObject->GetKey();
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeLinkedSet)
|
||||
{
|
||||
@@ -953,14 +936,7 @@ class RestUtils
|
||||
foreach ($aFields as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
try
|
||||
{
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||
}
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
}
|
||||
return $oObject;
|
||||
}
|
||||
@@ -980,14 +956,7 @@ class RestUtils
|
||||
foreach ($aFields as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
try
|
||||
{
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
throw new Exception("$sAttCode: ".$e->getMessage(), $e->getCode());
|
||||
}
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
}
|
||||
return $oObject;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -240,7 +240,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sTip .= Dict::S('Core:Synchro:LastSynchro').'<br/>'.$aStruct['last_synchro']."</p>";
|
||||
}
|
||||
$sSynchroIcon = ' <img style="vertical-align:middle;" id="synchro_icon" src="../images/locked.png"/>';
|
||||
$sTip = addslashes($sTip);
|
||||
$oPage->add_ready_script("$('#synchro_icon').qtip( { content: '$sTip', show: 'mouseover', hide: { fixed: true }, style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );");
|
||||
}
|
||||
|
||||
@@ -286,7 +285,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
{
|
||||
$sComment = (isset($aExtraParams['fieldsComments'][$sAttCode])) ? $aExtraParams['fieldsComments'][$sAttCode] : '';
|
||||
$this->DisplayCaseLog($oPage, $sAttCode, $sComment, $sPrefix, $bEditMode);
|
||||
$aFieldsMap[$sAttCode] = $this->m_iFormId.'_'.$sAttCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,28 +431,15 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
if (count($aTriggers) > 0)
|
||||
{
|
||||
// Display notifications regarding the object
|
||||
$iId = $this->GetKey();
|
||||
$sTriggersList = implode(',', $aTriggers);
|
||||
$aNotifSearches = array();
|
||||
$iNotifsCount = 0;
|
||||
$aNotificationClasses = MetaModel::EnumChildClasses('EventNotification', ENUM_CHILD_CLASSES_EXCLUDETOP);
|
||||
foreach($aNotificationClasses as $sNotifClass)
|
||||
{
|
||||
$aNotifSearches[$sNotifClass] = DBObjectSearch::FromOQL("SELECT $sNotifClass AS Ev JOIN Trigger AS T ON Ev.trigger_id = T.id WHERE T.id IN ($sTriggersList) AND Ev.object_id = $iId");
|
||||
$oNotifSet = new DBObjectSet($aNotifSearches[$sNotifClass]);
|
||||
$iNotifsCount += $oNotifSet->Count();
|
||||
}
|
||||
// Display notifications regarding the object: on block per subclass to have the intersting columns
|
||||
$sCount = ($iNotifsCount > 0) ? ' ('.$iNotifsCount.')' : '';
|
||||
$oNotifSearch = DBObjectSearch::FromOQL("SELECT EventNotificationEmail AS Ev JOIN Trigger AS T ON Ev.trigger_id = T.id WHERE T.id IN ($sTriggersList) AND Ev.object_id = $iId");
|
||||
$oNotifSet = new DBObjectSet($oNotifSearch);
|
||||
$sCount = ($oNotifSet->Count() > 0) ? ' ('.$oNotifSet->Count().')' : '';
|
||||
$oPage->SetCurrentTab(Dict::S('UI:NotificationsTab').$sCount);
|
||||
|
||||
foreach($aNotificationClasses as $sNotifClass)
|
||||
{
|
||||
|
||||
$oPage->p(MetaModel::GetClassIcon($sNotifClass, true).' '.MetaModel::GetName($sNotifClass));
|
||||
$oBlock = new DisplayBlock($aNotifSearches[$sNotifClass], 'list', false);
|
||||
$oBlock->Display($oPage, 'notifications_'.$sNotifClass, array('menu' => false));
|
||||
}
|
||||
$oBlock = new DisplayBlock($oNotifSearch, 'list', false);
|
||||
$oBlock->Display($oPage, 'notifications', array('menu' => false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -819,6 +804,9 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sClassAlias = $oSet->GetClassAlias();
|
||||
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
|
||||
|
||||
// Load only the requested columns
|
||||
$oSet->OptimizeColumnLoad(array($sClassAlias => $aList));
|
||||
|
||||
$sTableId = isset($aExtraParams['table_id']) ? $aExtraParams['table_id'] : null;
|
||||
$aClassAliases = array( $sClassAlias => $sClassName);
|
||||
$oDataTable = new DataTable($iListId, $oSet, $aClassAliases, $sTableId);
|
||||
@@ -918,6 +906,16 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
}
|
||||
// Load only the requested columns
|
||||
$aAttToLoad = array(); // attributes to load
|
||||
foreach($aAuthorizedClasses as $sAlias => $sClassName)
|
||||
{
|
||||
foreach($aList[$sAlias] as $sAttCode)
|
||||
{
|
||||
$aAttToLoad[$sAlias][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
$oSet->OptimizeColumnLoad($aAttToLoad);
|
||||
|
||||
$sSelectMode = 'none';
|
||||
|
||||
@@ -1030,7 +1028,12 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
foreach($aList[$sAlias] as $sAttCodeEx => $oAttDef)
|
||||
{
|
||||
$aHeader[] = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx;
|
||||
$sStar = '';
|
||||
if (!$oAttDef->IsNullAllowed() && isset($aParams['showMandatoryFields']))
|
||||
{
|
||||
$sStar = '*';
|
||||
}
|
||||
$aHeader[] = ($bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx) : $sAttCodeEx).$sStar;
|
||||
}
|
||||
}
|
||||
$sHtml = implode($sSeparator, $aHeader)."\n";
|
||||
@@ -1216,27 +1219,15 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$aRow[] = '<td>'.date('H:i:s', $iDate).'</td>';
|
||||
}
|
||||
}
|
||||
else if($oAttDef instanceof AttributeCaseLog)
|
||||
{
|
||||
$rawValue = $oObj->Get($sAttCodeEx);
|
||||
$outputValue = str_replace("\n", "<br/>", htmlentities($rawValue->__toString(), ENT_QUOTES, 'UTF-8'));
|
||||
// Trick for Excel: treat the content as text even if it begins with an equal sign
|
||||
$aRow[] = '<td x:str>'.$outputValue.'</td>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$rawValue = $oObj->Get($sAttCodeEx);
|
||||
// Due to custom formatting rules, empty friendlynames may be rendered as non-empty strings
|
||||
// let's fix this and make sure we render an empty string if the key == 0
|
||||
if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
if ($sKeyAttCode != 'id')
|
||||
if ($oObj->Get($sKeyAttCode) == 0)
|
||||
{
|
||||
if ($oObj->Get($sKeyAttCode) == 0)
|
||||
{
|
||||
$rawValue = '';
|
||||
}
|
||||
$rawValue = '';
|
||||
}
|
||||
}
|
||||
if ($bLocalize)
|
||||
@@ -1433,24 +1424,20 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sFilterCode);
|
||||
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$oKeyAttDef = $oAttDef->GetFinalAttDef();
|
||||
$sKeyAttClass = $oKeyAttDef->GetHostClass();
|
||||
$sKeyAttCode = $oKeyAttDef->GetCode();
|
||||
|
||||
$sTargetClass = $oKeyAttDef->GetTargetClass();
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$oSearch = new DBObjectSearch($sTargetClass);
|
||||
$oSearch->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', true);
|
||||
$oAllowedValues = new DBObjectSet($oSearch);
|
||||
|
||||
$iFieldSize = $oKeyAttDef->GetMaxSize();
|
||||
$iMaxComboLength = $oKeyAttDef->GetMaximumComboLength();
|
||||
$sHtml .= "<label>".MetaModel::GetFilterLabel($sKeyAttClass, $sKeyAttCode).":</label> ";
|
||||
$iFieldSize = $oAttDef->GetMaxSize();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
$sHtml .= "<label>".MetaModel::GetFilterLabel($sClassName, $sFilterCode).":</label> ";
|
||||
$aExtKeyParams = $aExtraParams;
|
||||
$aExtKeyParams['iFieldSize'] = $oKeyAttDef->GetMaxSize();
|
||||
$aExtKeyParams['iMinChars'] = $oKeyAttDef->GetMinAutoCompleteChars();
|
||||
$sHtml .= UIExtKeyWidget::DisplayFromAttCode($oPage, $sKeyAttCode, $sKeyAttClass, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sSearchFormId.'search_'.$sFilterCode, false, $sFilterCode, '', $aExtKeyParams, true);
|
||||
$aExtKeyParams['iFieldSize'] = $oAttDef->GetMaxSize();
|
||||
$aExtKeyParams['iMinChars'] = $oAttDef->GetMinAutoCompleteChars();
|
||||
$sHtml .= UIExtKeyWidget::DisplayFromAttCode($oPage, $sFilterCode, $sClassName, $oAttDef->GetLabel(), $oAllowedValues, $sFilterValue, $sSearchFormId.'search_'.$sFilterCode, false, $sFilterCode, '', $aExtKeyParams, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1466,7 +1453,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sValue = "<select class=\"multiselect\" size=\"1\" name=\"{$sFilterCode}[]\" multiple>\n";
|
||||
$bMultiSelect = true;
|
||||
//$sValue .= "<option value=\"\">".Dict::S('UI:SearchValue:Any')."</option>\n";
|
||||
asort($aAllowedValues);
|
||||
foreach($aAllowedValues as $key => $value)
|
||||
{
|
||||
if (is_array($sFilterValue) && in_array($key, $sFilterValue))
|
||||
@@ -1511,10 +1497,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
if (is_scalar($sValue))
|
||||
{
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
|
||||
}
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
|
||||
}
|
||||
$sHtml .= "<input type=\"hidden\" name=\"class\" value=\"$sClassName\" />\n";
|
||||
$sHtml .= "<input type=\"hidden\" name=\"dosearch\" value=\"1\" />\n";
|
||||
@@ -1527,16 +1510,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
if ($bMultiSelect)
|
||||
{
|
||||
$aOptions = array(
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect({header: false, noneSelectedText: '".addslashes(Dict::S('UI:SearchValue:Any'))."', selectedList: 1, selectedText:'".addslashes(Dict::S('UI:SearchValue:NbSelected'))."'});");
|
||||
}
|
||||
/*
|
||||
// OQL query builder
|
||||
@@ -1559,10 +1533,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sHtml .= "<input type=\"hidden\" name=\"dosearch\" value=\"1\" />\n";
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
if (is_scalar($sValue))
|
||||
{
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
|
||||
}
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
|
||||
}
|
||||
$sHtml .= "<input type=\"hidden\" name=\"operation\" value=\"search_oql\" />\n";
|
||||
$sHtml .= $oAppContext->GetForForm();
|
||||
@@ -2013,10 +1984,7 @@ EOF
|
||||
$oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"$iTransactionId\">\n");
|
||||
foreach($aExtraParams as $sName => $value)
|
||||
{
|
||||
if (is_scalar($value))
|
||||
{
|
||||
$oPage->add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">\n");
|
||||
}
|
||||
$oPage->add("<input type=\"hidden\" name=\"$sName\" value=\"$value\">\n");
|
||||
}
|
||||
$oPage->add($oAppContext->GetForForm());
|
||||
if ($sButtonsPosition != 'top')
|
||||
@@ -2125,138 +2093,6 @@ EOF
|
||||
}
|
||||
return $oObj->DisplayModifyForm( $oPage, $aExtraParams);
|
||||
}
|
||||
|
||||
public function DisplayStimulusForm(WebPage $oPage, $sStimulus)
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$aTransitions = $this->EnumTransitions();
|
||||
$aStimuli = MetaModel::EnumStimuli($sClass);
|
||||
if (!isset($aTransitions[$sStimulus]))
|
||||
{
|
||||
// Invalid stimulus
|
||||
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $this->GetName(), $this->GetStateLabel()));
|
||||
}
|
||||
$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
|
||||
$sActionDetails = $aStimuli[$sStimulus]->GetDescription();
|
||||
$aTransition = $aTransitions[$sStimulus];
|
||||
$sTargetState = $aTransition['target_state'];
|
||||
$aTargetStates = MetaModel::EnumStates($sClass);
|
||||
$oPage->add("<div class=\"page_header\">\n");
|
||||
$oPage->add("<h1>$sActionLabel - <span class=\"hilite\">{$this->GetName()}</span></h1>\n");
|
||||
$oPage->set_title($sActionLabel);
|
||||
$oPage->add("</div>\n");
|
||||
$aTargetState = $aTargetStates[$sTargetState];
|
||||
$aExpectedAttributes = $aTargetState['attribute_list'];
|
||||
$oPage->add("<h1>$sActionDetails</h1>\n");
|
||||
$sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position');
|
||||
if ($sButtonsPosition == 'bottom')
|
||||
{
|
||||
// bottom: Displays the ticket details BEFORE the actions
|
||||
$oPage->add('<div class="ui-widget-content">');
|
||||
$this->DisplayBareProperties($oPage);
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
$oPage->add("<div class=\"wizContainer\">\n");
|
||||
$oPage->add("<form id=\"apply_stimulus\" method=\"post\" onSubmit=\"return OnSubmit('apply_stimulus');\">\n");
|
||||
$aDetails = array();
|
||||
$iFieldIndex = 0;
|
||||
$aFieldsMap = array();
|
||||
|
||||
$aDetailsList =$this->FlattenZList(MetaModel::GetZListItems($sClass, 'details'));
|
||||
// Order the fields based on their dependencies, set the fields for which there is only one possible value
|
||||
// and perform this in the order of dependencies to avoid dead-ends
|
||||
$aDeps = array();
|
||||
foreach($aDetailsList as $sAttCode)
|
||||
{
|
||||
$aDeps[$sAttCode] = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode);
|
||||
}
|
||||
$aList =$this->OrderDependentFields($aDeps);
|
||||
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
// Consider only the "expected" fields for the target state
|
||||
if (array_key_exists($sAttCode, $aExpectedAttributes))
|
||||
{
|
||||
$iExpectCode = $aExpectedAttributes[$sAttCode];
|
||||
// Prompt for an attribute if
|
||||
// - the attribute must be changed or must be displayed to the user for confirmation
|
||||
// - or the field is mandatory and currently empty
|
||||
if ( ($iExpectCode & (OPT_ATT_MUSTCHANGE | OPT_ATT_MUSTPROMPT)) ||
|
||||
(($iExpectCode & OPT_ATT_MANDATORY) && ($this->Get($sAttCode) == '')) )
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aArgs = array('this' => $this);
|
||||
// If the field is mandatory, set it to the only possible value
|
||||
if ((!$oAttDef->IsNullAllowed()) || ($iExpectCode & OPT_ATT_MANDATORY))
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$oAllowedValues = MetaModel::GetAllowedValuesAsObjectSet($sClass, $sAttCode, $aArgs);
|
||||
if ($oAllowedValues->Count() == 1)
|
||||
{
|
||||
$oRemoteObj = $oAllowedValues->Fetch();
|
||||
$this->Set($sAttCode, $oRemoteObj->GetKey());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs);
|
||||
if (count($aAllowedValues) == 1)
|
||||
{
|
||||
$aValues = array_keys($aAllowedValues);
|
||||
$this->Set($sAttCode, $aValues[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHTMLValue = cmdbAbstractObject::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef,$this->Get($sAttCode),$this->GetEditValue($sAttCode), 'att_'.$iFieldIndex, '', $iExpectCode, $aArgs);
|
||||
$aDetails[] = array('label' => '<span>'.$oAttDef->GetLabel().'</span>', 'value' => "<span id=\"field_att_$iFieldIndex\">$sHTMLValue</span>");
|
||||
$aFieldsMap[$sAttCode] = 'att_'.$iFieldIndex;
|
||||
$iFieldIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oPage->add('<table><tr><td>');
|
||||
$oPage->details($aDetails);
|
||||
$oPage->add('</td></tr></table>');
|
||||
$oPage->add("<input type=\"hidden\" name=\"id\" value=\"".$this->GetKey()."\" id=\"id\">\n");
|
||||
$aFieldsMap['id'] = 'id';
|
||||
$oPage->add("<input type=\"hidden\" name=\"class\" value=\"$sClass\">\n");
|
||||
$oPage->add("<input type=\"hidden\" name=\"operation\" value=\"apply_stimulus\">\n");
|
||||
$oPage->add("<input type=\"hidden\" name=\"stimulus\" value=\"$sStimulus\">\n");
|
||||
$oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">\n");
|
||||
$oAppContext = new ApplicationContext();
|
||||
$oPage->add($oAppContext->GetForForm());
|
||||
$oPage->add("<button type=\"button\" class=\"action\" onClick=\"BackToDetails('$sClass', ".$this->GetKey().")\"><span>".Dict::S('UI:Button:Cancel')."</span></button> \n");
|
||||
$oPage->add("<button type=\"submit\" class=\"action\"><span>$sActionLabel</span></button>\n");
|
||||
$oPage->add("</form>\n");
|
||||
$oPage->add("</div>\n");
|
||||
if ($sButtonsPosition != 'top')
|
||||
{
|
||||
// bottom or both: Displays the ticket details AFTER the actions
|
||||
$oPage->add('<div class="ui-widget-content">');
|
||||
$this->DisplayBareProperties($oPage);
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
$iFieldsCount = count($aFieldsMap);
|
||||
$sJsonFieldsMap = json_encode($aFieldsMap);
|
||||
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
// Initializes the object once at the beginning of the page...
|
||||
var oWizardHelper = new WizardHelper('$sClass', '', '$sTargetState');
|
||||
oWizardHelper.SetFieldsMap($sJsonFieldsMap);
|
||||
oWizardHelper.SetFieldsCount($iFieldsCount);
|
||||
EOF
|
||||
);
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
// Starts the validation when the page is ready
|
||||
CheckFields('apply_stimulus', false);
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public static function ProcessZlist($aList, $aDetails, $sCurrentTab, $sCurrentCol, $sCurrentSet)
|
||||
{
|
||||
@@ -2698,8 +2534,7 @@ EOF
|
||||
$this->Set($sAttCode, $iValue);
|
||||
}
|
||||
}
|
||||
else if (($oAttDef->GetEditClass() == 'LinkedSet') && !$oAttDef->IsIndirect() &&
|
||||
(($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE) || ($oAttDef->GetEditMode() == LINKSET_EDITMODE_ADDREMOVE)))
|
||||
else if (($oAttDef->GetEditClass() == 'LinkedSet') && !$oAttDef->IsIndirect() && ($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE))
|
||||
{
|
||||
$oLinkset = $this->Get($sAttCode);
|
||||
$sLinkedClass = $oLinkset->GetClass();
|
||||
@@ -2715,16 +2550,13 @@ EOF
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!array_key_exists('to_be_removed', $value) || !in_array($oLink->GetKey(), $value['to_be_removed']))
|
||||
{
|
||||
$aObjSet[] = $oLink;
|
||||
}
|
||||
$aObjSet[] = $oLink;
|
||||
}
|
||||
}
|
||||
|
||||
if (array_key_exists('to_be_created', $value) && (count($value['to_be_created']) > 0))
|
||||
{
|
||||
// Now handle the links to be created
|
||||
// Now handle the lniks to be created
|
||||
foreach($value['to_be_created'] as $aData)
|
||||
{
|
||||
$sSubClass = $aData['class'];
|
||||
@@ -2739,35 +2571,7 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
if (array_key_exists('to_be_added', $value) && (count($value['to_be_added']) > 0))
|
||||
{
|
||||
// Now handle the links to be added by making the remote object point to self
|
||||
foreach($value['to_be_added'] as $iObjKey)
|
||||
{
|
||||
$oLink = MetaModel::GetObject($sLinkedClass, $iObjKey, false);
|
||||
if ($oLink)
|
||||
{
|
||||
$aObjSet[] = $oLink;
|
||||
$bModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (array_key_exists('to_be_removed', $value) && (count($value['to_be_removed']) > 0))
|
||||
{
|
||||
// Now handle the links to be removed by making the remote object point to nothing
|
||||
// Keep them in the set (modified), DBWriteLinks will handle them
|
||||
foreach($value['to_be_removed'] as $iObjKey)
|
||||
{
|
||||
$oLink = MetaModel::GetObject($sLinkedClass, $iObjKey, false);
|
||||
if ($oLink)
|
||||
{
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
$oLink->Set($sExtKeyToMe, null);
|
||||
$aObjSet[] = $oLink;
|
||||
$bModified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($bModified)
|
||||
{
|
||||
$oNewSet = DBObjectSet::FromArray($oLinkset->GetClass(), $aObjSet);
|
||||
@@ -2806,8 +2610,7 @@ EOF
|
||||
{
|
||||
$value = array('fcontents' => utils::ReadPostedDocument("attr_{$sFormPrefix}{$sAttCode}", 'fcontents'));
|
||||
}
|
||||
else if (($oAttDef->GetEditClass() == 'LinkedSet') && !$oAttDef->IsIndirect() &&
|
||||
(($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE) || ($oAttDef->GetEditMode() == LINKSET_EDITMODE_ADDREMOVE)) )
|
||||
else if (($oAttDef->GetEditClass() == 'LinkedSet') && !$oAttDef->IsIndirect() && ($oAttDef->GetEditMode() == LINKSET_EDITMODE_INPLACE))
|
||||
{
|
||||
$aRawToBeCreated = json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbc", '{}', 'raw_data'), true);
|
||||
$aToBeCreated = array();
|
||||
@@ -2827,9 +2630,7 @@ EOF
|
||||
}
|
||||
|
||||
$value = array('to_be_created' => $aToBeCreated,
|
||||
'to_be_deleted' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbd", '[]', 'raw_data'), true),
|
||||
'to_be_added' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tba", '[]', 'raw_data'), true),
|
||||
'to_be_removed' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbr", '[]', 'raw_data'), true) );
|
||||
'to_be_deleted' => json_decode(utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}_tbd", '[]', 'raw_data'), true) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2848,7 +2649,7 @@ EOF
|
||||
$aFinalValues[$sAttCode] = $aValues[$sAttCode];
|
||||
}
|
||||
$this->UpdateObjectFromArray($aFinalValues);
|
||||
|
||||
|
||||
// Invoke extensions after the update of the object from the form
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
@@ -3069,7 +2870,7 @@ EOF
|
||||
|
||||
// Attribute is read-only
|
||||
$sHTMLValue = $this->GetAsHTML($sAttCode);
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->GetEditValue($sAttCode), ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$sHTMLValue .= '<input type="hidden" id="'.$sInputId.'" name="attr_'.$sPrefix.$sAttCode.'" value="'.htmlentities($this->Get($sAttCode), ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$aFieldsMap[$sAttCode] = $sInputId;
|
||||
$sComment .= $sSynchroIcon;
|
||||
}
|
||||
@@ -3101,7 +2902,7 @@ EOF
|
||||
if (!isset($aTransitions[$sStimulus]))
|
||||
{
|
||||
// Invalid stimulus
|
||||
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus,$this->GetName(),$this->GetStateLabel()));
|
||||
throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel()));
|
||||
}
|
||||
$aTransition = $aTransitions[$sStimulus];
|
||||
$sTargetState = $aTransition['target_state'];
|
||||
@@ -3246,11 +3047,7 @@ EOF
|
||||
$currValue = $aKeys[0]; // The only value is the first key
|
||||
//echo "<p>current value for $sAttCode : $currValue</p>";
|
||||
$oDummyObj->Set($sAttCode, $currValue);
|
||||
$aComments[$sAttCode] = '';
|
||||
if ($sAttCode != MetaModel::GetStateAttributeCode($sClass))
|
||||
{
|
||||
$aComments[$sAttCode] .= '<input type="checkbox" checked id="enable_'.$iFormId.'_'.$sAttCode.'" onClick="ToogleField(this.checked, \''.$iFormId.'_'.$sAttCode.'\')"/>';
|
||||
}
|
||||
$aComments[$sAttCode] = '<input type="checkbox" checked id="enable_'.$iFormId.'_'.$sAttCode.'" onClick="ToogleField(this.checked, \''.$iFormId.'_'.$sAttCode.'\')"/>';
|
||||
$aComments[$sAttCode] .= '<div class="mono_value">1</div>';
|
||||
}
|
||||
else
|
||||
@@ -3277,11 +3074,7 @@ EOF
|
||||
$sReadyScript .= "$('#multi_values_$sAttCode').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );";
|
||||
|
||||
$oDummyObj->Set($sAttCode, null);
|
||||
$aComments[$sAttCode] = '';
|
||||
if ($sAttCode != MetaModel::GetStateAttributeCode($sClass))
|
||||
{
|
||||
$aComments[$sAttCode] .= '<input type="checkbox" id="enable_'.$iFormId.'_'.$sAttCode.'" onClick="ToogleField(this.checked, \''.$iFormId.'_'.$sAttCode.'\')"/>';
|
||||
}
|
||||
$aComments[$sAttCode] = '<input type="checkbox" id="enable_'.$iFormId.'_'.$sAttCode.'" onClick="ToogleField(this.checked, \''.$iFormId.'_'.$sAttCode.'\')"/>';
|
||||
$aComments[$sAttCode] .= '<div class="multi_values" id="multi_values_'.$sAttCode.'">'.$iCount.'</div>';
|
||||
}
|
||||
$sReadyScript .= 'ToogleField('.(($iCount == 1) ? 'true': 'false').', \''.$iFormId.'_'.$sAttCode.'\');'."\n";
|
||||
@@ -3355,7 +3148,7 @@ EOF
|
||||
$aRows = array();
|
||||
|
||||
$oP->add("<div class=\"page_header\">\n");
|
||||
$oP->add("<h1>".MetaModel::GetClassIcon($sClass)." ".Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), MetaModel::GetName($sClass))."</h1>\n");
|
||||
$oP->add("<h1>".MetaModel::GetClassIcon($sClass)." ".Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), $sClass)."</h1>\n");
|
||||
$oP->add("</div>\n");
|
||||
$oP->set_title(Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), $sClass));
|
||||
if (!$bPreview)
|
||||
@@ -3368,10 +3161,8 @@ EOF
|
||||
}
|
||||
utils::RemoveTransaction($sTransactionId);
|
||||
}
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
foreach($aSelectedObj as $iId)
|
||||
{
|
||||
set_time_limit(5);
|
||||
$oObj = MetaModel::GetObject($sClass, $iId);
|
||||
$aErrors = $oObj->UpdateObjectFromPostedForm('');
|
||||
$bResult = (count($aErrors) == 0);
|
||||
@@ -3402,7 +3193,6 @@ EOF
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
$oP->Table($aHeaders, $aRows);
|
||||
if ($bPreview)
|
||||
{
|
||||
@@ -3431,12 +3221,12 @@ EOF
|
||||
{
|
||||
foreach($value as $vKey => $vValue)
|
||||
{
|
||||
$oP->add("<input type=\"hidden\" name=\"{$sKey}[$vKey]\" value=\"".htmlentities($vValue, ENT_QUOTES, 'UTF-8')."\">\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"{$sKey}[$vKey]\" value=\"$vValue\">\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->add("<input type=\"hidden\" name=\"$sKey\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\">\n");
|
||||
$oP->add("<input type=\"hidden\" name=\"$sKey\" value=\"$value\">\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
|
||||
/**
|
||||
* A user editable dashboard page
|
||||
@@ -29,26 +28,20 @@ require_once(APPROOT.'core/modelreflection.class.inc.php');
|
||||
abstract class Dashboard
|
||||
{
|
||||
protected $sTitle;
|
||||
protected $bAutoReload;
|
||||
protected $iAutoReloadSec;
|
||||
protected $sLayoutClass;
|
||||
protected $aWidgetsData;
|
||||
protected $oDOMNode;
|
||||
protected $sId;
|
||||
protected $aCells;
|
||||
protected $oMetaModel;
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
$this->sTitle = '';
|
||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||
$this->bAutoReload = false;
|
||||
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
||||
$this->sLayoutClass = null;
|
||||
$this->aCells = array();
|
||||
$this->oDOMNode = null;
|
||||
$this->sId = $sId;
|
||||
}
|
||||
|
||||
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$this->aCells = array(); // reset the content of the dashboard
|
||||
@@ -56,97 +49,60 @@ abstract class Dashboard
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc->loadXML($sXml);
|
||||
restore_error_handler();
|
||||
$this->FromDOMDocument($oDoc);
|
||||
}
|
||||
|
||||
public function FromDOMDocument(DOMDocument $oDoc)
|
||||
{
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
if ($oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0))
|
||||
$oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0);
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
|
||||
$oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0);
|
||||
$this->sTitle = $oTitleNode->textContent;
|
||||
|
||||
$oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0);
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$iCellRank = 0;
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
$aDashletList = array();
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
}
|
||||
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$sDashletClass = $oDomNode->getAttribute('xsi:type');
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank)
|
||||
{
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$oNewDashlet = new $sDashletClass($sId);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
||||
}
|
||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
||||
$aDashletList = array();
|
||||
foreach($aDashletOrder as $aItem)
|
||||
{
|
||||
$aDashletList[] = $aItem['dashlet'];
|
||||
}
|
||||
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
|
||||
}
|
||||
else
|
||||
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
|
||||
foreach($aCellOrder as $aItem)
|
||||
{
|
||||
$this->sLayoutClass = 'DashboardLayoutOneCol';
|
||||
$this->aCells[] = $aItem['dashlets'];
|
||||
}
|
||||
|
||||
if ($oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0))
|
||||
{
|
||||
$this->sTitle = $oTitleNode->textContent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->sTitle = '';
|
||||
}
|
||||
|
||||
$this->bAutoReload = false;
|
||||
$this->iAutoReloadSec = MetaModel::GetConfig()->GetStandardReloadInterval();
|
||||
if ($oAutoReloadNode = $this->oDOMNode->getElementsByTagName('auto_reload')->item(0))
|
||||
{
|
||||
if ($oAutoReloadEnabled = $oAutoReloadNode->getElementsByTagName('enabled')->item(0))
|
||||
{
|
||||
$this->bAutoReload = ($oAutoReloadEnabled->textContent == 'true');
|
||||
}
|
||||
if ($oAutoReloadInterval = $oAutoReloadNode->getElementsByTagName('interval')->item(0))
|
||||
{
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$oAutoReloadInterval->textContent);
|
||||
}
|
||||
}
|
||||
|
||||
if ($oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0))
|
||||
{
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
$aCellOrder = array();
|
||||
$iCellRank = 0;
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$aDashletList = array();
|
||||
$oCellRank = $oCellNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oCellRank)
|
||||
{
|
||||
$iCellRank = (float)$oCellRank->textContent;
|
||||
}
|
||||
$oDashletsNode = $oCellNode->getElementsByTagName('dashlets')->item(0);
|
||||
{
|
||||
$oDashletList = $oDashletsNode->getElementsByTagName('dashlet');
|
||||
$iRank = 0;
|
||||
$aDashletOrder = array();
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$sDashletClass = $oDomNode->getAttribute('xsi:type');
|
||||
$oRank = $oDomNode->getElementsByTagName('rank')->item(0);
|
||||
if ($oRank)
|
||||
{
|
||||
$iRank = (float)$oRank->textContent;
|
||||
}
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
$aDashletOrder[] = array('rank' => $iRank, 'dashlet' => $oNewDashlet);
|
||||
}
|
||||
usort($aDashletOrder, array(get_class($this), 'SortOnRank'));
|
||||
$aDashletList = array();
|
||||
foreach($aDashletOrder as $aItem)
|
||||
{
|
||||
$aDashletList[] = $aItem['dashlet'];
|
||||
}
|
||||
$aCellOrder[] = array('rank' => $iCellRank, 'dashlets' => $aDashletList);
|
||||
}
|
||||
}
|
||||
usort($aCellOrder, array(get_class($this), 'SortOnRank'));
|
||||
foreach($aCellOrder as $aItem)
|
||||
{
|
||||
$this->aCells[] = $aItem['dashlets'];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->aCells = array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static function SortOnRank($aItem1, $aItem2)
|
||||
{
|
||||
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
|
||||
@@ -176,31 +132,14 @@ abstract class Dashboard
|
||||
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
$oDoc->appendChild($oMainNode);
|
||||
|
||||
$this->ToDOMNode($oMainNode);
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
public function ToDOMNode($oDefinition)
|
||||
{
|
||||
$oDoc = $oDefinition->ownerDocument;
|
||||
|
||||
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
|
||||
$oDefinition->appendChild($oNode);
|
||||
$oMainNode->appendChild($oNode);
|
||||
|
||||
$oNode = $oDoc->createElement('title', $this->sTitle);
|
||||
$oDefinition->appendChild($oNode);
|
||||
|
||||
$oAutoReloadNode = $oDoc->createElement('auto_reload');
|
||||
$oDefinition->appendChild($oAutoReloadNode);
|
||||
$oNode = $oDoc->createElement('enabled', $this->bAutoReload ? 'true' : 'false');
|
||||
$oAutoReloadNode->appendChild($oNode);
|
||||
$oNode = $oDoc->createElement('interval', $this->iAutoReloadSec);
|
||||
$oAutoReloadNode->appendChild($oNode);
|
||||
$oMainNode->appendChild($oNode);
|
||||
|
||||
$oCellsNode = $oDoc->createElement('cells');
|
||||
$oDefinition->appendChild($oCellsNode);
|
||||
$oMainNode->appendChild($oCellsNode);
|
||||
|
||||
$iCellRank = 0;
|
||||
foreach ($this->aCells as $aCell)
|
||||
@@ -227,15 +166,15 @@ abstract class Dashboard
|
||||
$oDashlet->ToDOMNode($oNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
public function FromParams($aParams)
|
||||
{
|
||||
$this->sLayoutClass = $aParams['layout_class'];
|
||||
$this->sTitle = $aParams['title'];
|
||||
$this->bAutoReload = $aParams['auto_reload'] == 'true';
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int) $aParams['auto_reload_sec']);
|
||||
|
||||
foreach($aParams['cells'] as $aCell)
|
||||
{
|
||||
@@ -244,7 +183,7 @@ abstract class Dashboard
|
||||
{
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
$oNewDashlet = new $sDashletClass($this->oMetaModel, $sId);
|
||||
$oNewDashlet = new $sDashletClass($sId);
|
||||
|
||||
$oForm = $oNewDashlet->GetForm();
|
||||
$oForm->SetParamsContainer($sId);
|
||||
@@ -257,7 +196,7 @@ abstract class Dashboard
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function Save()
|
||||
{
|
||||
|
||||
@@ -277,32 +216,12 @@ abstract class Dashboard
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
|
||||
|
||||
public function SetTitle($sTitle)
|
||||
{
|
||||
$this->sTitle = $sTitle;
|
||||
}
|
||||
|
||||
public function GetAutoReload()
|
||||
{
|
||||
return $this->bAutoReload;
|
||||
}
|
||||
|
||||
public function SetAutoReload($bAutoReload)
|
||||
{
|
||||
$this->bAutoReload = $bAutoReload;
|
||||
}
|
||||
|
||||
public function GetAutoReloadInterval()
|
||||
{
|
||||
return $this->iAutoReloadSec;
|
||||
}
|
||||
|
||||
public function SetAutoReloadInterval($iAutoReloadSec)
|
||||
{
|
||||
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
|
||||
}
|
||||
|
||||
|
||||
public function AddDashlet($oDashlet)
|
||||
{
|
||||
$sId = $this->GetNewDashletId();
|
||||
@@ -312,7 +231,7 @@ abstract class Dashboard
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
|
||||
$oPage->add('<h1>'.Dict::S($this->sTitle).'</h1>');
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
@@ -347,62 +266,24 @@ abstract class Dashboard
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('UI:DashboardEdit:AutoReloadSec'), $this->iAutoReloadSec);
|
||||
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
||||
$oForm->AddField($oField);
|
||||
|
||||
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
|
||||
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
|
||||
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
$('#select_layout').buttonset();
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var oDashlet = ui.draggable.data('itopDashlet');
|
||||
oDashlet._remove_dashlet();
|
||||
},
|
||||
});
|
||||
|
||||
$('#event_bus').bind('dashlet-selected', function(event, data){
|
||||
var sDashletId = data.dashlet_id;
|
||||
var sPropId = 'dashlet_properties_'+sDashletId;
|
||||
$('.dashlet_properties').each(function() {
|
||||
var sId = $(this).attr('id');
|
||||
var bShow = (sId == sPropId);
|
||||
if (bShow)
|
||||
{
|
||||
$(this).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
$('#select_layout input').click( function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$(':itop-dashboard').dashboard('option', {layout_class: sLayoutClass});
|
||||
} );
|
||||
$('#row_attr_dashboard_title').property_field('option', {parent_selector: ':itop-dashboard', auto_apply: false, 'do_apply': function() {
|
||||
var sTitle = $('#attr_dashboard_title').val();
|
||||
$(':itop-dashboard').dashboard('option', {title: sTitle});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
EOF
|
||||
);
|
||||
@@ -437,6 +318,7 @@ EOF
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
$oPage->add_ready_script("$('.layout_cell').droppable({accept:'.dashlet_icon', hoverClass:'dragHover'});");
|
||||
}
|
||||
|
||||
public function RenderDashletsProperties($oPage)
|
||||
@@ -456,7 +338,7 @@ EOF
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
|
||||
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
@@ -485,12 +367,11 @@ EOF
|
||||
class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
protected $bCustomized;
|
||||
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->bCustomized = false;
|
||||
$this->oMetaModel = new ModelReflectionRuntime();
|
||||
}
|
||||
|
||||
public function SetCustomFlag($bCustomized)
|
||||
@@ -544,34 +425,37 @@ class RuntimeDashboard extends Dashboard
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderEditionTools($oPage)
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/edit.png\"><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
|
||||
if ($this->bCustomized)
|
||||
parent::Render($oPage, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
}
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
|
||||
|
||||
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/edit.png\"><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
|
||||
$sEditMenu = addslashes($sEditMenu);
|
||||
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
|
||||
$oPage->add_ready_script(
|
||||
if ($this->bCustomized)
|
||||
{
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
}
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
|
||||
|
||||
|
||||
$sEditMenu = addslashes($sEditMenu);
|
||||
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#logOffBtn').parent().before('$sEditMenu');
|
||||
$('#DashboardMenu>ul').popupmenu();
|
||||
|
||||
EOF
|
||||
);
|
||||
$oPage->add_script(
|
||||
);
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function EditDashboard(sId)
|
||||
{
|
||||
@@ -594,42 +478,10 @@ function RevertDashboard(sId)
|
||||
return false;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
{
|
||||
parent::RenderProperties($oPage);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#select_layout input').click( function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {layout_class: sLayoutClass});
|
||||
} );
|
||||
$('#row_attr_dashboard_title').property_field('option', {parent_selector: '.itop-dashboard', auto_apply: false, 'do_apply': function() {
|
||||
var sTitle = $('#attr_dashboard_title').val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {title: sTitle});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
$('#row_attr_auto_reload').property_field('option', {parent_selector: '.itop-dashboard', auto_apply: true, 'do_apply': function() {
|
||||
var bAutoReload = $('#attr_auto_reload').is(':checked');
|
||||
$('.itop-dashboard').runtimedashboard('option', {auto_reload: bAutoReload});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
$('#row_attr_auto_reload_sec').property_field('option', {parent_selector: '.itop-dashboard', auto_apply: true, 'do_apply': function() {
|
||||
var iAutoReloadSec = $('#attr_auto_reload_sec').val();
|
||||
$('.itop-dashboard').runtimedashboard('option', {auto_reload_sec: iAutoReloadSec});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function RenderEditor($oPage)
|
||||
{
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
@@ -650,8 +502,6 @@ EOF
|
||||
|
||||
$sId = addslashes($this->sId);
|
||||
$sLayoutClass = addslashes($this->sLayoutClass);
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = addslashes($this->sTitle);
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
|
||||
@@ -670,7 +520,7 @@ $('#dashboard_editor').dialog({
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
var oDashboard = $(':itop-dashboard').data('dashboard');
|
||||
if (oDashboard.is_dirty())
|
||||
{
|
||||
if (!confirm('$sAutoApplyConfirmationMessage'))
|
||||
@@ -686,7 +536,7 @@ $('#dashboard_editor').dialog({
|
||||
oDashboard.save();
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
var oDashboard = $(':itop-dashboard').data('dashboard');
|
||||
if (oDashboard.is_modified())
|
||||
{
|
||||
if (!confirm('$sCancelConfirmationMessage'))
|
||||
@@ -702,14 +552,40 @@ $('#dashboard_editor').dialog({
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
$('#dashboard_editor .ui-layout-center').dashboard({
|
||||
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
|
||||
auto_reload: $sAutoReload, auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var oDashlet = ui.draggable;
|
||||
oDashlet.remove();
|
||||
},
|
||||
});
|
||||
|
||||
$('#event_bus').bind('dashlet-selected', function(event, data){
|
||||
var sDashletId = data.dashlet_id;
|
||||
var sPropId = 'dashlet_properties_'+sDashletId;
|
||||
$('.dashlet_properties').each(function() {
|
||||
var sId = $(this).attr('id');
|
||||
var bShow = (sId == sPropId);
|
||||
if (bShow)
|
||||
{
|
||||
$(this).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
|
||||
$('#dashboard_editor').layout({
|
||||
east: {
|
||||
@@ -730,7 +606,7 @@ $('#dashboard_editor').layout({
|
||||
window.onbeforeunload = function() {
|
||||
if (!window.bLeavingOnUserAction)
|
||||
{
|
||||
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
|
||||
var oDashboard = $(':itop-dashboard').data('dashboard');
|
||||
if (oDashboard)
|
||||
{
|
||||
if (oDashboard.is_dirty())
|
||||
@@ -811,8 +687,7 @@ EOF
|
||||
foreach($aDashlets as $sDashletClass => $aDashletInfo)
|
||||
{
|
||||
$oSubForm = new DesignerForm();
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
$oDashlet = new $sDashletClass($oMetaModel, 0);
|
||||
$oDashlet = new $sDashletClass(0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
||||
|
||||
@@ -107,16 +107,14 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
$oPage->add('<table style="width:100%"><tbody>');
|
||||
$iCellIdx = 0;
|
||||
$fColSize = 100 / $this->iNbCols;
|
||||
$sStyle = $bEditMode ? 'border: 1px #ccc dashed; width:'.$fColSize.'%;' : 'width: '.$fColSize.'%;';
|
||||
$sClass = $bEditMode ? 'layout_cell edit_mode' : 'dashboard';
|
||||
$sStyle = $bEditMode ? 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode"' : 'style="width: '.$fColSize.'%;" class="dashboard"';
|
||||
$iNbRows = ceil(count($aCells) / $this->iNbCols);
|
||||
for($iRows = 0; $iRows < $iNbRows; $iRows++)
|
||||
{
|
||||
$oPage->add('<tr>');
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$sCellClass = ($iRows == $iNbRows-1) ? $sClass.' layout_last_used_rank' : $sClass;
|
||||
$oPage->add("<td style=\"$sStyle\" class=\"$sCellClass\" data-dashboard-cell-index=\"$iCellIdx\">");
|
||||
$oPage->add("<td $sStyle>");
|
||||
if (array_key_exists($iCellIdx, $aCells))
|
||||
{
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
@@ -146,7 +144,7 @@ abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
}
|
||||
if ($bEditMode) // Add one row for extensibility
|
||||
{
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension" data-dashboard-cell-index="'.$iCellIdx.'"';
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension"';
|
||||
$oPage->add('<tr>');
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -75,35 +75,7 @@ class DataTable
|
||||
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
|
||||
}
|
||||
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
|
||||
|
||||
// Load only the requested columns
|
||||
$aColumnsToLoad = array();
|
||||
foreach($oCustomSettings->aColumns as $sAlias => $aColumnsInfo)
|
||||
{
|
||||
foreach($aColumnsInfo as $sAttCode => $aData)
|
||||
{
|
||||
if ($sAttCode != '_key_')
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aColumnsToLoad[$sAlias][] = $sAttCode;
|
||||
}
|
||||
else
|
||||
{
|
||||
// See if this column is a must to load
|
||||
$sClass = $this->aClassAliases[$sAlias];
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->alwaysLoadInTables())
|
||||
{
|
||||
$aColumnsToLoad[$sAlias][] = $sAttCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->oSet->OptimizeColumnLoad($aColumnsToLoad);
|
||||
|
||||
|
||||
|
||||
$bToolkitMenu = true;
|
||||
if (isset($aExtraParams['toolkit_menu']))
|
||||
{
|
||||
@@ -292,13 +264,13 @@ EOF;
|
||||
{
|
||||
$sMenuTitle = Dict::S('UI:ConfigureThisList');
|
||||
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png"><ul>';
|
||||
|
||||
|
||||
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
|
||||
$aActions = array(
|
||||
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
|
||||
);
|
||||
$this->oSet->Rewind();
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions, $this->sTableId, $this->iListId);
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions);
|
||||
$this->oSet->Rewind();
|
||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
|
||||
return $sHtml;
|
||||
@@ -551,7 +523,6 @@ EOF;
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
var oTable = $('#{$this->iListId} table.listResults');
|
||||
oTable.tableHover();
|
||||
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
|
||||
EOF
|
||||
);
|
||||
@@ -765,7 +736,7 @@ class DataTableSettings implements Serializable
|
||||
}
|
||||
}
|
||||
|
||||
static public function GetTableSettings($aClassAliases, $sTableId = null, $bOnlyOnTable = false)
|
||||
static public function GetTableSettings($aClassAliases, $sTableId = null)
|
||||
{
|
||||
$pref = null;
|
||||
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
|
||||
@@ -778,11 +749,8 @@ class DataTableSettings implements Serializable
|
||||
|
||||
if ($pref == null)
|
||||
{
|
||||
if (!$bOnlyOnTable)
|
||||
{
|
||||
// Try the global preferred values for this class / set of classes
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
|
||||
}
|
||||
// Try the global preferred values for this class / set of classes
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
|
||||
if ($pref == null)
|
||||
{
|
||||
// no such settings, use the default values provided by the data model
|
||||
@@ -812,13 +780,12 @@ class DataTableSettings implements Serializable
|
||||
return $aSortOrder;
|
||||
}
|
||||
|
||||
public function Save($sTargetTableId = null)
|
||||
public function Save()
|
||||
{
|
||||
$sSaveId = is_null($sTargetTableId) ? $this->sTableId : $sTargetTableId;
|
||||
if ($sSaveId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
|
||||
if ($this->sTableId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
|
||||
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey($sSaveId), $sSettings);
|
||||
appUserPreferences::SetPref($this->GetPrefsKey($this->sTableId), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -204,11 +204,6 @@ class DisplayBlock
|
||||
$bAutoReload = false;
|
||||
if (isset($aExtraParams['auto_reload']))
|
||||
{
|
||||
if ($aExtraParams['auto_reload'] === true)
|
||||
{
|
||||
// Note: does not work in the switch (case true) because a positive number evaluates to true!!!
|
||||
$aExtraParams['auto_reload'] = 'standard';
|
||||
}
|
||||
switch($aExtraParams['auto_reload'])
|
||||
{
|
||||
case 'fast':
|
||||
@@ -218,15 +213,16 @@ class DisplayBlock
|
||||
|
||||
case 'standard':
|
||||
case 'true':
|
||||
case true:
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = MetaModel::GetConfig()->GetStandardReloadInterval()*1000;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_numeric($aExtraParams['auto_reload']) && ($aExtraParams['auto_reload'] > 0))
|
||||
if (is_numeric($aExtraParams['auto_reload']))
|
||||
{
|
||||
$bAutoReload = true;
|
||||
$iReloadInterval = max(MetaModel::GetConfig()->Get('min_reload_interval'), $aExtraParams['auto_reload'])*1000;
|
||||
$iReloadInterval = $aExtraParams['auto_reload']*1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -261,7 +257,7 @@ class DisplayBlock
|
||||
);
|
||||
');
|
||||
}
|
||||
if (($bAutoReload) && ($this->m_sStyle != 'search')) // Search form do NOT auto-reload
|
||||
if ($bAutoReload)
|
||||
{
|
||||
$oPage->add_script('setInterval("ReloadBlock(\''.$sId.'\', \''.$this->m_sStyle.'\', \''.$sFilter.'\', \"'.$sExtraParams.'\")", '.$iReloadInterval.');');
|
||||
}
|
||||
@@ -1105,7 +1101,6 @@ EOF
|
||||
|
||||
$oTitle = new title($sTitle);
|
||||
$oChart->set_title( $oTitle );
|
||||
$oTitle->set_style("{font-size: 16px; font-family: Tahoma; font-weight: bold; text-align: center;}");
|
||||
}
|
||||
$oChart->set_bg_colour('#FFFFFF');
|
||||
$oChart->add_element( $oChartElement );
|
||||
@@ -1435,21 +1430,17 @@ class MenuBlock extends DisplayBlock
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count() < $iLimit)))
|
||||
{
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
//
|
||||
// Group by <state>
|
||||
$oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias());
|
||||
$aGroupBy = array('__state__' => $oGroupByExp);
|
||||
$aQueryParams = array();
|
||||
if (isset($aExtraParams['query_params']))
|
||||
$oSet->Rewind();
|
||||
$aStates = array();
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aQueryParams = $aExtraParams['query_params'];
|
||||
$aStates[$oObj->GetState()] = $oObj->GetState();
|
||||
}
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
if (count($aRes) == 1)
|
||||
$oSet->Rewind();
|
||||
if (count($aStates) == 1)
|
||||
{
|
||||
// All objects are in the same state...
|
||||
$sState = $aRes[0]['__state__'];
|
||||
$sState = array_pop($aStates);
|
||||
$aTransitions = Metamodel::EnumTransitions($sClass, $sState);
|
||||
if (count($aTransitions))
|
||||
{
|
||||
@@ -1457,11 +1448,8 @@ class MenuBlock extends DisplayBlock
|
||||
$aStimuli = Metamodel::EnumStimuli($sClass);
|
||||
foreach($aTransitions as $sStimulusCode => $aTransitionDef)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
// As soon as the user rights implementation will browse the object set,
|
||||
// then we might consider using OptimizeColumnLoad() here
|
||||
$iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet);
|
||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? $iActionAllowed : UR_ALLOWED_NO;
|
||||
$oChecker = new StimulusChecker($this->m_oFilter, $sState, $sStimulusCode);
|
||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? $oChecker->IsAllowed() : UR_ALLOWED_NO;
|
||||
switch($iActionAllowed)
|
||||
{
|
||||
case UR_ALLOWED_YES:
|
||||
@@ -1584,3 +1572,114 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some dummy menus for testing
|
||||
*/
|
||||
class ExtraMenus implements iPopupMenuExtension
|
||||
{
|
||||
/*
|
||||
const MENU_OBJLIST_ACTIONS = 1; // $param is a DBObjectSet containing the list of objects
|
||||
const MENU_OBJLIST_TOOLKIT = 2; // $param is a DBObjectSet containing the list of objects
|
||||
const MENU_OBJDETAILS_ACTIONS = 3; // $param is a DBObject instance: the object currently displayed
|
||||
const MENU_DASHBOARD_ACTIONS = 4; // $param is a Dashboard instance: the dashboard currently displayed
|
||||
const MENU_USER_ACTIONS = 5; // $param is a null ??
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the list of items to be added to a menu. The items will be inserted in the menu in the order of the returned array
|
||||
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx above
|
||||
* @param mixed $param Depends on $iMenuId see the constants define above
|
||||
* @return Array An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
|
||||
*/
|
||||
public static function EnumItems($iMenuId, $param)
|
||||
{
|
||||
switch($iMenuId)
|
||||
{
|
||||
/*
|
||||
case iPopupMenuExtension::MENU_OBJLIST_ACTIONS:
|
||||
// $param is a DBObjectSet
|
||||
$aResult = array(
|
||||
new JSPopupMenuItem('Test::Item1', 'List Test 1', "alert('Test 1')"),
|
||||
new JSPopupMenuItem('Test::Item2', 'List Test 2', "alert('Test 2')"),
|
||||
);
|
||||
break;
|
||||
|
||||
$this->AddMenuSeparator($aActions);
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
|
||||
$sOQL = addslashes($sFilterDesc);
|
||||
$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
|
||||
*/
|
||||
|
||||
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
|
||||
// $param is a DBObjectSet
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($param->GetFilter()->GetClass());
|
||||
$sOQL = addslashes($param->GetFilter()->ToOQL(true));
|
||||
$sFilter = urlencode($param->GetFilter()->serialize());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
// Static menus: Email this page, CSV Export & Add to Dashboard
|
||||
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?body=".urlencode($sUrl)),
|
||||
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), $sUrl."&format=csv"),
|
||||
new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL')"),
|
||||
new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sContext')"),
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
|
||||
// $param is a DBObject
|
||||
$oObj = $param;
|
||||
$oFilter = DBobjectSearch::FromOQL("SELECT ".get_class($oObj)." WHERE id=".$oObj->GetKey());
|
||||
$sFilter = $oFilter->serialize();
|
||||
$sUrl = ApplicationContext::MakeObjectUrl(get_class($oObj), $oObj->GetKey());
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
// Static menus: Email this page & CSV Export
|
||||
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl)),
|
||||
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv&{$sContext}"),
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
|
||||
// $param is a Dashboard
|
||||
$oAppContext = new ApplicationContext();
|
||||
$aParams = $oAppContext->GetAsHash();
|
||||
$sMenuId = ApplicationMenu::GetActiveNodeId();
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sMenuId),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sMenuId', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn' })"),
|
||||
);
|
||||
break;
|
||||
|
||||
/*
|
||||
case iPopupMenuExtension::MENU_USER_ACTIONS:
|
||||
// $param is null ??
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new JSPopupMenuItem('Test::Item1', 'Reset preferences...', "alert('Test 1')"),
|
||||
new JSPopupMenuItem('Test::Item2', 'Do Something Stupid', "alert('Hey Dude !')"),
|
||||
);
|
||||
break;
|
||||
*/
|
||||
|
||||
default:
|
||||
// Unknown type of menu, do nothing
|
||||
$aResult = array();
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,8 +36,6 @@ class DesignerForm
|
||||
protected $aSubmitParams;
|
||||
protected $sSubmitTo;
|
||||
protected $bReadOnly;
|
||||
protected $sSelectorClass;
|
||||
protected $bDisplayed;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -50,9 +48,7 @@ class DesignerForm
|
||||
$this->sFormId = 'form_'.rand();
|
||||
$this->oParentForm = null;
|
||||
$this->bReadOnly = false;
|
||||
$this->sSelectorClass = '';
|
||||
$this->StartFieldSet($this->sCurrentFieldSet);
|
||||
$this->bDisplayed = true;
|
||||
}
|
||||
|
||||
public function AddField(DesignerFormField $oField)
|
||||
@@ -76,6 +72,7 @@ class DesignerForm
|
||||
|
||||
public function Render($oP, $bReturnHTML = false)
|
||||
{
|
||||
$sReturn = '';
|
||||
if ($this->oParentForm == null)
|
||||
{
|
||||
$sFormId = $this->sFormId;
|
||||
@@ -83,7 +80,6 @@ class DesignerForm
|
||||
}
|
||||
else
|
||||
{
|
||||
$sReturn = '';
|
||||
$sFormId = $this->oParentForm->sFormId;
|
||||
}
|
||||
$sHiddenFields = '';
|
||||
@@ -151,16 +147,6 @@ class DesignerForm
|
||||
$this->aSubmitParams = $oParentForm->aSubmitParams;
|
||||
}
|
||||
|
||||
public function SetSelectorClass($sSelectorClass)
|
||||
{
|
||||
$this->sSelectorClass = $sSelectorClass;
|
||||
}
|
||||
|
||||
public function GetSelectorClass()
|
||||
{
|
||||
return $this->sSelectorClass;
|
||||
}
|
||||
|
||||
|
||||
public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null)
|
||||
{
|
||||
@@ -264,17 +250,12 @@ EOF
|
||||
$oP->add($sReturn);
|
||||
}
|
||||
}
|
||||
public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel, $sIntroduction = null)
|
||||
public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel)
|
||||
{
|
||||
$sDialogTitle = addslashes($sDialogTitle);
|
||||
$sOkButtonLabel = addslashes($sOkButtonLabel);
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$sCancelButtonLabel = 'Cancel'; //TODO: localize
|
||||
$oPage->add("<div id=\"$sDialogId\">");
|
||||
if ($sIntroduction != null)
|
||||
{
|
||||
$oPage->add('<div class="ui-dialog-header">'.$sIntroduction.'</div>');
|
||||
}
|
||||
$this->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
@@ -287,7 +268,7 @@ $('#$sDialogId').dialog({
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oForm = $(this).closest('.ui-dialog').find('form');
|
||||
var oForm = $(this).parents('.ui-dialog :first').find('form');
|
||||
oForm.submit();
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
|
||||
@@ -362,28 +343,6 @@ EOF
|
||||
$this->oParentForm = $oParentForm;
|
||||
}
|
||||
|
||||
public function GetParentForm()
|
||||
{
|
||||
return $this->oParentForm;
|
||||
}
|
||||
|
||||
public function SetDisplayed($bDisplayed)
|
||||
{
|
||||
$this->bDisplayed = $bDisplayed;
|
||||
}
|
||||
|
||||
public function IsDisplayed()
|
||||
{
|
||||
if ($this->oParentForm == null)
|
||||
{
|
||||
return $this->bDisplayed;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ($this->bDisplayed && $this->oParentForm->IsDisplayed());
|
||||
}
|
||||
}
|
||||
|
||||
public function AddScript($sScript)
|
||||
{
|
||||
$this->sScript .= $sScript;
|
||||
@@ -530,8 +489,6 @@ class DesignerFormField
|
||||
protected $bMandatory;
|
||||
protected $bReadOnly;
|
||||
protected $bAutoApply;
|
||||
protected $aCSSClasses;
|
||||
protected $bDisplayed;
|
||||
|
||||
public function __construct($sCode, $sLabel, $defaultValue)
|
||||
{
|
||||
@@ -541,8 +498,6 @@ class DesignerFormField
|
||||
$this->bMandatory = false;
|
||||
$this->bReadOnly = false;
|
||||
$this->bAutoApply = false;
|
||||
$this->aCSSClasses = array();
|
||||
$this->bDisplayed = true;
|
||||
}
|
||||
|
||||
public function GetCode()
|
||||
@@ -581,16 +536,6 @@ class DesignerFormField
|
||||
return $this->bAutoApply;
|
||||
}
|
||||
|
||||
public function SetDisplayed($bDisplayed)
|
||||
{
|
||||
$this->bDisplayed = $bDisplayed;
|
||||
}
|
||||
|
||||
public function IsDisplayed()
|
||||
{
|
||||
return $this->bDisplayed;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
@@ -629,11 +574,6 @@ class DesignerFormField
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function AddCSSClass($sCSSClass)
|
||||
{
|
||||
$this->aCSSClasses[] = $sCSSClass;
|
||||
}
|
||||
}
|
||||
|
||||
class DesignerLabelField extends DesignerFormField
|
||||
@@ -666,75 +606,34 @@ class DesignerLabelField extends DesignerFormField
|
||||
class DesignerTextField extends DesignerFormField
|
||||
{
|
||||
protected $sValidationPattern;
|
||||
protected $aForbiddenValues;
|
||||
protected $sExplainForbiddenValues;
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
$this->sValidationPattern = '';
|
||||
$this->aForbiddenValues = null;
|
||||
$this->sExplainForbiddenValues = null;
|
||||
}
|
||||
|
||||
public function SetValidationPattern($sValidationPattern)
|
||||
{
|
||||
$this->sValidationPattern = $sValidationPattern;
|
||||
}
|
||||
|
||||
public function SetForbiddenValues($aValues, $sExplain)
|
||||
{
|
||||
$this->aForbiddenValues = $aValues;
|
||||
|
||||
$iDefaultKey = array_search($this->defaultValue, $this->aForbiddenValues);
|
||||
if ($iDefaultKey !== false)
|
||||
{
|
||||
// The default (current) value is always allowed...
|
||||
unset($this->aForbiddenValues[$iDefaultKey]);
|
||||
|
||||
}
|
||||
|
||||
$this->sExplainForbiddenValues = $sExplain;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$sHtmlValue = "<span>".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\"/></span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPattern = addslashes($this->sValidationPattern);
|
||||
if (is_array($this->aForbiddenValues))
|
||||
{
|
||||
$sForbiddenValues = json_encode($this->aForbiddenValues);
|
||||
$sExplainForbiddenValues = addslashes($this->sExplainForbiddenValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sForbiddenValues = 'null';
|
||||
$sExplainForbiddenValues = 'null';
|
||||
}
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$oP->add_ready_script(
|
||||
$sPattern = addslashes($this->sValidationPattern);
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$sReadOnly = $this->IsReadOnly() ? 'readonly' : '';
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', '$sFormId', $sForbiddenValues, '$sExplainForbiddenValues'); } );
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', '$sFormId'); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
$sHtmlValue = "<input type=\"text\" $sCSSClasses id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sHtmlValue);
|
||||
);
|
||||
return array('label' => $this->sLabel, 'value' => "<input type=\"text\" id=\"$sId\" $sReadOnly name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
|
||||
}
|
||||
|
||||
public function ReadParam(&$aValues)
|
||||
@@ -745,11 +644,6 @@ EOF
|
||||
{
|
||||
$aValues[$this->sCode] = $this->defaultValue;
|
||||
}
|
||||
else if(($this->aForbiddenValues != null) && in_array($aValues[$this->sCode], $this->aForbiddenValues))
|
||||
{
|
||||
// Reject the value...
|
||||
$aValues[$this->sCode] = $this->defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,101 +654,18 @@ class DesignerLongTextField extends DesignerTextField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sPattern = addslashes($this->sValidationPattern);
|
||||
if (is_array($this->aForbiddenValues))
|
||||
{
|
||||
$sForbiddenValues = json_encode($this->aForbiddenValues);
|
||||
$sExplainForbiddenValues = addslashes($this->sExplainForbiddenValues);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sForbiddenValues = 'null';
|
||||
$sExplainForbiddenValues = 'null';
|
||||
}
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$sReadOnly = $this->IsReadOnly() ? 'readonly' : '';
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', '$sFormId', $sForbiddenValues, '$sExplainForbiddenValues'); } );
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', '$sFormId'); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => "<textarea $sCSSClasses id=\"$sId\" $sReadOnly name=\"$sName\">".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."</textarea>");
|
||||
}
|
||||
}
|
||||
|
||||
class DesignerIntegerField extends DesignerFormField
|
||||
{
|
||||
protected $iMin; // Lower boundary, inclusive
|
||||
protected $iMax; // Higher boundary, inclusive
|
||||
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
$this->iMin = 0; // Positive integer is the default
|
||||
$this->iMax = null;
|
||||
}
|
||||
|
||||
public function SetBoundaries($iMin = null, $iMax = null)
|
||||
{
|
||||
$this->iMin = $iMin;
|
||||
$this->iMax = $iMax;
|
||||
}
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$sHtmlValue = "<span>".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\"/></span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sMin = json_encode($this->iMin);
|
||||
$sMax = json_encode($this->iMax);
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').bind('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, '$sFormId', $sMin, $sMax); } );
|
||||
{
|
||||
var myTimer = null;
|
||||
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
$sHtmlValue = "<input type=\"text\" $sCSSClasses id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sHtmlValue);
|
||||
}
|
||||
|
||||
public function ReadParam(&$aValues)
|
||||
{
|
||||
parent::ReadParam($aValues);
|
||||
|
||||
if (!is_null($this->iMin) && ($aValues[$this->sCode] < $this->iMin))
|
||||
{
|
||||
// Reject the value...
|
||||
$aValues[$this->sCode] = $this->defaultValue;
|
||||
}
|
||||
if (!is_null($this->iMax) && ($aValues[$this->sCode] > $this->iMax))
|
||||
{
|
||||
// Reject the value...
|
||||
$aValues[$this->sCode] = $this->defaultValue;
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => "<textarea id=\"$sId\" $sReadOnly name=\"$sName\">".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."</textarea>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,72 +709,39 @@ class DesignerComboField extends DesignerFormField
|
||||
$sChecked = $this->defaultValue ? 'checked' : '';
|
||||
$sMandatory = $this->bMandatory ? 'true' : 'false';
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$aSelected = array();
|
||||
$aHiddenValues = array();
|
||||
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
|
||||
{
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
if(in_array($sKey, $this->defaultValue))
|
||||
{
|
||||
$aSelected[] = $sDisplayValue;
|
||||
$aHiddenValues[] = "<input type=\"hidden\" name=\"{$sName}[]\" value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($sKey == $this->defaultValue)
|
||||
{
|
||||
$aSelected[] = $sDisplayValue;
|
||||
$aHiddenValues[] = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml = "<span $sCSSClasses>".htmlentities(implode(', ', $aSelected), ENT_QUOTES, 'UTF-8').implode($aHiddenValues)."</span>";
|
||||
$sHtml = "<select multiple size=\"8\"id=\"$sId\" name=\"$sName\" $sReadOnly>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml = "<select id=\"$sId\" name=\"$sName\" $sReadOnly>";
|
||||
$sHtml .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>";
|
||||
}
|
||||
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
|
||||
{
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
$sHtml = "<select $sCSSClasses multiple size=\"8\"id=\"$sId\" name=\"$sName\">";
|
||||
$sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\">";
|
||||
$sHtml .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>";
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
|
||||
{
|
||||
if ($this->bMultipleSelection)
|
||||
{
|
||||
$sSelected = in_array($sKey, $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
}
|
||||
// Quick and dirty: display the menu parents as a tree
|
||||
$sHtmlValue = str_replace(' ', ' ', htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8'));
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
|
||||
}
|
||||
$sHtml .= "</select>";
|
||||
if ($this->bOtherChoices)
|
||||
{
|
||||
$sHtml .= '<br/><input type="checkbox" id="other_chk_'.$sId.'"><label for="other_chk_'.$sId.'"> Other:</label> <input type="text" id="other_'.$sId.'" name="other_'.$sName.'" size="30"/>';
|
||||
}
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', '$sFormId', null, null); } );
|
||||
EOF
|
||||
);
|
||||
// Quick and dirty: display the menu parents as a tree
|
||||
$sHtmlValue = str_replace(' ', ' ', htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8'));
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>$sHtmlValue</option>";
|
||||
}
|
||||
$sHtml .= "</select>";
|
||||
if ($this->bOtherChoices)
|
||||
{
|
||||
$sHtml .= '<br/><input type="checkbox" id="other_chk_'.$sId.'"><label for="other_chk_'.$sId.'"> Other:</label> <input type="text" id="other_'.$sId.'" name="other_'.$sName.'" size="30"/>';
|
||||
}
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', '$sFormId'); } );
|
||||
EOF
|
||||
);
|
||||
return array('label' => $this->sLabel, 'value' => $sHtml);
|
||||
}
|
||||
|
||||
@@ -990,21 +768,9 @@ class DesignerBooleanField extends DesignerFormField
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sChecked = $this->defaultValue ? 'checked' : '';
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$sLabel = $this->defaultValue ? Dict::S('UI:UserManagement:ActionAllowed:Yes') : Dict::S('UI:UserManagement:ActionAllowed:No'); //TODO use our own yes/no translations
|
||||
$sHtmlValue = "<span>".htmlentities($sLabel)."<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\"/></span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
}
|
||||
$sHtmlValue = "<input $sCSSClasses type=\"checkbox\" $sChecked id=\"$sId\" name=\"$sName\" value=\"true\">";
|
||||
}
|
||||
return array('label' => $this->sLabel, 'value' => $sHtmlValue);
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled' : ''; // readonly does not work as expected on checkboxes:
|
||||
// readonly prevents the user from changing the input's value not its state (checked/unchecked)
|
||||
return array('label' => $this->sLabel, 'value' => "<input type=\"checkbox\" $sChecked $sReadOnly id=\"$sId\" name=\"$sName\" value=\"true\">");
|
||||
}
|
||||
|
||||
public function ReadParam(&$aValues)
|
||||
@@ -1032,8 +798,8 @@ class DesignerBooleanField extends DesignerFormField
|
||||
{
|
||||
$sValue = utils::ReadParam($this->oForm->GetParamName($this->sCode), 'false', false, 'raw_data');
|
||||
}
|
||||
$aValues[$this->sCode] = ($sValue == 'true');
|
||||
}
|
||||
$aValues[$this->sCode] = ($sValue == 'true');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1062,26 +828,19 @@ class DesignerHiddenField extends DesignerFormField
|
||||
|
||||
class DesignerIconSelectionField extends DesignerFormField
|
||||
{
|
||||
protected $sUploadUrl;
|
||||
protected $aAllowedValues;
|
||||
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
$this->bAutoApply = true;
|
||||
$this->sUploadUrl = null;
|
||||
}
|
||||
|
||||
public function SetAllowedValues($aAllowedValues)
|
||||
{
|
||||
$this->aAllowedValues = $aAllowedValues;
|
||||
}
|
||||
|
||||
public function EnableUpload($sIconUploadUrl)
|
||||
{
|
||||
$this->sUploadUrl = $sIconUploadUrl;
|
||||
}
|
||||
|
||||
|
||||
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
@@ -1096,12 +855,11 @@ class DesignerIconSelectionField extends DesignerFormField
|
||||
}
|
||||
}
|
||||
$sJSItems = json_encode($this->aAllowedValues);
|
||||
$sPostUploadTo = ($this->sUploadUrl == null) ? 'null' : "'{$this->sUploadUrl}'";
|
||||
if (!$this->IsReadOnly())
|
||||
{
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').icon_select({current_idx: $idx, items: $sJSItems, post_upload_to: $sPostUploadTo});
|
||||
$('#$sId').icon_select({current_idx: $idx, items: $sJSItems});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
@@ -1110,71 +868,6 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
class RunTimeIconSelectionField extends DesignerIconSelectionField
|
||||
{
|
||||
public function __construct($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
parent::__construct($sCode, $sLabel, $defaultValue);
|
||||
|
||||
$aAllIcons = self::FindIconsOnDisk(APPROOT.'env-'.utils::GetCurrentEnvironment());
|
||||
ksort($aAllIcons);
|
||||
$aValues = array();
|
||||
foreach($aAllIcons as $sFilePath)
|
||||
{
|
||||
$aValues[] = array('value' => $sFilePath, 'label' => basename($sFilePath), 'icon' => utils::GetAbsoluteUrlModulesRoot().$sFilePath);
|
||||
}
|
||||
$this->SetAllowedValues($aValues);
|
||||
}
|
||||
|
||||
static protected function FindIconsOnDisk($sBaseDir, $sDir = '')
|
||||
{
|
||||
$aResult = array();
|
||||
// Populate automatically the list of icon files
|
||||
if ($hDir = @opendir($sBaseDir.'/'.$sDir))
|
||||
{
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != 'lifecycle') && is_dir($sBaseDir.'/'.$sDir.'/'.$sFile))
|
||||
{
|
||||
$sDirSubPath = ($sDir == '') ? $sFile : $sDir.'/'.$sFile;
|
||||
$aResult = array_merge($aResult, self::FindIconsOnDisk($sBaseDir, $sDirSubPath));
|
||||
}
|
||||
if (preg_match("/\.(png|jpg|jpeg|gif)$/i", $sFile, $aMatches)) // png, jp(e)g and gif are considered valid
|
||||
{
|
||||
$aResult[$sFile.'_'.$sDir] = $sDir.'/'.$sFile;
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
public function ValueFromDOMNode($oDOMNode)
|
||||
{
|
||||
return $oDOMNode->textContent;
|
||||
}
|
||||
|
||||
public function ValueToDOMNode($oDOMNode, $value)
|
||||
{
|
||||
$oTextNode = $oDOMNode->ownerDocument->createTextNode($value);
|
||||
$oDOMNode->appendChild($oTextNode);
|
||||
}
|
||||
|
||||
public function MakeFileUrl($value)
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot().$value;
|
||||
}
|
||||
|
||||
public function GetDefaultValue($sClass = 'Contact')
|
||||
{
|
||||
$sIconPath = MetaModel::GetClassIcon($sClass, false);
|
||||
$sIcon = str_replace(utils::GetAbsoluteUrlModulesRoot(), '', $sIconPath);
|
||||
return $sIcon;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class DesignerSortableField extends DesignerFormField
|
||||
{
|
||||
protected $aAllowedValues;
|
||||
@@ -1195,16 +888,31 @@ class DesignerSortableField extends DesignerFormField
|
||||
$bOpen = false;
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sReadOnly = $this->IsReadOnly() ? 'readonly="readonly"' : '';
|
||||
$aResult = array('label' => $this->sLabel, 'value' => "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" $sReadOnly value=\"".htmlentities($this->defaultValue, ENT_QUOTES, 'UTF-8')."\">");
|
||||
|
||||
|
||||
$sJSFields = json_encode(array_keys($this->aAllowedValues));
|
||||
$sHtml = "<span class=\"sort_$sId fieldslist\" id=\"sortable_$sId\">";
|
||||
foreach($this->defaultValue as $sValue)
|
||||
{
|
||||
$sHtml .= "<span class=\"movable_attr\">$sValue</span>";
|
||||
}
|
||||
$sHtml .="</span>";
|
||||
$sIconClass = $bOpen ? 'ui-icon-circle-triangle-s' : 'ui-icon-circle-triangle-e';
|
||||
$sStyle = $bOpen ? '' : 'style="display:none"';
|
||||
$sHtml .= "<div class=\"fieldspicker\"><table><tr><td><span id=\"collapse_$sId\" class=\"ui-icon $sIconClass\" style=\"opacity: 0.5\"></span>Fields</td></tr><tr><td><div $sStyle id=\"fieldsbasket_$sId\" class=\"sort_$sId fieldsbasket\">";
|
||||
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
|
||||
{
|
||||
$sHtml .= "<span class=\"movable_attr\">$sDisplayValue</span>";
|
||||
}
|
||||
$sHtml .="</div></td></tr>";
|
||||
$sHtml .="<tr id=\"trash_icon_$sId\" $sStyle><td><span class=\"ui-icon ui-icon-trash\" style=\"opacity: 0.5\"></span>Trash</td></tr><tr id=\"trash_$sId\" $sStyle><td><div id=\"recycle_$sId\" class=\"sort_$sId fieldstrash\"></div></div></td></tr></table></div>";
|
||||
$oP->add_ready_script(
|
||||
"$('#$sId').sortable_field({aAvailableFields: $sJSFields});"
|
||||
<<<EOF
|
||||
$('#collapse_$sId').click(function() { $(this).toggleClass('ui-icon-circle-triangle-s').toggleClass('ui-icon-circle-triangle-e'); $('#fieldsbasket_$sId').toggle(); $('#trash_icon_$sId').toggle(); $('#trash_$sId').toggle(); } );
|
||||
$('#fieldsbasket_$sId .movable_attr').draggable({connectToSortable: '#sortable_$sId', helper: 'clone', revert: false });
|
||||
$('#recycle_$sId').sortable({ receive: function(event, ui) { ui.item.animate({opacity: 0.25}, { complete: function() { $(this).remove(); } });} });
|
||||
$('#sortable_$sId').sortable({connectWith: '#recycle_$sId', forcePlaceholderSize: true});
|
||||
$('#sortable_$sId').disableSelection();
|
||||
EOF
|
||||
);
|
||||
|
||||
return $aResult;
|
||||
return array('label' => $this->sLabel, 'value' => $sHtml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,44 +944,15 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
$sName = $this->oForm->GetFieldName($this->sCode);
|
||||
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
|
||||
|
||||
$sCSSClasses = '';
|
||||
if (count($this->aCSSClasses) > 0)
|
||||
$sHtml = "<select id=\"$sId\" name=\"$sName\" $sReadOnly>";
|
||||
foreach($this->aSubForms as $sKey => $aFormData)
|
||||
{
|
||||
$sCSSClasses = 'class="'.implode(' ', $this->aCSSClasses).'"';
|
||||
$sDisplayValue = $aFormData['label'];
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."</option>";
|
||||
}
|
||||
|
||||
$sHtml .= "</select>";
|
||||
|
||||
if ($this->IsReadOnly())
|
||||
{
|
||||
$aSelected = array();
|
||||
$aHiddenValues = array();
|
||||
$sDisplayValue = '';
|
||||
$sHiddenValue = '';
|
||||
foreach($this->aSubForms as $sKey => $aFormData)
|
||||
{
|
||||
if ($sKey == $this->defaultValue)
|
||||
{
|
||||
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');
|
||||
$sHiddenValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\"/>";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sHtml = "<span $sCSSClasses>".$sDisplayValue.$sHiddenValue."</span>";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
|
||||
foreach($this->aSubForms as $sKey => $aFormData)
|
||||
{
|
||||
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');;
|
||||
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
|
||||
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>".$sDisplayValue."</option>";
|
||||
}
|
||||
$sHtml .= "</select>";
|
||||
}
|
||||
|
||||
if ($sRenderMode == 'property')
|
||||
{
|
||||
$sHtml .= '</td><td class="prop_icon prop_apply"><span title="Apply" class="ui-icon ui-icon-circle-check"/></td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>';
|
||||
@@ -1282,31 +961,20 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
foreach($this->aSubForms as $sKey => $aFormData)
|
||||
{
|
||||
$sId = $this->oForm->GetFieldId($this->sCode);
|
||||
$sStyle = (($sKey == $this->defaultValue) && $this->oForm->IsDisplayed()) ? '' : 'style="display:none"';
|
||||
$sStyle = ($sKey == $this->defaultValue) ? '' : 'style="display:none"';
|
||||
$oSubForm = $aFormData['form'];
|
||||
$oSubForm->SetParentForm($this->oForm);
|
||||
$oSubForm->CopySubmitParams($this->oForm);
|
||||
$oSubForm->SetPrefix($this->oForm->GetPrefix().$sKey.'_');
|
||||
$oSubForm->SetSelectorClass("subform_{$sId} {$sId}_{$sKey}");
|
||||
|
||||
if ($sRenderMode == 'property')
|
||||
{
|
||||
$oSubForm->SetDisplayed($sKey == $this->defaultValue);
|
||||
$sHtml .= "</tbody><tbody class=\"subform_{$sId} {$sId}_{$sKey}\" $sStyle>";
|
||||
$sHtml .= "</tbody><tbody class=\"subform\" id=\"{$sId}_{$sKey}\" $sStyle>";
|
||||
$sHtml .= $oSubForm->RenderAsPropertySheet($oP, true);
|
||||
$oParentForm = $this->oForm->GetParentForm();
|
||||
if($oParentForm)
|
||||
{
|
||||
$sHtml .= "</tbody><tbody class=\"".$oParentForm->GetSelectorClass()."\">";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "</tbody><tbody>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<div class=\"subform_{$sId} {$sId}_{$sKey}\" $sStyle>";
|
||||
$sHtml .= "<div class=\"subform\" id=\"{$sId}_{$sKey}\" $sStyle>";
|
||||
$sHtml .= $oSubForm->Render($oP, true);
|
||||
$sHtml .= "</div>";
|
||||
}
|
||||
@@ -1314,7 +982,7 @@ class DesignerFormSelectorField extends DesignerFormField
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#$sId').bind('change reverted', function() { $('.subform_{$sId}').hide(); $('.{$sId}_'+this.value).show(); } );
|
||||
$('#$sId').bind('change reverted', function() { $('.subform').hide(); $('#{$sId}_'+this.value).show(); } );
|
||||
EOF
|
||||
);
|
||||
return array('label' => $this->sLabel, 'value' => $sHtml);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Class iTopWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -80,15 +80,6 @@ class iTopWebPage extends NiceWebPage
|
||||
$this->add_linked_script('../js/jquery.multiselect.min.js');
|
||||
$this->add_linked_script('../js/ajaxfileupload.js');
|
||||
|
||||
$aMultiselectOptions = array(
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSMultiselectOptions = json_encode($aMultiselectOptions);
|
||||
$sSearchAny = addslashes(Dict::S('UI:SearchValue:Any'));
|
||||
$sSearchNbSelected = addslashes(Dict::S('UI:SearchValue:NbSelected'));
|
||||
$this->add_dict_entry('UI:FillAllMandatoryFields');
|
||||
@@ -99,18 +90,6 @@ class iTopWebPage extends NiceWebPage
|
||||
{
|
||||
$sInitClosed = 'initClosed: true,';
|
||||
}
|
||||
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function ShowAboutBox()
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'about_box'}, function(data){
|
||||
$('body').append(data);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
$this->m_sInitScript =
|
||||
<<< EOF
|
||||
@@ -174,7 +153,7 @@ EOF
|
||||
$('#left-pane').layout({ resizable: false, spacing_open: 0, south: { size: 94 }, enableCursorHotkey: false });
|
||||
|
||||
// Accordion Menu
|
||||
$("#accordion").accordion({ header: "h3", navigation: true, heightStyle: "content", collapsible: false, icons: false }); // collapsible will be enabled once the item will be selected
|
||||
$("#accordion").accordion({ header: "h3", navigation: true, autoHeight: false, collapsible: false, icons: false }); // collapsible will be enabled once the item will be selected
|
||||
|
||||
// Tabs, using JQuery BBQ to store the history
|
||||
// The "tab widgets" to handle.
|
||||
@@ -183,17 +162,6 @@ EOF
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Ugly patch for a change in the behavior of jQuery UI:
|
||||
// Before jQuery UI 1.9, tabs were always considered as "local" (opposed to Ajax)
|
||||
// when their href was beginning by #. Starting with 1.9, a <base> tag in the page
|
||||
// is taken into account and causes "local" tabs to be considered as Ajax
|
||||
// unless their URL is equal to the URL of the page...
|
||||
$('div[id^=tabbedContent] > ul > li > a').each(function() {
|
||||
var sHash = location.hash;
|
||||
var sCleanLocation = location.href.toString().replace(sHash, '').replace(/#$/, '');
|
||||
$(this).attr("href", sCleanLocation+$(this).attr("href"));
|
||||
});
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
@@ -203,7 +171,7 @@ EOF
|
||||
}
|
||||
});
|
||||
|
||||
$('.multiselect').multiselect($sJSMultiselectOptions);
|
||||
$('.multiselect').multiselect({header: false, noneSelectedText: '$sSearchAny', selectedList: 1, selectedText:'$sSearchNbSelected'});
|
||||
|
||||
$('.resizable').filter(':visible').resizable();
|
||||
}
|
||||
@@ -404,7 +372,7 @@ EOF
|
||||
{
|
||||
if ($('#rawOutput > div').html() != '')
|
||||
{
|
||||
$('#rawOutput').dialog( {autoOpen: true, modal:false, width: '80%'});
|
||||
$('#rawOutput').dialog( {autoOpen: true, modal:false});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,11 +499,6 @@ EOF
|
||||
{
|
||||
$sNorthPane .= $oExtensionInstance->GetNorthPaneHtml($this);
|
||||
}
|
||||
|
||||
if (UserRights::IsAdministrator() && ExecutionKPI::IsEnabled())
|
||||
{
|
||||
$sNorthPane .= '<div id="admin-banner"><span style="padding:5px;">'.ExecutionKPI::GetDescription().'<span></div>';
|
||||
}
|
||||
|
||||
$sSouthPane = '';
|
||||
foreach (MetaModel::EnumPlugins('iPageUIExtension') as $oExtensionInstance)
|
||||
@@ -636,6 +599,12 @@ EOF
|
||||
$sHtml .= "</head>\n";
|
||||
$sHtml .= "<body>\n";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Render the revision number
|
||||
if (ITOP_REVISION == '$WCREV$')
|
||||
{
|
||||
@@ -672,7 +641,7 @@ EOF
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<li><a href=\"#tab_{$container_index}$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
|
||||
$sTabs .= "<li><a href=\"#tab_$i\" class=\"tab\"><span>".htmlentities($sTabName, ENT_QUOTES, 'UTF-8')."</span></a></li>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</ul>\n";
|
||||
@@ -680,7 +649,7 @@ EOF
|
||||
$i = 0;
|
||||
foreach($m_aTabs as $sTabName => $sTabContent)
|
||||
{
|
||||
$sTabs .= "<div id=\"tab_{$container_index}$i\">".$sTabContent."</div>\n";
|
||||
$sTabs .= "<div id=\"tab_$i\">".$sTabContent."</div>\n";
|
||||
$i++;
|
||||
}
|
||||
$sTabs .= "</div>\n<!-- end of tabs-->\n";
|
||||
@@ -721,10 +690,6 @@ EOF
|
||||
$aActions[$oChangePwd->GetUID()] = $oChangePwd->GetMenuItem();
|
||||
}
|
||||
utils::GetPopupMenuItems($this, iPopupMenuExtension::MENU_USER_ACTIONS, null, $aActions);
|
||||
|
||||
$oAbout = new JSPopupMenuItem('UI:AboutBox', Dict::S('UI:AboutBox'), 'return ShowAboutBox();');
|
||||
$aActions[$oAbout->GetUID()] = $oAbout->GetMenuItem();
|
||||
|
||||
$sLogOffMenu .= $this->RenderPopupMenuItems($aActions);
|
||||
|
||||
|
||||
@@ -760,6 +725,18 @@ EOF
|
||||
$sApplicationBanner .= '<div id="admin-banner"><span style="padding:5px;">'.$this->m_sMessage.'<span></div>';
|
||||
}
|
||||
|
||||
$sEnvironment = utils::GetCurrentEnvironment();
|
||||
$sBackButton = utils::GetEnvironmentBackButton();
|
||||
if($sEnvironment != 'production')
|
||||
{
|
||||
$sEnvLabel = trim(MetaModel::GetConfig()->Get('app_env_label'));
|
||||
if (strlen($sEnvLabel) == 0)
|
||||
{
|
||||
$sEnvLabel = $sEnvironment;
|
||||
}
|
||||
$sApplicationBanner .= '<div id="admin-banner"><span style="padding:5px;">'.Dict::Format('UI:ApplicationEnvironment', $sEnvLabel).$sBackButton.'<span></div>';
|
||||
}
|
||||
|
||||
$sApplicationBanner .= $sBannerExtraHtml;
|
||||
|
||||
if (!empty($sNorthPane))
|
||||
@@ -776,18 +753,12 @@ EOF
|
||||
$sOnlineHelpUrl = MetaModel::GetConfig()->Get('online_help');
|
||||
//$sLogOffMenu = "<span id=\"logOffBtn\" style=\"height:55px;padding:0;margin:0;\"><img src=\"../images/onOffBtn.png\"></span>";
|
||||
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlAppRoot().'images/itop-logo.png';
|
||||
if (file_exists(MODULESROOT.'branding/main-logo.png'))
|
||||
{
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/main-logo.png';
|
||||
}
|
||||
|
||||
$sHtml .= $sNorthPane;
|
||||
$sHtml .= '<div id="left-pane" class="ui-layout-west">';
|
||||
$sHtml .= '<!-- Beginning of the left pane -->';
|
||||
$sHtml .= ' <div class="ui-layout-north">';
|
||||
$sHtml .= ' <div id="header-logo">';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="'.htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8').'"><img src="'.$sDisplayIcon.'" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="'.htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8').'"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="header-menu">';
|
||||
$sHtml .= ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>';
|
||||
@@ -816,7 +787,7 @@ EOF
|
||||
$sHtml .= '<td style="padding-right:20px;padding-left:10px;">'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="ui-layout-content" style="overflow:auto;">';
|
||||
$sHtml .= ' <div class="ui-layout-content">';
|
||||
$sHtml .= ' <!-- Beginning of page content -->';
|
||||
$sHtml .= self::FilterXSS($this->s_content);
|
||||
$sHtml .= ' <!-- End of page content -->';
|
||||
@@ -844,9 +815,7 @@ EOF
|
||||
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
echo $sHtml;
|
||||
$oKPI->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)');
|
||||
}
|
||||
else if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf') )
|
||||
{
|
||||
@@ -872,7 +841,6 @@ EOF
|
||||
$oMPDF->Output($sOutputName, 'I');
|
||||
}
|
||||
MetaModel::RecordQueryTrace();
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
|
||||
public function AddTabContainer($sTabContainer)
|
||||
@@ -982,7 +950,7 @@ EOF
|
||||
$container_index++;
|
||||
}
|
||||
$sSelector = '#tabbedContent_'.$container_index.' > ul';
|
||||
$this->add_ready_script("window.setTimeout(\"$('$sSelector').tabs('select', $tab_index);\", 100);"); // Let the time to the tabs widget to initialize
|
||||
$this->add_ready_script("$('$sSelector').tabs('select', $tab_index);");
|
||||
}
|
||||
|
||||
public function StartCollapsibleSection($sSectionLabel, $bOpen = false)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Class LoginWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -31,67 +31,72 @@ require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
|
||||
class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
const EXIT_PROMPT = 0;
|
||||
const EXIT_HTTP_401 = 1;
|
||||
const EXIT_RETURN_FALSE = 2;
|
||||
|
||||
protected static $sHandlerClass = __class__;
|
||||
public static function RegisterHandler($sClass)
|
||||
{
|
||||
self::$sHandlerClass = $sClass;
|
||||
}
|
||||
|
||||
public static function NewLoginWebPage()
|
||||
{
|
||||
return new self::$sHandlerClass;
|
||||
}
|
||||
|
||||
protected static $m_sLoginFailedMessage = '';
|
||||
|
||||
public function __construct($sTitle = 'iTop Login')
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->SetStyleSheet();
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct("iTop Login");
|
||||
$this->add_style(<<<EOF
|
||||
body {
|
||||
background: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#login-logo {
|
||||
margin-top: 150px;
|
||||
width: 300px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background: #f6f6f1;
|
||||
height: 54px;
|
||||
border-top: 1px solid #000;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
#login-logo img {
|
||||
border: 0;
|
||||
}
|
||||
#login {
|
||||
width: 300px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #000;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
border-top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
#pwd, #user,#old_pwd, #new_pwd, #retype_new_pwd {
|
||||
width: 10em;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #1C94C4;
|
||||
font-size: 16pt;
|
||||
}
|
||||
.v-spacer {
|
||||
padding-top: 1em;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function SetStyleSheet()
|
||||
{
|
||||
$this->add_linked_stylesheet("../css/login.css");
|
||||
}
|
||||
|
||||
public static function SetLoginFailedMessage($sMessage)
|
||||
{
|
||||
self::$m_sLoginFailedMessage = $sMessage;
|
||||
}
|
||||
|
||||
public function EnableResetPassword()
|
||||
{
|
||||
return MetaModel::GetConfig()->Get('forgot_password');
|
||||
}
|
||||
|
||||
public function DisplayLoginHeader($bMainAppLogo = false)
|
||||
{
|
||||
if ($bMainAppLogo)
|
||||
{
|
||||
$sLogo = 'itop-logo.png';
|
||||
$sBrandingLogo = 'main-logo.png';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLogo = 'itop-logo-external.png';
|
||||
$sBrandingLogo = 'login-logo.png';
|
||||
}
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlAppRoot().'images/'.$sLogo;
|
||||
if (file_exists(MODULESROOT.'branding/'.$sBrandingLogo))
|
||||
{
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/'.$sBrandingLogo;
|
||||
}
|
||||
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8')."\"><img title=\"$sVersionShort\" src=\"$sDisplayIcon\"></a></div>\n");
|
||||
}
|
||||
|
||||
|
||||
public function DisplayLoginForm($sLoginType, $bFailedLogin = false)
|
||||
{
|
||||
switch($sLoginType)
|
||||
@@ -106,7 +111,6 @@ class LoginWebPage extends NiceWebPage
|
||||
case 'url':
|
||||
$this->add_header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
|
||||
$this->add_header('HTTP/1.0 401 Unauthorized');
|
||||
$this->add_header('Content-type: text/html; charset=iso-8859-1');
|
||||
// Note: displayed when the user will click on Cancel
|
||||
$this->add('<p><strong>'.Dict::S('UI:Login:Error:AccessRestricted').'</strong></p>');
|
||||
break;
|
||||
@@ -117,7 +121,9 @@ class LoginWebPage extends NiceWebPage
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
$sAuthPwd = utils::ReadParam('suggest_pwd', '', true, 'raw_data');
|
||||
|
||||
$this->DisplayLoginHeader();
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
|
||||
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8')."\"><img title=\"$sVersionShort\" src=\"../images/itop-logo-external.png\"></a></div>\n");
|
||||
$this->add("<div id=\"login\">\n");
|
||||
$this->add("<h1>".Dict::S('UI:Login:Welcome')."</h1>\n");
|
||||
if ($bFailedLogin)
|
||||
@@ -136,15 +142,10 @@ class LoginWebPage extends NiceWebPage
|
||||
$this->add("<p>".Dict::S('UI:Login:IdentifyYourself')."</p>\n");
|
||||
}
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$sForgotPwd = $this->EnableResetPassword() ? $this->ForgotPwdLink() : '';
|
||||
$this->add("<table width=\"100%\">\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label></td><td style=\"text-align:left\"><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"pwd\">".Dict::S('UI:Login:PasswordPrompt').":</label></td><td style=\"text-align:left\"><input id=\"pwd\" type=\"password\" name=\"auth_pwd\" value=\"".htmlentities($sAuthPwd, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></span></td></tr>\n");
|
||||
if (strlen($sForgotPwd) > 0)
|
||||
{
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\">$sForgotPwd</td></tr>\n");
|
||||
}
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"submit\" value=\"".Dict::S('UI:Button:Login')."\" /></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"login\" />\n");
|
||||
|
||||
@@ -174,199 +175,11 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return '' to disable this feature
|
||||
*/
|
||||
public function ForgotPwdLink()
|
||||
{
|
||||
$sUrl = '?loginop=forgot_pwd';
|
||||
$sHtml = "<a href=\"$sUrl\" target=\"_blank\">".Dict::S('UI:Login:ForgotPwd')."</a>";
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function DisplayForgotPwdForm($bFailedToReset = false, $sFailureReason = null)
|
||||
{
|
||||
$this->DisplayLoginHeader();
|
||||
$this->add("<div id=\"login\">\n");
|
||||
$this->add("<h1>".Dict::S('UI:Login:ForgotPwdForm')."</h1>\n");
|
||||
$this->add("<p>".Dict::S('UI:Login:ForgotPwdForm+')."</p>\n");
|
||||
if ($bFailedToReset)
|
||||
{
|
||||
$this->add("<p class=\"hilite\">".Dict::Format('UI:Login:ResetPwdFailed', htmlentities($sFailureReason, ENT_QUOTES, 'UTF-8'))."</p>\n");
|
||||
}
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center\"><label for=\"user\">".Dict::S('UI:Login:UserNamePrompt').":</label><input id=\"user\" type=\"text\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"button\" onClick=\"window.close();\" value=\"".Dict::S('UI:Button:Cancel')."\" /></span> <span class=\"btn_border\"><input type=\"submit\" value=\"".Dict::S('UI:Login:ResetPassword')."\" /></span></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"forgot_pwd_go\" />\n");
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div>\n");
|
||||
}
|
||||
|
||||
protected function ForgotPwdGo()
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', true, 'raw_data');
|
||||
|
||||
try
|
||||
{
|
||||
UserRights::Login($sAuthUser); // Set the user's language (if possible!)
|
||||
$oUser = UserRights::GetUserObject();
|
||||
if ($oUser == null)
|
||||
{
|
||||
throw new Exception(Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser));
|
||||
}
|
||||
if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token'))
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible'));
|
||||
}
|
||||
if (!$oUser->CanChangePassword())
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd'));
|
||||
}
|
||||
|
||||
$sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed
|
||||
if ($sTo == '')
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail'));
|
||||
}
|
||||
|
||||
// This token allows the user to change the password without knowing the previous one
|
||||
$sToken = substr(md5(APPROOT.uniqid()), 0, 16);
|
||||
$oUser->Set('reset_pwd_token', $sToken);
|
||||
CMDBObject::SetTrackInfo('Reset password');
|
||||
$oUser->DBUpdate();
|
||||
|
||||
$oEmail = new Email();
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
$sFrom = MetaModel::GetConfig()->Get('forgot_password_from');
|
||||
if ($sFrom == '')
|
||||
{
|
||||
$sFrom = $sTo;
|
||||
}
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetSubject(Dict::S('UI:ResetPwd-EmailSubject'));
|
||||
$sResetUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=reset_pwd&auth_user='.urlencode($oUser->Get('login')).'&token='.urlencode($sToken);
|
||||
$oEmail->SetBody(Dict::Format('UI:ResetPwd-EmailBody', $sResetUrl));
|
||||
$iRes = $oEmail->Send($aIssues, true /* force synchronous exec */);
|
||||
switch ($iRes)
|
||||
{
|
||||
//case EMAIL_SEND_PENDING:
|
||||
case EMAIL_SEND_OK:
|
||||
break;
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
default:
|
||||
IssueLog::Error('Failed to send the email with the NEW password for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues));
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-Send'));
|
||||
}
|
||||
|
||||
$this->DisplayLoginHeader();
|
||||
$this->add("<div id=\"login\">\n");
|
||||
$this->add("<h1>".Dict::S('UI:Login:ForgotPwdForm')."</h1>\n");
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-EmailSent')."</p>");
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><input type=\"button\" onClick=\"window.close();\" value=\"".Dict::S('UI:Button:Done')."\" /></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div\n");
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$this->DisplayForgotPwdForm(true, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function DisplayResetPwdForm()
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
$sToken = utils::ReadParam('token', '', false, 'raw_data');
|
||||
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
$oUser = UserRights::GetUserObject();
|
||||
|
||||
$this->DisplayLoginHeader();
|
||||
$this->add("<div id=\"login\">\n");
|
||||
$this->add("<h1>".Dict::S('UI:ResetPwd-Title')."</h1>\n");
|
||||
if ($oUser == null)
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser)."</p>\n");
|
||||
}
|
||||
elseif ($oUser->Get('reset_pwd_token') != $sToken)
|
||||
{
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Error-InvalidToken')."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-EnterPassword', $oUser->GetFriendlyName())."</p>\n");
|
||||
|
||||
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function DoCheckPwd()
|
||||
{
|
||||
if ($('#new_pwd').val() != $('#retype_new_pwd').val())
|
||||
{
|
||||
alert('$sInconsistenPwdMsg');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"new_pwd\">".Dict::S('UI:Login:NewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"new_pwd\" name=\"new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"retype_new_pwd\">".Dict::S('UI:Login:RetypeNewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"retype_new_pwd\" name=\"retype_new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"submit\" onClick=\"return DoCheckPwd();\" value=\"".Dict::S('UI:Button:ChangePassword')."\" /></span></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"do_reset_pwd\" />\n");
|
||||
$this->add("<input type=\"hidden\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" />\n");
|
||||
$this->add("<input type=\"hidden\" name=\"token\" value=\"".htmlentities($sToken, ENT_QUOTES, 'UTF-8')."\" />\n");
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div\n");
|
||||
}
|
||||
}
|
||||
|
||||
public function DoResetPassword()
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
$sToken = utils::ReadParam('token', '', false, 'raw_data');
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data');
|
||||
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
$oUser = UserRights::GetUserObject();
|
||||
|
||||
$this->DisplayLoginHeader();
|
||||
$this->add("<div id=\"login\">\n");
|
||||
$this->add("<h1>".Dict::S('UI:ResetPwd-Title')."</h1>\n");
|
||||
if ($oUser == null)
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser)."</p>\n");
|
||||
}
|
||||
elseif ($oUser->Get('reset_pwd_token') != $sToken)
|
||||
{
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Error-InvalidToken')."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Trash the token and change the password
|
||||
$oUser->Set('reset_pwd_token', '');
|
||||
$oUser->SetPassword($sNewPwd); // Does record the change into the DB
|
||||
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Ready')."</p>");
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$this->add("<p><a href=\"$sUrl\">".Dict::S('UI:ResetPwd-Login')."</a></p>");
|
||||
}
|
||||
$this->add("</div\n");
|
||||
}
|
||||
|
||||
public function DisplayChangePwdForm($bFailedLogin = false)
|
||||
{
|
||||
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
|
||||
|
||||
$sVersionShort = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION);
|
||||
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
|
||||
$this->add_script(<<<EOF
|
||||
function GoBack()
|
||||
@@ -385,7 +198,8 @@ function DoCheckPwd()
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$this->DisplayLoginHeader();
|
||||
$sIconUrl = Utils::GetConfig()->Get('app_icon_url');
|
||||
$this->add("<div id=\"login-logo\"><a href=\"".htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8')."\"><img title=\"$sVersionShort\" src=\"../images/itop-logo.png\"></a></div>\n");
|
||||
$this->add("<div id=\"login\">\n");
|
||||
$this->add("<h1>".Dict::S('UI:Login:ChangeYourPassword')."</h1>\n");
|
||||
if ($bFailedLogin)
|
||||
@@ -393,11 +207,11 @@ EOF
|
||||
$this->add("<p class=\"hilite\">".Dict::S('UI:Login:IncorrectOldPassword')."</p>\n");
|
||||
}
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$this->add("<table width=\"100%\">\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"old_pwd\">".Dict::S('UI:Login:OldPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"old_pwd\" name=\"old_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"new_pwd\">".Dict::S('UI:Login:NewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"new_pwd\" name=\"new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"retype_new_pwd\">".Dict::S('UI:Login:RetypeNewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"retype_new_pwd\" name=\"retype_new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"button\" onClick=\"GoBack();\" value=\"".Dict::S('UI:Button:Cancel')."\" /></span> <span class=\"btn_border\"><input type=\"submit\" onClick=\"return DoCheckPwd();\" value=\"".Dict::S('UI:Button:ChangePassword')."\" /></span></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"> <input type=\"button\" onClick=\"GoBack();\" value=\"".Dict::S('UI:Button:Cancel')."\" /> <input type=\"submit\" onClick=\"return DoCheckPwd();\" value=\"".Dict::S('UI:Button:ChangePassword')."\" /></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"do_change_pwd\" />\n");
|
||||
$this->add("</form>\n");
|
||||
@@ -426,30 +240,7 @@ EOF
|
||||
return MetaModel::GetConfig()->GetSecureConnectionRequired();
|
||||
}
|
||||
|
||||
/**
|
||||
* Guess if a string looks like an UTF-8 string based on some ranges of multi-bytes encoding
|
||||
* @param string $sString
|
||||
* @return bool True if the string contains some typical UTF-8 multi-byte sequences
|
||||
*/
|
||||
static function LooksLikeUTF8($sString)
|
||||
{
|
||||
return preg_match('%(?:
|
||||
[\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
|
||||
|\xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
|
||||
|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
|
||||
|\xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
|
||||
|\xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
|
||||
|[\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
|
||||
|\xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
|
||||
)+%xs', $sString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt a login
|
||||
*
|
||||
* @param int iOnExit What action to take if the user is not logged on (one of the class constants EXIT_...)
|
||||
*/
|
||||
protected static function Login($iOnExit)
|
||||
protected static function Login()
|
||||
{
|
||||
if (self::SecureConnectionRequired() && !utils::IsConnectionSecure())
|
||||
{
|
||||
@@ -509,22 +300,7 @@ EOF
|
||||
else if (isset($_SERVER['PHP_AUTH_USER']))
|
||||
{
|
||||
$sAuthUser = $_SERVER['PHP_AUTH_USER'];
|
||||
// Unfortunately, the RFC is not clear about the encoding...
|
||||
// IE and FF supply the user and password encoded in ISO-8859-1 whereas Chrome provides them encoded in UTF-8
|
||||
// So let's try to guess if it's an UTF-8 string or not... fortunately all encodings share the same ASCII base
|
||||
if (!self::LooksLikeUTF8($sAuthUser))
|
||||
{
|
||||
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
|
||||
// Supposed to be harmless in case of a plain ASCII string...
|
||||
$sAuthUser = iconv('iso-8859-1', 'utf-8', $sAuthUser);
|
||||
}
|
||||
$sAuthPwd = $_SERVER['PHP_AUTH_PW'];
|
||||
if (!self::LooksLikeUTF8($sAuthPwd))
|
||||
{
|
||||
// Does not look like and UTF-8 string, try to convert it from iso-8859-1 to UTF-8
|
||||
// Supposed to be harmless in case of a plain ASCII string...
|
||||
$sAuthPwd = iconv('iso-8859-1', 'utf-8', $sAuthPwd);
|
||||
}
|
||||
$sLoginMode = 'basic';
|
||||
}
|
||||
break;
|
||||
@@ -567,24 +343,10 @@ EOF
|
||||
{
|
||||
$sLoginMode = $aAllowedLoginTypes[0]; // First in the list...
|
||||
}
|
||||
if (($iOnExit == self::EXIT_HTTP_401) || ($sLoginMode == 'basic'))
|
||||
{
|
||||
header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
header('Content-type: text/html; charset=iso-8859-1');
|
||||
exit;
|
||||
}
|
||||
else if($iOnExit == self::EXIT_RETURN_FALSE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, false /* no previous failed attempt */);
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, false /* no previous failed attempt */);
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -592,24 +354,10 @@ EOF
|
||||
{
|
||||
//echo "Check Credentials returned false for user $sAuthUser!";
|
||||
self::ResetSession();
|
||||
if (($iOnExit == self::EXIT_HTTP_401))
|
||||
{
|
||||
header('WWW-Authenticate: Basic realm="'.Dict::Format('UI:iTopVersion:Short', ITOP_VERSION));
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
header('Content-type: text/html; charset=iso-8859-1');
|
||||
exit;
|
||||
}
|
||||
else if($iOnExit == self::EXIT_RETURN_FALSE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, true /* failed attempt */);
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, true /* failed attempt */);
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -630,32 +378,16 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable: depending on the user, head toward a dedicated portal
|
||||
* @param bool $bIsAllowedToPortalUsers Whether or not the current page is considered as part of the portal
|
||||
*/
|
||||
protected static function ChangeLocation($bIsAllowedToPortalUsers)
|
||||
{
|
||||
if ( (!$bIsAllowedToPortalUsers) && (UserRights::IsPortalUser()))
|
||||
{
|
||||
// No rights to be here, redirect to the portal
|
||||
header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if the user is already authentified, if yes, then performs some additional validations:
|
||||
* - if $bMustBeAdmin is true, then the user must be an administrator, otherwise an error is displayed
|
||||
* - if $bIsAllowedToPortalUsers is false and the user has only access to the portal, then the user is redirected to the portal
|
||||
* @param bool $bMustBeAdmin Whether or not the user must be an admin to access the current page
|
||||
* @param bool $bIsAllowedToPortalUsers Whether or not the current page is considered as part of the portal
|
||||
* @param int iOnExit What action to take if the user is not logged on (one of the class constants EXIT_...)
|
||||
*/
|
||||
static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false, $iOnExit = self::EXIT_PROMPT)
|
||||
static function DoLogin($bMustBeAdmin = false, $bIsAllowedToPortalUsers = false)
|
||||
{
|
||||
$sMessage = ''; // In case we need to return a message to the calling web page
|
||||
$operation = utils::ReadParam('loginop', '');
|
||||
@@ -679,44 +411,16 @@ EOF
|
||||
}
|
||||
}
|
||||
self::ResetSession();
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayLoginForm( $sLoginMode, false /* not a failed attempt */);
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'forgot_pwd')
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayForgotPwdForm();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'forgot_pwd_go')
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->ForgotPwdGo();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'reset_pwd')
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DisplayResetPwdForm();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'do_reset_pwd')
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage->DoResetPassword();
|
||||
$oPage->output();
|
||||
exit;
|
||||
}
|
||||
else if ($operation == 'change_pwd')
|
||||
{
|
||||
$sAuthUser = $_SESSION['auth_user'];
|
||||
UserRights::Login($sAuthUser); // Set the user's language
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayChangePwdForm();
|
||||
$oPage->output();
|
||||
exit;
|
||||
@@ -729,7 +433,7 @@ EOF
|
||||
$sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data');
|
||||
if (UserRights::CanChangePassword() && ((!UserRights::CheckCredentials($sAuthUser, $sOldPwd)) || (!UserRights::ChangePassword($sOldPwd, $sNewPwd))))
|
||||
{
|
||||
$oPage = self::NewLoginWebPage();
|
||||
$oPage = new LoginWebPage();
|
||||
$oPage->DisplayChangePwdForm(true); // old pwd was wrong
|
||||
$oPage->output();
|
||||
exit;
|
||||
@@ -737,7 +441,7 @@ EOF
|
||||
$sMessage = Dict::S('UI:Login:PasswordChanged');
|
||||
}
|
||||
|
||||
$bRet = self::Login($iOnExit);
|
||||
self::Login();
|
||||
|
||||
if ($bMustBeAdmin && !UserRights::IsAdministrator())
|
||||
{
|
||||
@@ -748,14 +452,12 @@ EOF
|
||||
$oP->output();
|
||||
exit;
|
||||
}
|
||||
call_user_func(array(self::$sHandlerClass, 'ChangeLocation'), $bIsAllowedToPortalUsers);
|
||||
if ($iOnExit == self::EXIT_RETURN_FALSE)
|
||||
elseif ( (!$bIsAllowedToPortalUsers) && (UserRights::IsPortalUser()))
|
||||
{
|
||||
return $bRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $sMessage;
|
||||
// No rights to be here, redirect to the portal
|
||||
header('Location: '.utils::GetAbsoluteUrlAppRoot().'portal/index.php');
|
||||
}
|
||||
return $sMessage;
|
||||
}
|
||||
} // End of class
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -184,9 +184,8 @@ class ApplicationMenu
|
||||
$oPage->AddToMenu('</ul>');
|
||||
if ($bActive)
|
||||
{
|
||||
//$oPage->add_ready_script("$('#accordion').accordion('activate', $iAccordion);");
|
||||
// $oPage->add_ready_script("$('#accordion').accordion('option', {collapsible: true});"); // Make it auto-collapsible once it has been opened properly
|
||||
$oPage->add_ready_script("$('#accordion').accordion('option', {collapsible: true, active: $iAccordion});"); // Make it auto-collapsible once it has been opened properly
|
||||
$oPage->add_ready_script("$('#accordion').accordion('activate', $iAccordion);");
|
||||
$oPage->add_ready_script("$('#accordion').accordion('option', {collapsible: true});"); // Make it auto-collapsible once it has been opened properly
|
||||
}
|
||||
}
|
||||
$oPage->AddToMenu('</div>');
|
||||
@@ -300,9 +299,7 @@ class ApplicationMenu
|
||||
// Make sure the root menu is sorted on 'rank'
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
$oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']);
|
||||
$aChildren = self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'];
|
||||
usort($aChildren, array('ApplicationMenu', 'CompareOnRank'));
|
||||
$oMenuNode = self::GetMenuNode($aChildren[0]['index']);
|
||||
$oMenuNode = self::GetMenuNode(self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'][0]['index']);
|
||||
$sMenuId = $oMenuNode->GetMenuId();
|
||||
}
|
||||
return $sMenuId;
|
||||
@@ -879,41 +876,8 @@ class DashboardMenuNode extends MenuNode
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$sDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $this->sMenuId);
|
||||
$oPage->add('<div class="dashboard_contents" id="'.$sDivId.'">');
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
$oPage->add('</div>');
|
||||
$oDashboard->RenderEditionTools($oPage);
|
||||
|
||||
if ($oDashboard->GetAutoReload())
|
||||
{
|
||||
$sId = $this->sMenuId;
|
||||
$sExtraParams = json_encode($aExtraParams);
|
||||
$iReloadInterval = 1000 * $oDashboard->GetAutoReloadInterval();
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
setInterval("ReloadDashboard('$sDivId');", $iReloadInterval);
|
||||
|
||||
function ReloadDashboard(sDivId)
|
||||
{
|
||||
var oExtraParams = $sExtraParams;
|
||||
// Do not reload when a dialog box is active
|
||||
if (!($('.ui-dialog:visible').length > 0))
|
||||
{
|
||||
$('.dashboard_contents#'+sDivId).block();
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
|
||||
{ operation: 'reload_dashboard', dashboard_id: '$sId', extra_params: oExtraParams},
|
||||
function(data){
|
||||
$('.dashboard_contents#'+sDivId).html(data);
|
||||
$('.dashboard_contents#'+sDivId).unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$bEdit = utils::ReadParam('edit', false);
|
||||
if ($bEdit)
|
||||
{
|
||||
|
||||
@@ -37,10 +37,9 @@ class NiceWebPage extends WebPage
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
$this->m_aReadyScripts = array();
|
||||
$this->add_linked_script("../js/jquery-1.10.0.min.js");
|
||||
$this->add_linked_script("../js/jquery-migrate-1.2.1.min.js"); // Needed since many other plugins still rely on oldies like $.browser
|
||||
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.10.3.custom.min.css');
|
||||
$this->add_linked_script('../js/jquery-ui-1.10.3.custom.min.js');
|
||||
$this->add_linked_script("../js/jquery-1.7.1.min.js");
|
||||
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.17.custom.css');
|
||||
$this->add_linked_script('../js/jquery-ui-1.8.17.custom.min.js');
|
||||
$this->add_linked_script("../js/hovertip.js");
|
||||
// table sorting
|
||||
$this->add_linked_script("../js/jquery.tablesorter.js");
|
||||
@@ -99,7 +98,6 @@ EOF
|
||||
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
|
||||
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
|
||||
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
|
||||
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
|
||||
|
||||
$sAppContext = addslashes($this->GetApplicationContext());
|
||||
|
||||
@@ -114,23 +112,6 @@ function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLModulesRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulePage(sModule, sPage, aArguments)
|
||||
{
|
||||
// aArguments is optional, it default to an empty hash
|
||||
aArguments = typeof aArguments !== 'undefined' ? aArguments : {};
|
||||
|
||||
var sUrl = '$sAbsURLAppRoot'+'pages/exec.php?exec_module='+sModule+'&exec_page='+sPage+'&exec_env='+'$sEnvironment';
|
||||
for (var sArgName in aArguments)
|
||||
{
|
||||
if (aArguments.hasOwnProperty(sArgName))
|
||||
{
|
||||
sUrl = sUrl + '&'+sArgName+'='+aArguments[sArgname];
|
||||
}
|
||||
}
|
||||
return sUrl;
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
@@ -219,7 +200,7 @@ EOF
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
//$this->set_base($this->m_sRootUrl.'pages/');
|
||||
$this->set_base($this->m_sRootUrl.'pages/');
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
{
|
||||
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Class PortalWebPage
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -64,7 +64,6 @@ class PortalWebPage extends NiceWebPage
|
||||
$sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sAppContext = addslashes($oAppContext->GetForLink());
|
||||
$this->add_dict_entry('UI:FillAllMandatoryFields');
|
||||
if ($sAlternateStyleSheet != '')
|
||||
{
|
||||
$this->add_linked_stylesheet("../portal/$sAlternateStyleSheet/portal.css");
|
||||
@@ -236,17 +235,6 @@ EOF
|
||||
|
||||
// For Wizard helper to process the ajax replies
|
||||
$this->add('<div id="ajax_content"></div>');
|
||||
|
||||
// Customize the logo (unless a customer CSS has been defined)
|
||||
if ($sAlternateStyleSheet == '')
|
||||
{
|
||||
if (file_exists(MODULESROOT.'branding/portal-logo.png'))
|
||||
{
|
||||
$sDisplayIcon = utils::GetAbsoluteUrlModulesRoot().'branding/portal-logo.png';
|
||||
$this->add_style("div#portal #logo {background: url(\"$sDisplayIcon\") no-repeat scroll 0 0 transparent;}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
@@ -324,7 +312,7 @@ EOF
|
||||
|
||||
$sUniqueId = $sClass.$this->GetUniqueId();
|
||||
$this->add("<div id=\"$sUniqueId\">\n"); // The id here MUST be the same as currentId, otherwise the pagination will be broken
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $sUniqueId, 'menu' => false, 'toolkit_menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $sUniqueId, 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$this->add("</div>\n");
|
||||
}
|
||||
else
|
||||
@@ -420,7 +408,7 @@ EOF
|
||||
}
|
||||
$oObjSearch->AddCondition_ReferencedBy($oLinkSet->GetFilter(), $sRemoteAttCode);
|
||||
|
||||
$aExtraParams = array('menu' => false, 'toolkit_menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList));
|
||||
$aExtraParams = array('menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList));
|
||||
$oBlock = new DisplayBlock($oObjSearch, 'list', false);
|
||||
$oBlock->Display($this, 1, $aExtraParams);
|
||||
}
|
||||
@@ -430,7 +418,8 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null, $aFilterParams = array())
|
||||
|
||||
protected function DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, $sFieldName = null)
|
||||
{
|
||||
if (is_null($sFieldName))
|
||||
{
|
||||
@@ -461,7 +450,7 @@ EOF
|
||||
{
|
||||
throw new Exception("Attribute specification '$sAttSpec', '$sAttCode' should be either a link set or an external key");
|
||||
}
|
||||
$this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName, $aFilterParams);
|
||||
$this->DisplaySearchField($sTargetClass, $sSubSpec, $aExtraParams, $sPrefix, $sFieldName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -475,24 +464,7 @@ EOF
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$sFilterDefName = 'PORTAL_TICKETS_SEARCH_FILTER_'.$sAttSpec;
|
||||
if (defined($sFilterDefName))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oFitlerWithParams = DBObjectSearch::FromOQL(constant($sFilterDefName));
|
||||
$sFilterOQL = $oFitlerWithParams->ToOQL(true, $aFilterParams);
|
||||
$oAllowedValues = new DBObjectSet(DBObjectSearch::FromOQL($sFilterOQL), array(), $aFilterParams);
|
||||
}
|
||||
catch(OQLException $e)
|
||||
{
|
||||
throw new Exception("Incorrect filter '$sFilterDefName' for attribute '$sAttcode': ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass));
|
||||
}
|
||||
$oAllowedValues = new DBObjectSet(new DBObjectSearch($sTargetClass));
|
||||
|
||||
$iFieldSize = $oAttDef->GetMaxSize();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
@@ -512,8 +484,7 @@ EOF
|
||||
if (is_null($aAllowedValues))
|
||||
{
|
||||
// Any value is possible, display an input box
|
||||
$sSanitizedValue = htmlentities($sFilterValue, ENT_QUOTES, 'UTF-8');
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> <input class=\"textSearch\" name=\"$sPrefix$sFieldName\" value=\"$sSanitizedValue\"/>\n");
|
||||
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label> <input class=\"textSearch\" name=\"$sPrefix$sFieldName\" value=\"$sFilterValue\"/>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -550,30 +521,9 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The organization of the current user (i.e. the organization of its contact)
|
||||
* @throws Exception
|
||||
*/
|
||||
function GetUserOrg()
|
||||
{
|
||||
$oOrg = null;
|
||||
$iContactId = UserRights::GetContactId();
|
||||
$oContact = MetaModel::GetObject('Contact', $iContactId, false); // false => Can fail
|
||||
if (is_object($oContact))
|
||||
{
|
||||
$oOrg = MetaModel::GetObject('Organization', $oContact->Get('org_id'), false); // false => can fail
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(Dict::S('Portal:ErrorNoContactForThisUser'));
|
||||
}
|
||||
return $oOrg;
|
||||
}
|
||||
|
||||
public function DisplaySearchForm($sClass, $aAttList, $aExtraParams, $sPrefix, $bClosed = true)
|
||||
{
|
||||
$oUserOrg = $this->GetUserOrg();
|
||||
$aFilterParams = array('org_id' => $oUserOrg->GetKey(), 'contact_id' => UserRights::GetContactId());
|
||||
$sCSSClass = ($bClosed) ? 'DrawerClosed' : '';
|
||||
$this->add("<div id=\"ds_$sPrefix\" class=\"SearchDrawer $sCSSClass\">\n");
|
||||
$this->add_ready_script(
|
||||
@@ -590,17 +540,13 @@ EOF
|
||||
foreach($aAttList as $sAttSpec)
|
||||
{
|
||||
//$oAppContext->Reset($sAttSpec); // Make sure the same parameter will not be passed twice
|
||||
$this->DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix, null, $aFilterParams);
|
||||
$this->DisplaySearchField($sClass, $sAttSpec, $aExtraParams, $sPrefix);
|
||||
}
|
||||
$this->add("</p>\n");
|
||||
$this->add("<p align=\"right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Search')."\"></p>\n");
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
// Note: use DumpHiddenParams() to transmit arrays as hidden params
|
||||
if (is_scalar($sValue))
|
||||
{
|
||||
$this->add("<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n");
|
||||
}
|
||||
$this->add("<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n");
|
||||
}
|
||||
// $this->add($oAppContext->GetForForm());
|
||||
$this->add("</form>\n");
|
||||
@@ -796,7 +742,7 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $iId, false);
|
||||
$oObj = MetaModel::GetObject($sClass, $iId, false);
|
||||
if (!is_object($oObj))
|
||||
{
|
||||
throw new Exception("Could not find the object $sClass/$iId");
|
||||
@@ -849,10 +795,7 @@ EOF
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_BACK)
|
||||
{
|
||||
if (utils::ReadParam('step_back', 1) != 1)
|
||||
{
|
||||
$aButtons[] = "<input id=\"btn_back\" type=\"submit\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoBack('{$this->m_sWizardId}');\">";
|
||||
}
|
||||
$aButtons[] = "<input id=\"btn_back\" type=\"submit\" value=\"".Dict::S('UI:Button:Back')."\" onClick=\"GoBack('{$this->m_sWizardId}');\">";
|
||||
}
|
||||
if ($iButtonFlags & BUTTON_NEXT)
|
||||
{
|
||||
|
||||
@@ -94,34 +94,13 @@ class QueryOQL extends Query
|
||||
{
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'webservices/export.php?format=spreadsheet&login_mode=basic&query='.$this->GetKey();
|
||||
$sOql = $this->Get('oql');
|
||||
$sMessage = null;
|
||||
try
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$aParameters = $oSearch->GetQueryParams();
|
||||
foreach($aParameters as $sParam => $val)
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
$aParameters = $oSearch->GetQueryParams();
|
||||
foreach($aParameters as $sParam => $val)
|
||||
{
|
||||
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
|
||||
}
|
||||
|
||||
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
|
||||
|
||||
if (count($aParameters) == 0)
|
||||
{
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
$aExtraParams = array(
|
||||
//'menu' => $sShowMenu,
|
||||
'table_id' => 'query_preview_'.$this->getKey(),
|
||||
);
|
||||
$sBlockId = 'block_query_preview_'.$this->GetKey(); // make a unique id (edition occuring in the same DOM)
|
||||
$oBlock->Display($oPage, $sBlockId, $aExtraParams);
|
||||
}
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
$sMessage = '<div class="message message_error" style="padding-left: 30px;"><div style="padding: 10px;">'.Dict::Format('UI:RunQuery:Error', $e->getHtmlDesc()).'</div></div>';
|
||||
$oPage->p($sMessage);
|
||||
$sUrl .= '&arg_'.$sParam.'=["'.$sParam.'"]';
|
||||
}
|
||||
$oPage->p(Dict::S('UI:Query:UrlForExcel').':<br/><textarea cols="80" rows="3" READONLY>'.$sUrl.'</textarea>');
|
||||
}
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -166,8 +166,6 @@ class ShortcutOQL extends Shortcut
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("oql", array("allowed_values"=>null, "sql"=>"oql", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("auto_reload", array("allowed_values"=>new ValueSetEnum('none,custom'), "sql"=>"auto_reload", "default_value"=>"none", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("auto_reload_sec", array("allowed_values"=>null, "sql"=>"auto_reload_sec", "default_value"=>60, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('name', 'context', 'oql')); // Attributes to be displayed for the complete details
|
||||
@@ -181,21 +179,6 @@ class ShortcutOQL extends Shortcut
|
||||
{
|
||||
$oPage->set_title($this->Get('name'));
|
||||
|
||||
switch($this->Get('auto_reload'))
|
||||
{
|
||||
case 'custom':
|
||||
$iRate = (int)$this->Get('auto_reload_sec');
|
||||
if ($iRate > 0)
|
||||
{
|
||||
// Must a string otherwise it can be evaluated to 'true' and defaults to "standard" refresh rate!
|
||||
$aExtraParams['auto_reload'] = (string)$iRate;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'none':
|
||||
}
|
||||
|
||||
$bSearchPane = true;
|
||||
$bSearchOpen = false;
|
||||
try
|
||||
@@ -209,18 +192,7 @@ class ShortcutOQL extends Shortcut
|
||||
|
||||
}
|
||||
|
||||
public function CloneTableSettings($sTableSettings)
|
||||
{
|
||||
$aTableSettings = json_decode($sTableSettings, true);
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL($this->Get('oql'));
|
||||
$oCustomSettings = new DataTableSettings($oFilter->GetSelectedClasses());
|
||||
$oCustomSettings->iDefaultPageSize = $aTableSettings['iPageSize'];
|
||||
$oCustomSettings->aColumns = $aTableSettings['oColumns'];
|
||||
$oCustomSettings->Save('shortcut_'.$this->GetKey());
|
||||
}
|
||||
|
||||
public static function GetCreationForm($sOQL = null, $sTableSettings = null)
|
||||
public static function GetCreationForm($sOQL = null)
|
||||
{
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
@@ -243,36 +215,20 @@ class ShortcutOQL extends Shortcut
|
||||
$oField = new DesignerTextField('name', Dict::S('Class:Shortcut/Attribute:name'), $sDefault);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
/*
|
||||
$oField = new DesignerComboField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), 'none');
|
||||
$oAttDef = MetaModel::GetAttributeDef(__class__, 'auto_reload');
|
||||
$oField->SetAllowedValues($oAttDef->GetAllowedValues());
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
*/
|
||||
$oField = new DesignerBooleanField('auto_reload', Dict::S('Class:ShortcutOQL/Attribute:auto_reload'), false);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('Class:ShortcutOQL/Attribute:auto_reload_sec'), MetaModel::GetConfig()->GetStandardReloadInterval());
|
||||
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
|
||||
$oField->SetMandatory(false);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
|
||||
//$oField = new DesignerLongTextField('oql', Dict::S('Class:Shortcut/Attribute:oql'), $sOQL);
|
||||
//$oField->SetMandatory();
|
||||
$oField = new DesignerHiddenField('oql', '', $sOQL);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
$oField = new DesignerHiddenField('table_settings', '', $sTableSettings);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
public static function GetCreationDlgFromOQL($oPage, $sOQL, $sTableSettings)
|
||||
public static function GetCreationDlgFromOQL($oPage, $sOQL)
|
||||
{
|
||||
$oPage->add('<div id="shortcut_creation_dlg">');
|
||||
|
||||
$oForm = self::GetCreationForm($sOQL, $sTableSettings);
|
||||
$oForm = self::GetCreationForm($sOQL);
|
||||
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
@@ -284,19 +240,9 @@ class ShortcutOQL extends Shortcut
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
|
||||
$sRateTitle = addslashes(Dict::Format('Class:ShortcutOQL/Attribute:auto_reload_sec/tip', MetaModel::GetConfig()->Get('min_reload_interval')));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
function ShortcutCreationOK()
|
||||
{
|
||||
var oForm = $('#shortcut_creation_dlg form');
|
||||
|
||||
20
application/templates/notifications_menu.html
Normal file
@@ -0,0 +1,20 @@
|
||||
<div class="page_header" style="padding:0.5em;">
|
||||
<h1><itopstring>UI:NotificationsMenu:Title</itopstring></h1>
|
||||
</div>
|
||||
<itoptoggle name="UI:NotificationsMenu:Help" open="true">
|
||||
<div style="padding: 1em; font-size:10pt;background:#E8F3CF;margin-top: 0.25em;">
|
||||
<img src="../images/bell.png" style="margin-top: -60px; margin-right: 10px; float: right;">
|
||||
<itopstring>UI:NotificationsMenu:HelpContent</itopstring>
|
||||
</div>
|
||||
</itoptoggle>
|
||||
<p> </p>
|
||||
<itoptabs>
|
||||
<itoptab name="UI:NotificationsMenu:Triggers">
|
||||
<h2><itopstring>UI:NotificationsMenu:AvailableTriggers</itopstring></h2>
|
||||
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql">SELECT Trigger</itopblock>
|
||||
</itoptab>
|
||||
<itoptab name="UI:NotificationsMenu:Actions">
|
||||
<h2><itopstring>UI:NotificationsMenu:AvailableActions</itopstring></h2>
|
||||
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql">SELECT ActionEmail</itopblock>
|
||||
</itoptab>
|
||||
</itoptabs>
|
||||
@@ -207,16 +207,7 @@ class UIExtKeyWidget
|
||||
$sHTMLValue .= "</select>\n";
|
||||
if (($this->bSearchMode) && $bSearchMultiple)
|
||||
{
|
||||
$aOptions = array(
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect($sJSOptions);");
|
||||
$oPage->add_ready_script("$('.multiselect').multiselect({header: false, noneSelectedText: '".addslashes(Dict::S('UI:SearchValue:Any'))."', selectedList: 1, selectedText:'".addslashes(Dict::S('UI:SearchValue:NbSelected'))."'});");
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
@@ -317,9 +308,8 @@ EOF
|
||||
if ( ($oCurrObject != null) && ($this->sAttCode != ''))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oCurrObject), $this->sAttCode);
|
||||
$aArgs = array('this' => $oCurrObject);
|
||||
$aParams = array('query_params' => $aArgs);
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aArgs);
|
||||
$aParams = array('query_params' => array('this' => $oCurrObject));
|
||||
$oSet = $oAttDef->GetAllowedValuesAsObjectSet($aParams);
|
||||
$oFilter = $oSet->GetFilter();
|
||||
}
|
||||
else
|
||||
@@ -453,7 +443,7 @@ EOF
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $this->sTargetClass, $oNewObj, array(), array('formPrefix' => $this->iId, 'noRelations' => true));
|
||||
$oPage->add('</div></div></div>');
|
||||
// $oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: $(window).width()*0.8, height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("\$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$oPage->add_ready_script("$('#dcr_{$this->iId} form').removeAttr('onsubmit');");
|
||||
$oPage->add_ready_script("$('#dcr_{$this->iId} form').bind('submit.uilinksWizard', oACWidget_{$this->iId}.DoCreateObject);");
|
||||
}
|
||||
|
||||
@@ -46,24 +46,14 @@ class UILinksWidgetDirect
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$this->sLinkedClass = $oLinksetDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
{
|
||||
case LINKSET_EDITMODE_INPLACE: // The whole linkset can be edited 'in-place'
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'details'));
|
||||
break;
|
||||
|
||||
default:
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list'));
|
||||
array_unshift($aZList, 'friendlyname');
|
||||
}
|
||||
$aZList = MetaModel::FlattenZList(MetaModel::GetZListItems($this->sLinkedClass, 'list'));
|
||||
foreach($aZList as $sLinkedAttCode)
|
||||
{
|
||||
if ($sLinkedAttCode != $sExtKeyToMe)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->sLinkedClass, $sLinkedAttCode);
|
||||
|
||||
if ((!$oAttDef->IsExternalField() || ($oAttDef->GetKeyAttCode() != $sExtKeyToMe)) &&
|
||||
(!$oAttDef->IsLinkSet()) )
|
||||
if (!$oAttDef->IsExternalField() || ($oAttDef->GetKeyAttCode() != $sExtKeyToMe) )
|
||||
{
|
||||
$this->aZlist[] = $sLinkedAttCode;
|
||||
}
|
||||
@@ -98,18 +88,6 @@ class UILinksWidgetDirect
|
||||
$this->DisplayEditInPlace($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj);
|
||||
break;
|
||||
|
||||
case LINKSET_EDITMODE_ADDREMOVE: // The whole linkset can be edited 'in-place'
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$oExtKeyDef = MetaModel::GetAttributeDef($sTargetClass, $sExtKeyToMe);
|
||||
$aButtons = array('add');
|
||||
if ($oExtKeyDef->IsNullAllowed())
|
||||
{
|
||||
$aButtons = array('add', 'remove');
|
||||
}
|
||||
$this->DisplayEditInPlace($oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons);
|
||||
break;
|
||||
|
||||
case LINKSET_EDITMODE_ACTIONS:
|
||||
default:
|
||||
$this->DisplayAsBlock($oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, true /* bDisplayMenu*/);
|
||||
@@ -152,7 +130,7 @@ class UILinksWidgetDirect
|
||||
}
|
||||
}
|
||||
|
||||
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
protected function DisplayEditInPlace(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
|
||||
@@ -178,16 +156,10 @@ class UILinksWidgetDirect
|
||||
// 'modify' => 'Modify...' ,
|
||||
'creation_title' => Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'create' => Dict::Format('UI:ClickToCreateNew', MetaModel::GetName($this->sLinkedClass)),
|
||||
'remove' => Dict::S('UI:Button:Remove'),
|
||||
'add' => Dict::Format('UI:AddAnExisting_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
'selection_title' => Dict::Format('UI:SelectionOf_Class', MetaModel::GetName($this->sLinkedClass)),
|
||||
);
|
||||
$oContext = new ApplicationContext();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?'.$oContext->GetForLink();
|
||||
$sSubmitUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sJSONLabels = json_encode($aLabels);
|
||||
$sJSONButtons = json_encode($aButtons);
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, submit_to: '$sSubmitUrl', buttons: $sJSONButtons, oWizardHelper: $sWizHelper });");
|
||||
$oPage->add_ready_script("$('#{$this->sInputid}').directlinks({class_name: '$this->sClass', att_code: '$this->sAttCode', input_name:'$sInputName', labels: $sJSONLabels, sumit_to: '$sSubmitUrl' });");
|
||||
}
|
||||
|
||||
public function GetObjectCreationDlg(WebPage $oPage, $sProposedRealClass = '')
|
||||
@@ -240,103 +212,6 @@ class UILinksWidgetDirect
|
||||
$oPage->add('</div></div>');
|
||||
}
|
||||
|
||||
public function GetObjectsSelectionDlg($oPage, $oCurrentObj)
|
||||
{
|
||||
$sHtml = "<div class=\"wizContainer\" style=\"vertical-align:top;\">\n";
|
||||
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinksetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$valuesDef instanceof ValueSetObjects)
|
||||
{
|
||||
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$this->SetSearchDefaultFromContext($oCurrentObj, $oFilter);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'search', false);
|
||||
$sHtml .= $oBlock->GetDisplay($oPage, "SearchFormToAdd_{$this->sInputid}", array('open' => true));
|
||||
$sHtml .= "<form id=\"ObjectsAddForm_{$this->sInputid}\">\n";
|
||||
$sHtml .= "<div id=\"SearchResultsToAdd_{$this->sInputid}\" style=\"vertical-align:top;background: #fff;height:100%;overflow:auto;padding:0;border:0;\">\n";
|
||||
$sHtml .= "<div style=\"background: #fff; border:0; text-align:center; vertical-align:middle;\"><p>".Dict::S('UI:Message:EmptyList:UseSearchForm')."</p></div>\n";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "<input type=\"hidden\" id=\"count_{$this->sInputid}\" value=\"0\"/>";
|
||||
$sHtml .= "<button type=\"button\" class=\"cancel\">".Dict::S('UI:Button:Cancel')."</button> <button type=\"button\" class=\"ok\" disabled=\"disabled\">".Dict::S('UI:Button:Add')."</button>";
|
||||
$sHtml .= "</div>\n";
|
||||
$sHtml .= "</form>\n";
|
||||
$oPage->add($sHtml);
|
||||
//$oPage->add_ready_script("$('#SearchFormToAdd_{$this->sAttCode}{$this->sNameSuffix} form').bind('submit.uilinksWizard', oWidget{$this->sInputId}.SearchObjectsToAdd);");
|
||||
//$oPage->add_ready_script("$('#SearchFormToAdd_{$this->sAttCode}{$this->sNameSuffix}').resize(oWidget{$this->siInputId}.UpdateSizes);");
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for objects to be linked to the current object (i.e "remote" objects)
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of $this->sLinkedClass
|
||||
* @param array $aAlreadyLinked Array of indentifiers of objects which are already linke to the current object (or about to be linked)
|
||||
* @param DBObject $oCurrentObj The object currently being edited... if known...
|
||||
*/
|
||||
public function SearchObjectsToAdd(WebPage $oP, $sRemoteClass = '', $aAlreadyLinked = array(), $oCurrentObj = null)
|
||||
{
|
||||
if ($sRemoteClass == '')
|
||||
{
|
||||
$sRemoteClass = $this->sLinkedClass;
|
||||
}
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinksetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!$valuesDef instanceof ValueSetObjects)
|
||||
{
|
||||
throw new Exception('Error: only ValueSetObjects are supported for "allowed_values" in AttributeLinkedSet ('.$this->sClass.'/'.$this->sAttCode.').');
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($valuesDef->GetFilterExpression());
|
||||
}
|
||||
|
||||
if (($oCurrentObj != null) && MetaModel::IsSameFamilyBranch($sRemoteClass, $this->sClass))
|
||||
{
|
||||
// Prevent linking to self if the linked object is of the same family
|
||||
// and laready present in the database
|
||||
if (!$oCurrentObj->IsNew())
|
||||
{
|
||||
$oFilter->AddCondition('id', $oCurrentObj->GetKey(), '!=');
|
||||
}
|
||||
}
|
||||
if (count($aAlreadyLinked) > 0)
|
||||
{
|
||||
$oFilter->AddCondition('id', $aAlreadyLinked, 'NOTIN');
|
||||
}
|
||||
if ($oCurrentObj != null)
|
||||
{
|
||||
$aArgs = array_merge($oCurrentObj->ToArgs('this'), $oFilter->GetInternalParams());
|
||||
$oFilter->SetInternalParams($aArgs);
|
||||
}
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->sInputid}", array('menu' => false, 'cssCount'=> '#count_'.$this->sInputid , 'selection_mode' => true, 'table_id' => 'add_'.$this->sInputid)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
foreach($aLinkedObjectIds as $iObjectId)
|
||||
{
|
||||
$oLinkObj = MetaModel::GetObject($this->sLinkedClass, $iObjectId);
|
||||
$oP->add($this->GetObjectRow($oP, $oLinkObj, $oLinkObj->GetKey()));
|
||||
}
|
||||
}
|
||||
|
||||
public function GetObjectModificationDlg()
|
||||
{
|
||||
|
||||
@@ -354,9 +229,9 @@ class UILinksWidgetDirect
|
||||
}
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
public function GetRow($oPage, $sRealClass, $aValues, $iTempId)
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
if ($sRealClass == '')
|
||||
{
|
||||
$sRealClass = $this->sLinkedClass;
|
||||
@@ -364,60 +239,17 @@ class UILinksWidgetDirect
|
||||
$oLinkObj = new $sRealClass();
|
||||
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
|
||||
|
||||
return $this->GetObjectRow($oPage, $oLinkObj, $iTempId);
|
||||
}
|
||||
|
||||
protected function GetObjectRow($oPage, $oLinkObj, $iTempId)
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$aRow = array();
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>';
|
||||
$aRow['form::select'] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.(-$iTempId).'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[$sLinkedAttCode] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
return $oPage->GetTableRow($aRow, $aAttribs);
|
||||
return $oPage->GetTableRow($aRow, $aAttribs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
* @param DBObject $oSourceObj
|
||||
* @param DBObjectSearch $oSearch
|
||||
*/
|
||||
protected function SetSearchDefaultFromContext($oSourceObj, &$oSearch)
|
||||
public function UpdateFromArray($oObj, $aData)
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sSrcClass = get_class($oSourceObj);
|
||||
$sDestClass = $oSearch->GetClass();
|
||||
foreach($oAppContext->GetNames() as $key)
|
||||
{
|
||||
// Find the value of the object corresponding to each 'context' parameter
|
||||
$aCallSpec = array($sSrcClass, 'MapContextParam');
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sSrcClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sSrcClass, $sAttCode);
|
||||
$defaultValue = $oSourceObj->Get($sAttCode);
|
||||
|
||||
// Find the attcode for the same 'context' parameter in the destination class
|
||||
// and sets its value as the default value for the search condition
|
||||
$aCallSpec = array($sDestClass, 'MapContextParam');
|
||||
$sAttCode = '';
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sDestClass, $sAttCode) && !empty($defaultValue))
|
||||
{
|
||||
$oSearch->AddCondition($sAttCode, $defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ EOF
|
||||
*/
|
||||
protected function DisplayFormTable(WebPage $oP, $aConfig, $aData)
|
||||
{
|
||||
$sHtml = "<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\">";
|
||||
$sHtml = '';
|
||||
$sHtml .= "<table class=\"listResults\">\n";
|
||||
// Header
|
||||
$sHtml .= "<thead>\n";
|
||||
@@ -259,11 +259,11 @@ EOF
|
||||
$sEmptyRowStyle = 'style="display:none;"';
|
||||
}
|
||||
|
||||
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."<input type=\"hidden\" name=\"attr_{$this->m_sAttCode}{$this->m_sNameSuffix}\" value=\"\"></td></td>";
|
||||
foreach($aData as $iRowId => $aRow)
|
||||
{
|
||||
$sHtml .= $this->DisplayFormRow($oP, $aConfig, $aRow, $iRowId);
|
||||
}
|
||||
$sHtml .= "<tr $sEmptyRowStyle id=\"{$this->m_sAttCode}{$this->m_sNameSuffix}_empty_row\"><td colspan=\"".count($aConfig)."\" style=\"text-align:center;\">".Dict::S('UI:Message:EmptyList:UseAdd')."</td></tr>";
|
||||
$sHtml .= "</tbody>\n";
|
||||
|
||||
// Footer
|
||||
|
||||
@@ -52,10 +52,8 @@ class UIPasswordWidget
|
||||
{
|
||||
$sCode = $this->sAttCode.$this->sNameSuffix;
|
||||
$iWidgetIndex = self::$iWidgetIndex;
|
||||
|
||||
$aPasswordValues = utils::ReadPostedParam("attr_{$sCode}", null, 'raw_data');
|
||||
$sPasswordValue = $aPasswordValues ? $aPasswordValues['value'] : '*****';
|
||||
$sConfirmPasswordValue = $aPasswordValues ? $aPasswordValues['confirm'] : '*****';
|
||||
$sPasswordValue = utils::ReadPostedParam("attr_{$sCode}[value]", '*****', 'raw_data');
|
||||
$sConfirmPasswordValue = utils::ReadPostedParam("attr_{$sCode}[confirm]", '*****', 'raw_data');
|
||||
$sChangedValue = (($sPasswordValue != '*****') || ($sConfirmPasswordValue != '*****')) ? 1 : 0;
|
||||
$sHtmlValue = '';
|
||||
$sHtmlValue = '<input type="password" maxlength="255" name="attr_'.$sCode.'[value]" id="'.$this->iId.'" value="'.htmlentities($sPasswordValue, ENT_QUOTES, 'UTF-8').'"/> <span class="form_validation" id="v_'.$this->iId.'"></span><br/>';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -766,76 +766,33 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge standard menu items with plugin provided menus items
|
||||
* Get the "Back" button to go out of the current environment
|
||||
*/
|
||||
public static function GetPopupMenuItems($oPage, $iMenuId, $param, &$aActions, $sTableId = null, $sDataTableId = null)
|
||||
public static function GetEnvironmentBackButton()
|
||||
{
|
||||
// 1st - add standard built-in menu items
|
||||
//
|
||||
switch($iMenuId)
|
||||
if (isset($_SESSION['itop_return_env']))
|
||||
{
|
||||
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
|
||||
// $param is a DBObjectSet
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sDataTableId = is_null($sDataTableId) ? '' : $sDataTableId;
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($param->GetFilter()->GetClass());
|
||||
$sOQL = addslashes($param->GetFilter()->ToOQL(true));
|
||||
$sFilter = urlencode($param->GetFilter()->serialize());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
// Static menus: Email this page, CSV Export & Add to Dashboard
|
||||
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?body=".urlencode($sUrl).' '), // Add an extra space to make it work in Outlook
|
||||
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), $sUrl."&format=csv"),
|
||||
new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL')"),
|
||||
new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')"),
|
||||
);
|
||||
break;
|
||||
|
||||
case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
|
||||
// $param is a DBObject
|
||||
$oObj = $param;
|
||||
$oFilter = DBobjectSearch::FromOQL("SELECT ".get_class($oObj)." WHERE id=".$oObj->GetKey());
|
||||
$sFilter = $oFilter->serialize();
|
||||
$sUrl = ApplicationContext::MakeObjectUrl(get_class($oObj), $oObj->GetKey());
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
// Static menus: Email this page & CSV Export
|
||||
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl).' '), // Add an extra space to make it work in Outlook
|
||||
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv&{$sContext}"),
|
||||
);
|
||||
break;
|
||||
|
||||
case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
|
||||
// $param is a Dashboard
|
||||
$oAppContext = new ApplicationContext();
|
||||
$aParams = $oAppContext->GetAsHash();
|
||||
$sMenuId = ApplicationMenu::GetActiveNodeId();
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sMenuId),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sMenuId', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn' })"),
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
// Unknown type of menu, do nothing
|
||||
$aResult = array();
|
||||
if (isset($_SESSION['itop_return_url']))
|
||||
{
|
||||
$sReturnUrl = $_SESSION['itop_return_url'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sReturnUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?switch_env='.$_SESSION['itop_return_env'];
|
||||
}
|
||||
return ' <button onclick="window;location.href=\''.addslashes($sReturnUrl).'\'">'.Dict::S('UI:Button:Back').'</button>';
|
||||
}
|
||||
foreach($aResult as $oMenuItem)
|
||||
else
|
||||
{
|
||||
$aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem();
|
||||
return '';
|
||||
}
|
||||
|
||||
// Invoke the plugins
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "Back" button to go out of the current environment
|
||||
*/
|
||||
public static function GetPopupMenuItems($oPage, $iMenuId, $param, &$aActions)
|
||||
{
|
||||
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
|
||||
{
|
||||
if (is_object($param) && !($param instanceof DBObject))
|
||||
@@ -882,35 +839,6 @@ class utils
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to a page that will execute the requested module page
|
||||
*
|
||||
* To be compatible with this mechanism, the called page must include approot
|
||||
* with an absolute path OR not include it at all (losing the direct access to the page)
|
||||
* if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
|
||||
* require_once(__DIR__.'/../../approot.inc.php');
|
||||
*
|
||||
* @return string ...
|
||||
*/
|
||||
static public function GetAbsoluteUrlModulePage($sModule, $sPage, $aArguments = array(), $sEnvironment = null)
|
||||
{
|
||||
$sEnvironment = is_null($sEnvironment) ? self::GetCurrentEnvironment() : $sEnvironment;
|
||||
$aArgs = array();
|
||||
$aArgs[] = 'exec_module='.$sModule;
|
||||
$aArgs[] = 'exec_page='.$sPage;
|
||||
$aArgs[] = 'exec_env='.$sEnvironment;
|
||||
foreach($aArguments as $sName => $sValue)
|
||||
{
|
||||
if (($sName == 'exec_module')||($sName == 'exec_page')||($sName == 'exec_env'))
|
||||
{
|
||||
throw new Exception("Module page: $sName is a reserved page argument name");
|
||||
}
|
||||
$aArgs[] = $sName.'='.urlencode($sValue);
|
||||
}
|
||||
$sArgs = implode('&', $aArgs);
|
||||
return self::GetAbsoluteUrlAppRoot().'pages/exec.php?'.$sArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name unique amongst the given list
|
||||
* @param string $sProposed The default value
|
||||
@@ -941,129 +869,6 @@ class utils
|
||||
static public function GetSafeId($sId)
|
||||
{
|
||||
return str_replace(array(':', '[', ']', '+', '-'), '_', $sId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to execute an HTTP POST request
|
||||
* Source: http://netevil.org/blog/2006/nov/http-post-from-php-without-curl
|
||||
* originaly named after do_post_request
|
||||
* Does not require cUrl but requires openssl for performing https POSTs.
|
||||
*
|
||||
* @param string $sUrl The URL to POST the data to
|
||||
* @param hash $aData The data to POST as an array('param_name' => value)
|
||||
* @param string $sOptionnalHeaders Additional HTTP headers as a string with newlines between headers
|
||||
* @param hash $aResponseHeaders An array to be filled with reponse headers: WARNING: the actual content of the array depends on the library used: cURL or fopen, test with both !! See: http://fr.php.net/manual/en/function.curl-getinfo.php
|
||||
* @return string The result of the POST request
|
||||
* @throws Exception
|
||||
*/
|
||||
static public function DoPostRequest($sUrl, $aData, $sOptionnalHeaders = null, &$aResponseHeaders = null)
|
||||
{
|
||||
// $sOptionnalHeaders is a string containing additional HTTP headers that you would like to send in your request.
|
||||
|
||||
if (function_exists('curl_init'))
|
||||
{
|
||||
// If cURL is available, let's use it, since it provides a greater control over the various HTTP/SSL options
|
||||
// For instance fopen does not allow to work around the bug: http://stackoverflow.com/questions/18191672/php-curl-ssl-routinesssl23-get-server-helloreason1112
|
||||
// by setting the SSLVERSION to 3 as done below.
|
||||
$aHeaders = explode("\n", $sOptionnalHeaders);
|
||||
$aHTTPHeaders = array();
|
||||
foreach($aHeaders as $sHeaderString)
|
||||
{
|
||||
if(preg_match('/^([^:]): (.+)$/', $sHeaderString, $aMatches))
|
||||
{
|
||||
$aHTTPHeaders[$aMatches[1]] = $aMatches[2];
|
||||
}
|
||||
}
|
||||
$aOptions = array(
|
||||
CURLOPT_RETURNTRANSFER => true, // return the content of the request
|
||||
CURLOPT_HEADER => false, // don't return the headers in the output
|
||||
CURLOPT_FOLLOWLOCATION => true, // follow redirects
|
||||
CURLOPT_ENCODING => "", // handle all encodings
|
||||
CURLOPT_USERAGENT => "spider", // who am i
|
||||
CURLOPT_AUTOREFERER => true, // set referer on redirect
|
||||
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
|
||||
CURLOPT_TIMEOUT => 120, // timeout on response
|
||||
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
|
||||
CURLOPT_SSL_VERIFYPEER => false, // Disabled SSL Cert checks
|
||||
CURLOPT_SSLVERSION => 3, // MUST to prevent a strange SSL error: http://stackoverflow.com/questions/18191672/php-curl-ssl-routinesssl23-get-server-helloreason1112
|
||||
CURLOPT_POST => count($aData),
|
||||
CURLOPT_POSTFIELDS => http_build_query($aData),
|
||||
CURLOPT_HTTPHEADER => $aHTTPHeaders,
|
||||
);
|
||||
|
||||
$ch = curl_init($sUrl);
|
||||
curl_setopt_array($ch, $aOptions);
|
||||
$response = curl_exec($ch);
|
||||
$iErr = curl_errno($ch);
|
||||
$sErrMsg = curl_error( $ch );
|
||||
$aHeaders = curl_getinfo( $ch );
|
||||
if ($iErr !== 0)
|
||||
{
|
||||
throw new Exception("Problem opening URL: $sUrl, $sErrMsg");
|
||||
}
|
||||
if (is_array($aResponseHeaders))
|
||||
{
|
||||
$aHeaders = curl_getinfo($ch);
|
||||
foreach($aHeaders as $sCode => $sValue)
|
||||
{
|
||||
$sName = str_replace(' ' , '-', ucwords(str_replace('_', ' ', $sCode))); // Transform "content_type" into "Content-Type"
|
||||
$aResponseHeaders[$sName] = $sValue;
|
||||
}
|
||||
}
|
||||
curl_close( $ch );
|
||||
}
|
||||
else
|
||||
{
|
||||
// cURL is not available let's try with streams and fopen...
|
||||
|
||||
$sData = http_build_query($aData);
|
||||
$aParams = array('http' => array(
|
||||
'method' => 'POST',
|
||||
'content' => $sData,
|
||||
'header'=> "Content-type: application/x-www-form-urlencoded\r\nContent-Length: ".strlen($sData)."\r\n",
|
||||
));
|
||||
if ($sOptionnalHeaders !== null)
|
||||
{
|
||||
$aParams['http']['header'] .= $sOptionnalHeaders;
|
||||
}
|
||||
$ctx = stream_context_create($aParams);
|
||||
|
||||
$fp = @fopen($sUrl, 'rb', false, $ctx);
|
||||
if (!$fp)
|
||||
{
|
||||
global $php_errormsg;
|
||||
if (isset($php_errormsg))
|
||||
{
|
||||
throw new Exception("Wrong URL: $sUrl, $php_errormsg");
|
||||
}
|
||||
elseif ((strtolower(substr($sUrl, 0, 5)) == 'https') && !extension_loaded('openssl'))
|
||||
{
|
||||
throw new Exception("Cannot connect to $sUrl: missing module 'openssl'");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Wrong URL: $sUrl");
|
||||
}
|
||||
}
|
||||
$response = @stream_get_contents($fp);
|
||||
if ($response === false)
|
||||
{
|
||||
throw new Exception("Problem reading data from $sUrl, $php_errormsg");
|
||||
}
|
||||
if (is_array($aResponseHeaders))
|
||||
{
|
||||
$aMeta = stream_get_meta_data($fp);
|
||||
$aHeaders = $aMeta['wrapper_data'];
|
||||
foreach($aHeaders as $sHeaderString)
|
||||
{
|
||||
if(preg_match('/^([^:]+): (.+)$/', $sHeaderString, $aMatches))
|
||||
{
|
||||
$aResponseHeaders[$aMatches[1]] = trim($aMatches[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -497,16 +497,13 @@ class WebPage implements Page
|
||||
/**
|
||||
* Build a series of hidden field[s] from an array
|
||||
*/
|
||||
// By Rom - je verrais bien une serie d'outils pour gerer des parametres que l'on retransmet entre pages d'un wizard...
|
||||
// ptet deriver webpage en webwizard
|
||||
public function add_input_hidden($sLabel, $aData)
|
||||
{
|
||||
foreach($aData as $sKey => $sValue)
|
||||
foreach($aData as $sKey=>$sValue)
|
||||
{
|
||||
// Note: protection added to protect against the Notice 'array to string conversion' that appeared with PHP 5.4
|
||||
// (this function seems unused though!)
|
||||
if (is_scalar($sValue))
|
||||
{
|
||||
$this->add("<input type=\"hidden\" name=\"".$sLabel."[$sKey]\" value=\"$sValue\">");
|
||||
}
|
||||
$this->add("<input type=\"hidden\" name=\"".$sLabel."[$sKey]\" value=\"$sValue\">");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,7 @@ class MyHelpers
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_callstack($iLevelsToIgnore = 0, $aCallStack = null)
|
||||
public static function get_callstack_html($iLevelsToIgnore = 0, $aCallStack = null)
|
||||
{
|
||||
if ($aCallStack == null) $aCallStack = debug_backtrace();
|
||||
|
||||
@@ -231,16 +231,6 @@ class MyHelpers
|
||||
{
|
||||
$sLine = empty($aCallInfo['line']) ? "" : $aCallInfo['line'];
|
||||
$sFile = empty($aCallInfo['file']) ? "" : $aCallInfo['file'];
|
||||
if ($sFile != '')
|
||||
{
|
||||
$sFile = str_replace('\\', '/', $sFile);
|
||||
$sAppRoot = str_replace('\\', '/', APPROOT);
|
||||
$iPos = strpos($sFile, $sAppRoot);
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$sFile = substr($sFile, strlen($sAppRoot));
|
||||
}
|
||||
}
|
||||
$sClass = empty($aCallInfo['class']) ? "" : $aCallInfo['class'];
|
||||
$sType = empty($aCallInfo['type']) ? "" : $aCallInfo['type'];
|
||||
$sFunction = empty($aCallInfo['function']) ? "" : $aCallInfo['function'];
|
||||
@@ -269,11 +259,11 @@ class MyHelpers
|
||||
$args .= $a;
|
||||
break;
|
||||
case 'string':
|
||||
$a = Str::pure2html(self::beautifulstr($a, 64, true, false));
|
||||
$a = Str::pure2html(self::beautifulstr($a, 1024, true, true));
|
||||
$args .= "\"$a\"";
|
||||
break;
|
||||
case 'array':
|
||||
$args .= 'array('.count($a).')';
|
||||
$args .= 'Array('.count($a).')';
|
||||
break;
|
||||
case 'object':
|
||||
$args .= 'Object('.get_class($a).')';
|
||||
@@ -282,25 +272,19 @@ class MyHelpers
|
||||
$args .= 'Resource('.strstr($a, '#').')';
|
||||
break;
|
||||
case 'boolean':
|
||||
$args .= $a ? 'true' : 'false';
|
||||
$args .= $a ? 'True' : 'False';
|
||||
break;
|
||||
case 'NULL':
|
||||
$args .= 'null';
|
||||
$args .= 'Null';
|
||||
break;
|
||||
default:
|
||||
$args .= 'Unknown';
|
||||
}
|
||||
}
|
||||
$sFunctionInfo = "$sClass$sType$sFunction($args)";
|
||||
$sFunctionInfo = "$sClass $sType $sFunction($args)";
|
||||
}
|
||||
$aDigestCallStack[] = array('File'=>$sFile, 'Line'=>$sLine, 'Function'=>$sFunctionInfo);
|
||||
}
|
||||
return $aDigestCallStack;
|
||||
}
|
||||
|
||||
public static function get_callstack_html($iLevelsToIgnore = 0, $aCallStack = null)
|
||||
{
|
||||
$aDigestCallStack = self::get_callstack($iLevelsToIgnore, $aCallStack);
|
||||
return self::make_table_from_assoc_array($aDigestCallStack);
|
||||
}
|
||||
|
||||
@@ -309,17 +293,6 @@ class MyHelpers
|
||||
return self::get_callstack_html($iLevelsToIgnore, $aCallStack);
|
||||
}
|
||||
|
||||
public static function get_callstack_text($iLevelsToIgnore = 0, $aCallStack = null)
|
||||
{
|
||||
$aDigestCallStack = self::get_callstack($iLevelsToIgnore, $aCallStack);
|
||||
$aRes = array();
|
||||
foreach ($aDigestCallStack as $aCall)
|
||||
{
|
||||
$aRes[] = $aCall['File'].' at '.$aCall['Line'].', '.$aCall['Function'];
|
||||
}
|
||||
return implode("\n", $aRes);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Source: New
|
||||
// Last modif: 2004/12/20 RQU
|
||||
|
||||
@@ -34,65 +34,18 @@ class ExecAsyncTask implements iBackgroundProcess
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$sNow = date('Y-m-d H:i:s');
|
||||
$sOQL = "SELECT AsyncTask WHERE ISNULL(started) AND (ISNULL(planned) OR (planned < '$sNow'))";
|
||||
$sOQL = "SELECT AsyncTask WHERE ISNULL(started) AND (ISNULL(planned) OR (planned < NOW()))";
|
||||
$oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL), array('created' => true) /* order by*/, array());
|
||||
$iProcessed = 0;
|
||||
while ((time() < $iTimeLimit) && ($oTask = $oSet->Fetch()))
|
||||
{
|
||||
try
|
||||
{
|
||||
$oTask->Set('started', time());
|
||||
$oTask->DBUpdate();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Corrupted task !! (for example: "Failed to reload object")
|
||||
IssueLog::Error('Failed to process async task #'.$oTask->GetKey().' - reason: '.$e->getMessage().' - fatal error, deleting the task.');
|
||||
if ($oTask->Get('event_id') != 0)
|
||||
{
|
||||
$oEventLog = MetaModel::GetObject('Event', $oTask->Get('event_id'));
|
||||
$oEventLog->Set('message', 'Failed, corrupted data: '.$e->getMessage());
|
||||
$oEventLog->DBUpdate();
|
||||
}
|
||||
$oTask->DBDelete();
|
||||
continue; // end of processing for this task
|
||||
}
|
||||
$oTask->Set('started', time());
|
||||
$oTask->DBUpdate();
|
||||
|
||||
try
|
||||
{
|
||||
$oTask->Process();
|
||||
$iProcessed++;
|
||||
$oTask->Process();
|
||||
$iProcessed++;
|
||||
|
||||
$oTask->DBDelete();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$iRemaining = $oTask->Get('remaining_retries');
|
||||
if ($iRemaining > 0)
|
||||
{
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
|
||||
if (is_array($aRetries) && array_key_exists(get_class($oTask), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($oTask)];
|
||||
$iRetryDelay = $aConfig['retry_delay'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$iRetryDelay = 600;
|
||||
}
|
||||
IssueLog::Info('Failed to process async task #'.$oTask->GetKey().' - reason: '.$e->getMessage().' - remaining retries: '.$iRemaining.' - next retry in '.$iRetryDelay.'s');
|
||||
|
||||
$oTask->Set('remaining_retries', $iRemaining - 1);
|
||||
$oTask->Set('started', null);
|
||||
$oTask->Set('planned', time() + $iRetryDelay);
|
||||
$oTask->DBUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Error('Failed to process async task #'.$oTask->GetKey().' - reason: '.$e->getMessage());
|
||||
}
|
||||
}
|
||||
$oTask->DBDelete();
|
||||
}
|
||||
if ($iProcessed == $oSet->Count())
|
||||
{
|
||||
@@ -135,8 +88,6 @@ abstract class AsyncTask extends DBObject
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("planned", array("allowed_values"=>null, "sql"=>"planned", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("event_id", array("targetclass"=>"Event", "jointype"=> "", "allowed_values"=>null, "sql"=>"event_id", "is_null_allowed"=>true, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("remaining_retries", array("allowed_values"=>null, "sql"=>"remaining_retries", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
// MetaModel::Init_SetZListItems('details', array()); // Attributes to be displayed for the complete details
|
||||
// MetaModel::Init_SetZListItems('list', array()); // Attributes to be displayed for a list
|
||||
@@ -148,14 +99,6 @@ abstract class AsyncTask extends DBObject
|
||||
protected function OnInsert()
|
||||
{
|
||||
$this->Set('created', time());
|
||||
|
||||
$aRetries = MetaModel::GetConfig()->Get('async_task_retries', array());
|
||||
if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries))
|
||||
{
|
||||
$aConfig = $aRetries[get_class($this)];
|
||||
$iRetries = $aConfig['max_retries'];
|
||||
$this->Set('remaining_retries', $iRetries);
|
||||
}
|
||||
}
|
||||
|
||||
public function Process()
|
||||
@@ -197,7 +140,7 @@ class AsyncSendEmail extends AsyncTask
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("version", array("allowed_values"=>null, "sql"=>"version", "default_value"=>Email::ORIGINAL_FORMAT, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -81,8 +81,6 @@ define('DEL_MOVEUP', 3);
|
||||
*
|
||||
* @package iTopORM
|
||||
*/
|
||||
define('ATTRIBUTE_TRACKING_NONE', 0); // Do not track changes of the attribute
|
||||
define('ATTRIBUTE_TRACKING_ALL', 3); // Do track all changes of the attribute
|
||||
define('LINKSET_TRACKING_NONE', 0); // Do not track changes in the link set
|
||||
define('LINKSET_TRACKING_LIST', 1); // Do track added/removed items
|
||||
define('LINKSET_TRACKING_DETAILS', 2); // Do track modified items
|
||||
@@ -92,7 +90,6 @@ define('LINKSET_EDITMODE_NONE', 0); // The linkset cannot be edited at all from
|
||||
define('LINKSET_EDITMODE_ADDONLY', 1); // The only possible action is to open a new window to create a new object
|
||||
define('LINKSET_EDITMODE_ACTIONS', 2); // Show the usual 'Actions' popup menu
|
||||
define('LINKSET_EDITMODE_INPLACE', 3); // The "linked" objects can be created/modified/deleted in place
|
||||
define('LINKSET_EDITMODE_ADDREMOVE', 4); // The "linked" objects can be added/removed in place
|
||||
|
||||
|
||||
/**
|
||||
@@ -211,7 +208,6 @@ abstract class AttributeDefinition
|
||||
public function IsExternalField() {return false;}
|
||||
public function IsWritable() {return false;}
|
||||
public function LoadInObject() {return true;}
|
||||
public function AlwaysLoadInTables() {return $this->GetOptional('always_load_in_tables', false);}
|
||||
public function GetValue($oHostObject){return null;} // must return the value if LoadInObject returns false
|
||||
public function IsNullAllowed() {return true;}
|
||||
public function GetCode() {return $this->m_sCode;}
|
||||
@@ -345,12 +341,6 @@ abstract class AttributeDefinition
|
||||
return $this->GetDescription();
|
||||
}
|
||||
}
|
||||
|
||||
public function GetTrackingLevel()
|
||||
{
|
||||
return $this->GetOptional('tracking_level', ATTRIBUTE_TRACKING_ALL);
|
||||
}
|
||||
|
||||
public function GetValuesDef() {return null;}
|
||||
public function GetPrerequisiteAttributes() {return array();}
|
||||
|
||||
@@ -1915,12 +1905,7 @@ class AttributeCaseLog extends AttributeLongText
|
||||
// Facilitate things: allow the user to Set the value from a string
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if ($proposedValue instanceof ormCaseLog)
|
||||
{
|
||||
// Passthrough
|
||||
$ret = $proposedValue;
|
||||
}
|
||||
else
|
||||
if (!($proposedValue instanceof ormCaseLog))
|
||||
{
|
||||
// Append the new value if an instance of the object is supplied
|
||||
//
|
||||
@@ -1942,21 +1927,13 @@ class AttributeCaseLog extends AttributeLongText
|
||||
{
|
||||
$oCaseLog = new ormCaseLog();
|
||||
}
|
||||
|
||||
if ($proposedValue instanceof stdClass)
|
||||
if (strlen($proposedValue) > 0)
|
||||
{
|
||||
$oCaseLog->AddLogEntryFromJSON($proposedValue);
|
||||
$oCaseLog->AddLogEntry(parent::MakeRealValue($proposedValue, $oHostObj));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen($proposedValue) > 0)
|
||||
{
|
||||
$oCaseLog->AddLogEntry(parent::MakeRealValue($proposedValue, $oHostObj));
|
||||
}
|
||||
}
|
||||
$ret = $oCaseLog;
|
||||
return $oCaseLog;
|
||||
}
|
||||
return $ret;
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
public function GetSQLExpressions($sPrefix = '')
|
||||
@@ -2074,45 +2051,6 @@ class AttributeCaseLog extends AttributeLongText
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a value that will be JSON encoded
|
||||
* The operation is the opposite to FromJSONToValue
|
||||
*/
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
return $value->GetForJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to form a value, given JSON decoded data
|
||||
* The operation is the opposite to GetForJSON
|
||||
*/
|
||||
public function FromJSONToValue($json)
|
||||
{
|
||||
if (is_string($json))
|
||||
{
|
||||
// Will be correctly handled in MakeRealValue
|
||||
$ret = $json;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($json->add_item))
|
||||
{
|
||||
// Will be correctly handled in MakeRealValue
|
||||
$ret = $json->add_item;
|
||||
if (!isset($ret->message))
|
||||
{
|
||||
throw new Exception("Missing mandatory entry: 'message'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$ret = ormCaseLog::FromJSON($json);
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2139,7 +2077,8 @@ class AttributeEmailAddress extends AttributeString
|
||||
{
|
||||
public function GetValidationPattern()
|
||||
{
|
||||
return $this->GetOptional('validation_pattern', '^'.utils::GetConfig()->Get('email_validation_pattern').'$');
|
||||
// return "^([0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*@([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,9})$";
|
||||
return "^[a-zA-Z0-9._&-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$";
|
||||
}
|
||||
|
||||
public function GetAsHTML($sValue, $oHostObject = null, $bLocalize = true)
|
||||
@@ -2398,15 +2337,6 @@ class AttributeEnum extends AttributeString
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get a value that will be JSON encoded
|
||||
* The operation is the opposite to FromJSONToValue
|
||||
*/
|
||||
public function GetForJSON($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetAllowedValues($aArgs = array(), $sContains = '')
|
||||
{
|
||||
$aRawValues = parent::GetAllowedValues($aArgs, $sContains);
|
||||
@@ -2630,7 +2560,7 @@ class AttributeDateTime extends AttributeDBField
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$sValue);
|
||||
return $sTextQualifier.$sEscaped.$sTextQualifier;
|
||||
return '"'.$sEscaped.'"';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2903,15 +2833,7 @@ class AttributeExternalKey extends AttributeDBFieldVoid
|
||||
|
||||
|
||||
public function GetDefaultValue() {return 0;}
|
||||
public function IsNullAllowed()
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('disable_mandatory_ext_keys'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return $this->Get("is_null_allowed");
|
||||
}
|
||||
|
||||
public function IsNullAllowed() {return $this->Get("is_null_allowed");}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
@@ -3438,26 +3360,26 @@ class AttributeBlob extends AttributeDefinition
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!array_key_exists($sPrefix, $aCols))
|
||||
if (!isset($aCols[$sPrefix]))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
|
||||
}
|
||||
$sMimeType = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : '';
|
||||
$sMimeType = $aCols[$sPrefix];
|
||||
|
||||
if (!array_key_exists($sPrefix.'_data', $aCols))
|
||||
if (!isset($aCols[$sPrefix.'_data']))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '".$sPrefix."_data' from {$sAvailable}");
|
||||
}
|
||||
$data = isset($aCols[$sPrefix.'_data']) ? $aCols[$sPrefix.'_data'] : null;
|
||||
$data = $aCols[$sPrefix.'_data'];
|
||||
|
||||
if (!array_key_exists($sPrefix.'_filename', $aCols))
|
||||
if (!isset($aCols[$sPrefix.'_filename']))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '".$sPrefix."_filename' from {$sAvailable}");
|
||||
}
|
||||
$sFileName = isset($aCols[$sPrefix.'_filename']) ? $aCols[$sPrefix.'_filename'] : '';
|
||||
$sFileName = $aCols[$sPrefix.'_filename'];
|
||||
|
||||
$value = new ormDocument($data, $sMimeType, $sFileName);
|
||||
return $value;
|
||||
@@ -3903,12 +3825,6 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
throw new CoreException("Unknown item code '$sItemCode' for attribute ".$this->GetHostClass().'::'.$this->GetCode());
|
||||
}
|
||||
|
||||
protected function GetBooleanLabel($bValue)
|
||||
{
|
||||
$sDictKey = $bValue ? 'yes' : 'no';
|
||||
return Dict::S('BooleanLabel:'.$sDictKey, 'def:'.$sDictKey);
|
||||
}
|
||||
|
||||
public function GetSubItemAsHTMLForHistory($sItemCode, $sOldValue, $sNewValue, $sLabel)
|
||||
{
|
||||
switch($sItemCode)
|
||||
@@ -3939,12 +3855,12 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
$sHtmlNew = (int)$sNewValue ? date(self::GetDateFormat(true /*full*/), (int)$sNewValue) : null;
|
||||
break;
|
||||
case 'passed':
|
||||
$sHtmlOld = $this->GetBooleanLabel((int)$sOldValue);
|
||||
$sHtmlNew = $this->GetBooleanLabel((int)$sNewValue);
|
||||
$sHtmlOld = (int)$sOldValue ? '1' : '0';
|
||||
$sHtmlNew = (int)$sNewValue ? '1' : '0';
|
||||
break;
|
||||
case 'triggered':
|
||||
$sHtmlOld = $this->GetBooleanLabel((int)$sOldValue);
|
||||
$sHtmlNew = $this->GetBooleanLabel((int)$sNewValue);
|
||||
$sHtmlOld = (int)$sOldValue ? '1' : '0';
|
||||
$sHtmlNew = (int)$sNewValue ? '1' : '0';
|
||||
break;
|
||||
case 'overrun':
|
||||
$sHtmlOld = (int)$sOldValue > 0 ? AttributeDuration::FormatDuration((int)$sOldValue) : '';
|
||||
@@ -4013,8 +3929,10 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
}
|
||||
break;
|
||||
case 'passed':
|
||||
$sHtml = $value ? '1' : '0';
|
||||
break;
|
||||
case 'triggered':
|
||||
$sHtml = $this->GetBooleanLabel($value);
|
||||
$sHtml = $value ? '1' : '0';
|
||||
break;
|
||||
case 'overrun':
|
||||
$sHtml = Str::pure2html(AttributeDuration::FormatDuration($value));
|
||||
@@ -4028,141 +3946,12 @@ class AttributeStopWatch extends AttributeDefinition
|
||||
|
||||
public function GetSubItemAsCSV($sItemCode, $value, $sSeparator = ',', $sTextQualifier = '"')
|
||||
{
|
||||
$sFrom = array("\r\n", $sTextQualifier);
|
||||
$sTo = array("\n", $sTextQualifier.$sTextQualifier);
|
||||
$sEscaped = str_replace($sFrom, $sTo, (string)$value);
|
||||
$sRet = $sTextQualifier.$sEscaped.$sTextQualifier;
|
||||
|
||||
switch($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
case 'started':
|
||||
case 'laststart':
|
||||
case 'stopped':
|
||||
break;
|
||||
|
||||
default:
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
break;
|
||||
|
||||
case 'passed':
|
||||
case 'triggered':
|
||||
$sRet = $sTextQualifier.$this->GetBooleanLabel($value).$sTextQualifier;
|
||||
break;
|
||||
|
||||
case 'overrun':
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sRet;
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function GetSubItemAsXML($sItemCode, $value)
|
||||
{
|
||||
$sRet = Str::pure2xml((string)$value);
|
||||
|
||||
switch($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
case 'started':
|
||||
case 'laststart':
|
||||
case 'stopped':
|
||||
break;
|
||||
|
||||
default:
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
break;
|
||||
|
||||
case 'passed':
|
||||
case 'triggered':
|
||||
$sRet = $this->GetBooleanLabel($value);
|
||||
break;
|
||||
|
||||
case 'overrun':
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implemented for the HTML spreadsheet format!
|
||||
*/
|
||||
public function GetSubItemAsEditValue($sItemCode, $value)
|
||||
{
|
||||
$sRet = $value;
|
||||
|
||||
switch($sItemCode)
|
||||
{
|
||||
case 'timespent':
|
||||
break;
|
||||
|
||||
case 'started':
|
||||
case 'laststart':
|
||||
case 'stopped':
|
||||
if (is_null($value))
|
||||
{
|
||||
$sRet = ''; // Undefined
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = date(self::GetDateFormat(), $value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
|
||||
{
|
||||
$sThPrefix = $iThreshold.'_';
|
||||
if (substr($sItemCode, 0, strlen($sThPrefix)) == $sThPrefix)
|
||||
{
|
||||
// The current threshold is concerned
|
||||
$sThresholdCode = substr($sItemCode, strlen($sThPrefix));
|
||||
switch($sThresholdCode)
|
||||
{
|
||||
case 'deadline':
|
||||
if ($value)
|
||||
{
|
||||
$sRet = date(self::GetDateFormat(true /*full*/), $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = '';
|
||||
}
|
||||
break;
|
||||
case 'passed':
|
||||
case 'triggered':
|
||||
$sRet = $this->GetBooleanLabel($value);
|
||||
break;
|
||||
case 'overrun':
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sRet;
|
||||
return Str::pure2xml((string)$value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4272,7 +4061,7 @@ class AttributeSubItem extends AttributeDefinition
|
||||
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemAsCSV($this->Get('item_code'), $value, $sSeparator, $sTextQualifier);
|
||||
$res = $oParent->GetSubItemAsCSV($this->Get('item_code'), $value, $sSeparator = ',', $sTextQualifier = '"');
|
||||
return $res;
|
||||
}
|
||||
|
||||
@@ -4291,16 +4080,6 @@ class AttributeSubItem extends AttributeDefinition
|
||||
$sValue = $oParent->GetSubItemAsHTMLForHistory($this->Get('item_code'), $sOldValue, $sNewValue, $sLabel);
|
||||
return $sValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* As of now, this function must be implemented to have the value in spreadsheet format
|
||||
*/
|
||||
public function GetEditValue($value, $oHostObj = null)
|
||||
{
|
||||
$oParent = $this->GetTargetAttDef();
|
||||
$res = $oParent->GetSubItemAsEditValue($this->Get('item_code'), $value);
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4348,19 +4127,19 @@ class AttributeOneWayPassword extends AttributeDefinition
|
||||
|
||||
public function FromSQLToValue($aCols, $sPrefix = '')
|
||||
{
|
||||
if (!array_key_exists($sPrefix, $aCols))
|
||||
if (!isset($aCols[$sPrefix]))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
|
||||
}
|
||||
$hashed = isset($aCols[$sPrefix]) ? $aCols[$sPrefix] : '';
|
||||
$hashed = $aCols[$sPrefix];
|
||||
|
||||
if (!array_key_exists($sPrefix.'_salt', $aCols))
|
||||
if (!isset($aCols[$sPrefix.'_salt']))
|
||||
{
|
||||
$sAvailable = implode(', ', array_keys($aCols));
|
||||
throw new MissingColumnException("Missing column '".$sPrefix."_salt' from {$sAvailable}");
|
||||
}
|
||||
$sSalt = isset($aCols[$sPrefix.'_salt']) ? $aCols[$sPrefix.'_salt'] : '';
|
||||
$sSalt = $aCols[$sPrefix.'_salt'];
|
||||
|
||||
$value = new ormPassword($hashed, $sSalt);
|
||||
return $value;
|
||||
@@ -4727,7 +4506,7 @@ class AttributeComputedFieldVoid extends AttributeDefinition
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
{
|
||||
return array("="=>"equals", "!="=>"differs from");
|
||||
return array();
|
||||
}
|
||||
public function GetBasicFilterLooseOperator()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -17,19 +17,6 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* interface iProcess
|
||||
* Something that can be executed
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
interface iProcess
|
||||
{
|
||||
public function Process($iUnixTimeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* interface iBackgroundProcess
|
||||
* Any extension that must be called regularly to be executed in the background
|
||||
@@ -38,30 +25,10 @@ interface iProcess
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
interface iBackgroundProcess extends iProcess
|
||||
interface iBackgroundProcess
|
||||
{
|
||||
/*
|
||||
Gives the repetition rate in seconds
|
||||
@returns integer
|
||||
*/
|
||||
public function GetPeriodicity();
|
||||
}
|
||||
|
||||
/**
|
||||
* interface iScheduledProcess
|
||||
* A variant of process that must be called at specific times
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
interface iScheduledProcess extends iProcess
|
||||
{
|
||||
/*
|
||||
Gives the exact time at which the process must be run next time
|
||||
@returns DateTime
|
||||
*/
|
||||
public function GetNextOccurrence();
|
||||
public function Process($iUnixTimeLimit);
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -296,17 +296,10 @@ class BulkChange
|
||||
$oReconFilter = new CMDBSearchFilter($oExtKey->GetTargetClass());
|
||||
foreach ($this->m_aExtKeys[$sAttCode] as $sForeignAttCode => $iCol)
|
||||
{
|
||||
if ($sForeignAttCode == 'id')
|
||||
{
|
||||
$value = (int) $aRowData[$iCol];
|
||||
}
|
||||
else
|
||||
{
|
||||
// The foreign attribute is one of our reconciliation key
|
||||
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode);
|
||||
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
}
|
||||
$oReconFilter->AddCondition($sForeignAttCode, $value, '=');
|
||||
// The foreign attribute is one of our reconciliation key
|
||||
$oForeignAtt = MetaModel::GetAttributeDef($oExtKey->GetTargetClass(), $sForeignAttCode);
|
||||
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
$oReconFilter->AddCondition($sForeignAttCode, $value);
|
||||
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
|
||||
@@ -788,10 +781,8 @@ class BulkChange
|
||||
{
|
||||
$aVisited = array();
|
||||
}
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
foreach($this->m_aData as $iRow => $aRowData)
|
||||
{
|
||||
set_time_limit(5);
|
||||
if (isset($aResult[$iRow]["__STATUS__"]))
|
||||
{
|
||||
// An issue at the earlier steps - skip the rest
|
||||
@@ -910,13 +901,11 @@ class BulkChange
|
||||
$iObj = $oObj->GetKey();
|
||||
if (!in_array($iObj, $aVisited))
|
||||
{
|
||||
set_time_limit(5);
|
||||
$iRow++;
|
||||
$this->UpdateMissingObject($aResult, $iRow, $oObj, $oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
|
||||
// Fill in the blanks - the result matrix is expected to be 100% complete
|
||||
//
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -45,9 +45,6 @@ class CMDBChangeOp extends DBObject
|
||||
"db_table" => "priv_changeop",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "optype",
|
||||
'indexes' => array(
|
||||
array('objclass', 'objkey'),
|
||||
)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
@@ -176,7 +176,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
|
||||
$oMyChangeOp->Set("objkey", $objkey);
|
||||
$oMyChangeOp->Set("fclass", get_class($this));
|
||||
$oMyChangeOp->Set("fname", substr($this->GetRawName(), 0, 255)); // Protect against very long friendly names
|
||||
$oMyChangeOp->Set("fname", $this->GetRawName());
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
|
||||
@@ -189,9 +189,8 @@ abstract class CMDBObject extends DBObject
|
||||
foreach ($aValues as $sAttCode=> $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField()) continue;
|
||||
if ($oAttDef->IsLinkSet()) continue;
|
||||
if ($oAttDef->GetTrackingLevel() == ATTRIBUTE_TRACKING_NONE) continue;
|
||||
if ($oAttDef->IsExternalField()) continue; // #@# temporary
|
||||
if ($oAttDef->IsLinkSet()) continue; // #@# temporary
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -255,6 +255,12 @@ class CMDBSource
|
||||
|
||||
public static function Query($sSQLQuery)
|
||||
{
|
||||
// Add info into the query as a comment, for easier error tracking
|
||||
// disabled until we need it really!
|
||||
//
|
||||
//$aTraceInf['file'] = __FILE__;
|
||||
// $sSQLQuery .= MyHelpers::MakeSQLComment($aTraceInf);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSQLQuery);
|
||||
if (!$result)
|
||||
@@ -301,9 +307,7 @@ class CMDBSource
|
||||
|
||||
public static function QueryToScalar($sSql)
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSql);
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
@@ -324,9 +328,7 @@ class CMDBSource
|
||||
public static function QueryToArray($sSql)
|
||||
{
|
||||
$aData = array();
|
||||
$oKPI = new ExecutionKPI();
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSql);
|
||||
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
@@ -478,23 +480,14 @@ class CMDBSource
|
||||
return ($aFieldData["Type"]);
|
||||
}
|
||||
|
||||
public static function HasIndex($sTable, $sIndexId, $aFields = null)
|
||||
public static function HasIndex($sTable, $sField)
|
||||
{
|
||||
$aTableInfo = self::GetTableInfo($sTable);
|
||||
if (empty($aTableInfo)) return false;
|
||||
if (!array_key_exists($sIndexId, $aTableInfo['Indexes'])) return false;
|
||||
|
||||
if ($aFields == null)
|
||||
{
|
||||
// Just searching for the name
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compare the columns
|
||||
$sSearchedIndex = implode(',', $aFields);
|
||||
$sExistingIndex = implode(',', $aTableInfo['Indexes'][$sIndexId]);
|
||||
|
||||
return ($sSearchedIndex == $sExistingIndex);
|
||||
if (!array_key_exists($sField, $aTableInfo["Fields"])) return false;
|
||||
$aFieldData = $aTableInfo["Fields"][$sField];
|
||||
// $aFieldData could be 'PRI' for the primary key, or 'MUL', or ?
|
||||
return (strlen($aFieldData["Key"]) > 0);
|
||||
}
|
||||
|
||||
// Returns an array of (fieldname => array of field info)
|
||||
@@ -544,17 +537,6 @@ class CMDBSource
|
||||
// Table does not exist
|
||||
self::$m_aTablesInfo[strtolower($sTableName)] = null;
|
||||
}
|
||||
|
||||
if (!is_null(self::$m_aTablesInfo[strtolower($sTableName)]))
|
||||
{
|
||||
$aIndexes = self::QueryToArray("SHOW INDEXES FROM `$sTableName`");
|
||||
$aMyIndexes = array();
|
||||
foreach ($aIndexes as $aIndexColumn)
|
||||
{
|
||||
$aMyIndexes[$aIndexColumn['Key_name']][$aIndexColumn['Seq_in_index']-1] = $aIndexColumn['Column_name'];
|
||||
}
|
||||
self::$m_aTablesInfo[strtolower($sTableName)]["Indexes"] = $aMyIndexes;
|
||||
}
|
||||
}
|
||||
//public static function EnumTables()
|
||||
//{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -47,6 +47,8 @@ define ('DEFAULT_LOG_GLOBAL', true);
|
||||
define ('DEFAULT_LOG_NOTIFICATION', true);
|
||||
define ('DEFAULT_LOG_ISSUE', true);
|
||||
define ('DEFAULT_LOG_WEB_SERVICE', true);
|
||||
define ('DEFAULT_LOG_KPI_DURATION', false);
|
||||
define ('DEFAULT_LOG_KPI_MEMORY', false);
|
||||
define ('DEFAULT_LOG_QUERIES', false);
|
||||
|
||||
define ('DEFAULT_QUERY_CACHE_ENABLED', true);
|
||||
@@ -147,14 +149,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'disable_mandatory_ext_keys' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'For developpers: allow every external keys to be undefined',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'graphviz_path' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Path to the Graphviz "dot" executable for graphing objects lifecycle',
|
||||
@@ -332,14 +326,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'async_task_retries' => array(
|
||||
'type' => 'array',
|
||||
'description' => 'Automatic retries of asynchronous tasks in case of failure (per class)',
|
||||
'default' => array('AsyncSendEmail' => array('max_retries' => 0, 'retry_delay' => 600)),
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_asynchronous' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'If set, the emails are sent off line, which requires cron.php to be activated. Exception: some features like the email test utility will force the serialized mode',
|
||||
@@ -539,24 +525,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'forgot_password' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Enable the "Forgot password" feature',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'forgot_password_from' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Sender email address for the "forgot password" feature. If empty, defaults to the recipient\'s email address.',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'deadline_format' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'The format used for displaying "deadline" attributes: any string with the following placeholders: $date$, $difference$',
|
||||
@@ -649,74 +617,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'email_validation_pattern' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Regular expression to validate/detect the format of an eMail address',
|
||||
'default' => "[a-zA-Z0-9._&'-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9-]{2,}",
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'log_kpi_duration' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Level of logging for troubleshooting performance issues (1 to enable, 2 +blame callers)',
|
||||
// examples... not used
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'log_kpi_memory' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Level of logging for troubleshooting memory limit issues',
|
||||
// examples... not used
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'log_kpi_user_id' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Limit the scope of users to the given user id (* means no limit)',
|
||||
// examples... not used
|
||||
'default' => '*',
|
||||
'value' => '*',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'max_linkset_output' => array(
|
||||
'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.',
|
||||
'default' => 100,
|
||||
'value' => 100,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'demo_mode' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Set to true to prevent users from changing passwords/languages',
|
||||
'default' => false,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'portal_tickets' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'CSV list of classes supported in the portal',
|
||||
// examples... not used
|
||||
'default' => 'UserRequest',
|
||||
'value' => 'UserRequest',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'min_reload_interval' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Minimum refresh interval (seconds) for dashboards, shortcuts, etc. Even if the interval is set programmatically, it is forced to that minimum',
|
||||
'default' => 5, // In iTop 2.0.3, this was the hardcoded value
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
@@ -745,8 +645,6 @@ class Config
|
||||
case 'float':
|
||||
$value = (float) $value;
|
||||
break;
|
||||
case 'array':
|
||||
break;
|
||||
default:
|
||||
throw new CoreException('Unknown type for setting', array('property' => $sPropCode, 'type' => $sType));
|
||||
}
|
||||
@@ -777,6 +675,8 @@ class Config
|
||||
protected $m_bLogNotification;
|
||||
protected $m_bLogIssue;
|
||||
protected $m_bLogWebService;
|
||||
protected $m_bLogKPIDuration; // private setting
|
||||
protected $m_bLogKPIMemory; // private setting
|
||||
protected $m_bLogQueries; // private setting
|
||||
protected $m_bQueryCacheEnabled; // private setting
|
||||
|
||||
@@ -886,6 +786,8 @@ class Config
|
||||
$this->m_bLogNotification = DEFAULT_LOG_NOTIFICATION;
|
||||
$this->m_bLogIssue = DEFAULT_LOG_ISSUE;
|
||||
$this->m_bLogWebService = DEFAULT_LOG_WEB_SERVICE;
|
||||
$this->m_bLogKPIDuration = DEFAULT_LOG_KPI_DURATION;
|
||||
$this->m_bLogKPIDuration = DEFAULT_LOG_KPI_DURATION;
|
||||
$this->m_iMinDisplayLimit = DEFAULT_MIN_DISPLAY_LIMIT;
|
||||
$this->m_iMaxDisplayLimit = DEFAULT_MAX_DISPLAY_LIMIT;
|
||||
$this->m_iStandardReloadInterval = DEFAULT_STANDARD_RELOAD_INTERVAL;
|
||||
@@ -1003,14 +905,7 @@ class Config
|
||||
{
|
||||
if ($this->IsProperty($sPropCode))
|
||||
{
|
||||
if (is_string($rawvalue))
|
||||
{
|
||||
$value = trim($rawvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $rawvalue;
|
||||
}
|
||||
$value = trim($rawvalue);
|
||||
$this->Set($sPropCode, $value, $sConfigFile);
|
||||
}
|
||||
}
|
||||
@@ -1028,6 +923,8 @@ class Config
|
||||
$this->m_bLogNotification = isset($MySettings['log_notification']) ? (bool) trim($MySettings['log_notification']) : DEFAULT_LOG_NOTIFICATION;
|
||||
$this->m_bLogIssue = isset($MySettings['log_issue']) ? (bool) trim($MySettings['log_issue']) : DEFAULT_LOG_ISSUE;
|
||||
$this->m_bLogWebService = isset($MySettings['log_web_service']) ? (bool) trim($MySettings['log_web_service']) : DEFAULT_LOG_WEB_SERVICE;
|
||||
$this->m_bLogKPIDuration = isset($MySettings['log_kpi_duration']) ? (bool) trim($MySettings['log_kpi_duration']) : DEFAULT_LOG_KPI_DURATION;
|
||||
$this->m_bLogKPIMemory = isset($MySettings['log_kpi_memory']) ? (bool) trim($MySettings['log_kpi_memory']) : DEFAULT_LOG_KPI_MEMORY;
|
||||
$this->m_bLogQueries = isset($MySettings['log_queries']) ? (bool) trim($MySettings['log_queries']) : DEFAULT_LOG_QUERIES;
|
||||
$this->m_bQueryCacheEnabled = isset($MySettings['query_cache_enabled']) ? (bool) trim($MySettings['query_cache_enabled']) : DEFAULT_QUERY_CACHE_ENABLED;
|
||||
|
||||
@@ -1166,6 +1063,16 @@ class Config
|
||||
return $this->m_bLogWebService;
|
||||
}
|
||||
|
||||
public function GetLogKPIDuration()
|
||||
{
|
||||
return $this->m_bLogKPIDuration;
|
||||
}
|
||||
|
||||
public function GetLogKPIMemory()
|
||||
{
|
||||
return $this->m_bLogKPIMemory;
|
||||
}
|
||||
|
||||
public function GetLogQueries()
|
||||
{
|
||||
return $this->m_bLogQueries;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -26,7 +26,6 @@
|
||||
|
||||
require_once('metamodel.class.php');
|
||||
require_once('deletionplan.class.inc.php');
|
||||
require_once('mutex.class.inc.php');
|
||||
|
||||
|
||||
/**
|
||||
@@ -400,25 +399,16 @@ abstract class DBObject
|
||||
{
|
||||
throw new CoreException("Unknown external key '$sExtKeyAttCode' for the class ".get_class($this));
|
||||
}
|
||||
|
||||
$oExtFieldAtt = MetaModel::FindExternalField(get_class($this), $sExtKeyAttCode, $sRemoteAttCode);
|
||||
if (!is_null($oExtFieldAtt))
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
|
||||
$sRemoteClass = $oKeyAttDef->GetTargetClass();
|
||||
$oRemoteObj = MetaModel::GetObject($sRemoteClass, $this->GetStrict($sExtKeyAttCode), false);
|
||||
if (is_null($oRemoteObj))
|
||||
{
|
||||
return $this->GetStrict($oExtFieldAtt->GetCode());
|
||||
return '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
|
||||
$sRemoteClass = $oKeyAttDef->GetTargetClass();
|
||||
$oRemoteObj = MetaModel::GetObject($sRemoteClass, $this->GetStrict($sExtKeyAttCode), false);
|
||||
if (is_null($oRemoteObj))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $oRemoteObj->Get($sRemoteAttCode);
|
||||
}
|
||||
return $oRemoteObj->Get($sRemoteAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -443,9 +433,7 @@ abstract class DBObject
|
||||
{
|
||||
// Lazy load (polymorphism): complete by reloading the entire object
|
||||
// #@# non-scalar attributes.... handle that differently?
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->Reload();
|
||||
$oKPI->ComputeStats('Reload', get_class($this).'/'.$sAttCode);
|
||||
}
|
||||
elseif ($sAttCode == 'friendlyname')
|
||||
{
|
||||
@@ -946,7 +934,7 @@ abstract class DBObject
|
||||
}
|
||||
elseif ($oAtt->IsScalar())
|
||||
{
|
||||
$aValues = $oAtt->GetAllowedValues($this->ToArgsForQuery());
|
||||
$aValues = $oAtt->GetAllowedValues($this->ToArgs());
|
||||
if (count($aValues) > 0)
|
||||
{
|
||||
if (!array_key_exists($toCheck, $aValues))
|
||||
@@ -982,6 +970,7 @@ abstract class DBObject
|
||||
{
|
||||
$this->DoComputeValues();
|
||||
|
||||
$this->m_aCheckIssues = array();
|
||||
$aChanges = $this->ListChanges();
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
|
||||
@@ -1036,8 +1025,6 @@ abstract class DBObject
|
||||
}
|
||||
if (is_null($this->m_bCheckStatus))
|
||||
{
|
||||
$this->m_aCheckIssues = array();
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$this->DoCheckToWrite();
|
||||
$oKPI->ComputeStats('CheckToWrite', get_class($this));
|
||||
@@ -1212,39 +1199,24 @@ abstract class DBObject
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (!$oAttDef->IsLinkSet()) continue;
|
||||
|
||||
$oOriginalSet = $this->m_aOrigValues[$sAttCode];
|
||||
if ($oOriginalSet != null)
|
||||
{
|
||||
$aOriginalList = $oOriginalSet->ToArray();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aOriginalList = array();
|
||||
}
|
||||
|
||||
|
||||
$oLinks = $this->Get($sAttCode);
|
||||
$oLinks->Rewind();
|
||||
while ($oLinkedObject = $oLinks->Fetch())
|
||||
{
|
||||
if (!array_key_exists($oLinkedObject->GetKey(), $aOriginalList))
|
||||
{
|
||||
// New object added to the set, make it point properly
|
||||
$oLinkedObject->Set($oAttDef->GetExtKeyToMe(), $this->m_iKey);
|
||||
}
|
||||
$oLinkedObject->Set($oAttDef->GetExtKeyToMe(), $this->m_iKey);
|
||||
if ($oLinkedObject->IsModified())
|
||||
{
|
||||
// Objects can be modified because:
|
||||
// 1) They've just been added into the set, so their ExtKey is modified
|
||||
// 2) They are about to be removed from the set BUT NOT deleted, their ExtKey has been reset
|
||||
$oLinkedObject->DBWrite();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the objects that were initialy present and disappeared from the list
|
||||
// (if any)
|
||||
if (count($aOriginalList) > 0)
|
||||
$oOriginalSet = $this->m_aOrigValues[$sAttCode];
|
||||
if ($oOriginalSet != null)
|
||||
{
|
||||
$aOriginalList = $oOriginalSet->ToArray();
|
||||
$aNewSet = $oLinks->ToArray();
|
||||
|
||||
foreach($aOriginalList as $iId => $oObject)
|
||||
@@ -1467,95 +1439,6 @@ abstract class DBObject
|
||||
return $this->m_iKey;
|
||||
}
|
||||
|
||||
protected function MakeInsertStatementSingleTable($aAuthorizedExtKeys, &$aStatements, $sTableClass)
|
||||
{
|
||||
$sTable = MetaModel::DBGetTable($sTableClass);
|
||||
// Abstract classes or classes having no specific attribute do not have an associated table
|
||||
if ($sTable == '') return;
|
||||
|
||||
$sClass = get_class($this);
|
||||
|
||||
// fields in first array, values in the second
|
||||
$aFieldsToWrite = array();
|
||||
$aValuesToWrite = array();
|
||||
|
||||
if (!empty($this->m_iKey) && ($this->m_iKey >= 0))
|
||||
{
|
||||
// Add it to the list of fields to write
|
||||
$aFieldsToWrite[] = '`'.MetaModel::DBGetKey($sTableClass).'`';
|
||||
$aValuesToWrite[] = CMDBSource::Quote($this->m_iKey);
|
||||
}
|
||||
|
||||
$aHierarchicalKeys = array();
|
||||
foreach(MetaModel::ListAttributeDefs($sTableClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
// Skip this attribute if not defined in this table
|
||||
if (!MetaModel::IsAttributeOrigin($sTableClass, $sAttCode)) continue;
|
||||
// Skip link set that can still be undefined though the object is 100% loaded
|
||||
if ($oAttDef->IsLinkSet()) continue;
|
||||
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
if (is_array($aAuthorizedExtKeys))
|
||||
{
|
||||
if (!array_key_exists($sTargetClass, $aAuthorizedExtKeys) || !array_key_exists($value, $aAuthorizedExtKeys[$sTargetClass]))
|
||||
{
|
||||
$value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aAttColumns = $oAttDef->GetSQLValues($value);
|
||||
foreach($aAttColumns as $sColumn => $sValue)
|
||||
{
|
||||
$aFieldsToWrite[] = "`$sColumn`";
|
||||
$aValuesToWrite[] = CMDBSource::Quote($sValue);
|
||||
}
|
||||
if ($oAttDef->IsHierarchicalKey())
|
||||
{
|
||||
$aHierarchicalKeys[$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($aValuesToWrite) == 0) return false;
|
||||
|
||||
if (count($aHierarchicalKeys) > 0)
|
||||
{
|
||||
foreach($aHierarchicalKeys as $sAttCode => $oAttDef)
|
||||
{
|
||||
$aValues = MetaModel::HKInsertChildUnder($this->m_aCurrValues[$sAttCode], $oAttDef, $sTable);
|
||||
$aFieldsToWrite[] = '`'.$oAttDef->GetSQLRight().'`';
|
||||
$aValuesToWrite[] = $aValues[$oAttDef->GetSQLRight()];
|
||||
$aFieldsToWrite[] = '`'.$oAttDef->GetSQLLeft().'`';
|
||||
$aValuesToWrite[] = $aValues[$oAttDef->GetSQLLeft()];
|
||||
}
|
||||
}
|
||||
$aStatements[] = "INSERT INTO `$sTable` (".join(",", $aFieldsToWrite).") VALUES (".join(", ", $aValuesToWrite).");";
|
||||
}
|
||||
|
||||
public function MakeInsertStatements($aAuthorizedExtKeys, &$aStatements)
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$sRootClass = MetaModel::GetRootClass($sClass);
|
||||
|
||||
// First query built upon on the root class, because the ID must be created first
|
||||
$this->MakeInsertStatementSingleTable($aAuthorizedExtKeys, $aStatements, $sRootClass);
|
||||
|
||||
// Then do the leaf class, if different from the root class
|
||||
if ($sClass != $sRootClass)
|
||||
{
|
||||
$this->MakeInsertStatementSingleTable($aAuthorizedExtKeys, $aStatements, $sClass);
|
||||
}
|
||||
|
||||
// Then do the other classes
|
||||
foreach(MetaModel::EnumParentClasses($sClass) as $sParentClass)
|
||||
{
|
||||
if ($sParentClass == $sRootClass) continue;
|
||||
$this->MakeInsertStatementSingleTable($aAuthorizedExtKeys, $aStatements, $sParentClass);
|
||||
}
|
||||
}
|
||||
|
||||
public function DBInsert()
|
||||
{
|
||||
$this->DBInsertNoReload();
|
||||
@@ -1842,10 +1725,6 @@ abstract class DBObject
|
||||
}
|
||||
else
|
||||
{
|
||||
// Getting and setting time limit are not symetric:
|
||||
// www.php.net/manual/fr/function.set-time-limit.php#72305
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
|
||||
foreach ($oDeletionPlan->ListDeletes() as $sClass => $aToDelete)
|
||||
{
|
||||
foreach ($aToDelete as $iId => $aData)
|
||||
@@ -1857,7 +1736,6 @@ abstract class DBObject
|
||||
// As a temporary fix: delete only the objects that are still to be deleted...
|
||||
if ($oToDelete->m_bIsInDB)
|
||||
{
|
||||
set_time_limit(5);
|
||||
$oToDelete->DBDeleteSingleObject();
|
||||
}
|
||||
}
|
||||
@@ -1871,13 +1749,10 @@ abstract class DBObject
|
||||
foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef)
|
||||
{
|
||||
$oToUpdate->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]);
|
||||
set_time_limit(5);
|
||||
$oToUpdate->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
}
|
||||
|
||||
return $oDeletionPlan;
|
||||
@@ -2001,31 +1876,20 @@ abstract class DBObject
|
||||
$this->Set($sAttCode, $oSW);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create query parameters (SELECT ... WHERE service = :this->service_id)
|
||||
* to be used with the APIs DBObjectSearch/DBObjectSet
|
||||
*
|
||||
* Starting 2.0.2 the parameters are computed on demand, at the lowest level,
|
||||
* in VariableExpression::Render()
|
||||
*/
|
||||
public function ToArgsForQuery($sArgName = 'this')
|
||||
{
|
||||
return array($sArgName.'->object()' => $this);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create template placeholders
|
||||
* An improvement could be to compute the values on demand
|
||||
* (i.e. interpret the template to determine the placeholders)
|
||||
*/
|
||||
// Make standard context arguments
|
||||
// Note: Needs to be reviewed because it is currently called once per attribute when an object is written (CheckToWrite / CheckValue)
|
||||
// Several options here:
|
||||
// 1) cache the result
|
||||
// 2) set only the object ref and resolve the values iif needed from contextual templates and queries (easy for the queries, not for the templates)
|
||||
public function ToArgs($sArgName = 'this')
|
||||
{
|
||||
if (is_null($this->m_aAsArgs))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aScalarArgs = $this->ToArgsForQuery($sArgName);
|
||||
$aScalarArgs = array();
|
||||
$aScalarArgs[$sArgName] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->id'] = $this->GetKey();
|
||||
$aScalarArgs[$sArgName.'->object()'] = $this;
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink('iTopStandardURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = $this->GetHyperlink('PortalURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->name()'] = $this->GetName();
|
||||
@@ -2033,41 +1897,20 @@ abstract class DBObject
|
||||
$sClass = get_class($this);
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeCaseLog)
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $this->Get($sAttCode);
|
||||
if ($oAttDef->IsScalar())
|
||||
{
|
||||
$oCaseLog = $this->Get($sAttCode);
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $oCaseLog->GetText();
|
||||
$aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry();
|
||||
}
|
||||
elseif ($oAttDef->IsScalar())
|
||||
{
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $this->Get($sAttCode);
|
||||
// #@# Note: This has been proven to be quite slow, this can slow down bulk load
|
||||
$sAsHtml = $this->GetAsHtml($sAttCode);
|
||||
$aScalarArgs[$sArgName.'->html('.$sAttCode.')'] = $sAsHtml;
|
||||
$aScalarArgs[$sArgName.'->label('.$sAttCode.')'] = $this->GetEditValue($sAttCode); // "Nice" display value, but without HTML tags and entities
|
||||
}
|
||||
elseif ($oAttDef->IsLinkSet())
|
||||
// Do something for case logs... quick N' dirty...
|
||||
if ($aScalarArgs[$sArgName.'->'.$sAttCode] instanceof ormCaseLog)
|
||||
{
|
||||
$sRemoteName = $oAttDef->IsIndirect() ? $oAttDef->GetExtKeyToRemote().'_friendlyname' : 'friendlyname';
|
||||
|
||||
$oLinkSet = clone $this->Get($sAttCode); // Workaround/Safety net for Trac #887
|
||||
$iLimit = MetaModel::GetConfig()->Get('max_linkset_output');
|
||||
if ($iLimit > 0)
|
||||
{
|
||||
$oLinkSet->SetLimit($iLimit);
|
||||
}
|
||||
$aNames = $oLinkSet->GetColumnAsArray($sRemoteName);
|
||||
if ($iLimit > 0)
|
||||
{
|
||||
$iTotal = $oLinkSet->Count();
|
||||
if ($iTotal > count($aNames))
|
||||
{
|
||||
$aNames[] = '... '.Dict::Format('UI:TruncatedResults', count($aNames), $iTotal);
|
||||
}
|
||||
}
|
||||
$sNames = implode("\n", $aNames);
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $sNames;
|
||||
$oCaseLog = $aScalarArgs[$sArgName.'->'.$sAttCode];
|
||||
$aScalarArgs[$sArgName.'->'.$sAttCode] = $oCaseLog->GetText();
|
||||
$aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2271,7 +2114,7 @@ abstract class DBObject
|
||||
$iDepth = $bPropagate ? $iMaxDepth - 1 : 0;
|
||||
|
||||
$oFlt = DBObjectSearch::FromOQL($sQuery);
|
||||
$oObjSet = new DBObjectSet($oFlt, array(), $this->ToArgsForQuery());
|
||||
$oObjSet = new DBObjectSet($oFlt, array(), $this->ToArgs());
|
||||
while ($oObj = $oObjSet->Fetch())
|
||||
{
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
@@ -2350,17 +2193,10 @@ abstract class DBObject
|
||||
$oDeletionPlan->SetDeletionIssues($this, $this->m_aDeleteIssues, $this->m_bSecurityIssue);
|
||||
|
||||
$aDependentObjects = $this->GetReferencingObjects(true /* allow all data */);
|
||||
|
||||
// Getting and setting time limit are not symetric:
|
||||
// www.php.net/manual/fr/function.set-time-limit.php#72305
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
|
||||
foreach ($aDependentObjects as $sRemoteClass => $aPotentialDeletes)
|
||||
{
|
||||
foreach ($aPotentialDeletes as $sRemoteExtKey => $aData)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
$oAttDef = $aData['attribute'];
|
||||
$iDeletePropagationOption = $oAttDef->GetDeletionPropagationOption();
|
||||
$oDepSet = $aData['objects'];
|
||||
@@ -2390,7 +2226,6 @@ abstract class DBObject
|
||||
}
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -720,19 +720,6 @@ class DBObjectSearch
|
||||
|
||||
public function AddCondition_PointingTo(DBObjectSearch $oFilter, $sExtKeyAttCode, $iOperatorCode = TREE_OPERATOR_EQUALS)
|
||||
{
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}'");
|
||||
}
|
||||
$oAttExtKey = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
if(!MetaModel::IsSameFamilyBranch($oFilter->GetClass(), $oAttExtKey->GetTargetClass()))
|
||||
{
|
||||
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
|
||||
{
|
||||
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
}
|
||||
// Note: though it seems to be a good practice to clone the given source filter
|
||||
// (as it was done and fixed an issue in MergeWith())
|
||||
// this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge)
|
||||
@@ -747,6 +734,20 @@ class DBObjectSearch
|
||||
|
||||
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
|
||||
{
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored");
|
||||
}
|
||||
$oAttExtKey = MetaModel::GetAttributeDef($this->GetClass(), $sExtKeyAttCode);
|
||||
if(!MetaModel::IsSameFamilyBranch($oFilter->GetClass(), $oAttExtKey->GetTargetClass()))
|
||||
{
|
||||
throw new CoreException("The specified filter (pointing to {$oFilter->GetClass()}) is not compatible with the key '{$this->GetClass()}::$sExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
|
||||
{
|
||||
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
}
|
||||
|
||||
// Find the node on which the new tree must be attached (most of the time it is "this")
|
||||
$oReceivingFilter = $this->GetNode($this->GetClassAlias());
|
||||
|
||||
@@ -756,17 +757,6 @@ class DBObjectSearch
|
||||
|
||||
public function AddCondition_ReferencedBy(DBObjectSearch $oFilter, $sForeignExtKeyAttCode)
|
||||
{
|
||||
$sForeignClass = $oFilter->GetClass();
|
||||
if (!MetaModel::IsValidKeyAttCode($sForeignClass, $sForeignExtKeyAttCode))
|
||||
{
|
||||
throw new CoreException("The attribute code '$sForeignExtKeyAttCode' is not an external key of the class '{$sForeignClass}'");
|
||||
}
|
||||
$oAttExtKey = MetaModel::GetAttributeDef($sForeignClass, $sForeignExtKeyAttCode);
|
||||
if(!MetaModel::IsSameFamilyBranch($this->GetClass(), $oAttExtKey->GetTargetClass()))
|
||||
{
|
||||
// à refaire en spécifique dans FromOQL
|
||||
throw new CoreException("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::$sForeignExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
// Note: though it seems to be a good practice to clone the given source filter
|
||||
// (as it was done and fixed an issue in MergeWith())
|
||||
// this was not implemented here because it was causing a regression (login as admin, select an org, click on any badge)
|
||||
@@ -782,6 +772,16 @@ class DBObjectSearch
|
||||
protected function AddCondition_ReferencedBy_InNameSpace(DBObjectSearch $oFilter, $sForeignExtKeyAttCode, &$aClassAliases, &$aAliasTranslation)
|
||||
{
|
||||
$sForeignClass = $oFilter->GetClass();
|
||||
$sForeignClassAlias = $oFilter->GetClassAlias();
|
||||
if (!MetaModel::IsValidKeyAttCode($sForeignClass, $sForeignExtKeyAttCode))
|
||||
{
|
||||
throw new CoreException("The attribute code '$sForeignExtKeyAttCode' is not an external key of the class '{$sForeignClass}' - the condition will be ignored");
|
||||
}
|
||||
$oAttExtKey = MetaModel::GetAttributeDef($sForeignClass, $sForeignExtKeyAttCode);
|
||||
if(!MetaModel::IsSameFamilyBranch($this->GetClass(), $oAttExtKey->GetTargetClass()))
|
||||
{
|
||||
throw new CoreException("The specified filter (objects referencing an object of class {$this->GetClass()}) is not compatible with the key '{$sForeignClass}::$sForeignExtKeyAttCode', which is pointing to {$oAttExtKey->GetTargetClass()}");
|
||||
}
|
||||
|
||||
// Find the node on which the new tree must be attached (most of the time it is "this")
|
||||
$oReceivingFilter = $this->GetNode($this->GetClassAlias());
|
||||
@@ -1129,7 +1129,7 @@ class DBObjectSearch
|
||||
$sFltCode = $oExpression->GetName();
|
||||
if (empty($sClassAlias))
|
||||
{
|
||||
// Need to find the right alias
|
||||
// Try to find an alias
|
||||
// Build an array of field => array of aliases
|
||||
$aFieldClasses = array();
|
||||
foreach($aClassAliases as $sAlias => $sReal)
|
||||
@@ -1139,8 +1139,29 @@ class DBObjectSearch
|
||||
$aFieldClasses[$sAnFltCode][] = $sAlias;
|
||||
}
|
||||
}
|
||||
if (!array_key_exists($sFltCode, $aFieldClasses))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown filter code', $sQuery, $oExpression->GetNameDetails(), array_keys($aFieldClasses));
|
||||
}
|
||||
if (count($aFieldClasses[$sFltCode]) > 1)
|
||||
{
|
||||
throw new OqlNormalizeException('Ambiguous filter code', $sQuery, $oExpression->GetNameDetails());
|
||||
}
|
||||
$sClassAlias = $aFieldClasses[$sFltCode][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!array_key_exists($sClassAlias, $aClassAliases))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class [alias]', $sQuery, $oExpression->GetParentDetails(), array_keys($aClassAliases));
|
||||
}
|
||||
$sClass = $aClassAliases[$sClassAlias];
|
||||
if (!MetaModel::IsValidFilterCode($sClass, $sFltCode))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown filter code', $sQuery, $oExpression->GetNameDetails(), MetaModel::GetFiltersList($sClass));
|
||||
}
|
||||
}
|
||||
|
||||
return new FieldExpression($sFltCode, $sClassAlias);
|
||||
}
|
||||
elseif ($oExpression instanceof VariableOqlExpression)
|
||||
@@ -1221,13 +1242,15 @@ class DBObjectSearch
|
||||
|
||||
$oOql = new OqlInterpreter($sQuery);
|
||||
$oOqlQuery = $oOql->ParseObjectQuery();
|
||||
|
||||
$oMetaModel = new ModelReflectionRuntime();
|
||||
$oOqlQuery->Check($oMetaModel, $sQuery); // Exceptions thrown in case of issue
|
||||
|
||||
|
||||
$sClass = $oOqlQuery->GetClass();
|
||||
$sClassAlias = $oOqlQuery->GetClassAlias();
|
||||
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
throw new UnknownClassOqlException($sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses());
|
||||
}
|
||||
|
||||
$oResultFilter = new DBObjectSearch($sClass, $sClassAlias);
|
||||
$aAliases = array($sClassAlias => $sClass);
|
||||
|
||||
@@ -1243,6 +1266,21 @@ class DBObjectSearch
|
||||
{
|
||||
$sJoinClass = $oJoinSpec->GetClass();
|
||||
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
|
||||
if (!MetaModel::IsValidClass($sJoinClass))
|
||||
{
|
||||
throw new UnknownClassOqlException($sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses());
|
||||
}
|
||||
if (array_key_exists($sJoinClassAlias, $aAliases))
|
||||
{
|
||||
if ($sJoinClassAlias != $sJoinClass)
|
||||
{
|
||||
throw new OqlNormalizeException('Duplicate class alias', $sQuery, $oJoinSpec->GetClassAliasDetails());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new OqlNormalizeException('Duplicate class name', $sQuery, $oJoinSpec->GetClassDetails());
|
||||
}
|
||||
}
|
||||
|
||||
// Assumption: ext key on the left only !!!
|
||||
// normalization should take care of this
|
||||
@@ -1252,17 +1290,32 @@ class DBObjectSearch
|
||||
|
||||
$oRightField = $oJoinSpec->GetRightField();
|
||||
$sToClass = $oRightField->GetParent();
|
||||
$sPKeyDescriptor = $oRightField->GetName();
|
||||
if ($sPKeyDescriptor != 'id')
|
||||
{
|
||||
throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sQuery, $oRightField->GetNameDetails(), array('id'));
|
||||
}
|
||||
|
||||
$aAliases[$sJoinClassAlias] = $sJoinClass;
|
||||
$aJoinItems[$sJoinClassAlias] = new DBObjectSearch($sJoinClass, $sJoinClassAlias);
|
||||
|
||||
if (!array_key_exists($sFromClass, $aJoinItems))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sQuery, $oLeftField->GetParentDetails(), array_keys($aJoinItems));
|
||||
}
|
||||
if (!array_key_exists($sToClass, $aJoinItems))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sQuery, $oRightField->GetParentDetails(), array_keys($aJoinItems));
|
||||
}
|
||||
$aExtKeys = array_keys(MetaModel::GetExternalKeys($aAliases[$sFromClass]));
|
||||
if (!in_array($sExtKeyAttCode, $aExtKeys))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown external key in join condition (left expression)', $sQuery, $oLeftField->GetNameDetails(), $aExtKeys);
|
||||
}
|
||||
|
||||
if ($sFromClass == $sJoinClassAlias)
|
||||
{
|
||||
$oReceiver = $aJoinItems[$sToClass];
|
||||
$oNewComer = $aJoinItems[$sFromClass];
|
||||
|
||||
$aAliasTranslation = array();
|
||||
$oReceiver->AddCondition_ReferencedBy_InNameSpace($oNewComer, $sExtKeyAttCode, $oReceiver->m_aClasses, $aAliasTranslation);
|
||||
$aJoinItems[$sToClass]->AddCondition_ReferencedBy($aJoinItems[$sFromClass], $sExtKeyAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1297,11 +1350,7 @@ class DBObjectSearch
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
|
||||
break;
|
||||
}
|
||||
$oReceiver = $aJoinItems[$sFromClass];
|
||||
$oNewComer = $aJoinItems[$sToClass];
|
||||
|
||||
$aAliasTranslation = array();
|
||||
$oReceiver->AddCondition_PointingTo_InNameSpace($oNewComer, $sExtKeyAttCode, $oReceiver->m_aClasses, $aAliasTranslation, $iOperatorCode);
|
||||
$aJoinItems[$sFromClass]->AddCondition_PointingTo($aJoinItems[$sToClass], $sExtKeyAttCode, $iOperatorCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1311,6 +1360,10 @@ class DBObjectSearch
|
||||
foreach ($oOqlQuery->GetSelectedClasses() as $oClassDetails)
|
||||
{
|
||||
$sClassToSelect = $oClassDetails->GetValue();
|
||||
if (!array_key_exists($sClassToSelect, $aAliases))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class [alias]', $sQuery, $oClassDetails, array_keys($aAliases));
|
||||
}
|
||||
$aSelected[$sClassToSelect] = $aAliases[$sClassToSelect];
|
||||
}
|
||||
$oResultFilter->m_aClasses = $aAliases;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -92,22 +92,19 @@ class DBObjectSet
|
||||
{
|
||||
// Complete the attribute list with the attribute codes
|
||||
$aAttToLoadWithAttDef = array();
|
||||
foreach($this->m_oFilter->GetSelectedClasses() as $sClassAlias => $sClass)
|
||||
foreach($aAttToLoad as $sClassAlias => $aAttList)
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias] = array();
|
||||
if (array_key_exists($sClassAlias, $aAttToLoad))
|
||||
$aSelectedClasses = $this->m_oFilter->GetSelectedClasses();
|
||||
$sClass = $aSelectedClasses[$sClassAlias];
|
||||
foreach($aAttList as $sAttToLoad)
|
||||
{
|
||||
$aAttList = $aAttToLoad[$sClassAlias];
|
||||
foreach($aAttList as $sAttToLoad)
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad);
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad] = $oAttDef;
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
}
|
||||
// Add the external key friendly name anytime
|
||||
$oFriendlyNameAttDef = MetaModel::GetAttributeDef($sClass, $sAttToLoad.'_friendlyname');
|
||||
$aAttToLoadWithAttDef[$sClassAlias][$sAttToLoad.'_friendlyname'] = $oFriendlyNameAttDef;
|
||||
}
|
||||
}
|
||||
// Add the friendly name anytime
|
||||
@@ -115,7 +112,7 @@ class DBObjectSet
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['friendlyname'] = $oFriendlyNameAttDef;
|
||||
|
||||
// Make sure that the final class is requested anytime, whatever the specification (needed for object construction!)
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttToLoadWithAttDef[$sClassAlias]))
|
||||
if (!MetaModel::IsStandaloneClass($sClass) && !array_key_exists('finalclass', $aAttList))
|
||||
{
|
||||
$aAttToLoadWithAttDef[$sClassAlias]['finalclass'] = MetaModel::GetAttributeDef($sClass, 'finalclass');
|
||||
}
|
||||
@@ -418,7 +415,7 @@ class DBObjectSet
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
$this->m_iCount = $aRow['COUNT'];
|
||||
}
|
||||
return $this->m_iCount; // WARNING this value can be wrong, see Trac #887
|
||||
return $this->m_iCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -741,10 +738,13 @@ class DBObjectSet
|
||||
{
|
||||
foreach($aVals as $sCode => $oExpr)
|
||||
{
|
||||
if (is_object($oExpr)) // Array_merge_recursive creates an array when the same key is present multiple times... ignore them
|
||||
if ($oExpr instanceof ScalarExpression)
|
||||
{
|
||||
$oScalarExpr = $oExpr->GetAsScalar($aScalarArgs);
|
||||
$aConst[$sClassAlias][$sCode] = $oScalarExpr->GetValue();
|
||||
$aConst[$sClassAlias][$sCode] = $oExpr->GetValue();
|
||||
}
|
||||
else //Variable
|
||||
{
|
||||
$aConst[$sClassAlias][$sCode] = $aScalarArgs[$oExpr->GetName()];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -758,16 +758,7 @@ class DBObjectSet
|
||||
{
|
||||
if (MetaModel::IsValidObject($value))
|
||||
{
|
||||
if (strpos($sArgName, '->object()') === false)
|
||||
{
|
||||
// Lazy syntax - develop the object contextual parameters
|
||||
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgsForQuery($sArgName));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave as is
|
||||
$aScalarArgs[$sArgName] = $value;
|
||||
}
|
||||
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgs($sArgName));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Algorithm to delete object(s) and maintain data integrity
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -107,15 +107,10 @@ class DeletionPlan
|
||||
}
|
||||
}
|
||||
|
||||
// Getting and setting time limit are not symetric:
|
||||
// www.php.net/manual/fr/function.set-time-limit.php#72305
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
|
||||
foreach($this->m_aToUpdate as $sClass => $aToUpdate)
|
||||
{
|
||||
foreach($aToUpdate as $iId => $aData)
|
||||
{
|
||||
set_time_limit(5);
|
||||
$this->m_iToUpdate++;
|
||||
|
||||
$oObject = $aData['to_reset'];
|
||||
@@ -139,9 +134,9 @@ class DeletionPlan
|
||||
$this->m_bFoundSecurityIssue = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
set_time_limit($iPreviousTimeLimit);
|
||||
}
|
||||
|
||||
public function GetIssues()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -137,10 +137,7 @@ class EventNotification extends Event
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
"order_by_default" => array('date' => false),
|
||||
'indexes' => array(
|
||||
array('object_id'),
|
||||
)
|
||||
"order_by_default" => array('date' => false)
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -351,7 +348,7 @@ class EventLoginUsage extends Event
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_SILENT, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "jointype"=> "", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
$aZList = array('date', 'user_id');
|
||||
if (MetaModel::IsValidAttCode('Contact', 'name'))
|
||||
{
|
||||
|
||||
@@ -299,11 +299,14 @@ class BinaryExpression extends Expression
|
||||
{
|
||||
$aResult[$this->m_oRightExpr->GetParent()][$this->m_oRightExpr->GetName()] = $this->m_oLeftExpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
|
||||
}
|
||||
}
|
||||
else if ($this->m_sOperator == 'AND')
|
||||
else
|
||||
{
|
||||
// Strictly, this should be done only for the AND operator
|
||||
$aResult = array_merge_recursive($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields());
|
||||
$aResult = array_merge($this->m_oRightExpr->ListConstantFields(), $this->m_oLeftExpr->ListConstantFields()) ;
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
@@ -400,11 +403,6 @@ class ScalarExpression extends UnaryExpression
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetAsScalar($aArgs)
|
||||
{
|
||||
return clone $this;
|
||||
}
|
||||
}
|
||||
|
||||
class TrueExpression extends ScalarExpression
|
||||
@@ -613,22 +611,7 @@ class VariableExpression extends UnaryExpression
|
||||
{
|
||||
return CMDBSource::Quote($aArgs[$this->m_sName]);
|
||||
}
|
||||
elseif (($iPos = strpos($this->m_sName, '->')) !== false)
|
||||
{
|
||||
$sParamName = substr($this->m_sName, 0, $iPos);
|
||||
if (array_key_exists($sParamName.'->object()', $aArgs))
|
||||
{
|
||||
$sAttCode = substr($this->m_sName, $iPos + 2);
|
||||
$oObj = $aArgs[$sParamName.'->object()'];
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
return CMDBSource::Quote($oObj->GetKey());
|
||||
}
|
||||
return CMDBSource::Quote($oObj->Get($sAttCode));
|
||||
}
|
||||
}
|
||||
|
||||
if ($bRetrofitParams)
|
||||
elseif ($bRetrofitParams)
|
||||
{
|
||||
$aArgs[$this->m_sName] = null;
|
||||
return ':'.$this->m_sName;
|
||||
@@ -649,29 +632,12 @@ class VariableExpression extends UnaryExpression
|
||||
|
||||
public function GetAsScalar($aArgs)
|
||||
{
|
||||
$value = null;
|
||||
$value = '';
|
||||
if (array_key_exists($this->m_sName, $aArgs))
|
||||
{
|
||||
$value = $aArgs[$this->m_sName];
|
||||
}
|
||||
elseif (($iPos = strpos($this->m_sName, '->')) !== false)
|
||||
{
|
||||
$sParamName = substr($this->m_sName, 0, $iPos);
|
||||
if (array_key_exists($sParamName.'->object()', $aArgs))
|
||||
{
|
||||
$sAttCode = substr($this->m_sName, $iPos + 2);
|
||||
$oObj = $aArgs[$sParamName.'->object()'];
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
$value = $oObj->GetKey();
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $oObj->Get($sAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_null($value))
|
||||
else
|
||||
{
|
||||
throw new MissingQueryArgument('Missing query argument', array('expecting'=>$this->m_sName, 'available'=>array_keys($aArgs)));
|
||||
}
|
||||
|
||||
@@ -28,229 +28,70 @@ class ExecutionKPI
|
||||
{
|
||||
static protected $m_bEnabled_Duration = false;
|
||||
static protected $m_bEnabled_Memory = false;
|
||||
static protected $m_bBlameCaller = false;
|
||||
static protected $m_sAllowedUser = '*';
|
||||
|
||||
static protected $m_aStats = array(); // Recurrent operations
|
||||
static protected $m_aExecData = array(); // One shot operations
|
||||
static protected $m_aStats = array();
|
||||
|
||||
protected $m_fStarted = null;
|
||||
protected $m_iInitialMemory = null;
|
||||
|
||||
static public function EnableDuration($iLevel)
|
||||
static public function EnableDuration()
|
||||
{
|
||||
if ($iLevel > 0)
|
||||
{
|
||||
self::$m_bEnabled_Duration = true;
|
||||
if ($iLevel > 1)
|
||||
{
|
||||
self::$m_bBlameCaller = true;
|
||||
}
|
||||
}
|
||||
self::$m_bEnabled_Duration = true;
|
||||
}
|
||||
|
||||
static public function EnableMemory($iLevel)
|
||||
static public function EnableMemory()
|
||||
{
|
||||
if ($iLevel > 0)
|
||||
{
|
||||
self::$m_bEnabled_Memory = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string sUser A user login or * for all users
|
||||
*/
|
||||
static public function SetAllowedUser($sUser)
|
||||
{
|
||||
self::$m_sAllowedUser = $sUser;
|
||||
}
|
||||
|
||||
static public function IsEnabled()
|
||||
{
|
||||
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory)
|
||||
{
|
||||
if ((self::$m_sAllowedUser == '*') || (UserRights::GetUser() == trim(self::$m_sAllowedUser)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static public function GetDescription()
|
||||
{
|
||||
$aFeatures = array();
|
||||
if (self::$m_bEnabled_Duration) $aFeatures[] = 'Duration';
|
||||
if (self::$m_bEnabled_Memory) $aFeatures[] = 'Memory usage';
|
||||
$sFeatures = implode(', ', $aFeatures);
|
||||
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
|
||||
return "KPI logging is active for $sFor. Measures: $sFeatures";
|
||||
self::$m_bEnabled_Memory = true;
|
||||
}
|
||||
|
||||
static public function ReportStats()
|
||||
{
|
||||
if (!self::IsEnabled()) return;
|
||||
|
||||
global $fItopStarted;
|
||||
$sExecId = microtime(); // id to differentiate the hrefs!
|
||||
|
||||
$aBeginTimes = array();
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
{
|
||||
$aBeginTimes[] = $aOpStats['time_begin'];
|
||||
}
|
||||
array_multisort($aBeginTimes, self::$m_aExecData);
|
||||
|
||||
$sTableStyle = 'background-color: #ccc; margin: 10px;';
|
||||
|
||||
self::Report("<hr/>");
|
||||
self::Report("<div style=\"background-color: grey; padding: 10px;\">");
|
||||
self::Report("<h3><a name=\"".md5($sExecId)."\">KPIs</a> - ".$_SERVER['REQUEST_URI']." (".$_SERVER['REQUEST_METHOD'].")</h3>");
|
||||
self::Report("<p>".date('Y-m-d H:i:s', $fItopStarted)."</p>");
|
||||
self::Report("<p>log_kpi_user_id: ".MetaModel::GetConfig()->Get('log_kpi_user_id')."</p>");
|
||||
self::Report("<div>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>");
|
||||
self::Report("</thead>");
|
||||
foreach (self::$m_aExecData as $aOpStats)
|
||||
{
|
||||
$sOperation = $aOpStats['op'];
|
||||
$sBegin = $sEnd = $sDuration = $sMemBegin = $sMemEnd = $sMemPeak = '?';
|
||||
|
||||
$sBegin = round($aOpStats['time_begin'], 3);
|
||||
$sEnd = round($aOpStats['time_end'], 3);
|
||||
$fDuration = $aOpStats['time_end'] - $aOpStats['time_begin'];
|
||||
$sDuration = round($fDuration, 3);
|
||||
|
||||
if (isset($aOpStats['mem_begin']))
|
||||
{
|
||||
$sMemBegin = self::MemStr($aOpStats['mem_begin']);
|
||||
$sMemEnd = self::MemStr($aOpStats['mem_end']);
|
||||
if (isset($aOpStats['mem_peak']))
|
||||
{
|
||||
$sMemPeak = self::MemStr($aOpStats['mem_peak']);
|
||||
}
|
||||
}
|
||||
|
||||
self::Report("<tr>");
|
||||
self::Report(" <td>$sOperation</td><td>$sBegin</td><td>$sEnd</td><td>$sDuration</td><td>$sMemBegin</td><td>$sMemEnd</td><td>$sMemPeak</td>");
|
||||
self::Report("</tr>");
|
||||
}
|
||||
self::Report("</table>");
|
||||
self::Report("</div>");
|
||||
|
||||
$aConsolidatedStats = array();
|
||||
foreach (self::$m_aStats as $sOperation => $aOpStats)
|
||||
{
|
||||
echo "<h2>KPIs for $sOperation</h2>\n";
|
||||
$fTotalOp = 0;
|
||||
$iTotalOp = 0;
|
||||
$fMinOp = null;
|
||||
$fMaxOp = 0;
|
||||
$sMaxOpArguments = null;
|
||||
echo "<ul>\n";
|
||||
foreach ($aOpStats as $sArguments => $aEvents)
|
||||
{
|
||||
foreach ($aEvents as $aEventData)
|
||||
{
|
||||
$fDuration = $aEventData['time'];
|
||||
$fTotalOp += $fDuration;
|
||||
$iTotalOp++;
|
||||
|
||||
$fMinOp = is_null($fMinOp) ? $fDuration : min($fMinOp, $fDuration);
|
||||
if ($fDuration > $fMaxOp)
|
||||
{
|
||||
$sMaxOpArguments = $sArguments;
|
||||
$fMaxOp = $fDuration;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aConsolidatedStats[$sOperation] = array(
|
||||
'count' => $iTotalOp,
|
||||
'duration' => $fTotalOp,
|
||||
'min' => $fMinOp,
|
||||
'max' => $fMaxOp,
|
||||
'avg' => $fTotalOp / $iTotalOp,
|
||||
'max_args' => $sMaxOpArguments
|
||||
);
|
||||
}
|
||||
|
||||
self::Report("<div>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>");
|
||||
self::Report("</thead>");
|
||||
foreach ($aConsolidatedStats as $sOperation => $aOpStats)
|
||||
{
|
||||
$sOperation = '<a href="#'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
$sCount = $aOpStats['count'];
|
||||
$sDuration = round($aOpStats['duration'], 3);
|
||||
$sMin = round($aOpStats['min'], 3);
|
||||
$sMax = '<a href="#'.md5($sExecId.$aOpStats['max_args']).'">'.round($aOpStats['max'], 3).'</a>';
|
||||
$sAvg = round($aOpStats['avg'], 3);
|
||||
|
||||
self::Report("<tr>");
|
||||
self::Report(" <td>$sOperation</td><td>$sCount</td><td>$sDuration</td><td>$sMin</td><td>$sMax</td><td>$sAvg</td>");
|
||||
self::Report("</tr>");
|
||||
}
|
||||
self::Report("</table>");
|
||||
self::Report("</div>");
|
||||
|
||||
self::Report("</div>");
|
||||
|
||||
// Report operation details
|
||||
foreach (self::$m_aStats as $sOperation => $aOpStats)
|
||||
{
|
||||
$sOperationHtml = '<a name="'.md5($sExecId.$sOperation).'">'.$sOperation.'</a>';
|
||||
self::Report("<h4>$sOperationHtml</h4>");
|
||||
self::Report("<p><a href=\"#".md5($sExecId)."\">Back to page stats</a></p>");
|
||||
self::Report("<table border=\"1\" style=\"$sTableStyle\">");
|
||||
self::Report("<thead>");
|
||||
self::Report(" <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>");
|
||||
self::Report("</thead>");
|
||||
foreach ($aOpStats as $sArguments => $aEvents)
|
||||
{
|
||||
$sHtmlArguments = '<a name="'.md5($sExecId.$sArguments).'"><div style="white-space: pre-wrap;">'.$sArguments.'</div></a>';
|
||||
if ($aConsolidatedStats[$sOperation]['max_args'] == $sArguments)
|
||||
{
|
||||
$sHtmlArguments = '<span style="color: red;">'.$sHtmlArguments.'</span>';
|
||||
}
|
||||
if (isset($aEvents[0]['callers']))
|
||||
{
|
||||
$sHtmlArguments .= '<div style="padding: 10px;">';
|
||||
$sHtmlArguments .= '<table border="1" bgcolor="#cfc">';
|
||||
$sHtmlArguments .= '<tr><td colspan="2" bgcolor="#e9b96">Call stack for the <b>FIRST</b> caller</td></tr>';
|
||||
|
||||
foreach ($aEvents[0]['callers'] as $aCall)
|
||||
{
|
||||
$sHtmlArguments .= '<tr>';
|
||||
$sHtmlArguments .= '<td>'.$aCall['Function'].'</td>';
|
||||
$sHtmlArguments .= '<td>'.$aCall['File'].':'.$aCall['Line'].'</td>';
|
||||
$sHtmlArguments .= '</tr>';
|
||||
}
|
||||
$sHtmlArguments .= '</table>';
|
||||
$sHtmlArguments .= '</div>';
|
||||
}
|
||||
|
||||
$fTotalInter = 0;
|
||||
$fMinInter = null;
|
||||
$fMaxInter = 0;
|
||||
foreach ($aEvents as $aEventData)
|
||||
foreach ($aEvents as $fDuration)
|
||||
{
|
||||
$fDuration = $aEventData['time'];
|
||||
$fTotalInter += $fDuration;
|
||||
$fMinInter = is_null($fMinInter) ? $fDuration : min($fMinInter, $fDuration);
|
||||
$fMaxInter = max($fMaxInter, $fDuration);
|
||||
|
||||
$fMinOp = is_null($fMinOp) ? $fDuration : min($fMinOp, $fDuration);
|
||||
$fMaxOp = max($fMaxOp, $fDuration);
|
||||
}
|
||||
$fTotalOp += $fTotalInter;
|
||||
$iTotalOp++;
|
||||
|
||||
$iCountInter = count($aEvents);
|
||||
$sTotalInter = round($fTotalInter, 3);
|
||||
$sMinInter = round($fMinInter, 3);
|
||||
$sMaxInter = round($fMaxInter, 3);
|
||||
self::Report("<tr>");
|
||||
self::Report(" <td>$sHtmlArguments</td><td>$iCountInter</td><td>$sTotalInter</td><td>$sMinInter</td><td>$sMaxInter</td>");
|
||||
self::Report("</tr>");
|
||||
$sTotalInter = round($fTotalInter, 3)."s";
|
||||
if ($iCountInter > 1)
|
||||
{
|
||||
$sMinInter = round($fMinInter, 3)."s";
|
||||
$sMaxInter = round($fMaxInter, 3)."s";
|
||||
$sTimeDesc = "$sTotalInter (from $sMinInter to $sMaxInter) in $iCountInter times";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sTimeDesc = "$sTotalInter";
|
||||
}
|
||||
echo "<li>Spent $sTimeDesc, on: <span style=\"font-size:60%\">$sArguments</span></li>\n";
|
||||
}
|
||||
self::Report("</table>");
|
||||
echo "</ul>\n";
|
||||
echo "<ul>Sumary for $sOperation\n";
|
||||
echo "<li>Total: $iTotalOp (".round($fTotalOp, 3).")</li>\n";
|
||||
echo "<li>Min: ".round($fMinOp, 3)."</li>\n";
|
||||
echo "<li>Max: ".round($fMaxOp, 3)."</li>\n";
|
||||
echo "<li>Avg: ".round($fTotalOp / $iTotalOp, 3)."</li>\n";
|
||||
echo "</ul>\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,43 +105,25 @@ class ExecutionKPI
|
||||
//
|
||||
public function ComputeAndReport($sOperationDesc)
|
||||
{
|
||||
global $fItopStarted;
|
||||
|
||||
$aNewEntry = null;
|
||||
|
||||
if (self::$m_bEnabled_Duration)
|
||||
{
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$aNewEntry = array(
|
||||
'op' => $sOperationDesc,
|
||||
'time_begin' => $this->m_fStarted - $fItopStarted,
|
||||
'time_end' => $fStopped - $fItopStarted,
|
||||
);
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_fStarted = $fStopped;
|
||||
$fDuration = $fStopped - $this->m_fStarted;
|
||||
$this->Report($sOperationDesc.' / duration: '.round($fDuration, 3));
|
||||
}
|
||||
|
||||
if (self::$m_bEnabled_Memory)
|
||||
{
|
||||
$iCurrentMemory = self::memory_get_usage();
|
||||
if (is_null($aNewEntry))
|
||||
{
|
||||
$aNewEntry = array('op' => $sOperationDesc);
|
||||
}
|
||||
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
|
||||
$aNewEntry['mem_end'] = $iCurrentMemory;
|
||||
$iMemory = self::memory_get_usage();
|
||||
$iMemoryUsed = $iMemory - $this->m_iInitialMemory;
|
||||
$this->Report($sOperationDesc.' / memory: '.self::MemStr($iMemoryUsed).' (Total: '.self::MemStr($iMemory).')');
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
$aNewEntry['mem_peak'] = memory_get_peak_usage();
|
||||
$iMemoryPeak = memory_get_peak_usage();
|
||||
$this->Report($sOperationDesc.' / memory peak: '.self::MemStr($iMemoryPeak));
|
||||
}
|
||||
// Reset for the next operation (if the object is recycled)
|
||||
$this->m_iInitialMemory = $iCurrentMemory;
|
||||
}
|
||||
|
||||
if (!is_null($aNewEntry))
|
||||
{
|
||||
self::$m_aExecData[] = $aNewEntry;
|
||||
}
|
||||
$this->ResetCounters();
|
||||
}
|
||||
|
||||
@@ -310,19 +133,7 @@ class ExecutionKPI
|
||||
{
|
||||
$fStopped = MyHelpers::getmicrotime();
|
||||
$fDuration = $fStopped - $this->m_fStarted;
|
||||
if (self::$m_bBlameCaller)
|
||||
{
|
||||
self::$m_aStats[$sOperation][$sArguments][] = array(
|
||||
'time' => $fDuration,
|
||||
'callers' => MyHelpers::get_callstack(1),
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::$m_aStats[$sOperation][$sArguments][] = array(
|
||||
'time' => $fDuration
|
||||
);
|
||||
}
|
||||
self::$m_aStats[$sOperation][$sArguments][] = $fDuration;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,11 +150,9 @@ class ExecutionKPI
|
||||
}
|
||||
}
|
||||
|
||||
const HtmlReportFile = 'log/kpi.html';
|
||||
|
||||
static protected function Report($sText)
|
||||
protected function Report($sText)
|
||||
{
|
||||
file_put_contents(APPROOT.self::HtmlReportFile, "$sText\n", FILE_APPEND | LOCK_EX);
|
||||
echo "$sText<br/>\n";
|
||||
}
|
||||
|
||||
static protected function MemStr($iMemory)
|
||||
@@ -395,3 +204,13 @@ class ExecutionKPI
|
||||
}
|
||||
}
|
||||
|
||||
class ApplicationStartupKPI extends ExecutionKPI
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
global $fItopStarted;
|
||||
$this->m_fStarted = $fItopStarted;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -174,7 +174,7 @@ abstract class MetaModel
|
||||
// (it is not possible to guess it when called as myderived::...)
|
||||
if (!array_key_exists($sClass, self::$m_aClassParams))
|
||||
{
|
||||
throw new CoreException("Unknown class '$sClass'");
|
||||
throw new CoreException("Unknown class '$sClass', expected a value in {".implode(', ', array_keys(self::$m_aClassParams))."}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,19 +671,6 @@ abstract class MetaModel
|
||||
return $aTables;
|
||||
}
|
||||
|
||||
final static public function DBGetIndexes($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (isset(self::$m_aClassParams[$sClass]['indexes']))
|
||||
{
|
||||
return self::$m_aClassParams[$sClass]['indexes'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
final static public function DBGetKey($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -840,10 +827,6 @@ abstract class MetaModel
|
||||
final static public function GetAttributeDef($sClass, $sAttCode)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (!isset(self::$m_aAttribDefs[$sClass][$sAttCode]))
|
||||
{
|
||||
throw new Exception("Unknown attribute $sAttCode from class $sClass");
|
||||
}
|
||||
return self::$m_aAttribDefs[$sClass][$sAttCode];
|
||||
}
|
||||
|
||||
@@ -875,32 +858,15 @@ abstract class MetaModel
|
||||
|
||||
final static public function GetExternalFields($sClass, $sKeyAttCode)
|
||||
{
|
||||
static $aExtFields = array();
|
||||
if (!isset($aExtFields[$sClass][$sKeyAttCode]))
|
||||
$aExtFields = array();
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt)
|
||||
{
|
||||
$aExtFields[$sClass][$sKeyAttCode] = array();
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAtt)
|
||||
if ($oAtt->IsExternalField() && ($oAtt->GetKeyAttCode() == $sKeyAttCode))
|
||||
{
|
||||
if ($oAtt->IsExternalField() && ($oAtt->GetKeyAttCode() == $sKeyAttCode))
|
||||
{
|
||||
$aExtFields[$sClass][$sKeyAttCode][$oAtt->GetExtAttCode()] = $oAtt;
|
||||
}
|
||||
$aExtFields[] = $oAtt;
|
||||
}
|
||||
}
|
||||
return $aExtFields[$sClass][$sKeyAttCode];
|
||||
}
|
||||
|
||||
final static public function FindExternalField($sClass, $sKeyAttCode, $sRemoteAttCode)
|
||||
{
|
||||
$aExtFields = self::GetExternalFields($sClass, $sKeyAttCode);
|
||||
if (isset($aExtFields[$sRemoteAttCode]))
|
||||
{
|
||||
return $aExtFields[$sRemoteAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return $aExtFields;
|
||||
}
|
||||
|
||||
final static public function GetExtKeyFriends($sClass, $sExtKeyAttCode)
|
||||
@@ -947,10 +913,9 @@ abstract class MetaModel
|
||||
* Get the attribute label
|
||||
* @param string sClass Persistent class
|
||||
* @param string sAttCodeEx Extended attribute code: attcode[->attcode]
|
||||
* @param bool $bShowMandatory If true, add a star character (at the end or before the ->) to show that the field is mandatory
|
||||
* @return string A user friendly format of the string: AttributeName or AttributeName->ExtAttributeName
|
||||
*/
|
||||
public static function GetLabel($sClass, $sAttCodeEx, $bShowMandatory = false)
|
||||
public static function GetLabel($sClass, $sAttCodeEx)
|
||||
{
|
||||
$sLabel = '';
|
||||
if (preg_match('/(.+)->(.+)/', $sAttCodeEx, $aMatches) > 0)
|
||||
@@ -958,17 +923,16 @@ abstract class MetaModel
|
||||
$sAttribute = $aMatches[1];
|
||||
$sField = $aMatches[2];
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttribute);
|
||||
$sMandatory = ($bShowMandatory && !$oAttDef->IsNullAllowed()) ? '*' : '';
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$oTargetAttDef = MetaModel::GetAttributeDef($sTargetClass, $sField);
|
||||
$sLabel = $oAttDef->GetLabel().$sMandatory.'->'.$oTargetAttDef->GetLabel();
|
||||
$sLabel = $oAttDef->GetLabel().'->'.$oTargetAttDef->GetLabel();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Let's return something displayable... but this should never happen!
|
||||
$sLabel = $oAttDef->GetLabel().$sMandatory.'->'.$aMatches[2];
|
||||
$sLabel = $oAttDef->GetLabel().'->'.$aMatches[2];
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -980,8 +944,7 @@ abstract class MetaModel
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCodeEx);
|
||||
$sMandatory = ($bShowMandatory && !$oAttDef->IsNullAllowed()) ? '*' : '';
|
||||
$sLabel = $oAttDef->GetLabel().$sMandatory;
|
||||
$sLabel = $oAttDef->GetLabel();
|
||||
}
|
||||
}
|
||||
return $sLabel;
|
||||
@@ -2114,28 +2077,17 @@ abstract class MetaModel
|
||||
{
|
||||
if (self::IsValidObject($value))
|
||||
{
|
||||
if (strpos($sArgName, '->object()') === false)
|
||||
{
|
||||
// Lazy syntax - develop the object contextual parameters
|
||||
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgsForQuery($sArgName));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leave as is
|
||||
$aScalarArgs[$sArgName] = $value;
|
||||
}
|
||||
$aScalarArgs = array_merge($aScalarArgs, $value->ToArgs($sArgName));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_scalar($value))
|
||||
{
|
||||
$aScalarArgs[$sArgName] = (string) $value;
|
||||
}
|
||||
$aScalarArgs[$sArgName] = (string) $value;
|
||||
}
|
||||
}
|
||||
// Add standard contextual arguments
|
||||
//
|
||||
$aScalarArgs['current_contact_id'] = UserRights::GetContactId();
|
||||
|
||||
return $aScalarArgs;
|
||||
}
|
||||
|
||||
@@ -3343,7 +3295,7 @@ abstract class MetaModel
|
||||
{
|
||||
if(!self::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown attribute code '".$sAttCode."' for the name definition";
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sAttCode."' for the name definition";
|
||||
$aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass));
|
||||
}
|
||||
}
|
||||
@@ -3352,7 +3304,7 @@ abstract class MetaModel
|
||||
{
|
||||
if (!empty($sReconcKeyAttCode) && !self::IsValidAttCode($sClass, $sReconcKeyAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown attribute code '".$sReconcKeyAttCode."' in the list of reconciliation keys";
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sReconcKeyAttCode."' in the list of reconciliation keys";
|
||||
$aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass));
|
||||
}
|
||||
}
|
||||
@@ -3367,7 +3319,7 @@ abstract class MetaModel
|
||||
{
|
||||
if (!self::IsValidClass($oAttDef->GetTargetClass()))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown class '".$oAttDef->GetTargetClass()."' for the external key '$sAttCode'";
|
||||
$aErrors[$sClass][] = "Unkown class '".$oAttDef->GetTargetClass()."' for the external key '$sAttCode'";
|
||||
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetClasses())."}";
|
||||
}
|
||||
}
|
||||
@@ -3376,7 +3328,7 @@ abstract class MetaModel
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
if (!self::IsValidAttCode($sClass, $sKeyAttCode) || !self::IsValidKeyAttCode($sClass, $sKeyAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown key attribute code '".$sKeyAttCode."' for the external field $sAttCode";
|
||||
$aErrors[$sClass][] = "Unkown key attribute code '".$sKeyAttCode."' for the external field $sAttCode";
|
||||
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetKeysList($sClass))."}";
|
||||
}
|
||||
else
|
||||
@@ -3386,15 +3338,11 @@ abstract class MetaModel
|
||||
$sExtAttCode = $oAttDef->GetExtAttCode();
|
||||
if (!self::IsValidAttCode($sTargetClass, $sExtAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown key attribute code '".$sExtAttCode."' for the external field $sAttCode";
|
||||
$aErrors[$sClass][] = "Unkown key attribute code '".$sExtAttCode."' for the external field $sAttCode";
|
||||
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetKeysList($sTargetClass))."}";
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ($oAttDef->IsLinkSet())
|
||||
{
|
||||
// Do nothing...
|
||||
}
|
||||
else // standard attributes
|
||||
{
|
||||
// Check that the default values definition is a valid object!
|
||||
@@ -3427,7 +3375,7 @@ abstract class MetaModel
|
||||
{
|
||||
if (!self::IsValidAttCode($sClass, $sDependOnAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown attribute code '".$sDependOnAttCode."' in the list of prerequisite attributes";
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sDependOnAttCode."' in the list of prerequisite attributes";
|
||||
$aSugFix[$sClass][] = "Expecting a value in ".implode(", ", self::GetAttributesList($sClass));
|
||||
}
|
||||
}
|
||||
@@ -3454,7 +3402,7 @@ abstract class MetaModel
|
||||
// Lifecycle - check that the state attribute does exist as an attribute
|
||||
if (!self::IsValidAttCode($sClass, $sStateAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown attribute code '".$sStateAttCode."' for the state definition";
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sStateAttCode."' for the state definition";
|
||||
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}";
|
||||
}
|
||||
else
|
||||
@@ -3528,7 +3476,7 @@ abstract class MetaModel
|
||||
{
|
||||
if (!self::IsValidAttCode($sClass, $sMyAttCode))
|
||||
{
|
||||
$aErrors[$sClass][] = "Unknown attribute code '".$sMyAttCode."' from ZList '$sListCode'";
|
||||
$aErrors[$sClass][] = "Unkown attribute code '".$sMyAttCode."' from ZList '$sListCode'";
|
||||
$aSugFix[$sClass][] = "Expecting a value in {".implode(", ", self::GetAttributesList($sClass))."}";
|
||||
}
|
||||
}
|
||||
@@ -3987,7 +3935,7 @@ abstract class MetaModel
|
||||
$aCreateTableItems[$sTable][$sField] = $sFieldDefinition;
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aCreateTableItems[$sTable][] = "INDEX (`$sField`)";
|
||||
$aCreateTableItems[$sTable][$sField.'_ix'] = "INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3995,7 +3943,7 @@ abstract class MetaModel
|
||||
$aAlterTableItems[$sTable][$sField] = "ADD $sFieldDefinition";
|
||||
if ($bIndexNeeded)
|
||||
{
|
||||
$aAlterTableItems[$sTable][] = "ADD INDEX (`$sField`)";
|
||||
$aAlterTableItems[$sTable][$sField.'_ix'] = "ADD INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4030,58 +3978,15 @@ abstract class MetaModel
|
||||
|
||||
// Create indexes (external keys only... so far)
|
||||
//
|
||||
if ($bIndexNeeded && !CMDBSource::HasIndex($sTable, $sField, array($sField)))
|
||||
if ($bIndexNeeded && !CMDBSource::HasIndex($sTable, $sField))
|
||||
{
|
||||
$aErrors[$sClass][$sAttCode][] = "Foreign key '$sField' in table '$sTable' should have an index";
|
||||
if (CMDBSource::HasIndex($sTable, $sField))
|
||||
{
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` DROP INDEX `$sField`, ADD INDEX (`$sField`)";
|
||||
$aAlterTableItems[$sTable][] = "DROP INDEX `$sField`";
|
||||
$aAlterTableItems[$sTable][] = "ADD INDEX (`$sField`)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
$aAlterTableItems[$sTable][] = "ADD INDEX (`$sField`)";
|
||||
}
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` ADD INDEX (`$sField`)";
|
||||
$aAlterTableItems[$sTable][$sField.'_ix'] = "ADD INDEX (`$sField`)";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check indexes
|
||||
foreach (self::DBGetIndexes($sClass) as $aColumns)
|
||||
{
|
||||
$sIndexId = implode('_', $aColumns);
|
||||
|
||||
if(!CMDBSource::HasIndex($sTable, $sIndexId, $aColumns))
|
||||
{
|
||||
$sColumns = "`".implode("`, `", $aColumns)."`";
|
||||
if (CMDBSource::HasIndex($sTable, $sIndexId))
|
||||
{
|
||||
$aErrors[$sClass]['*'][] = "Wrong index '$sIndexId' ($sColumns) in table '$sTable'";
|
||||
$aSugFix[$sClass]['*'][] = "ALTER TABLE `$sTable` DROP INDEX `$sIndexId`, ADD INDEX `$sIndexId` ($sColumns)";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aErrors[$sClass]['*'][] = "Missing index '$sIndexId' ($sColumns) in table '$sTable'";
|
||||
$aSugFix[$sClass]['*'][] = "ALTER TABLE `$sTable` ADD INDEX `$sIndexId` ($sColumns)";
|
||||
}
|
||||
if (array_key_exists($sTable, $aCreateTable))
|
||||
{
|
||||
$aCreateTableItems[$sTable][] = "INDEX `$sIndexId` ($sColumns)";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CMDBSource::HasIndex($sTable, $sIndexId))
|
||||
{
|
||||
$aAlterTableItems[$sTable][] = "DROP INDEX `$sIndexId`";
|
||||
}
|
||||
$aAlterTableItems[$sTable][] = "ADD INDEX `$sIndexId` ($sColumns)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find out unused columns
|
||||
//
|
||||
foreach($aTableInfo['Fields'] as $sField => $aFieldData)
|
||||
@@ -4623,9 +4528,14 @@ abstract class MetaModel
|
||||
self::$m_bLogWebService = false;
|
||||
}
|
||||
|
||||
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'));
|
||||
if (self::$m_oConfig->GetLogKPIDuration())
|
||||
{
|
||||
ExecutionKPI::EnableDuration();
|
||||
}
|
||||
if (self::$m_oConfig->GetLogKPIMemory())
|
||||
{
|
||||
ExecutionKPI::EnableMemory();
|
||||
}
|
||||
|
||||
self::$m_bTraceQueries = self::$m_oConfig->GetLogQueries();
|
||||
self::$m_bIndentQueries = self::$m_oConfig->Get('query_indentation_enabled');
|
||||
@@ -5142,12 +5052,6 @@ abstract class MetaModel
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* It is not recommended to use this function: call GetLinkClasses instead
|
||||
* Return classes having at least to external keys (thus too many classes as compared to GetLinkClasses)
|
||||
* The only difference with EnumLinkingClasses is the output format
|
||||
*/
|
||||
public static function EnumLinksClasses()
|
||||
{
|
||||
// Returns a flat array of classes having at least two external keys
|
||||
@@ -5170,11 +5074,6 @@ abstract class MetaModel
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
/**
|
||||
* It is not recommended to use this function: call GetLinkClasses instead
|
||||
* Return classes having at least to external keys (thus too many classes as compared to GetLinkClasses)
|
||||
* The only difference with EnumLinksClasses is the output format
|
||||
*/
|
||||
public static function EnumLinkingClasses($sClass = "")
|
||||
{
|
||||
// N-N links, array of sLinkClass => (array of sAttCode=>sClass)
|
||||
@@ -5211,38 +5110,6 @@ abstract class MetaModel
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function has two siblings that will be soon deprecated:
|
||||
* EnumLinkingClasses and EnumLinkClasses
|
||||
*
|
||||
* Using GetLinkClasses is the recommended way to determine if a class is
|
||||
* actually an N-N relation because it is based on the decision made by the
|
||||
* designer the data model
|
||||
*/
|
||||
public static function GetLinkClasses()
|
||||
{
|
||||
$aRet = array();
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
if (isset(self::$m_aClassParams[$sClass]["is_link"]))
|
||||
{
|
||||
if (self::$m_aClassParams[$sClass]["is_link"])
|
||||
{
|
||||
$aExtKeys = array();
|
||||
foreach (self::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$aExtKeys[$sAttCode] = $oAttDef->GetTargetClass();
|
||||
}
|
||||
}
|
||||
$aRet[$sClass] = $aExtKeys;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
public static function GetLinkLabel($sLinkClass, $sAttCode)
|
||||
{
|
||||
self::_check_subclass($sLinkClass);
|
||||
@@ -5312,27 +5179,18 @@ abstract class MetaModel
|
||||
$sEnvironment = MetaModel::GetEnvironmentId();
|
||||
}
|
||||
$aEntries = array();
|
||||
if (extension_loaded('apcu'))
|
||||
{
|
||||
// Beware: APCu behaves slightly differently from APC !!
|
||||
$aCacheUserData = @apc_cache_info();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aCacheUserData = @apc_cache_info('user');
|
||||
}
|
||||
$aCacheUserData = @apc_cache_info('user');
|
||||
if (is_array($aCacheUserData) && isset($aCacheUserData['cache_list']))
|
||||
{
|
||||
$sPrefix = 'itop-'.$sEnvironment.'-';
|
||||
|
||||
foreach($aCacheUserData['cache_list'] as $i => $aEntry)
|
||||
{
|
||||
$sEntryKey = array_key_exists('info', $aEntry) ? $aEntry['info'] : $aEntry['key'];
|
||||
$sEntryKey = $aEntry['info'];
|
||||
if (strpos($sEntryKey, $sPrefix) === 0)
|
||||
{
|
||||
$sCleanKey = substr($sEntryKey, strlen($sPrefix));
|
||||
$aEntries[$sCleanKey] = $aEntry;
|
||||
$aEntries[$sCleanKey]['info'] = $sEntryKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,261 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2013 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/>
|
||||
|
||||
|
||||
/**
|
||||
* Reflection API for the MetaModel (partial)
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class ModelReflection
|
||||
{
|
||||
abstract public function GetClassIcon($sClass, $bImgTag = true);
|
||||
abstract public function IsValidAttCode($sClass, $sAttCode);
|
||||
abstract public function GetName($sClass);
|
||||
abstract public function GetLabel($sClass, $sAttCodeEx);
|
||||
abstract public function GetValueLabel($sClass, $sAttCode, $sValue);
|
||||
abstract public function ListAttributes($sClass, $sScope = null);
|
||||
abstract public function GetAttributeProperty($sClass, $sAttCode, $sPropName, $default = null);
|
||||
abstract public function GetAllowedValues_att($sClass, $sAttCode);
|
||||
abstract public function HasChildrenClasses($sClass);
|
||||
abstract public function GetClasses($sCategories = '', $bExcludeLinks = false);
|
||||
abstract public function IsValidClass($sClass);
|
||||
abstract public function IsSameFamilyBranch($sClassA, $sClassB);
|
||||
abstract public function GetParentClass($sClass);
|
||||
abstract public function GetFiltersList($sClass);
|
||||
abstract public function IsValidFilterCode($sClass, $sFilterCode);
|
||||
|
||||
abstract public function GetQuery($sOQL);
|
||||
|
||||
abstract public function DictString($sStringCode, $sDefault = null, $bUserLanguageOnly = false);
|
||||
|
||||
public function DictFormat($sFormatCode /*, ... arguments ....*/)
|
||||
{
|
||||
$sLocalizedFormat = $this->DictString($sFormatCode);
|
||||
$aArguments = func_get_args();
|
||||
array_shift($aArguments);
|
||||
|
||||
if ($sLocalizedFormat == $sFormatCode)
|
||||
{
|
||||
// Make sure the information will be displayed (ex: an error occuring before the dictionary gets loaded)
|
||||
return $sFormatCode.' - '.implode(', ', $aArguments);
|
||||
}
|
||||
|
||||
return vsprintf($sLocalizedFormat, $aArguments);
|
||||
}
|
||||
|
||||
abstract public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '');
|
||||
}
|
||||
|
||||
abstract class QueryReflection
|
||||
{
|
||||
/**
|
||||
* Throws an exception in case of an invalid syntax
|
||||
*/
|
||||
abstract public function __construct($sOQL);
|
||||
|
||||
abstract public function GetClass();
|
||||
abstract public function GetClassAlias();
|
||||
}
|
||||
|
||||
|
||||
class ModelReflectionRuntime extends ModelReflection
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
public function GetClassIcon($sClass, $bImgTag = true)
|
||||
{
|
||||
return MetaModel::GetClassIcon($sClass, $bImgTag);
|
||||
}
|
||||
|
||||
public function IsValidAttCode($sClass, $sAttCode)
|
||||
{
|
||||
return MetaModel::IsValidAttCode($sClass, $sAttCode);
|
||||
}
|
||||
|
||||
public function GetName($sClass)
|
||||
{
|
||||
return MetaModel::GetName($sClass);
|
||||
}
|
||||
|
||||
public function GetLabel($sClass, $sAttCodeEx)
|
||||
{
|
||||
return MetaModel::GetLabel($sClass, $sAttCodeEx);
|
||||
}
|
||||
|
||||
public function GetValueLabel($sClass, $sAttCode, $sValue)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
return $oAttDef->GetValueLabel($sValue);
|
||||
}
|
||||
|
||||
public function ListAttributes($sClass, $sScope = null)
|
||||
{
|
||||
$aScope = null;
|
||||
if ($sScope != null)
|
||||
{
|
||||
$aScope = array();
|
||||
foreach (explode(',', $sScope) as $sScopeClass)
|
||||
{
|
||||
$aScope[] = trim($sScopeClass);
|
||||
}
|
||||
}
|
||||
$aAttributes = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
$sAttributeClass = get_class($oAttDef);
|
||||
if ($aScope != null)
|
||||
{
|
||||
foreach ($aScope as $sScopeClass)
|
||||
{
|
||||
if (($sAttributeClass == $sScopeClass) || is_subclass_of($sAttributeClass, $sScopeClass))
|
||||
{
|
||||
$aAttributes[$sAttCode] = $sAttributeClass;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttributes[$sAttCode] = $sAttributeClass;
|
||||
}
|
||||
}
|
||||
return $aAttributes;
|
||||
}
|
||||
|
||||
public function GetAttributeProperty($sClass, $sAttCode, $sPropName, $default = null)
|
||||
{
|
||||
$ret = $default;
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aParams = $oAttDef->GetParams();
|
||||
if (array_key_exists($sPropName, $aParams))
|
||||
{
|
||||
$ret = $aParams[$sPropName];
|
||||
}
|
||||
|
||||
if ($oAttDef instanceof AttributeHierarchicalKey)
|
||||
{
|
||||
if ($sPropName == 'targetclass')
|
||||
{
|
||||
$ret = $sClass;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function GetAllowedValues_att($sClass, $sAttCode)
|
||||
{
|
||||
return MetaModel::GetAllowedValues_att($sClass, $sAttCode);
|
||||
}
|
||||
|
||||
public function HasChildrenClasses($sClass)
|
||||
{
|
||||
return MetaModel::HasChildrenClasses($sClass);
|
||||
}
|
||||
|
||||
public function GetClasses($sCategories = '', $bExcludeLinks = false)
|
||||
{
|
||||
$aClasses = MetaModel::GetClasses($sCategories);
|
||||
if ($bExcludeLinks)
|
||||
{
|
||||
$aExcluded = MetaModel::GetLinkClasses();
|
||||
$aRes = array();
|
||||
foreach ($aClasses as $sClass)
|
||||
{
|
||||
if (!array_key_exists($sClass, $aExcluded))
|
||||
{
|
||||
$aRes[] = $sClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRes = $aClasses;
|
||||
}
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function IsValidClass($sClass)
|
||||
{
|
||||
return MetaModel::IsValidClass($sClass);
|
||||
}
|
||||
|
||||
public function IsSameFamilyBranch($sClassA, $sClassB)
|
||||
{
|
||||
return MetaModel::IsSameFamilyBranch($sClassA, $sClassB);
|
||||
}
|
||||
|
||||
public function GetParentClass($sClass)
|
||||
{
|
||||
return MetaModel::GetParentClass($sClass);
|
||||
}
|
||||
|
||||
public function GetFiltersList($sClass)
|
||||
{
|
||||
return MetaModel::GetFiltersList($sClass);
|
||||
}
|
||||
|
||||
public function IsValidFilterCode($sClass, $sFilterCode)
|
||||
{
|
||||
return MetaModel::IsValidFilterCode($sClass, $sFilterCode);
|
||||
}
|
||||
|
||||
public function GetQuery($sOQL)
|
||||
{
|
||||
return new QueryReflectionRuntime($sOQL);
|
||||
}
|
||||
|
||||
public function DictString($sStringCode, $sDefault = null, $bUserLanguageOnly = false)
|
||||
{
|
||||
return Dict::S($sStringCode, $sDefault, $bUserLanguageOnly);
|
||||
}
|
||||
|
||||
public function GetIconSelectionField($sCode, $sLabel = '', $defaultValue = '')
|
||||
{
|
||||
return new RunTimeIconSelectionField($sCode, $sLabel, $defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class QueryReflectionRuntime extends QueryReflection
|
||||
{
|
||||
protected $oFilter;
|
||||
|
||||
/**
|
||||
* throws an exception in case of a wrong syntax
|
||||
*/
|
||||
public function __construct($sOQL)
|
||||
{
|
||||
$this->oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
}
|
||||
|
||||
public function GetClass()
|
||||
{
|
||||
return $this->oFilter->GetClass();
|
||||
}
|
||||
|
||||
public function GetClassAlias()
|
||||
{
|
||||
return $this->oFilter->GetClassAlias();
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2013 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/>
|
||||
|
||||
|
||||
/**
|
||||
* Class iTopMutex
|
||||
* A class to serialize the execution of some code sections
|
||||
* Emulates the API of PECL Mutex class
|
||||
* Relies on MySQL locks because the API sem_get is not always present in the
|
||||
* installed PHP.
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class iTopMutex
|
||||
{
|
||||
protected $sName;
|
||||
protected $hDBLink;
|
||||
protected $bLocked; // Whether or not this instance of the Mutex is locked
|
||||
static protected $aAcquiredLocks = array(); // Number of instances of the Mutex, having the lock, in this page
|
||||
|
||||
public function __construct($sName)
|
||||
{
|
||||
// Compute the name of a lock for mysql
|
||||
// Note: the name is server-wide!!!
|
||||
$this->sName = 'itop.'.$sName;
|
||||
$this->bLocked = false; // Not yet locked
|
||||
|
||||
if (!array_key_exists($this->sName, self::$aAcquiredLocks))
|
||||
{
|
||||
self::$aAcquiredLocks[$this->sName] = 0;
|
||||
}
|
||||
|
||||
// It is a MUST to create a dedicated session each time a lock is required, because
|
||||
// using GET_LOCK anytime on the same session will RELEASE the current and unique session lock (known issue)
|
||||
$oConfig = utils::GetConfig();
|
||||
$this->InitMySQLSession($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd());
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->bLocked)
|
||||
{
|
||||
$this->Unlock();
|
||||
}
|
||||
mysqli_close($this->hDBLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire the mutex
|
||||
*/
|
||||
public function Lock()
|
||||
{
|
||||
if ($this->bLocked)
|
||||
{
|
||||
// Lock already acquired
|
||||
return;
|
||||
}
|
||||
if (self::$aAcquiredLocks[$this->sName] == 0)
|
||||
{
|
||||
do
|
||||
{
|
||||
$res = $this->QueryToScalar("SELECT GET_LOCK('".$this->sName."', 3600)");
|
||||
if (is_null($res))
|
||||
{
|
||||
throw new Exception("Failed to acquire the lock '".$this->sName."'");
|
||||
}
|
||||
// $res === '1' means I hold the lock
|
||||
// $res === '0' means it timed out
|
||||
}
|
||||
while ($res !== '1');
|
||||
}
|
||||
$this->bLocked = true;
|
||||
self::$aAcquiredLocks[$this->sName]++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to acquire the mutex
|
||||
* @returns bool True if the mutex is acquired, false if already locked elsewhere
|
||||
*/
|
||||
public function TryLock()
|
||||
{
|
||||
if ($this->bLocked)
|
||||
{
|
||||
return true; // Already acquired
|
||||
}
|
||||
if (self::$aAcquiredLocks[$this->sName] > 0)
|
||||
{
|
||||
self::$aAcquiredLocks[$this->sName]++;
|
||||
$this->bLocked = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
$res = $this->QueryToScalar("SELECT GET_LOCK('".$this->sName."', 0)");
|
||||
if (is_null($res))
|
||||
{
|
||||
throw new Exception("Failed to acquire the lock '".$this->sName."'");
|
||||
}
|
||||
// $res === '1' means I hold the lock
|
||||
// $res === '0' means it timed out
|
||||
if ($res === '1')
|
||||
{
|
||||
$this->bLocked = true;
|
||||
self::$aAcquiredLocks[$this->sName]++;
|
||||
}
|
||||
return ($res === '1');
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the mutex
|
||||
*/
|
||||
public function Unlock()
|
||||
{
|
||||
if (!$this->bLocked)
|
||||
{
|
||||
// ??? the lock is not acquired, exit
|
||||
return;
|
||||
}
|
||||
if (self::$aAcquiredLocks[$this->sName] == 0)
|
||||
{
|
||||
return; // Safety net
|
||||
}
|
||||
|
||||
if (self::$aAcquiredLocks[$this->sName] == 1)
|
||||
{
|
||||
$res = $this->QueryToScalar("SELECT RELEASE_LOCK('".$this->sName."')");
|
||||
}
|
||||
$this->bLocked = false;
|
||||
self::$aAcquiredLocks[$this->sName]--;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function InitMySQLSession($sHost, $sUser, $sPwd)
|
||||
{
|
||||
$aConnectInfo = explode(':', $sHost);
|
||||
if (count($aConnectInfo) > 1)
|
||||
{
|
||||
// Override the default port
|
||||
$sServer = $aConnectInfo[0];
|
||||
$iPort = $aConnectInfo[1];
|
||||
$this->hDBLink = @mysqli_connect($sServer, $sUser, $sPwd, '', $iPort);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->hDBLink = @mysqli_connect($sHost, $sUser, $sPwd);
|
||||
}
|
||||
|
||||
if (!$this->hDBLink)
|
||||
{
|
||||
throw new Exception("Could not connect to the DB server (host=$sHost, user=$sUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function QueryToScalar($sSql)
|
||||
{
|
||||
$result = mysqli_query($this->hDBLink, $sSql);
|
||||
if (!$result)
|
||||
{
|
||||
throw new Exception("Failed to issue MySQL query '".$sSql."': ".mysqli_error($this->hDBLink).' (mysql errno: '.mysqli_errno($this->hDBLink).')');
|
||||
}
|
||||
if ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH))
|
||||
{
|
||||
$res = $aRow[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
mysqli_free_result($result);
|
||||
throw new Exception("No result for query '".$sSql."'");
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
@@ -65,11 +65,8 @@ class OQLException extends CoreException
|
||||
|
||||
if (!is_null($this->m_aExpecting) && (count($this->m_aExpecting) > 0))
|
||||
{
|
||||
if (count($this->m_aExpecting) < 30)
|
||||
{
|
||||
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
|
||||
$sRet .= ", expecting ".htmlentities($sExpectations, ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
$sExpectations = '{'.implode(', ', $this->m_aExpecting).'}';
|
||||
$sRet .= ", expecting ".htmlentities($sExpectations, ENT_QUOTES, 'UTF-8');
|
||||
$sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting);
|
||||
if (strlen($sSuggest) > 0)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -127,38 +127,15 @@ class OqlJoinSpec
|
||||
}
|
||||
}
|
||||
|
||||
interface CheckableExpression
|
||||
class BinaryOqlExpression extends BinaryExpression
|
||||
{
|
||||
/**
|
||||
* Check the validity of the expression with regard to the data model
|
||||
* and the query in which it is used
|
||||
*
|
||||
* @param ModelReflection $oModelReflection MetaModel to consider
|
||||
* @param array $aAliases Aliases to class names (for the current query)
|
||||
* @param string $sSourceQuery For the reporting
|
||||
* @throws OqlNormalizeException
|
||||
*/
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery);
|
||||
}
|
||||
|
||||
class BinaryOqlExpression extends BinaryExpression implements CheckableExpression
|
||||
class ScalarOqlExpression extends ScalarExpression
|
||||
{
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
$this->m_oLeftExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
|
||||
$this->m_oRightExpr->Check($oModelReflection, $aAliases, $sSourceQuery);
|
||||
}
|
||||
}
|
||||
|
||||
class ScalarOqlExpression extends ScalarExpression implements CheckableExpression
|
||||
{
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
// a scalar is always fine
|
||||
}
|
||||
}
|
||||
|
||||
class FieldOqlExpression extends FieldExpression implements CheckableExpression
|
||||
class FieldOqlExpression extends FieldExpression
|
||||
{
|
||||
protected $m_oParent;
|
||||
protected $m_oName;
|
||||
@@ -184,84 +161,22 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression
|
||||
{
|
||||
return $this->m_oName;
|
||||
}
|
||||
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
$sClassAlias = $this->GetParent();
|
||||
$sFltCode = $this->GetName();
|
||||
if (empty($sClassAlias))
|
||||
{
|
||||
// Try to find an alias
|
||||
// Build an array of field => array of aliases
|
||||
$aFieldClasses = array();
|
||||
foreach($aAliases as $sAlias => $sReal)
|
||||
{
|
||||
foreach($oModelReflection->GetFiltersList($sReal) as $sAnFltCode)
|
||||
{
|
||||
$aFieldClasses[$sAnFltCode][] = $sAlias;
|
||||
}
|
||||
}
|
||||
if (!array_key_exists($sFltCode, $aFieldClasses))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), array_keys($aFieldClasses));
|
||||
}
|
||||
if (count($aFieldClasses[$sFltCode]) > 1)
|
||||
{
|
||||
throw new OqlNormalizeException('Ambiguous filter code', $sSourceQuery, $this->GetNameDetails());
|
||||
}
|
||||
$sClassAlias = $aFieldClasses[$sFltCode][0];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!array_key_exists($sClassAlias, $aAliases))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $this->GetParentDetails(), array_keys($aAliases));
|
||||
}
|
||||
$sClass = $aAliases[$sClassAlias];
|
||||
if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), $oModelReflection->GetFiltersList($sClass));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VariableOqlExpression extends VariableExpression implements CheckableExpression
|
||||
class VariableOqlExpression extends VariableExpression
|
||||
{
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
// a scalar is always fine
|
||||
}
|
||||
}
|
||||
|
||||
class ListOqlExpression extends ListExpression implements CheckableExpression
|
||||
class ListOqlExpression extends ListExpression
|
||||
{
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
foreach ($this->GetItems() as $oItemExpression)
|
||||
{
|
||||
$oItemExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FunctionOqlExpression extends FunctionExpression implements CheckableExpression
|
||||
class FunctionOqlExpression extends FunctionExpression
|
||||
{
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
foreach ($this->GetArgs() as $oArgExpression)
|
||||
{
|
||||
$oArgExpression->Check($oModelReflection, $aAliases, $sSourceQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IntervalOqlExpression extends IntervalExpression implements CheckableExpression
|
||||
class IntervalOqlExpression extends IntervalExpression
|
||||
{
|
||||
public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery)
|
||||
{
|
||||
// an interval is always fine (made of a scalar and unit)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class OqlQuery
|
||||
@@ -320,155 +235,6 @@ class OqlObjectQuery extends OqlQuery
|
||||
{
|
||||
return $this->m_oClassAlias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively check the validity of the expression with regard to the data model
|
||||
* and the query in which it is used
|
||||
*
|
||||
* @param ModelReflection $oModelReflection MetaModel to consider
|
||||
* @throws OqlNormalizeException
|
||||
*/
|
||||
public function Check(ModelReflection $oModelReflection, $sSourceQuery)
|
||||
{
|
||||
$sClass = $this->GetClass();
|
||||
$sClassAlias = $this->GetClassAlias();
|
||||
|
||||
if (!$oModelReflection->IsValidClass($sClass))
|
||||
{
|
||||
throw new UnknownClassOqlException($sSourceQuery, $this->GetClassDetails(), $oModelReflection->GetClasses());
|
||||
}
|
||||
|
||||
$aAliases = array($sClassAlias => $sClass);
|
||||
|
||||
$aJoinSpecs = $this->GetJoins();
|
||||
if (is_array($aJoinSpecs))
|
||||
{
|
||||
foreach ($aJoinSpecs as $oJoinSpec)
|
||||
{
|
||||
$sJoinClass = $oJoinSpec->GetClass();
|
||||
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
|
||||
if (!$oModelReflection->IsValidClass($sJoinClass))
|
||||
{
|
||||
throw new UnknownClassOqlException($sSourceQuery, $oJoinSpec->GetClassDetails(), $oModelReflection->GetClasses());
|
||||
}
|
||||
if (array_key_exists($sJoinClassAlias, $aAliases))
|
||||
{
|
||||
if ($sJoinClassAlias != $sJoinClass)
|
||||
{
|
||||
throw new OqlNormalizeException('Duplicate class alias', $sSourceQuery, $oJoinSpec->GetClassAliasDetails());
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new OqlNormalizeException('Duplicate class name', $sSourceQuery, $oJoinSpec->GetClassDetails());
|
||||
}
|
||||
}
|
||||
|
||||
// Assumption: ext key on the left only !!!
|
||||
// normalization should take care of this
|
||||
$oLeftField = $oJoinSpec->GetLeftField();
|
||||
$sFromClass = $oLeftField->GetParent();
|
||||
$sExtKeyAttCode = $oLeftField->GetName();
|
||||
|
||||
$oRightField = $oJoinSpec->GetRightField();
|
||||
$sToClass = $oRightField->GetParent();
|
||||
$sPKeyDescriptor = $oRightField->GetName();
|
||||
if ($sPKeyDescriptor != 'id')
|
||||
{
|
||||
throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sSourceQuery, $oRightField->GetNameDetails(), array('id'));
|
||||
}
|
||||
|
||||
$aAliases[$sJoinClassAlias] = $sJoinClass;
|
||||
|
||||
if (!array_key_exists($sFromClass, $aAliases))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sSourceQuery, $oLeftField->GetParentDetails(), array_keys($aAliases));
|
||||
}
|
||||
if (!array_key_exists($sToClass, $aAliases))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sSourceQuery, $oRightField->GetParentDetails(), array_keys($aAliases));
|
||||
}
|
||||
$aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], 'AttributeExternalKey');
|
||||
if (!array_key_exists($sExtKeyAttCode, $aExtKeys))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown external key in join condition (left expression)', $sSourceQuery, $oLeftField->GetNameDetails(), array_keys($aExtKeys));
|
||||
}
|
||||
|
||||
if ($sFromClass == $sJoinClassAlias)
|
||||
{
|
||||
$sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
|
||||
if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
|
||||
{
|
||||
throw new OqlNormalizeException("The joined class ($aAliases[$sFromClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$sOperator = $oJoinSpec->GetOperator();
|
||||
switch($sOperator)
|
||||
{
|
||||
case '=':
|
||||
$iOperatorCode = TREE_OPERATOR_EQUALS;
|
||||
break;
|
||||
case 'BELOW':
|
||||
$iOperatorCode = TREE_OPERATOR_BELOW;
|
||||
break;
|
||||
case 'BELOW_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_BELOW_STRICT;
|
||||
break;
|
||||
case 'NOT_BELOW':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_BELOW;
|
||||
break;
|
||||
case 'NOT_BELOW_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT;
|
||||
break;
|
||||
case 'ABOVE':
|
||||
$iOperatorCode = TREE_OPERATOR_ABOVE;
|
||||
break;
|
||||
case 'ABOVE_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_ABOVE_STRICT;
|
||||
break;
|
||||
case 'NOT_ABOVE':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE;
|
||||
break;
|
||||
case 'NOT_ABOVE_STRICT':
|
||||
$iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT;
|
||||
break;
|
||||
}
|
||||
$sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass');
|
||||
if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass))
|
||||
{
|
||||
throw new OqlNormalizeException("The joined class ($aAliases[$sToClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails());
|
||||
}
|
||||
$aAttList = $oModelReflection->ListAttributes($aAliases[$sFromClass]);
|
||||
$sAttType = $aAttList[$sExtKeyAttCode];
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, 'AttributeHierarchicalKey') && ($sAttType != 'AttributeHierarchicalKey'))
|
||||
{
|
||||
throw new OqlNormalizeException("The specified tree operator $sOperator is not applicable to the key", $sSourceQuery, $oLeftField->GetNameDetails());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the select information
|
||||
//
|
||||
$aSelected = array();
|
||||
foreach ($this->GetSelectedClasses() as $oClassDetails)
|
||||
{
|
||||
$sClassToSelect = $oClassDetails->GetValue();
|
||||
if (!array_key_exists($sClassToSelect, $aAliases))
|
||||
{
|
||||
throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $oClassDetails, array_keys($aAliases));
|
||||
}
|
||||
$aSelected[$sClassToSelect] = $aAliases[$sClassToSelect];
|
||||
}
|
||||
|
||||
// Check the condition tree
|
||||
//
|
||||
if ($this->m_oCondition instanceof Expression)
|
||||
{
|
||||
$this->m_oCondition->Check($oModelReflection, $aAliases, $sSourceQuery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -48,80 +48,6 @@ class ormCaseLog {
|
||||
return $this->m_sLog;
|
||||
}
|
||||
|
||||
public static function FromJSON($oJson)
|
||||
{
|
||||
if (!isset($oJson->items))
|
||||
{
|
||||
throw new Exception("Missing 'items' elements");
|
||||
}
|
||||
$oCaseLog = new ormCaseLog();
|
||||
foreach($oJson->items as $oItem)
|
||||
{
|
||||
$oCaseLog->AddLogEntryFromJSON($oItem);
|
||||
}
|
||||
return $oCaseLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a value that will be further JSON encoded
|
||||
*/
|
||||
public function GetForJSON()
|
||||
{
|
||||
$aEntries = array();
|
||||
$iPos = 0;
|
||||
for($index=count($this->m_aIndex)-1 ; $index >= 0 ; $index--)
|
||||
{
|
||||
$iPos += $this->m_aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']);
|
||||
$iPos += $this->m_aIndex[$index]['text_length'];
|
||||
|
||||
// Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
|
||||
// therefore we have changed the format. To preserve the compatibility with existing
|
||||
// installations of iTop, both format are allowed:
|
||||
// the 'date' item is either a DateTime object, or a unix timestamp
|
||||
if (is_int($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
// Unix timestamp
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'),$this->m_aIndex[$index]['date']);
|
||||
}
|
||||
elseif (is_object($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
if (version_compare(phpversion(), '5.3.0', '>='))
|
||||
{
|
||||
// DateTime
|
||||
$sDate = $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
|
||||
}
|
||||
else
|
||||
{
|
||||
// No Warning... but the date is unknown
|
||||
$sDate = '';
|
||||
}
|
||||
}
|
||||
$aEntries[] = array(
|
||||
'date' => $sDate,
|
||||
'user_login' => $this->m_aIndex[$index]['user_name'],
|
||||
'user_id' => $this->m_aIndex[$index]['user_id'],
|
||||
'message' => $sTextEntry
|
||||
);
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1))
|
||||
{
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
|
||||
$aEntries[] = array(
|
||||
'date' => '',
|
||||
'user_login' => '',
|
||||
'message' => $sTextEntry
|
||||
);
|
||||
}
|
||||
|
||||
// Order by ascending date
|
||||
$aRet = array('entries' => array_reverse($aEntries));
|
||||
return $aRet;
|
||||
}
|
||||
|
||||
public function GetIndex()
|
||||
{
|
||||
return $this->m_aIndex;
|
||||
@@ -304,62 +230,7 @@ class ormCaseLog {
|
||||
}
|
||||
$this->m_bModified = true;
|
||||
}
|
||||
|
||||
|
||||
public function AddLogEntryFromJSON($oJson)
|
||||
{
|
||||
$sText = isset($oJson->message) ? $oJson->message : '';
|
||||
|
||||
if (isset($oJson->user_id))
|
||||
{
|
||||
if (!UserRights::IsAdministrator())
|
||||
{
|
||||
throw new Exception("Only administrators can set the user id", RestResult::UNAUTHORIZED);
|
||||
}
|
||||
try
|
||||
{
|
||||
$oUser = RestUtils::FindObjectFromKey('User', $oJson->user_id);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new Exception('user_id: '.$e->getMessage(), $e->getCode());
|
||||
}
|
||||
$iUserId = $oUser->GetKey();
|
||||
$sOnBehalfOf = $oUser->GetFriendlyName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$iUserId = UserRights::GetUserId();
|
||||
$sOnBehalfOf = UserRights::GetUserFriendlyName();
|
||||
}
|
||||
|
||||
if (isset($oJson->date))
|
||||
{
|
||||
$oDate = new DateTime($oJson->date);
|
||||
$iDate = (int) $oDate->format('U');
|
||||
}
|
||||
else
|
||||
{
|
||||
$iDate = time();
|
||||
}
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'), $iDate);
|
||||
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
|
||||
$iSepLength = strlen($sSeparator);
|
||||
$iTextlength = strlen($sText);
|
||||
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
|
||||
$this->m_aIndex[] = array(
|
||||
'user_name' => $sOnBehalfOf,
|
||||
'user_id' => $iUserId,
|
||||
'date' => $iDate,
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
);
|
||||
|
||||
$this->m_bModified = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function GetModifiedEntry()
|
||||
{
|
||||
$sModifiedEntry = '';
|
||||
|
||||
@@ -117,32 +117,5 @@ class ormDocument
|
||||
{
|
||||
return "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode\">".$this->GetFileName()."</a>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an URL to download a document like an image (uses HTTP caching)
|
||||
* @return string
|
||||
*/
|
||||
public function GetDownloadURL($sClass, $Id, $sAttCode)
|
||||
{
|
||||
// Compute a signature to reset the cache anytime the data changes (this is acceptable if used only with icon files)
|
||||
$sSignature = md5($this->GetData());
|
||||
return utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=download_document&class=$sClass&id=$Id&field=$sAttCode&s=$sSignature&cache=86400";
|
||||
}
|
||||
|
||||
|
||||
public function IsPreviewAvailable()
|
||||
{
|
||||
$bRet = false;
|
||||
switch($this->GetMimeType())
|
||||
{
|
||||
case 'image/png':
|
||||
case 'image/jpg':
|
||||
case 'image/jpeg':
|
||||
case 'image/gif':
|
||||
$bRet = true;
|
||||
break;
|
||||
}
|
||||
return $bRet;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -66,6 +66,7 @@ class ormStopWatch
|
||||
{
|
||||
$this->aThresholds[$iPercent] = array(
|
||||
'deadline' => $tDeadline, // unix time (seconds)
|
||||
'passed' => $bPassed,
|
||||
'triggered' => $bTriggered,
|
||||
'overrun' => $iOverrun
|
||||
);
|
||||
@@ -121,16 +122,14 @@ class ormStopWatch
|
||||
}
|
||||
public function IsThresholdPassed($iPercent)
|
||||
{
|
||||
$bRet = false;
|
||||
if (array_key_exists($iPercent, $this->aThresholds))
|
||||
{
|
||||
$aThresholdData = $this->aThresholds[$iPercent];
|
||||
if (!is_null($aThresholdData['deadline']) && ($aThresholdData['deadline'] <= time()))
|
||||
{
|
||||
$bRet = true;
|
||||
}
|
||||
return $this->aThresholds[$iPercent]['passed'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return $bRet;
|
||||
}
|
||||
public function IsThresholdTriggered($iPercent)
|
||||
{
|
||||
@@ -163,7 +162,8 @@ class ormStopWatch
|
||||
}
|
||||
else
|
||||
{
|
||||
$aProperties['Elapsed'] = 'running <img src="../images/indicator.gif">';
|
||||
$iElapsedTemp = ''; //$this->ComputeDuration($oHostObject, $oAttDef, $this->iLastStart, time());
|
||||
$aProperties['Elapsed'] = $this->iTimeSpent.' + '.$iElapsedTemp.' s + <img src="../images/indicator.gif">';
|
||||
}
|
||||
|
||||
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
|
||||
@@ -183,7 +183,7 @@ class ormStopWatch
|
||||
}
|
||||
$aProperties[$iPercent.'%'] = $sThresholdDesc;
|
||||
}
|
||||
$sRes = "<TABLE>";
|
||||
$sRes = "<TABLE class=\"listResults\">";
|
||||
$sRes .= "<TBODY>";
|
||||
foreach ($aProperties as $sProperty => $sValue)
|
||||
{
|
||||
@@ -213,10 +213,6 @@ class ormStopWatch
|
||||
protected function ComputeDeadline($oObject, $oAttDef, $iStartTime, $iDurationSec)
|
||||
{
|
||||
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
|
||||
if ($sWorkingTimeComputer == '')
|
||||
{
|
||||
$sWorkingTimeComputer = class_exists('SLAComputation') ? 'SLAComputation' : 'DefaultWorkingTimeComputer';
|
||||
}
|
||||
$aCallSpec = array($sWorkingTimeComputer, '__construct');
|
||||
if (!is_callable($aCallSpec))
|
||||
{
|
||||
@@ -238,10 +234,6 @@ class ormStopWatch
|
||||
protected function ComputeDuration($oObject, $oAttDef, $iStartTime, $iEndTime)
|
||||
{
|
||||
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
|
||||
if ($sWorkingTimeComputer == '')
|
||||
{
|
||||
$sWorkingTimeComputer = class_exists('SLAComputation') ? 'SLAComputation' : 'DefaultWorkingTimeComputer';
|
||||
}
|
||||
$oComputer = new $sWorkingTimeComputer();
|
||||
$aCallSpec = array($oComputer, 'GetOpenDuration');
|
||||
if (!is_callable($aCallSpec))
|
||||
@@ -258,22 +250,17 @@ class ormStopWatch
|
||||
public function Reset($oObject, $oAttDef)
|
||||
{
|
||||
$this->iTimeSpent = 0;
|
||||
$this->iStopped = null;
|
||||
$this->iStarted = null;
|
||||
$this->iLastStart = null;
|
||||
$this->iStopped = null;
|
||||
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
$aThresholdData['passed'] = false;
|
||||
$aThresholdData['triggered'] = false;
|
||||
$aThresholdData['deadline'] = null;
|
||||
$aThresholdData['overrun'] = null;
|
||||
}
|
||||
|
||||
if (!is_null($this->iLastStart))
|
||||
{
|
||||
// Currently running... starting again from now!
|
||||
$this->iStarted = time();
|
||||
$this->iLastStart = time();
|
||||
$this->ComputeDeadlines($oObject, $oAttDef);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,12 +315,14 @@ class ormStopWatch
|
||||
if (is_null($aThresholdData['deadline']) || ($aThresholdData['deadline'] > time()))
|
||||
{
|
||||
// The threshold is in the future, reset
|
||||
$aThresholdData['passed'] = false;
|
||||
$aThresholdData['triggered'] = false;
|
||||
$aThresholdData['overrun'] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The new threshold is in the past
|
||||
$aThresholdData['passed'] = true;
|
||||
// Note: the overrun can be wrong, but the correct algorithm to compute
|
||||
// the overrun of a deadline in the past requires that the ormStopWatch keeps track of all its history!!!
|
||||
}
|
||||
@@ -371,6 +360,7 @@ class ormStopWatch
|
||||
$iOverrun = $this->ComputeDuration($oObject, $oAttDef, $aThresholdData['deadline'], time());
|
||||
$aThresholdData['overrun'] = $iOverrun;
|
||||
}
|
||||
$aThresholdData['passed'] = true;
|
||||
}
|
||||
$aThresholdData['deadline'] = null;
|
||||
}
|
||||
@@ -397,9 +387,9 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$aList = array();
|
||||
foreach (MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
$aList = array();
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeStopWatch)
|
||||
@@ -408,8 +398,8 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
{
|
||||
$iPercent = $aThresholdData['percent']; // could be different than the index !
|
||||
|
||||
$sNow = date('Y-m-d H:i:s');
|
||||
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < '$sNow'";
|
||||
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < NOW()";
|
||||
//echo $sExpression."<br/>\n";
|
||||
$oFilter = DBObjectSearch::FromOQL($sExpression);
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
|
||||
@@ -417,6 +407,7 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
|
||||
//echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."\n";
|
||||
|
||||
// Execute planned actions
|
||||
//
|
||||
@@ -425,6 +416,7 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
$sVerb = $aActionData['verb'];
|
||||
$aParams = $aActionData['params'];
|
||||
$sParams = implode(', ', $aParams);
|
||||
//echo "Calling: $sVerb($sParams)<br/>\n";
|
||||
$aCallSpec = array($oObj, $sVerb);
|
||||
call_user_func_array($aCallSpec, $aParams);
|
||||
}
|
||||
@@ -446,12 +438,12 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
// Activate any existing trigger
|
||||
//
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oTriggerSet = new DBObjectSet(
|
||||
$oSet = new DBObjectSet(
|
||||
DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"),
|
||||
array(), // order by
|
||||
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
|
||||
);
|
||||
while ($oTrigger = $oTriggerSet->Fetch())
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($oObj->ToArgs('this'));
|
||||
}
|
||||
@@ -462,6 +454,9 @@ class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
}
|
||||
|
||||
$iProcessed = count($aList);
|
||||
return "Triggered $iProcessed threshold(s):".implode(", ", $aList);
|
||||
return "Triggered $iProcessed threshold(s)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -36,19 +36,15 @@ class ObjectResult
|
||||
{
|
||||
public $code;
|
||||
public $message;
|
||||
public $class;
|
||||
public $key;
|
||||
public $fields;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public function __construct($sClass = null, $iId = null)
|
||||
public function __construct()
|
||||
{
|
||||
$this->code = RestResult::OK;
|
||||
$this->message = '';
|
||||
$this->class = $sClass;
|
||||
$this->key = $iId;
|
||||
$this->fields = array();
|
||||
}
|
||||
|
||||
@@ -148,10 +144,11 @@ class RestResultWithObjects extends RestResult
|
||||
*/
|
||||
public function AddObject($iCode, $sMessage, $oObject, $aFields)
|
||||
{
|
||||
$oObjRes = new ObjectResult(get_class($oObject), $oObject->GetKey());
|
||||
$oObjRes = new ObjectResult();
|
||||
$oObjRes->code = $iCode;
|
||||
$oObjRes->message = $sMessage;
|
||||
|
||||
$oObjRes->class = get_class($oObject);
|
||||
foreach ($aFields as $sAttCode)
|
||||
{
|
||||
$oObjRes->AddField($oObject, $sAttCode);
|
||||
@@ -236,10 +233,8 @@ class CoreServices implements iRestServiceProvider
|
||||
*/
|
||||
public function ListOperations($sVersion)
|
||||
{
|
||||
// 1.1 - In the reply, objects have a 'key' entry so that it is no more necessary to split class::key programmaticaly
|
||||
//
|
||||
$aOps = array();
|
||||
if (in_array($sVersion, array('1.0', '1.1')))
|
||||
if ($sVersion == '1.0')
|
||||
{
|
||||
$aOps[] = array(
|
||||
'verb' => 'core/create',
|
||||
|
||||
@@ -488,6 +488,8 @@ class SQLQuery
|
||||
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aGroupBy, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
{
|
||||
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
|
||||
|
||||
$aTranslationTable[$this->m_sTable]['*'] = $this->m_sTableAlias;
|
||||
|
||||
// Handle the various kinds of join (or first table in the list)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -66,86 +66,6 @@ abstract class UserRightsAddOnAPI
|
||||
abstract public function IsAdministrator($oUser);
|
||||
abstract public function IsPortalUser($oUser);
|
||||
abstract public function FlushPrivileges();
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
public function MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings = array(), $sAttCode = null)
|
||||
{
|
||||
if ($sAttCode == null)
|
||||
{
|
||||
$sAttCode = $this->GetOwnerOrganizationAttCode($sClass);
|
||||
}
|
||||
if (empty($sAttCode))
|
||||
{
|
||||
return $oFilter = new DBObjectSearch($sClass);
|
||||
}
|
||||
|
||||
$oExpression = new FieldExpression($sAttCode, $sClass);
|
||||
$oFilter = new DBObjectSearch($sClass);
|
||||
$oListExpr = ListExpression::FromScalars($aAllowedOrgs);
|
||||
|
||||
$oCondition = new BinaryExpression($oExpression, 'IN', $oListExpr);
|
||||
$oFilter->AddConditionExpression($oCondition);
|
||||
|
||||
if ($this->HasSharing())
|
||||
{
|
||||
if (($sAttCode == 'id') && isset($aSettings['bSearchMode']) && $aSettings['bSearchMode'])
|
||||
{
|
||||
// Querying organizations (or derived)
|
||||
// and the expected list of organizations will be used as a search criteria
|
||||
// Therefore the query can also return organization having objects shared with the allowed organizations
|
||||
//
|
||||
// 1) build the list of organizations sharing something with the allowed organizations
|
||||
// Organization <== sharing_org_id == SharedObject having org_id IN {user orgs}
|
||||
$oShareSearch = new DBObjectSearch('SharedObject');
|
||||
$oOrgField = new FieldExpression('org_id', 'SharedObject');
|
||||
$oShareSearch->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
|
||||
$oSearchSharers = new DBObjectSearch('Organization');
|
||||
$oSearchSharers->AllowAllData();
|
||||
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
|
||||
$aSharers = array();
|
||||
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
|
||||
{
|
||||
$aSharers[] = $aRow['id'];
|
||||
}
|
||||
// 2) Enlarge the overall results: ... OR id IN(id1, id2, id3)
|
||||
if (count($aSharers) > 0)
|
||||
{
|
||||
$oSharersList = ListExpression::FromScalars($aSharers);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oExpression, 'IN', $oSharersList));
|
||||
}
|
||||
}
|
||||
|
||||
$aShareProperties = SharedObject::GetSharedClassProperties($sClass);
|
||||
if ($aShareProperties)
|
||||
{
|
||||
$sShareClass = $aShareProperties['share_class'];
|
||||
$sShareAttCode = $aShareProperties['attcode'];
|
||||
|
||||
$oSearchShares = new DBObjectSearch($sShareClass);
|
||||
$oSearchShares->AllowAllData();
|
||||
|
||||
$sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization');
|
||||
$oOrgField = new FieldExpression('org_id', $sShareClass);
|
||||
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
$aShared = array();
|
||||
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
|
||||
{
|
||||
$aShared[] = $aRow[$sShareAttCode];
|
||||
}
|
||||
if (count($aShared) > 0)
|
||||
{
|
||||
$oObjId = new FieldExpression('id', $sClass);
|
||||
$oSharedIdList = ListExpression::FromScalars($aShared);
|
||||
$oFilter->MergeConditionExpression(new BinaryExpression($oObjId, 'IN', $oSharedIdList));
|
||||
}
|
||||
}
|
||||
} // if HasSharing
|
||||
|
||||
return $oFilter;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -220,7 +140,6 @@ abstract class User extends cmdbAbstractObject
|
||||
return $sLastName;
|
||||
}
|
||||
}
|
||||
return $this->Get('login');
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -370,9 +289,6 @@ abstract class UserInternal extends User
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// When set, this token allows for password reset
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reset_pwd_token", array("allowed_values"=>null, "sql"=>"reset_pwd_token", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('contactid', 'first_name', 'email', 'login', 'language', 'profile_list', 'allowed_org_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'first_name', 'last_name', 'login')); // Attributes to be displayed for a list
|
||||
@@ -380,47 +296,6 @@ abstract class UserInternal extends User
|
||||
MetaModel::Init_SetZListItems('standard_search', array('login', 'contactid')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('login', 'contactid')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with care!
|
||||
*/
|
||||
public function SetPassword($sNewPassword)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* The email recipient is the person who is allowed to regain control when the password gets lost
|
||||
* Throws an exception if the feature cannot be available
|
||||
*/
|
||||
public function GetResetPasswordEmail()
|
||||
{
|
||||
if (!MetaModel::IsValidAttCode(get_class($this), 'contactid'))
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NoContact'));
|
||||
}
|
||||
$iContactId = $this->Get('contactid');
|
||||
if ($iContactId == 0)
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NoContact'));
|
||||
}
|
||||
$oContact = MetaModel::GetObject('Contact', $iContactId);
|
||||
// Determine the email attribute (the first one will be our choice)
|
||||
foreach (MetaModel::ListAttributeDefs(get_class($oContact)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeEmailAddress)
|
||||
{
|
||||
$sEmailAttCode = $sAttCode;
|
||||
// we've got one, exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($sEmailAttCode))
|
||||
{
|
||||
throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmailAtt'));
|
||||
}
|
||||
$sRes = trim($oContact->Get($sEmailAttCode));
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -792,7 +667,6 @@ class UserRights
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static function IsActionAllowed($sClass, $iActionCode, /*dbObjectSet*/ $oInstanceSet = null, $oUser = null)
|
||||
{
|
||||
// When initializing, we need to let everything pass trough
|
||||
@@ -999,11 +873,6 @@ class UserRights
|
||||
}
|
||||
return $oUser;
|
||||
}
|
||||
|
||||
public static function MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings = array(), $sAttCode = null)
|
||||
{
|
||||
return self::$m_oAddOn->MakeSelectFilter($sClass, $aAllowedOrgs, $aSettings, $sAttCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1411,8 +1411,4 @@ a.summary, a.summary:hover {
|
||||
}
|
||||
.fg-menu a img {
|
||||
border: 0;
|
||||
}
|
||||
div.ui-dialog-header {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 7px;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
@CHARSET "UTF-8";
|
||||
body {
|
||||
background: #eee;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
#login-logo {
|
||||
margin-top: 150px;
|
||||
width: 300px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
background: #f6f6f1;
|
||||
height: 54px;
|
||||
border-top: 1px solid #000;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
border-bottom: 0;
|
||||
text-align: center;
|
||||
}
|
||||
#login-logo img {
|
||||
border: 0;
|
||||
}
|
||||
#login {
|
||||
width: 300px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #000;
|
||||
border-left: 1px solid #000;
|
||||
border-right: 1px solid #000;
|
||||
border-top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
#login table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#pwd, #user,#old_pwd, #new_pwd, #retype_new_pwd {
|
||||
width: 10em;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #1C94C4;
|
||||
font-size: 16pt;
|
||||
}
|
||||
.v-spacer {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 260 B |
|
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 251 B |
|
Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 104 B |
|
Before Width: | Height: | Size: 348 B After Width: | Height: | Size: 125 B |
|
Before Width: | Height: | Size: 207 B After Width: | Height: | Size: 105 B |
|
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 90 B |
|
Before Width: | Height: | Size: 328 B After Width: | Height: | Size: 129 B |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 6.2 KiB After Width: | Height: | Size: 4.3 KiB |
@@ -16,17 +16,36 @@
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @author David M. Gümbel <david.guembel@itomig.de>
|
||||
* Localized data
|
||||
*
|
||||
* @author Stephan Rosenke <stephan.rosenke@itomig.de>
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserLocal' => 'iTop-Benutzer',
|
||||
'Class:UserLocal+' => 'Benutzer von iTop authentifiziert',
|
||||
'Class:UserLocal/Attribute:password' => 'Passwort',
|
||||
'Class:UserLocal/Attribute:password+' => 'Benutzerpasswort',
|
||||
));
|
||||
?>
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 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/>
|
||||
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @traductor Miguel Turrubiates <miguel_tf@yahoo.com>
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:UserLocal' => 'Usuario de iTop',
|
||||
'Class:UserLocal+' => 'Usuario Autenticado vía iTop',
|
||||
'Class:UserLocal/Attribute:password' => 'Contraseña',
|
||||
'Class:UserLocal/Attribute:password+' => 'Contraseña',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
@@ -1,32 +1,51 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:UserLocal' => 'iTopユーザー',
|
||||
'Class:UserLocal+' => 'iTopローカル認証ユーザー',
|
||||
'Class:UserLocal/Attribute:password' => 'パスワード',
|
||||
'Class:UserLocal/Attribute:password+' => '認証文字列',
|
||||
));
|
||||
?>
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @author Hirofumi Kosaka <kosaka@rworks.jp>
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:UserLocal' => 'iTopユーザー', // 'iTop user',
|
||||
'Class:UserLocal+' => 'iTopローカル認証ユーザー', // 'User authentified by iTop',
|
||||
'Class:UserLocal/Attribute:password' => 'パスワード', // 'Password',
|
||||
'Class:UserLocal/Attribute:password+' => '認証文字列', // 'user authentication string',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -74,10 +74,7 @@ class UserLocal extends UserInternal
|
||||
|
||||
public function CanChangePassword()
|
||||
{
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// For now everyone can change their password..
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,47 +85,18 @@ class UserLocal extends UserInternal
|
||||
// Let's ask the password to compare the hashed values
|
||||
if ($oPassword->CheckPassword($sOldPassword))
|
||||
{
|
||||
$this->SetPassword($sNewPassword);
|
||||
$this->Set('password', $sNewPassword);
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$sUserString = CMDBChange::GetCurrentUserName();
|
||||
$oChange->Set("userinfo", $sUserString);
|
||||
$oChange->DBInsert();
|
||||
$this->DBUpdateTracked($oChange, true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with care!
|
||||
*/
|
||||
public function SetPassword($sNewPassword)
|
||||
{
|
||||
$this->Set('password', $sNewPassword);
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$sUserString = CMDBChange::GetCurrentUserName();
|
||||
$oChange->Set("userinfo", $sUserString);
|
||||
$oChange->DBInsert();
|
||||
$this->DBUpdateTracked($oChange, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
|
||||
* for the given attribute in the current state of the object
|
||||
* @param $sAttCode string $sAttCode The code of the attribute
|
||||
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
if (MetaModel::GetConfig()->Get('demo_mode'))
|
||||
{
|
||||
if (strpos('contactid,login,language,password,profile_list,allowed_org_list', $sAttCode) !== false)
|
||||
{
|
||||
// contactid and allowed_org_list are disabled to make sure the portal remains accessible
|
||||
$aReasons[] = 'Sorry, this attribute is read-only in the demonstration mode!';
|
||||
$iFlags |= OPT_ATT_READONLY;
|
||||
}
|
||||
}
|
||||
return $iFlags;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -17,16 +17,32 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
/**
|
||||
* @author Vladimir Shilov <shilow@ukr.net>
|
||||
|
||||
* Localized data
|
||||
*
|
||||
* @author Vladimir Shilov <shilow@ukr.net>
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>
|
||||
// Class:<class_name>/Attribute:<attribute_code>+
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'Class:UserLocal' => 'Пользователь iTop',
|
||||
'Class:UserLocal+' => 'Пользователь аутентифицированный iTop',
|
||||
'Class:UserLocal/Attribute:password' => 'Пароль',
|
||||
'Class:UserLocal/Attribute:password+' => 'строка аутентификации пользователя',
|
||||
));
|
||||
?>
|
||||
|
||||
?>
|
||||
|
||||
@@ -35,19 +35,6 @@
|
||||
<attribute id=""/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<indexes>
|
||||
<index id="1">
|
||||
<attributes>
|
||||
<attribute id="temp_id"/>
|
||||
</attributes>
|
||||
</index>
|
||||
<index id="2">
|
||||
<attributes>
|
||||
<attribute id="item_class"/>
|
||||
<attribute id="item_id"/>
|
||||
</attributes>
|
||||
</index>
|
||||
</indexes>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="expire" xsi:type="AttributeDateTime">
|
||||
|
||||
@@ -350,8 +350,7 @@ EOF
|
||||
$oPage->add('</span>');
|
||||
$oPage->add('<div style="clear:both"></div>');
|
||||
$sMaxUpload = $this->GetMaxUpload();
|
||||
$oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file"><span style="display:none;" id="attachment_loading"> <img src="../images/indicator.gif"></span> '.$sMaxUpload);
|
||||
$oPage->add_ready_script('$("#file").off("change.itop-attachments").on("change.itop-attachments", function() {ajaxFileUpload();});'); // Workaround for a Chrome 36 bug causing multiple (12!) times the same upload. See http://www.redmine.org/issues/17151
|
||||
$oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading"> <img src="../images/indicator.gif"></span> '.$sMaxUpload);
|
||||
$oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>');
|
||||
$oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
|
||||
$oPage->add('</fieldset>');
|
||||
|
||||
@@ -5292,46 +5292,7 @@
|
||||
<menu id="Change:Overview" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>0</rank>
|
||||
<parent>ChangeManagement</parent>
|
||||
<definition>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-ChangeManagementOverview-ChangeByType</title>
|
||||
<query>SELECT Change</query>
|
||||
<group_by>finalclass</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-ChangeManagementOverview-ChangeUnassigned</title>
|
||||
<query>SELECT Change WHERE status = 'new'</query>
|
||||
<menu>false</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-ChangeManagementOverview-ChangeWithOutage</title>
|
||||
<query>SELECT Change WHERE outage = 'yes'</query>
|
||||
<menu>false</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
<definition_file>overview.xml</definition_file>
|
||||
</menu>
|
||||
<menu id="NewChange" xsi:type="NewObjectMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
|
||||
41
datamodels/1.x/itop-change-mgmt-1.0.0/overview.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-ChangeManagementOverview-ChangeByType</title>
|
||||
<query>SELECT Change</query>
|
||||
<group_by>finalclass</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-ChangeManagementOverview-ChangeUnassigned</title>
|
||||
<query>SELECT Change WHERE status = 'new'</query>
|
||||
<menu>false</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-ChangeManagementOverview-ChangeWithOutage</title>
|
||||
<query>SELECT Change WHERE outage = 'yes'</query>
|
||||
<menu>false</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -2122,7 +2122,6 @@
|
||||
<attribute id="name"/>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="owner_name"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
@@ -2312,7 +2311,6 @@
|
||||
<attribute id="device_name"/>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="owner_name"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
@@ -3234,7 +3232,6 @@
|
||||
<attribute id="name"/>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="owner_name"/>
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
@@ -5934,7 +5931,7 @@
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByBars">
|
||||
@@ -5946,7 +5943,7 @@
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletGroupByTable">
|
||||
@@ -5968,7 +5965,7 @@
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell id="1">
|
||||
<cell>
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletHeaderDynamic">
|
||||
@@ -5990,7 +5987,7 @@
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<cell>
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="4" xsi:type="DashletGroupByPie">
|
||||
|
||||
@@ -222,7 +222,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:Contact/Attribute:ticket_list+' => 'Tiquetes relacionados con el contrato',
|
||||
'Class:Contact/Attribute:team_list' => 'Equipos',
|
||||
'Class:Contact/Attribute:team_list+' => 'Equipos a los que pertenece este contacto',
|
||||
'Class:Contact/Attribute:finalclass' => 'Clase',
|
||||
'Class:Contact/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Contact/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
@@ -442,7 +442,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:Software/Attribute:description+' => '',
|
||||
'Class:Software/Attribute:instance_list' => 'Instalaciones',
|
||||
'Class:Software/Attribute:instance_list+' => 'Instancias de este software',
|
||||
'Class:Software/Attribute:finalclass' => 'Clase',
|
||||
'Class:Software/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Software/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
@@ -530,7 +530,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:FunctionalCI/Attribute:contract_list+' => 'Contratos soportando este I.C.s',
|
||||
'Class:FunctionalCI/Attribute:ticket_list' => 'Tiquetes',
|
||||
'Class:FunctionalCI/Attribute:ticket_list+' => 'Tiquetes relacionados con este I.C.s',
|
||||
'Class:FunctionalCI/Attribute:finalclass' => 'Clase',
|
||||
'Class:FunctionalCI/Attribute:finalclass' => 'Tipo',
|
||||
'Class:FunctionalCI/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
|
||||
@@ -1133,46 +1133,7 @@
|
||||
<menu id="Incident:Overview" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>0</rank>
|
||||
<parent>IncidentManagement</parent>
|
||||
<definition>
|
||||
<title>UI:IncidentMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-IncidentManagementOverview-IncidentByService</title>
|
||||
<query>SELECT Incident</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<rank>0</rank>
|
||||
<title>UI-IncidentManagementOverview-IncidentByPriority</title>
|
||||
<query>SELECT Incident</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-IncidentManagementOverview-IncidentUnassigned</title>
|
||||
<query>SELECT Incident WHERE status IN ("new", "escalated_tto")</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
<definition_file>incident-dashboard.xml</definition_file>
|
||||
</menu>
|
||||
<menu id="NewIncident" xsi:type="NewObjectMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<title>UI:IncidentMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell>
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-IncidentManagementOverview-IncidentByService</title>
|
||||
<query>SELECT Incident</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell>
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<rank>0</rank>
|
||||
<title>UI-IncidentManagementOverview-IncidentByPriority</title>
|
||||
<query>SELECT Incident</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell>
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-IncidentManagementOverview-IncidentUnassigned</title>
|
||||
<query>SELECT Incident WHERE status IN ("new", "escalated_tto")</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -751,47 +751,7 @@
|
||||
<menu id="Problem:Overview" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>0</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<definition>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-ProblemManagementOverview-ProblemByService</title>
|
||||
<query>SELECT Problem</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<rank>0</rank>
|
||||
<title>UI-ProblemManagementOverview-ProblemByPriority</title>
|
||||
<query>SELECT Problem</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-ProblemManagementOverview-ProblemUnassigned</title>
|
||||
<query>SELECT Problem WHERE status IN ("new")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
<definition_file>overview.xml</definition_file>
|
||||
</menu>
|
||||
<menu id="NewProblem" xsi:type="NewObjectMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
|
||||
43
datamodels/1.x/itop-problem-mgmt-1.0.0/overview.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-ProblemManagementOverview-ProblemByService</title>
|
||||
<query>SELECT Problem</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<rank>0</rank>
|
||||
<title>UI-ProblemManagementOverview-ProblemByPriority</title>
|
||||
<query>SELECT Problem</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-ProblemManagementOverview-ProblemUnassigned</title>
|
||||
<query>SELECT Problem WHERE status IN ("new")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
|
||||
@@ -1,25 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<constants>
|
||||
<constant id="PORTAL_POWER_USER_PROFILE" xsi:type="string" _delta="define"><![CDATA[Portal power user]]></constant>
|
||||
<constant id="PORTAL_SERVICECATEGORY_QUERY" xsi:type="string" _delta="define"><![CDATA[SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id]]></constant>
|
||||
<constant id="PORTAL_SERVICE_SUBCATEGORY_QUERY" xsi:type="string" _delta="define"><![CDATA[SELECT ServiceSubcategory WHERE service_id = :svc_id]]></constant>
|
||||
<constant id="PORTAL_VALIDATE_SERVICECATEGORY_QUERY" xsi:type="string" _delta="define"><![CDATA[SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id AND s.id = :id]]></constant>
|
||||
<constant id="PORTAL_VALIDATE_SERVICESUBCATEGORY_QUERY" xsi:type="string" _delta="define"><![CDATA[SELECT ServiceSubcategory AS Sub JOIN Service AS Svc ON Sub.service_id = Svc.id WHERE Sub.id=:id]]></constant>
|
||||
<constant id="PORTAL_ALL_PARAMS" xsi:type="string" _delta="define"><![CDATA[from_service_id,org_id,caller_id,service_id,servicesubcategory_id,title,description,impact,urgency,workgroup_id,moreinfo,caller_id,start_date,end_date,duration,impact_duration]]></constant>
|
||||
<constant id="PORTAL_SET_TYPE_FROM" xsi:type="string" _delta="define"><![CDATA[]]></constant>
|
||||
<constant id="PORTAL_TYPE_TO_CLASS" xsi:type="string" _delta="define"><![CDATA[]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_PUBLIC_LOG" xsi:type="string" _delta="define"><![CDATA[ticket_log]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_USER_COMMENT" xsi:type="string" _delta="define"><![CDATA[user_commment]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_FORM_ATTRIBUTES" xsi:type="string" _delta="define"><![CDATA[title,description,impact,urgency,workgroup_id,ticket_log]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_TYPE" xsi:type="string" _delta="define"><![CDATA[]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_LIST_ZLIST" xsi:type="string" _delta="define"><![CDATA[finalclass,title,start_date,status,servicesubcategory_id,priority,caller_id]]></constant>
|
||||
<constant id="PORTAL_TICKETS_SEARCH_CRITERIA" xsi:type="string" _delta="define"><![CDATA[ref,start_date,close_date,service_id,caller_id]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_CLOSED_ZLIST" xsi:type="string" _delta="define"><![CDATA[title,start_date,close_date,servicesubcategory_id]]></constant>
|
||||
<constant id="PORTAL_USERREQUEST_DETAILS_ZLIST" xsi:type="string" _delta="define"><![CDATA[{"col:left":["ref","caller_id","servicesubcategory_id","title","description","solution"],"col:right":["status","priority","start_date","resolution_date","last_update","agent_id"]}]]></constant>
|
||||
<constant id="PORTAL_TICKETS_SEARCH_FILTER_service_id" xsi:type="string" _delta="define"><![CDATA[SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id]]></constant>
|
||||
<constant id="PORTAL_TICKETS_SEARCH_FILTER_caller_id" xsi:type="string" _delta="define"><![CDATA[SELECT Person WHERE org_id = :org_id]]></constant>
|
||||
</constants>
|
||||
<classes>
|
||||
<class id="UserRequest" _delta="define">
|
||||
<parent>ResponseTicket</parent>
|
||||
@@ -1113,46 +1093,7 @@
|
||||
<menu id="UserRequest:Overview" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>0</rank>
|
||||
<parent>RequestManagement</parent>
|
||||
<definition>
|
||||
<title>UI:RequestMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-RequestManagementOverview-RequestByService</title>
|
||||
<query>SELECT UserRequest</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<rank>0</rank>
|
||||
<title>UI-RequestManagementOverview-RequestByPriority</title>
|
||||
<query>SELECT UserRequest</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-RequestManagementOverview-RequestUnassigned</title>
|
||||
<query>SELECT UserRequest WHERE status IN ("new", "escalated_tto")</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
<definition_file>request-dashboard.xml</definition_file>
|
||||
</menu>
|
||||
<menu id="NewUserRequest" xsi:type="NewObjectMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
|
||||
@@ -1 +1,36 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
define('PORTAL_POWER_USER_PROFILE', 'Portal power user');
|
||||
|
||||
define('PORTAL_SERVICECATEGORY_QUERY', 'SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id');
|
||||
define('PORTAL_SERVICE_SUBCATEGORY_QUERY', 'SELECT ServiceSubcategory WHERE service_id = :svc_id');
|
||||
|
||||
define('PORTAL_VALIDATE_SERVICECATEGORY_QUERY', 'SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id = :org_id AND s.id = :id');
|
||||
define('PORTAL_VALIDATE_SERVICESUBCATEGORY_QUERY', 'SELECT ServiceSubcategory AS Sub JOIN Service AS Svc ON Sub.service_id = Svc.id WHERE Sub.id=:id');
|
||||
|
||||
define('PORTAL_ALL_PARAMS', 'from_service_id,org_id,caller_id,service_id,servicesubcategory_id,title,description,impact,urgency,workgroup_id,moreinfo,caller_id,start_date,end_date,duration,impact_duration');
|
||||
|
||||
define('PORTAL_ATTCODE_LOG', 'ticket_log');
|
||||
define('PORTAL_ATTCODE_COMMENT', 'user_commment');
|
||||
define('PORTAL_REQUEST_FORM_ATTRIBUTES', 'title,description,impact,urgency,workgroup_id');
|
||||
|
||||
define('PORTAL_ATTCODE_TYPE', ''); // optional if the type has to be set
|
||||
define('PORTAL_SET_TYPE_FROM', ''); // The attribute to get the type from (Subcategory)
|
||||
|
||||
?>
|
||||
|
||||
41
datamodels/1.x/itop-request-mgmt-1.0.0/request-dashboard.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<title>UI:RequestMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<rank>0</rank>
|
||||
<title>UI-RequestManagementOverview-RequestByService</title>
|
||||
<query>SELECT UserRequest</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<rank>0</rank>
|
||||
<title>UI-RequestManagementOverview-RequestByPriority</title>
|
||||
<query>SELECT UserRequest</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<rank>0</rank>
|
||||
<title>UI-RequestManagementOverview-RequestUnassigned</title>
|
||||
<query>SELECT UserRequest WHERE status IN ("new", "escalated_tto")</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -2034,32 +2034,7 @@
|
||||
<menu id="Service:Overview" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>0</rank>
|
||||
<parent>ServiceManagement</parent>
|
||||
<definition>
|
||||
<title>UI:ServiceMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI-ServiceManagementOverview-CustomerContractToRenew</title>
|
||||
<query>SELECT CustomerContract AS c WHERE c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI-ServiceManagementOverview-ProviderContractToRenew</title>
|
||||
<query>SELECT ProviderContract AS c WHERE c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
<definition_file>overview.xml</definition_file>
|
||||
</menu>
|
||||
<menu id="ProviderContract" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
|
||||
@@ -106,7 +106,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:Contract/Attribute:document_list+' => 'Documentos adjuntos al contrato',
|
||||
'Class:Contract/Attribute:ci_list' => 'I.C.s',
|
||||
'Class:Contract/Attribute:ci_list+' => 'I.C.s soportados por el contrato',
|
||||
'Class:Contract/Attribute:finalclass' => 'Clase',
|
||||
'Class:Contract/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Contract/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
|
||||
27
datamodels/1.x/itop-service-mgmt-1.0.0/overview.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<title>UI:ServiceMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell id="1">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI-ServiceManagementOverview-CustomerContractToRenew</title>
|
||||
<query>SELECT CustomerContract AS c WHERE c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>2</rank>
|
||||
<dashlets>
|
||||
<dashlet id="2" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI-ServiceManagementOverview-ProviderContractToRenew</title>
|
||||
<query>SELECT ProviderContract AS c WHERE c.end_date < DATE_ADD(NOW(), INTERVAL 30 DAY)</query>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -55,7 +55,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:Ticket/Attribute:ci_list+' => 'I.C.s afectados por el incidente',
|
||||
'Class:Ticket/Attribute:contact_list' => 'Contactos',
|
||||
'Class:Ticket/Attribute:contact_list+' => 'Equipos y personas envueltas',
|
||||
'Class:Ticket/Attribute:finalclass' => 'Clase',
|
||||
'Class:Ticket/Attribute:finalclass' => 'Tipo',
|
||||
'Class:Ticket/Attribute:finalclass+' => '',
|
||||
));
|
||||
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
|
||||
<menus>
|
||||
<menu id="WelcomeMenu" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>10</rank>
|
||||
</menu>
|
||||
<menu id="WelcomeMenuPage" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>10</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
<definition>
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletHeaderDynamic">
|
||||
<rank>0</rank>
|
||||
<title>UI:ConfigurationManagementMenu</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/database.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:AllConfigItems</subtitle>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>status</group_by>
|
||||
<values>implementation,production,obsolete</values>
|
||||
</dashlet>
|
||||
<dashlet id="2" xsi:type="DashletBadge">
|
||||
<rank>1</rank>
|
||||
<class>BusinessProcess</class>
|
||||
</dashlet>
|
||||
<dashlet id="3" xsi:type="DashletBadge">
|
||||
<rank>2</rank>
|
||||
<class>Contact</class>
|
||||
</dashlet>
|
||||
<dashlet id="4" xsi:type="DashletBadge">
|
||||
<rank>3</rank>
|
||||
<class>Location</class>
|
||||
</dashlet>
|
||||
<dashlet id="5" xsi:type="DashletBadge">
|
||||
<rank>4</rank>
|
||||
<class>Server</class>
|
||||
</dashlet>
|
||||
<dashlet id="6" xsi:type="DashletBadge">
|
||||
<rank>5</rank>
|
||||
<class>DatabaseInstance</class>
|
||||
</dashlet>
|
||||
<dashlet id="7" xsi:type="DashletBadge">
|
||||
<rank>6</rank>
|
||||
<class>NetworkDevice</class>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="1">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="8" xsi:type="DashletHeaderDynamic">
|
||||
<rank>0</rank>
|
||||
<title>Menu:RequestManagement</title>
|
||||
<icon>itop-request-mgmt-1.0.0/images/user-request-deadline.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:AllOpenRequests</subtitle>
|
||||
<query>SELECT UserRequest WHERE status != "closed"</query>
|
||||
<group_by>status</group_by>
|
||||
<values>new,assigned,escalated_tto,escalated_ttr,resolved</values>
|
||||
</dashlet>
|
||||
<dashlet id="9" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI:WelcomeMenu:MyCalls</title>
|
||||
<query>SELECT UserRequest AS i WHERE i.caller_id = :current_contact_id AND status NOT IN ("closed", "resolved")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell id="2">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="10" xsi:type="DashletHeaderDynamic">
|
||||
<rank>0</rank>
|
||||
<title>Menu:IncidentManagement</title>
|
||||
<icon>itop-incident-mgmt-1.0.0/images/incident-escalated.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:OpenIncidents</subtitle>
|
||||
<query>SELECT Incident WHERE status != "closed"</query>
|
||||
<group_by>status</group_by>
|
||||
<values>new,assigned,escalated_tto,escalated_ttr,resolved</values>
|
||||
</dashlet>
|
||||
<dashlet id="11" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI:WelcomeMenu:MyIncidents</title>
|
||||
<query>SELECT Incident AS i WHERE i.agent_id = :current_contact_id AND status NOT IN ("closed", "resolved")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
<menu id="MyShortcuts" xsi:type="ShortcutContainerMenuNode" _delta="define">
|
||||
<rank>20</rank>
|
||||
<parent>WelcomeMenu</parent>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
@@ -44,6 +44,11 @@ class ItopWelcome extends ModuleHandlerAPI
|
||||
{
|
||||
public static function OnMenuCreation()
|
||||
{
|
||||
$oWelcomeMenu = new MenuGroup('WelcomeMenu', 10 /* fRank */);
|
||||
new DashboardMenuNode('WelcomeMenuPage', dirname(__FILE__).'/welcome_menu.xml', $oWelcomeMenu->GetIndex() /* oParent */, 10 /* fRank */);
|
||||
|
||||
new ShortcutContainerMenuNode('MyShortcuts', $oWelcomeMenu->GetIndex(), 20 /* fRank */);
|
||||
|
||||
$oToolsMenu = new MenuGroup('DataAdministration', 70 /* fRank */, 'Organization', UR_ACTION_MODIFY, UR_ALLOWED_YES|UR_ALLOWED_DEPENDS);
|
||||
new WebPageMenuNode('CSVImportMenu', utils::GetAbsoluteUrlAppRoot().'pages/csvimport.php', $oToolsMenu->GetIndex(), 1 /* fRank */);
|
||||
|
||||
@@ -53,7 +58,7 @@ class ItopWelcome extends ModuleHandlerAPI
|
||||
$oAdminMenu = new MenuGroup('AdminTools', 80 /* fRank */);
|
||||
new OQLMenuNode('UserAccountsMenu', 'SELECT User', $oAdminMenu->GetIndex(), 1 /* fRank */);
|
||||
new OQLMenuNode('ProfilesMenu', 'SELECT URP_Profiles', $oAdminMenu->GetIndex(), 2 /* fRank */);
|
||||
new WebPageMenuNode('NotificationsMenu', utils::GetAbsoluteUrlAppRoot().'pages/notifications.php', $oAdminMenu->GetIndex(), 3 /* fRank */);
|
||||
new TemplateMenuNode('NotificationsMenu', APPROOT.'application/templates/notifications_menu.html', $oAdminMenu->GetIndex(), 3 /* fRank */);
|
||||
new OQLMenuNode('AuditCategories', 'SELECT AuditCategory', $oAdminMenu->GetIndex(), 4 /* fRank */);
|
||||
new WebPageMenuNode('RunQueriesMenu', utils::GetAbsoluteUrlAppRoot().'pages/run_query.php', $oAdminMenu->GetIndex(), 8 /* fRank */);
|
||||
new OQLMenuNode('QueryMenu', 'SELECT Query', $oAdminMenu->GetIndex(), 8.5 /* fRank */);
|
||||
@@ -71,16 +76,16 @@ class MyPortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
if (strpos(MetaModel::GetConfig()->Get('portal_tickets'), $sClass) !== false)
|
||||
switch($sClass)
|
||||
{
|
||||
case 'UserRequest':
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = '';
|
||||
}
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ SetupWebPage::AddModule(
|
||||
//
|
||||
'datamodel' => array(
|
||||
'main.itop-welcome-itil.php',
|
||||
'model.itop-welcome-itil.php',
|
||||
),
|
||||
'webservice' => array(
|
||||
//'webservices.itop-welcome-itil.php',
|
||||
|
||||
86
datamodels/1.x/itop-welcome-itil/welcome_menu.xml
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell>
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="1" xsi:type="DashletHeaderDynamic">
|
||||
<rank>0</rank>
|
||||
<title>UI:ConfigurationManagementMenu</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/database.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:AllConfigItems</subtitle>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>status</group_by>
|
||||
<values>implementation,production,obsolete</values>
|
||||
</dashlet>
|
||||
<dashlet id="2" xsi:type="DashletBadge">
|
||||
<rank>1</rank>
|
||||
<class>BusinessProcess</class>
|
||||
</dashlet>
|
||||
<dashlet id="3" xsi:type="DashletBadge">
|
||||
<rank>2</rank>
|
||||
<class>Contact</class>
|
||||
</dashlet>
|
||||
<dashlet id="4" xsi:type="DashletBadge">
|
||||
<rank>3</rank>
|
||||
<class>Location</class>
|
||||
</dashlet>
|
||||
<dashlet id="5" xsi:type="DashletBadge">
|
||||
<rank>4</rank>
|
||||
<class>Server</class>
|
||||
</dashlet>
|
||||
<dashlet id="6" xsi:type="DashletBadge">
|
||||
<rank>5</rank>
|
||||
<class>DatabaseInstance</class>
|
||||
</dashlet>
|
||||
<dashlet id="7" xsi:type="DashletBadge">
|
||||
<rank>6</rank>
|
||||
<class>NetworkDevice</class>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell>
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="8" xsi:type="DashletHeaderDynamic">
|
||||
<rank>0</rank>
|
||||
<title>Menu:RequestManagement</title>
|
||||
<icon>itop-request-mgmt-1.0.0/images/user-request-deadline.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:AllOpenRequests</subtitle>
|
||||
<query>SELECT UserRequest WHERE status != "closed"</query>
|
||||
<group_by>status</group_by>
|
||||
<values>new,assigned,escalated_tto,escalated_ttr,resolved</values>
|
||||
</dashlet>
|
||||
<dashlet id="9" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI:WelcomeMenu:MyCalls</title>
|
||||
<query>SELECT UserRequest AS i WHERE i.caller_id = :current_contact_id AND status NOT IN ("closed", "resolved")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
<cell>
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="10" xsi:type="DashletHeaderDynamic">
|
||||
<rank>0</rank>
|
||||
<title>Menu:IncidentManagement</title>
|
||||
<icon>itop-incident-mgmt-1.0.0/images/incident-escalated.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:OpenIncidents</subtitle>
|
||||
<query>SELECT Incident WHERE status != "closed"</query>
|
||||
<group_by>status</group_by>
|
||||
<values>new,assigned,escalated_tto,escalated_ttr,resolved</values>
|
||||
</dashlet>
|
||||
<dashlet id="11" xsi:type="DashletObjectList">
|
||||
<rank>1</rank>
|
||||
<title>UI:WelcomeMenu:MyIncidents</title>
|
||||
<query>SELECT Incident AS i WHERE i.agent_id = :current_contact_id AND status NOT IN ("closed", "resolved")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,9 +20,8 @@
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @traductor Miguel Turrubiates <miguel_tf@yahoo.com>
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,9 +20,8 @@
|
||||
/**
|
||||
* Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
* @traductor Miguel Turrubiates <miguel_tf@yahoo.com>
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserLDAP' => 'Usuário externo via LDAP',
|
||||
'Class:UserLDAP' => 'Usuário externo',
|
||||
'Class:UserLDAP+' => '',
|
||||
'Class:UserLDAP/Attribute:password' => 'Senha',
|
||||
'Class:UserLDAP/Attribute:password+' => '',
|
||||
|
||||