Compare commits

..

1 Commits

Author SHA1 Message Date
Romain Quetiez
a55e337757 Created tag 2.0.1
SVN:2.0.1[2760]
2013-05-22 12:34:59 +00:00
296 changed files with 21297 additions and 20971 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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";

View File

@@ -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');

View File

@@ -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;
}

View File

@@ -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 = '&nbsp;<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).'&nbsp;'.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>&nbsp;";
$iFieldSize = $oAttDef->GetMaxSize();
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
$sHtml .= "<label>".MetaModel::GetFilterLabel($sClassName, $sFilterCode).":</label>&nbsp;";
$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>&nbsp;&nbsp;&nbsp;&nbsp;\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)."&nbsp;".Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), MetaModel::GetName($sClass))."</h1>\n");
$oP->add("<h1>".MetaModel::GetClassIcon($sClass)."&nbsp;".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");
}
}
}

View File

@@ -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']);

View File

@@ -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++)
{

File diff suppressed because it is too large Load Diff

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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(' ', '&nbsp;', 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.'">&nbsp;Other:</label>&nbsp;<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(' ', '&nbsp;', 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.'">&nbsp;Other:</label>&nbsp;<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);

View File

@@ -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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<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)

View File

@@ -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>&nbsp;&nbsp;<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>&nbsp;&nbsp;<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')."\" />&nbsp;&nbsp;<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
?>

View File

@@ -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)
{

View File

@@ -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});");

View File

@@ -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>&nbsp;<input class=\"textSearch\" name=\"$sPrefix$sFieldName\" value=\"$sSanitizedValue\"/>\n");
$this->add("<label>".MetaModel::GetFilterLabel($sClass, $sAttSpec).":</label>&nbsp;<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)
{

View File

@@ -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;
}

View File

@@ -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');

View 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>&nbsp;</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>

View File

@@ -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);");
}

View File

@@ -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>&nbsp;&nbsp;<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);
}
}
}
}
}

View File

@@ -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

View File

@@ -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').'"/>&nbsp;<span class="form_validation" id="v_'.$this->iId.'"></span><br/>';

View File

@@ -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 '&nbsp;<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;
}
}
}
?>
?>

View File

@@ -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\">");
}
}

View File

@@ -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

View File

@@ -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())));

View File

@@ -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()
{

View File

@@ -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);
}
?>

View File

@@ -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
//

View File

@@ -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();

View File

@@ -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))
{

View File

@@ -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()
//{

View File

@@ -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;

View File

@@ -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);
}
/**

View File

@@ -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;

View File

@@ -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
{

View File

@@ -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()

View File

@@ -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'))
{

View File

@@ -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)));
}

View File

@@ -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;
}
}
?>

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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)
{

View File

@@ -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);
}
}
}
?>

View File

@@ -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 = '';

View File

@@ -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;
}
}
?>

View File

@@ -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)";
}
}
?>

View File

@@ -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',

View File

@@ -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)

View File

@@ -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);
}
}
/**

View File

@@ -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;
}
}

View File

@@ -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;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 B

After

Width:  |  Height:  |  Size: 125 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

File diff suppressed because one or more lines are too long

View File

@@ -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',
));
?>
?>

View File

@@ -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&ntilde;a',
'Class:UserLocal/Attribute:password+' => 'Contrase&ntilde;a',
));
?>

View File

@@ -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',
));
?>

View File

@@ -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;
}
}
?>

View File

@@ -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+' => 'строка аутентификации пользователя',
));
?>
?>

View File

@@ -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">

View File

@@ -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">&nbsp;<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">&nbsp;<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>');

View File

@@ -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>

View 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>

View File

@@ -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">

View File

@@ -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+' => '',
));

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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>

View File

@@ -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>

View File

@@ -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)
?>

View 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>

View File

@@ -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 &lt; 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 &lt; 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>

View File

@@ -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+' => '',
));

View 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 &lt; 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 &lt; DATE_ADD(NOW(), INTERVAL 30 DAY)</query>
</dashlet>
</dashlets>
</cell>
</cells>
</dashboard>

View File

@@ -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+' => '',
));

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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',

View 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>

View File

@@ -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

View File

@@ -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

View File

@@ -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+' => '',

Some files were not shown because too many files have changed in this diff Show More