mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 15:34:12 +01:00
Compare commits
50 Commits
feature/62
...
support/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e6437a615 | ||
|
|
78e173d5fb | ||
|
|
6b8abce03a | ||
|
|
33a7005069 | ||
|
|
006a6037d1 | ||
|
|
e2f8be1745 | ||
|
|
ebae45f6a5 | ||
|
|
0685835d49 | ||
|
|
1b1e88f9a4 | ||
|
|
b90f443e75 | ||
|
|
4da64a64b1 | ||
|
|
6673e171dc | ||
|
|
afee7297cc | ||
|
|
3cc8b5b88a | ||
|
|
b2e6981b24 | ||
|
|
c0a79fa573 | ||
|
|
02ad6d19fe | ||
|
|
d16308ab62 | ||
|
|
4598959bc2 | ||
|
|
65a3755f81 | ||
|
|
dc46c65499 | ||
|
|
9d691c8e56 | ||
|
|
99f897bff7 | ||
|
|
8d83447222 | ||
|
|
dcc8ad08a4 | ||
|
|
c1b0b73b51 | ||
|
|
81173decca | ||
|
|
9aca062bf5 | ||
|
|
09aba95d0a | ||
|
|
1683ca2dd6 | ||
|
|
9e732d6045 | ||
|
|
69df343bd2 | ||
|
|
eb8f49ebfe | ||
|
|
398e294604 | ||
|
|
d04c6bccd5 | ||
|
|
f00c7c6bc2 | ||
|
|
d30e8c359f | ||
|
|
2bd4a61c00 | ||
|
|
e35c8323df | ||
|
|
e4e814281d | ||
|
|
635cb424a2 | ||
|
|
e95aa6cc69 | ||
|
|
c58fd17fc9 | ||
|
|
efdec7a343 | ||
|
|
2352c05d36 | ||
|
|
23634964a5 | ||
|
|
619252db99 | ||
|
|
ca4dbd833c | ||
|
|
f62a3b22a3 | ||
|
|
88416bca5d |
@@ -557,6 +557,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
{
|
||||
$oContact->Set('org_id', $iOrgId);
|
||||
}
|
||||
if (MetaModel::IsValidAttCode('Person', 'phone'))
|
||||
{
|
||||
$oContact->Set('phone', '+00 000 000 000');
|
||||
}
|
||||
$oContact->Set('email', 'my.email@foo.org');
|
||||
$iContactId = $oContact->DBInsertTrackedNoReload($oChange, true /* skip security */);
|
||||
}
|
||||
|
||||
@@ -1565,8 +1565,9 @@ EOF
|
||||
case 'LinkedSet':
|
||||
$aEventsList[] ='validate';
|
||||
$aEventsList[] ='change';
|
||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix, $oAttDef->DuplicatesAllowed());
|
||||
$sHTMLValue = $oWidget->Display($oPage, $value);
|
||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iId, $sNameSuffix, $oAttDef->DuplicatesAllowed(), $aArgs);
|
||||
$oObj = isset($aArgs['this']) ? $aArgs['this'] : null;
|
||||
$sHTMLValue = $oWidget->Display($oPage, $value, array(), $sFormPrefix, $oObj);
|
||||
break;
|
||||
|
||||
case 'Document':
|
||||
@@ -1733,7 +1734,7 @@ EOF
|
||||
if ($iKey > 0)
|
||||
{
|
||||
// The object already exists in the database, it's a modification
|
||||
$sButtons = "<input type=\"hidden\" name=\"id\" value=\"$iKey\">\n";
|
||||
$sButtons = "<input id=\"{$sPrefix}_id\" type=\"hidden\" name=\"id\" value=\"$iKey\">\n";
|
||||
$sButtons .= "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n";
|
||||
$sButtons .= "<button type=\"button\" class=\"action cancel\"><span>".Dict::S('UI:Button:Cancel')."</span></button> \n";
|
||||
$sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n";
|
||||
@@ -1819,6 +1820,10 @@ EOF
|
||||
$oPage->SetCurrentTab(Dict::S('UI:PropertiesTab'));
|
||||
|
||||
$aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams);
|
||||
if ($iKey > 0)
|
||||
{
|
||||
$aFieldsMap['id'] = $sPrefix.'_id';
|
||||
}
|
||||
// Now display the relations, one tab per relation
|
||||
if (!isset($aExtraParams['noRelations']))
|
||||
{
|
||||
|
||||
@@ -1107,7 +1107,7 @@ class MenuBlock extends DisplayBlock
|
||||
if (count($aTransitions))
|
||||
{
|
||||
$this->AddMenuSeparator($aActions);
|
||||
$aStimuli = Metamodel::EnumStimuli($sClass);
|
||||
$aStimuli = Metamodel::EnumStimuli(get_class($oObj));
|
||||
foreach($aTransitions as $sStimulusCode => $aTransitionDef)
|
||||
{
|
||||
$iActionAllowed = (get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction') ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO;
|
||||
|
||||
@@ -146,7 +146,12 @@ class iTopWebPage extends NiceWebPage
|
||||
// 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
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({ event: 'change'});
|
||||
tabs.tabs({ event: 'change', 'show': function(event, ui) {
|
||||
$('.resizable', ui.panel).resizable(); // Make resizable everything that claims to be resizable !
|
||||
}
|
||||
});
|
||||
|
||||
$('.resizable').filter(':visible').resizable();
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
@@ -198,7 +203,6 @@ EOF
|
||||
}
|
||||
});
|
||||
|
||||
$('.resizable').resizable(); // Make resizable everything that claims to be resizable !
|
||||
// Adjust initial size
|
||||
$('.v-resizable').each( function()
|
||||
{
|
||||
@@ -589,13 +593,13 @@ EOF
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos('?', $s_script) === false)
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?version=".ITOP_VERSION;
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&version=".ITOP_VERSION;
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
@@ -624,6 +628,8 @@ EOF
|
||||
echo "</style>\n";
|
||||
}
|
||||
echo "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/opensearch.xml.php\" />\n";
|
||||
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
|
||||
|
||||
@@ -271,23 +271,52 @@ EOF
|
||||
$aFilteredGroupNames = array();
|
||||
foreach($aMemberOf as $sGroupName)
|
||||
{
|
||||
phpCAS::log("Info: user if a member of the group: ".$sGroupName);
|
||||
$sGroupName = trim(iconv('UTF-8', 'ASCII//TRANSLIT', $sGroupName)); // Remove accents and spaces as well
|
||||
$aFilteredGroupNames[] = $sGroupName;
|
||||
if (in_array($sGroupName, $aCASMemberships))
|
||||
$bIsMember = false;
|
||||
foreach($aCASMemberships as $sCASPattern)
|
||||
{
|
||||
if (self::IsPattern($sCASPattern))
|
||||
{
|
||||
if (preg_match($sCASPattern, $sGroupName))
|
||||
{
|
||||
$bIsMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ($sPattern == $sGroupName)
|
||||
{
|
||||
$bIsMember = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bIsMember)
|
||||
{
|
||||
$bCASUserSynchro = MetaModel::GetConfig()->Get('cas_user_synchro');
|
||||
if ($bCASUserSynchro)
|
||||
{
|
||||
// If needed create a new user for this email/profile
|
||||
phpCAS::log('Info: cas_user_synchro is ON');
|
||||
self::CreateCASUser(phpCAS::getUser(), $aMemberOf);
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log('Info: cas_user_synchro is OFF');
|
||||
}
|
||||
$bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!$bFound)
|
||||
{
|
||||
phpCAS :: log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
|
||||
phpCAS::log("User ".phpCAS::getUser().", none of his/her groups (".implode('; ', $aFilteredGroupNames).") match any of the required groups: ".implode('; ', $aCASMemberships));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Too bad, the user is not part of any of the group => not allowed
|
||||
phpCAS :: log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
|
||||
phpCAS::log("No 'memberOf' attribute found for user ".phpCAS::getUser().". Are you using the SAML protocol (S1) ?");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -498,6 +527,123 @@ EOF
|
||||
}
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
protected static function CreateCASUser($sEmail, $aGroups)
|
||||
{
|
||||
if (!MetaModel::IsValidClass('URP_Profiles'))
|
||||
{
|
||||
phpCAS::log("URP_Profiles is not a valid class. Automatic creation of Users is not supported in this context, sorry.");
|
||||
return;
|
||||
}
|
||||
|
||||
// read all the existing profiles
|
||||
$oProfilesSearch = new DBObjectSearch('URP_Profiles');
|
||||
$oProfilesSet = new DBObjectSet($oProfilesSearch);
|
||||
$aAllProfiles = array();
|
||||
while($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
}
|
||||
|
||||
// Translate the CAS/LDAP group names into iTop profile names
|
||||
$aProfiles = array();
|
||||
$sPattern = MetaModel::GetConfig()->Get('cas_profile_pattern');
|
||||
foreach($aGroups as $sGroupName)
|
||||
{
|
||||
if (preg_match($sPattern, $sGroupName, $aMatches))
|
||||
{
|
||||
if (array_key_exists(strtolower($aMatches[1]), $aAllProfiles))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[strtolower($aMatches[1])];
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Warning: {$aMatches[1]} is not a valid iTop profile (extracted from group name: '$sGroupName'). Ignored.");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count($aProfiles) == 0)
|
||||
{
|
||||
phpCAS::log("Error: no group name matches the pattern: '$sPattern'. The user '$sEmail' has no profiles in iTop, and therefore cannot be created.");
|
||||
return;
|
||||
}
|
||||
|
||||
$oUser = MetaModel::GetObjectByName('UserExternal', $sEmail, false);
|
||||
if ($oUser == null)
|
||||
{
|
||||
// Create the user, link it to a contact
|
||||
phpCAS::log("Info: the user '$sEmail' does not exist. A new UserExternal will be created.");
|
||||
$oSearch = new DBObjectSearch('Person');
|
||||
$oSearch->AddCondition('email', $sEmail);
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iContactId = 0;
|
||||
switch($oSet->Count())
|
||||
{
|
||||
case 0:
|
||||
phpCAS::log("Error: found no contact with the email: '$sEmail'. Cannot create the user in iTop.");
|
||||
return;
|
||||
|
||||
case 1:
|
||||
$oContact = $oSet->Fetch();
|
||||
$iContactId = $oContact->GetKey();
|
||||
phpCAS::log("Info: Found 1 contact '".$oContact->GetName()."' (id=$iContactId) corresponding to the email '$sEmail'.");
|
||||
break;
|
||||
|
||||
default:
|
||||
phpCAS::log("Error: ".$oSet->Count()." contacts have the same email: '$sEmail'. Cannot create a user for this email.");
|
||||
return;
|
||||
}
|
||||
|
||||
$oUser = new UserExternal();
|
||||
$oUser->Set('login', $sEmail);
|
||||
$oUser->Set('contactid', $iContactId);
|
||||
$oUser->Set('language', MetaModel::GetConfig()->GetDefaultLanguage());
|
||||
}
|
||||
else
|
||||
{
|
||||
phpCAS::log("Info: the user '$sEmail' already exists (id=".$oUser->GetKey().").");
|
||||
}
|
||||
|
||||
// Now synchronize the profiles
|
||||
$oProfilesSet = DBObjectSet::FromScratch('URP_UserProfile');
|
||||
foreach($aProfiles as $iProfileId)
|
||||
{
|
||||
$oLink = new URP_UserProfile();
|
||||
$oLink->Set('profileid', $iProfileId);
|
||||
$oLink->Set('reason', 'CAS/LDAP Synchro');
|
||||
$oProfilesSet->AddObject($oLink);
|
||||
}
|
||||
$oUser->Set('profile_list', $oProfilesSet);
|
||||
phpCAS::log("Info: the user $sEmail (id=".$oUser->GetKey().") now has the following profiles: '".implode("', '", $aProfiles)."'.");
|
||||
|
||||
if ($oUser->IsNew() || $oUser->IsModified())
|
||||
{
|
||||
$oMyChange = MetaModel::NewObject("CMDBChange");
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", 'CAS/LDAP Synchro');
|
||||
$oMyChange->DBInsert();
|
||||
if ($oUser->IsNew())
|
||||
{
|
||||
$oUser->DBInsertTracked($oMyChange);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oUser->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected static function IsPattern($sCASPattern)
|
||||
{
|
||||
if ((substr($sCASPattern, 0, 1) == '/') && (substr($sCASPattern, -1) == '/'))
|
||||
{
|
||||
// the string is enclosed by slashes, let's assume it's a pattern
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // End of class
|
||||
?>
|
||||
|
||||
@@ -34,6 +34,7 @@ class UILinksWidget
|
||||
protected $m_iInputId;
|
||||
protected $m_aAttributes;
|
||||
protected $m_sExtKeyToRemote;
|
||||
protected $m_sExtKeyToMe;
|
||||
protected $m_sLinkedClass;
|
||||
protected $m_sRemoteClass;
|
||||
protected $m_bDuplicatesAllowed;
|
||||
@@ -50,6 +51,7 @@ class UILinksWidget
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sAttCode);
|
||||
$this->m_sLinkedClass = $oAttDef->GetLinkedClass();
|
||||
$this->m_sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
$this->m_sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
$oLinkingAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $this->m_sExtKeyToRemote);
|
||||
$this->m_sRemoteClass = $oLinkingAttDef->GetTargetClass();
|
||||
$sExtKeyToMe = $oAttDef->GetExtKeyToMe();
|
||||
@@ -97,7 +99,7 @@ class UILinksWidget
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @return string The HTML fragment of the one-row form
|
||||
*/
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId = null, $aArgs = array() )
|
||||
protected function GetFormRow(WebPage $oP, DBObject $oLinkedObj, $linkObjOrId = null, $aArgs = array(), $oCurrentObj )
|
||||
{
|
||||
$sPrefix = "$this->m_sAttCode{$this->m_sNameSuffix}";
|
||||
$aRow = array();
|
||||
@@ -107,6 +109,7 @@ class UILinksWidget
|
||||
$sPrefix .= "[$key][";
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['this'] = $linkObjOrId;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$key\">";
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"$key\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
@@ -121,8 +124,13 @@ class UILinksWidget
|
||||
{
|
||||
// form for creating a new record
|
||||
$sPrefix .= "[$linkObjOrId][";
|
||||
$oNewLinkObj = MetaModel::NewObject($this->m_sLinkedClass);
|
||||
$oRemoteObj = MetaModel::GetObject($this->m_sRemoteClass, -$linkObjOrId);
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToRemote, $oRemoteObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$oNewLinkObj->Set($this->m_sExtKeyToMe, $oCurrentObj); // Setting the extkey with the object alsoo fills the related external fields
|
||||
$sNameSuffix = "]"; // To make a tabular form
|
||||
$aArgs['prefix'] = $sPrefix;
|
||||
$aArgs['this'] = $oNewLinkObj;
|
||||
$aRow['form::checkbox'] = "<input class=\"selection\" type=\"checkbox\" onClick=\"oWidget".$this->m_iInputId.".OnSelectChange();\" value=\"$linkObjOrId\">";
|
||||
$aRow['form::checkbox'] .= "<input type=\"hidden\" name=\"attr_{$sPrefix}id{$sNameSuffix}\" value=\"\">";
|
||||
foreach($this->m_aEditableFields as $sFieldCode)
|
||||
@@ -207,9 +215,11 @@ class UILinksWidget
|
||||
* @param WebPage $oP The web page used for all the output
|
||||
* @param DBObjectSet The initial value of the linked set
|
||||
* @param Hash $aArgs Extra context arguments
|
||||
* @param string $sFormPrefix prefix of the fields in the current form
|
||||
* @param DBObject $oCurrentObj the current object to which the linkset is related
|
||||
* @return string The HTML fragment to be inserted into the page
|
||||
*/
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array())
|
||||
public function Display(WebPage $oPage, DBObjectSet $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
$sHtmlValue = '';
|
||||
$sTargetClass = self::GetTargetClass($this->m_sClass, $this->m_sAttCode);
|
||||
@@ -223,19 +233,20 @@ class UILinksWidget
|
||||
if ($oCurrentLink->IsNew())
|
||||
{
|
||||
$key = -$oLinkedObj->GetKey();
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $key, $aArgs);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $key, $aArgs, $oCurrentObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = $oCurrentLink->GetKey();
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj);
|
||||
}
|
||||
|
||||
}
|
||||
$sHtmlValue .= $this->DisplayFormTable($oPage, $this->m_aTableConfig, $aForm);
|
||||
$sDuplicates = ($this->m_bDuplicatesAllowed) ? 'true' : 'false';
|
||||
$sWizHelper = 'oWizardHelper'.$sFormPrefix;
|
||||
$oPage->add_ready_script(<<<EOF
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates);
|
||||
oWidget{$this->m_iInputId} = new LinksWidget('{$this->m_sAttCode}{$this->m_sNameSuffix}', '{$this->m_sClass}', '{$this->m_sAttCode}', '{$this->m_iInputId}', '{$this->m_sNameSuffix}', $sDuplicates, $sWizHelper);
|
||||
oWidget{$this->m_iInputId}.Init();
|
||||
EOF
|
||||
);
|
||||
@@ -344,7 +355,7 @@ EOF
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter)
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter, $oCurrentObj)
|
||||
{
|
||||
$aLinkedObjectIds = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
|
||||
@@ -353,7 +364,7 @@ EOF
|
||||
$oLinkedObj = MetaModel::GetObject($this->m_sRemoteClass, $iObjectId);
|
||||
if (is_object($oLinkedObj))
|
||||
{
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId ); // Not yet created link get negative Ids
|
||||
$aRow = $this->GetFormRow($oP, $oLinkedObj, -$iObjectId, array(), $oCurrentObj ); // Not yet created link get negative Ids
|
||||
$oP->add($this->DisplayFormRow($oP, $this->m_aTableConfig, $aRow, -$iObjectId));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -372,13 +372,13 @@ class WebPage
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos('?', $s_script) === false)
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?version=".ITOP_VERSION;
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&version=".ITOP_VERSION;
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
echo "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
@@ -413,6 +413,10 @@ class WebPage
|
||||
}
|
||||
echo "</style>\n";
|
||||
}
|
||||
if (class_exists('MetaModel') && MetaModel::GetConfig())
|
||||
{
|
||||
echo "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
}
|
||||
echo "</head>\n";
|
||||
echo "<body>\n";
|
||||
echo self::FilterXSS($this->s_content);
|
||||
|
||||
@@ -183,6 +183,7 @@ class ActionEmail extends ActionNotification
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
catch (OQLException $e)
|
||||
{
|
||||
@@ -275,6 +276,7 @@ class ActionEmail extends ActionNotification
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
$aHeaders = array();
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
@@ -294,7 +296,9 @@ class ActionEmail extends ActionNotification
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sReference = '<iTop/'.get_class($oObj).'/'.$oObj->GetKey().'>';
|
||||
$sMessageId = sprintf('<iTop_%s_%d_%f@%s.openitop.org>', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetConfig()->Get('session_name'));
|
||||
$sReference = $sMessageId;
|
||||
$aHeaders['Message-ID'] = $sMessageId;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
@@ -315,7 +319,7 @@ class ActionEmail extends ActionNotification
|
||||
if (isset($sBody)) $oLog->Set('body', $sBody);
|
||||
}
|
||||
|
||||
$oEmail = new EMail();
|
||||
$oEmail = new EMail('', '', '', $aHeaders);
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
|
||||
@@ -206,6 +206,15 @@ abstract class AttributeDefinition
|
||||
}
|
||||
return $sLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label corresponding to the given value
|
||||
* To be overloaded for localized enums
|
||||
*/
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
return GetAsHTML($sValue);
|
||||
}
|
||||
|
||||
public function GetLabel_Obsolete()
|
||||
{
|
||||
@@ -1333,7 +1342,12 @@ class AttributeFinalClass extends AttributeString
|
||||
{
|
||||
return '=';
|
||||
}
|
||||
|
||||
|
||||
public function GetValueLabel($sValue)
|
||||
{
|
||||
if (empty($sValue)) return '';
|
||||
return MetaModel::GetName($sValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ require_once('cmdbchangeop.class.inc.php');
|
||||
// Romain: temporary moved into application.inc.php (see explanations there)
|
||||
//require_once('event.class.inc.php');
|
||||
|
||||
require_once('templatestring.class.inc.php');
|
||||
require_once('csvparser.class.inc.php');
|
||||
require_once('bulkchange.class.inc.php');
|
||||
|
||||
@@ -279,9 +280,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$ret = $this->DBInsertTracked_Internal();
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -289,9 +291,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$ret = $this->DBInsertTracked_Internal(true);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -320,9 +323,10 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
public function DBCloneTracked(CMDBChange $oChange, $newKey = null)
|
||||
{
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->DBCloneTracked_Internal($newKey);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected function DBCloneTracked_Internal($newKey = null)
|
||||
@@ -347,9 +351,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_MODIFY);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->DBUpdateTracked_Internal();
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected function DBUpdateTracked_Internal()
|
||||
@@ -382,9 +387,10 @@ abstract class CMDBObject extends DBObject
|
||||
{
|
||||
$this->CheckUserRights($bSkipStrongSecurity, UR_ACTION_DELETE);
|
||||
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->DBDeleteTracked_Internal($oDeletionPlan);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected function DBDeleteTracked_Internal(&$oDeletionPlan = null)
|
||||
@@ -406,9 +412,10 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
public static function BulkDeleteTracked(CMDBChange $oChange, DBObjectSearch $oFilter)
|
||||
{
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->BulkDeleteTracked_Internal($oFilter);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected static function BulkDeleteTracked_Internal(DBObjectSearch $oFilter)
|
||||
@@ -445,9 +452,10 @@ abstract class CMDBObject extends DBObject
|
||||
|
||||
public static function BulkUpdateTracked(CMDBChange $oChange, DBObjectSearch $oFilter, array $aValues)
|
||||
{
|
||||
$oPreviousChange = self::$m_oCurrChange;
|
||||
self::$m_oCurrChange = $oChange;
|
||||
$this->BulkUpdateTracked_Internal($oFilter, $aValues);
|
||||
self::$m_oCurrChange = null;
|
||||
self::$m_oCurrChange = $oPreviousChange;
|
||||
}
|
||||
|
||||
protected static function BulkUpdateTracked_Internal(DBObjectSearch $oFilter, array $aValues)
|
||||
|
||||
@@ -383,6 +383,24 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_user_synchro' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Whether or not to synchronize users with CAS/LDAP',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_profile_pattern' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'A regular expression pattern to extract the name of the iTop profile from the name of an LDAP/CAS group',
|
||||
// examples... not used (nor 'description')
|
||||
'default' => '/^cn=([^,]+),/',
|
||||
'value' => '/^cn=([^,]+),/',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'cas_debug' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Activate the CAS debug',
|
||||
|
||||
@@ -154,7 +154,7 @@ abstract class DBObject
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function Reload()
|
||||
public function Reload()
|
||||
{
|
||||
assert($this->m_bIsInDB);
|
||||
$aRow = MetaModel::MakeSingleRow(get_class($this), $this->m_iKey, false/*, $this->m_bAllowAllData*/);
|
||||
@@ -367,6 +367,34 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
public function Get($sAttCode)
|
||||
{
|
||||
if (($iPos = strpos($sAttCode, '->')) === false)
|
||||
{
|
||||
return $this->GetStrict($sAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExtKeyAttCode = substr($sAttCode, 0, $iPos);
|
||||
$sRemoteAttCode = substr($sAttCode, $iPos + 2);
|
||||
if (!MetaModel::IsValidAttCode(get_class($this), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreException("Unknown external key '$sExtKeyAttCode' for the class ".get_class($this));
|
||||
}
|
||||
$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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetStrict($sAttCode)
|
||||
{
|
||||
if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this))))
|
||||
{
|
||||
@@ -1580,19 +1608,22 @@ abstract class DBObject
|
||||
if (!$bRet) $bSuccess = false;
|
||||
}
|
||||
|
||||
// Change state triggers...
|
||||
$sClass = get_class($this);
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sPreviousState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
if ($bSuccess)
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sNewState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
// Change state triggers...
|
||||
$sClass = get_class($this);
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateLeave AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sPreviousState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnStateEnter AS t WHERE t.target_class IN ('$sClassList') AND t.state='$sNewState'"));
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
}
|
||||
|
||||
return $bSuccess;
|
||||
|
||||
@@ -97,7 +97,7 @@ class Dict
|
||||
}
|
||||
|
||||
|
||||
public static function GetCurrentLanguage()
|
||||
public static function GetUserLanguage()
|
||||
{
|
||||
if (self::$m_sCurrentLanguage == null) // May happen when no user is logged in (i.e login screen, non authentifed page)
|
||||
{
|
||||
@@ -124,12 +124,12 @@ class Dict
|
||||
{
|
||||
// Attempt to find the string in the user language
|
||||
//
|
||||
if (!array_key_exists(self::GetCurrentLanguage(), self::$m_aData))
|
||||
if (!array_key_exists(self::GetUserLanguage(), self::$m_aData))
|
||||
{
|
||||
// It may happen, when something happens before the dictionnaries get loaded
|
||||
return $sStringCode;
|
||||
}
|
||||
$aCurrentDictionary = self::$m_aData[self::GetCurrentLanguage()];
|
||||
$aCurrentDictionary = self::$m_aData[self::GetUserLanguage()];
|
||||
if (array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
{
|
||||
return $aCurrentDictionary[$sStringCode];
|
||||
|
||||
@@ -35,6 +35,7 @@ class EMail
|
||||
protected $m_sSubject;
|
||||
protected $m_sTo;
|
||||
protected $m_aHeaders; // array of key=>value
|
||||
protected $m_aAttachments;
|
||||
|
||||
public function __construct($sTo = '', $sSubject = '', $sBody = '', $aHeaders = array())
|
||||
{
|
||||
@@ -42,6 +43,7 @@ class EMail
|
||||
$this->m_sSubject = $sSubject;
|
||||
$this->m_sBody = $sBody;
|
||||
$this->m_aHeaders = $aHeaders;
|
||||
$this->m_aAttachments = array();
|
||||
}
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
@@ -73,8 +75,14 @@ class EMail
|
||||
{
|
||||
$sHeaders = 'MIME-Version: 1.0' . "\r\n";
|
||||
// ! the case is important for MS-Outlook
|
||||
$sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
|
||||
$sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
|
||||
if (!array_key_exists('Content-Type', $this->m_aHeaders))
|
||||
{
|
||||
$sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
|
||||
}
|
||||
if (!array_key_exists('Content-Transfer-Encoding', $this->m_aHeaders))
|
||||
{
|
||||
$sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
|
||||
}
|
||||
foreach ($this->m_aHeaders as $sKey => $sValue)
|
||||
{
|
||||
$sHeaders .= "$sKey: $sValue\r\n";
|
||||
@@ -110,6 +118,7 @@ class EMail
|
||||
|
||||
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
|
||||
{
|
||||
$this->BuildMessage(); // assemble the attachments into the header/body structure
|
||||
if ($bForceSynchronous)
|
||||
{
|
||||
return $this->SendSynchronous($aIssues, $oLog);
|
||||
@@ -181,6 +190,36 @@ class EMail
|
||||
$this->AddToHeader('Reply-To', $sAddress);
|
||||
}
|
||||
|
||||
public function AddAttachment($data, $sFileName, $sMimeType)
|
||||
{
|
||||
$this->m_aAttachments[] = array('data' => $data, 'filename' => $sFileName, 'mimeType' => $sMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes care of the attachments (if any) to build the header/body of the message before storing or sending it
|
||||
*/
|
||||
protected function BuildMessage()
|
||||
{
|
||||
if (count($this->m_aAttachments) == 0) return; // Nothing to do if there are no attachments
|
||||
|
||||
$sDelimiter = '== iTopEmailPart---'.md5(date('r', time()))." ==";
|
||||
$sContentType = isset($this->m_aHeaders['Content-Type']) ? $this->m_aHeaders['Content-Type'] : 'text/html';
|
||||
$sContentHeader = "Content-Type: $sContentType\r\n";
|
||||
$this->m_aHeaders['Content-Type'] = "multipart/mixed; boundary=\"{$sDelimiter}\"";
|
||||
|
||||
$aAttachments = array();
|
||||
foreach($this->m_aAttachments as $aAttach)
|
||||
{
|
||||
$sAttachmentHeader = "Content-Type: {$aAttach['mimeType']};\r\n Name=\"{$aAttach['filename']}\"\r\n";
|
||||
$sAttachmentHeader .= "Content-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n filename=\"{$aAttach['filename']}\"\r\n";
|
||||
$sAttachmentHeader .= "\r\n";
|
||||
$sAttachment = chunk_split(base64_encode($aAttach['data']));
|
||||
$aAttachments[] = $sAttachmentHeader.$sAttachment."\r\n";
|
||||
}
|
||||
$this->m_sBody = "This is a multi-part message in MIME format.\r\n--".$sDelimiter."\r\n".$sContentHeader."\r\n".$this->m_sBody."\r\n--".$sDelimiter."\r\n";
|
||||
$this->m_sBody .= implode("--".$sDelimiter."\r\n", $aAttachments);
|
||||
$this->m_sBody .= "--".$sDelimiter."--";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -676,10 +676,38 @@ abstract class MetaModel
|
||||
if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass])) return false;
|
||||
return (self::$m_aAttribDefs[$sClass][$sAttCode]->IsExternalKey());
|
||||
}
|
||||
final static public function IsValidAttCode($sClass, $sAttCode)
|
||||
final static public function IsValidAttCode($sClass, $sAttCode, $bExtended = false)
|
||||
{
|
||||
if (!array_key_exists($sClass, self::$m_aAttribDefs)) return false;
|
||||
return (array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]));
|
||||
|
||||
if ($bExtended)
|
||||
{
|
||||
if (($iPos = strpos($sAttCode, '->')) === false)
|
||||
{
|
||||
$bRes = array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sExtKeyAttCode = substr($sAttCode, 0, $iPos);
|
||||
$sRemoteAttCode = substr($sAttCode, $iPos + 2);
|
||||
if (MetaModel::IsValidAttCode($sClass, $sExtKeyAttCode))
|
||||
{
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode);
|
||||
$sRemoteClass = $oKeyAttDef->GetTargetClass();
|
||||
$bRes = MetaModel::IsValidAttCode($sRemoteClass, $sRemoteAttCode, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$bRes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$bRes = array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]);
|
||||
}
|
||||
|
||||
return $bRes;
|
||||
}
|
||||
final static public function IsAttributeOrigin($sClass, $sAttCode)
|
||||
{
|
||||
|
||||
@@ -153,16 +153,25 @@ class ormCaseLog {
|
||||
* Add a new entry to the log and updates the internal index
|
||||
* @param $sText string The text of the new entry
|
||||
*/
|
||||
public function AddLogEntry($sText)
|
||||
public function AddLogEntry($sText, $sOnBehalfOf = '')
|
||||
{
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'));
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, UserRights::GetUserFriendlyName(), UserRights::GetUserId());
|
||||
if ($sOnBehalfOf == '')
|
||||
{
|
||||
$sOnBehalfOf = UserRights::GetUserFriendlyName();
|
||||
$iUserId = UserRights::GetUserId();
|
||||
}
|
||||
else
|
||||
{
|
||||
$iUserId = null;
|
||||
}
|
||||
$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' => UserRights::GetUserFriendlyName(),
|
||||
'user_id' => UserRights::GetUserId(),
|
||||
'user_name' => $sOnBehalfOf,
|
||||
'user_id' => $iUserId,
|
||||
'date' => time(),
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
|
||||
177
core/templatestring.class.inc.php
Normal file
177
core/templatestring.class.inc.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program 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 General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Simple helper class to interpret and transform a template string
|
||||
*
|
||||
* Usage:
|
||||
* $oString = new TemplateString("Blah $this->friendlyname$ is in location $this->location_id->name$ ('$this->location_id->org_id->name$)");
|
||||
* echo $oString->Render(array('this' => $oContact));
|
||||
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
/**
|
||||
* Helper class
|
||||
*/
|
||||
class TemplateStringPlaceholder
|
||||
{
|
||||
public $sToken;
|
||||
public $sAttCode;
|
||||
public $sFunction;
|
||||
public $sParamName;
|
||||
public $bIsValid;
|
||||
|
||||
public function __construct($sToken)
|
||||
{
|
||||
$this->sToken = $sToken;
|
||||
$this->sAttcode = '';
|
||||
$this->sFunction = '';
|
||||
$this->sParamName = '';
|
||||
$this->bIsValid = false; // Validity may be false in general, but it can work anyway (thanks to specialization) when rendering
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class TemplateString
|
||||
*/
|
||||
class TemplateString
|
||||
{
|
||||
protected $m_sRaw;
|
||||
protected $m_aPlaceholders;
|
||||
|
||||
public function __construct($sRaw)
|
||||
{
|
||||
$this->m_sRaw = $sRaw;
|
||||
$this->m_aPlaceholders = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the string into placholders
|
||||
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
|
||||
* @return void
|
||||
*/
|
||||
protected function Analyze($aParamTypes = array())
|
||||
{
|
||||
if (!is_null($this->m_aPlaceholders)) return;
|
||||
|
||||
$this->m_aPlaceholders = array();
|
||||
if (preg_match_all('/\\$([a-z0-9_]+(->[a-z0-9_]+)*)\\$/', $this->m_sRaw, $aMatches))
|
||||
{
|
||||
foreach($aMatches[1] as $sPlaceholder)
|
||||
{
|
||||
$oPlaceholder = new TemplateStringPlaceholder($sPlaceholder);
|
||||
$oPlaceholder->bIsValid = false;
|
||||
foreach ($aParamTypes as $sParamName => $sClass)
|
||||
{
|
||||
$sParamPrefix = $sParamName.'->';
|
||||
if (substr($sPlaceholder, 0, strlen($sParamPrefix)) == $sParamPrefix)
|
||||
{
|
||||
// Todo - detect functions (label...)
|
||||
$oPlaceholder->sFunction = '';
|
||||
|
||||
$oPlaceholder->sParamName = $sParamName;
|
||||
$sAttcode = substr($sPlaceholder, strlen($sParamPrefix));
|
||||
$oPlaceholder->sAttcode = $sAttcode;
|
||||
$oPlaceholder->bIsValid = MetaModel::IsValidAttCode($sClass, $sAttcode, true /* extended */);
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aPlaceholders[] = $oPlaceholder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the placeholders (for reporting purposes)
|
||||
* @return void
|
||||
*/
|
||||
public function GetPlaceholders()
|
||||
{
|
||||
return $this->m_aPlaceholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the format when possible
|
||||
* @param Hash $aParamTypes Class of the expected parameters: hash array of '<param_id>' => '<class_name>'
|
||||
* @return void
|
||||
*/
|
||||
public function IsValid($aParamTypes = array())
|
||||
{
|
||||
$this->Analyze($aParamTypes);
|
||||
|
||||
foreach($this->m_aPlaceholders as $oPlaceholder)
|
||||
{
|
||||
if (!$oPlaceholder->bIsValid)
|
||||
{
|
||||
if (count($aParamTypes) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (array_key_exists($oPlaceholder->sParamName, $aParamTypes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given parameters to replace the placeholders
|
||||
* @param Hash $aParamValues Value of the expected parameters: hash array of '<param_id>' => '<value>'
|
||||
* @return void
|
||||
*/
|
||||
public function Render($aParamValues = array())
|
||||
{
|
||||
$aParamTypes = array();
|
||||
foreach($aParamValues as $sParamName => $value)
|
||||
{
|
||||
$aParamTypes[$sParamName] = get_class($value);
|
||||
}
|
||||
$this->Analyze($aParamTypes);
|
||||
|
||||
$aSearch = array();
|
||||
$aReplace = array();
|
||||
foreach($this->m_aPlaceholders as $oPlaceholder)
|
||||
{
|
||||
if (array_key_exists($oPlaceholder->sParamName, $aParamValues))
|
||||
{
|
||||
$oRef = $aParamValues[$oPlaceholder->sParamName];
|
||||
try
|
||||
{
|
||||
$value = $oRef->Get($oPlaceholder->sAttcode);
|
||||
$aSearch[] = '$'.$oPlaceholder->sToken.'$';
|
||||
$aReplace[] = $value;
|
||||
$oPlaceholder->bIsValid = true;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oPlaceholder->bIsValid = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPlaceholder->bIsValid = false;
|
||||
}
|
||||
}
|
||||
return str_replace($aSearch, $aReplace, $this->m_sRaw);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -625,10 +625,6 @@ class UserRights
|
||||
|
||||
if (MetaModel::HasCategory($sClass, 'bizmodel'))
|
||||
{
|
||||
// #@# Temporary?????
|
||||
// The read access is controlled in MetaModel::MakeSelectQuery()
|
||||
if ($iActionCode == UR_ACTION_READ) return true;
|
||||
|
||||
if (is_null($oUser))
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
|
||||
@@ -176,6 +176,10 @@ legend {
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.ui-widget-content td legend a, .ui-widget-content td legend a:hover, .ui-widget-content td legend a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.ui-widget-content td a, p a, p a:visited, td a, td a:visited {
|
||||
text-decoration:none;
|
||||
color: #1C94C4;
|
||||
@@ -1104,4 +1108,7 @@ div.actions_button a, .actions_button a:hover, .actions_button a:visited {
|
||||
height:17px;
|
||||
line-height: 17px;
|
||||
display: block;
|
||||
}
|
||||
select#org_id {
|
||||
max-width: 90%;
|
||||
}
|
||||
@@ -639,7 +639,8 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Core:SyncDataSourceObsolete' => 'The data source is marked as obsolete. Operation cancelled.',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Only adminstrators or the user specified in the data source can execute this operation. Operation cancelled.',
|
||||
'Core:SyncTooManyMissingReplicas' => 'All records have been untouched for some time (all of the objects could be deleted). Please check that the process that writes into the synchronization table is still running. Operation cancelled.',
|
||||
|
||||
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s replicas, %2$s error(s), %3$s warning(s).',
|
||||
'Core:SynchroReplica:TargetObject' => 'Synchronized Object: %1$s',
|
||||
'Class:AsyncSendEmail' => 'Email (asynchronous)',
|
||||
'Class:AsyncSendEmail/Attribute:to' => 'To',
|
||||
'Class:AsyncSendEmail/Attribute:subject' => 'Subject',
|
||||
@@ -717,7 +718,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroReplica/Attribute:sync_source_id' => 'Synchro Data Source',
|
||||
'Class:SynchroReplica/Attribute:dest_id' => 'Destination object (ID)',
|
||||
'Class:SynchroReplica/Attribute:dest_class' => 'Destination type',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Lat seen',
|
||||
'Class:SynchroReplica/Attribute:status_last_seen' => 'Last seen',
|
||||
'Class:SynchroReplica/Attribute:status' => 'Status',
|
||||
'Class:SynchroReplica/Attribute:status/Value:modified' => 'Modified',
|
||||
'Class:SynchroReplica/Attribute:status/Value:new' => 'New',
|
||||
@@ -726,6 +727,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:SynchroReplica/Attribute:status/Value:synchronized' => 'Synchronized',
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator' => 'Object Created ?',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Last Error',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning' => 'Warnings',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Creation Date',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Last Modified Date',
|
||||
'Class:appUserPreferences' => 'User Preferences',
|
||||
|
||||
@@ -532,7 +532,9 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Audit:HeaderNbObjects' => '# Objects',
|
||||
'UI:Audit:HeaderNbErrors' => '# Errors',
|
||||
'UI:Audit:PercentageOk' => '% Ok',
|
||||
|
||||
'UI:Audit:ErrorIn_Rule_Reason' => 'OQL Error in the Rule %1$s: %2$s.',
|
||||
'UI:Audit:ErrorIn_Category_Reason' => 'OQL Error in the Category %1$s: %2$s.',
|
||||
|
||||
'UI:RunQuery:Title' => 'iTop - OQL Query Evaluation',
|
||||
'UI:RunQuery:QueryExamples' => 'Query Examples',
|
||||
'UI:RunQuery:HeaderPurpose' => 'Purpose',
|
||||
|
||||
@@ -386,6 +386,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:SynchroReplica/Attribute:status_dest_creator+' => '',
|
||||
'Class:SynchroReplica/Attribute:status_last_error' => 'Dernière erreur',
|
||||
'Class:SynchroReplica/Attribute:status_last_error+' => '',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning' => 'Avertissements',
|
||||
'Class:SynchroReplica/Attribute:status_last_warning+' => '',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date' => 'Date de création',
|
||||
'Class:SynchroReplica/Attribute:info_creation_date+' => '',
|
||||
'Class:SynchroReplica/Attribute:info_last_modified' => 'Date de dernière modification',
|
||||
@@ -605,6 +607,8 @@ Opérateurs :<br/>
|
||||
'Core:SyncDataSourceObsolete' => 'Cette source de données est obsolète. Opération annulée.',
|
||||
'Core:SyncDataSourceAccessRestriction' => 'Seuls les administrateurs et l\'utilisateur spécifié dans la source de données peuvent exécuter cette synchronisation. Opération annulée.',
|
||||
'Core:SyncTooManyMissingReplicas' => 'Tous les réplicas sont absents de l\'import. L\'import a-t-il réellement tourné. Opération annulée.',
|
||||
'Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings' => '%1$s replicas, %2$s erreur(s), %3$s avertissement(s).',
|
||||
'Core:SynchroReplica:TargetObject' => 'Objet Synchronisé : %1$s',
|
||||
'Core:Duration_Seconds' => '%1$ds',
|
||||
'Core:Duration_Minutes_Seconds' => '%1$dmin %2$ds',
|
||||
'Core:Duration_Hours_Minutes_Seconds' => '%1$dh %2$dmin %3$ds',
|
||||
|
||||
@@ -71,7 +71,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:URP_UserProfile/Attribute:reason' => 'Raison',
|
||||
'Class:URP_UserProfile/Attribute:reason+' => 'Justifie le rôle affecté à cet utilisateur',
|
||||
'Class:URP_UserOrg' => 'Utilisateur/Organisation',
|
||||
'Class:URP_UserOrg+' => 'Organizations permises pour l\'utilisateur',
|
||||
'Class:URP_UserOrg+' => 'Organisations permises pour l\'utilisateur',
|
||||
'Class:URP_UserOrg/Attribute:userid' => 'Utilisateur',
|
||||
'Class:URP_UserOrg/Attribute:userid+' => '',
|
||||
'Class:URP_UserOrg/Attribute:userlogin' => 'Login',
|
||||
@@ -215,7 +215,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:WelcomeMenu:OpenIncidents' => 'Incidents en cours: %1$d',
|
||||
'UI:WelcomeMenu:AllConfigItems' => 'Actifs: %1$d',
|
||||
'UI:WelcomeMenu:MyIncidents' => 'Mes Incidents',
|
||||
'UI:AllOrganizations' => ' Toutes les Organizations ',
|
||||
'UI:AllOrganizations' => ' Toutes les Organisations ',
|
||||
'UI:YourSearch' => 'Votre recherche',
|
||||
'UI:LoggedAsMessage' => 'Connecté comme: %1$s',
|
||||
'UI:LoggedAsMessage+Admin' => 'Connecté comme: %1$s (Administrateur)',
|
||||
@@ -416,6 +416,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Audit:HeaderNbObjects' => 'Nb d\'Objets',
|
||||
'UI:Audit:HeaderNbErrors' => 'Nb d\'Erreurs',
|
||||
'UI:Audit:PercentageOk' => '% Ok',
|
||||
'UI:Audit:ErrorIn_Rule_Reason' => 'Erreur OQL dans la règle %1$s: %2$s.',
|
||||
'UI:Audit:ErrorIn_Category_Reason' => 'Erreur OQL dans la catégorie %1$s: %2$s.',
|
||||
'UI:RunQuery:Title' => 'iTop - Evaluation de requêtes OQL',
|
||||
'UI:RunQuery:QueryExamples' => 'Exemples de requêtes',
|
||||
'UI:RunQuery:HeaderPurpose' => 'Objectif',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// JavaScript Document
|
||||
function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates, oWizHelper)
|
||||
{
|
||||
this.id = id;
|
||||
this.iInputId = iInputId;
|
||||
@@ -7,6 +7,7 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
this.sAttCode = sAttCode;
|
||||
this.sSuffix = sSuffix;
|
||||
this.bDuplicates = bDuplicates;
|
||||
this.oWizardHelper = oWizHelper;
|
||||
var me = this;
|
||||
this.Init = function()
|
||||
{
|
||||
@@ -202,6 +203,16 @@ function LinksWidget(id, sClass, sAttCode, iInputId, sSuffix, bDuplicates)
|
||||
// }
|
||||
|
||||
theMap['operation'] = 'doAddObjects';
|
||||
if (me.oWizardHelper == null)
|
||||
{
|
||||
theMap['json'] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not inside a "search form", updating a real object
|
||||
me.oWizardHelper.UpdateWizard();
|
||||
theMap['json'] = me.oWizardHelper.ToJSON();
|
||||
}
|
||||
$('#busy_'+me.iInputId).html(' <img src="../images/indicator.gif"/>');
|
||||
// Run the query and display the results
|
||||
$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap,
|
||||
|
||||
@@ -389,6 +389,7 @@ EOF
|
||||
{
|
||||
$('#attachment_'+att_id).attr('name', 'removed_attachments[]');
|
||||
$('#display_attachment_'+att_id).hide();
|
||||
$('#attachment_plugin').trigger('remove_attachment', [att_id]);
|
||||
return false; // Do not submit the form !
|
||||
}
|
||||
function ajaxFileUpload()
|
||||
@@ -433,6 +434,8 @@ EOF
|
||||
{
|
||||
$('#display_attachment_'+data.att_id).hover( function() { $(this).children(':button').toggleClass('btn_hidden'); } );
|
||||
}
|
||||
$('#attachment_plugin').trigger('add_attachment', [data.att_id, data.msg]);
|
||||
|
||||
//alert(data.msg);
|
||||
}
|
||||
}
|
||||
@@ -465,6 +468,7 @@ EOF
|
||||
$oPage->p(Dict::S('Attachments:AddAttachment').'<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading"> <img src="../images/indicator.gif"></span> '.$sMaxUpload);
|
||||
//$oPage->p('<input type="button" onClick="ajaxFileUpload();" value=" Upload !">');
|
||||
$oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>');
|
||||
$oPage->p('<input type="hidden" id="attachment_plugin"/>');
|
||||
$oPage->add('</fieldset>');
|
||||
if ($this->m_bDeleteEnabled)
|
||||
{
|
||||
|
||||
@@ -63,24 +63,4 @@ class ItopWelcome extends ModuleHandlerAPI
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Direct end-users to the standard Portal application
|
||||
*/
|
||||
class MyPortalURLMaker implements iDBObjectURLMaker
|
||||
{
|
||||
public static function MakeObjectURL($sClass, $iId)
|
||||
{
|
||||
switch($sClass)
|
||||
{
|
||||
case 'UserRequest':
|
||||
$sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class=$sClass&id=$iId";
|
||||
return $sUrl;
|
||||
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
15
pages/UI.php
15
pages/UI.php
@@ -393,6 +393,7 @@ function ApplyNextAction(Webpage $oP, CMDBObject $oObj, $sNextAction, $oMyChange
|
||||
}
|
||||
$oObj->DBUpdateTracked($oMyChange);
|
||||
}
|
||||
$oObj->Reload();
|
||||
$oObj->DisplayDetails($oP);
|
||||
}
|
||||
else
|
||||
@@ -842,7 +843,7 @@ try
|
||||
$currValue = $oObj->Get($sAttCode);
|
||||
if ($oAttDef instanceof AttributeCaseLog)
|
||||
{
|
||||
$currValue = '';
|
||||
$currValue = ' '; // Don't put an empty string, in case the field would be considered as mandatory...
|
||||
}
|
||||
if (is_object($currValue)) continue; // Skip non scalar values...
|
||||
if(!array_key_exists($currValue, $aValues[$sAttCode]))
|
||||
@@ -935,6 +936,7 @@ try
|
||||
}
|
||||
}
|
||||
$sTip .= "</ul></p>";
|
||||
$sTip = addslashes($sTip);
|
||||
$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);
|
||||
@@ -1578,12 +1580,7 @@ EOF
|
||||
{
|
||||
$sDisplayValue = empty($aVal['display']) ? '<i>'.Dict::S('Enum:Undefined').'</i>' : str_replace(array("\n", "\r"), " ", $aVal['display']);
|
||||
$sTip .= "<li>".Dict::Format('UI:BulkModify:Value_Exists_N_Times', $sDisplayValue, $aVal['count'])."</li>";
|
||||
$index++;
|
||||
if ($iMaxCount == $index)
|
||||
{
|
||||
$sTip .= "<li>".(count($aMultiValues) - $iMaxCount)." more different values...</li>";
|
||||
break;
|
||||
}
|
||||
$index++;
|
||||
if ($iMaxCount == $index)
|
||||
{
|
||||
$sTip .= "<li>".Dict::Format('UI:BulkModify:N_MoreValues', count($aValues[$sAttCode]) - $iMaxCount)."</li>";
|
||||
@@ -1591,6 +1588,7 @@ EOF
|
||||
}
|
||||
}
|
||||
$sTip .= "</ul></p>";
|
||||
$sTip = addslashes($sTip);
|
||||
$sReadyScript .= "$('#multi_values_$sAttCode').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );\n";
|
||||
$sComments .= '<div class="multi_values" id="multi_values_'.$sAttCode.'">'.count($aValues[$sAttCode]).'</div>';
|
||||
}
|
||||
@@ -2011,6 +2009,7 @@ EOF
|
||||
$oP->p(implode('</p><p>', $aErrors));
|
||||
}
|
||||
}
|
||||
$oObj->Reload();
|
||||
$oObj->DisplayDetails($oP);
|
||||
}
|
||||
else
|
||||
@@ -2070,8 +2069,6 @@ EOF
|
||||
$('#impacted_objects').empty();
|
||||
$('#impacted_objects').append(data);
|
||||
$('#impacted_objects').unblock();
|
||||
$('#impacted_objects .listResults').tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables
|
||||
$('#impacted_objects table.listResults').tableHover(); // hover tables
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -297,6 +297,9 @@ try
|
||||
$sSuffix = utils::ReadParam('sSuffix', '');
|
||||
$sRemoteClass = utils::ReadParam('sRemoteClass', $sClass, false, 'class');
|
||||
$bDuplicates = (utils::ReadParam('bDuplicates', 'false') == 'false') ? false : true;
|
||||
$sJson = utils::ReadParam('json', '', false, 'raw_data');
|
||||
$oWizardHelper = WizardHelper::FromJSON($sJson);
|
||||
$oObj = $oWizardHelper->GetTargetObject();
|
||||
$oWidget = new UILinksWidget($sClass, $sAttCode, $iInputId, $sSuffix, $bDuplicates);
|
||||
if ($sFilter != '')
|
||||
{
|
||||
@@ -306,7 +309,7 @@ try
|
||||
{
|
||||
$oFullSetFilter = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
$oWidget->DoAddObjects($oPage, $oFullSetFilter);
|
||||
$oWidget->DoAddObjects($oPage, $oFullSetFilter, $oObj);
|
||||
break;
|
||||
|
||||
case 'wizard_helper_preview':
|
||||
|
||||
105
pages/audit.php
105
pages/audit.php
@@ -177,52 +177,77 @@ try
|
||||
$oP->add("</tr>\n");
|
||||
while($oAuditCategory = $oCategoriesSet->fetch())
|
||||
{
|
||||
$oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'));
|
||||
FilterByContext($oDefinitionFilter, $oAppContext);
|
||||
|
||||
$aObjectsWithErrors = array();
|
||||
if (!empty($currentOrganization))
|
||||
try
|
||||
{
|
||||
if (MetaModel::IsValidFilterCode($oDefinitionFilter->GetClass(), 'org_id'))
|
||||
$oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set'));
|
||||
FilterByContext($oDefinitionFilter, $oAppContext);
|
||||
|
||||
$aObjectsWithErrors = array();
|
||||
if (!empty($currentOrganization))
|
||||
{
|
||||
$oDefinitionFilter->AddCondition('org_id', $currentOrganization, '=');
|
||||
if (MetaModel::IsValidFilterCode($oDefinitionFilter->GetClass(), 'org_id'))
|
||||
{
|
||||
$oDefinitionFilter->AddCondition('org_id', $currentOrganization, '=');
|
||||
}
|
||||
}
|
||||
$aResults = array();
|
||||
$oDefinitionSet = new CMDBObjectSet($oDefinitionFilter);
|
||||
$iCount = $oDefinitionSet->Count();
|
||||
$oRulesFilter = new CMDBSearchFilter('AuditRule');
|
||||
$oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '=');
|
||||
$oRulesSet = new DBObjectSet($oRulesFilter);
|
||||
while($oAuditRule = $oRulesSet->fetch() )
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['description'] = $oAuditRule->GetName();
|
||||
if ($iCount == 0)
|
||||
{
|
||||
// nothing to check, really !
|
||||
$aRow['nb_errors'] = "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."\">0</a>";
|
||||
$aRow['percent_ok'] = '100.00';
|
||||
$aRow['class'] = GetReportColor($iCount, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
$oRuleFilter = DBObjectSearch::FromOQL($oAuditRule->Get('query'));
|
||||
$oErrorObjectSet = GetRuleResultSet($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext);
|
||||
$iErrorsCount = $oErrorObjectSet->Count();
|
||||
while($oObj = $oErrorObjectSet->Fetch())
|
||||
{
|
||||
$aObjectsWithErrors[$oObj->GetKey()] = true;
|
||||
}
|
||||
$aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount</a>";
|
||||
$aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount));
|
||||
$aRow['class'] = GetReportColor($iCount, $iErrorsCount);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$aRow['nb_errors'] = "OQL Error";
|
||||
$aRow['percent_ok'] = 'n/a';
|
||||
$aRow['class'] = 'red';
|
||||
$sMessage = Dict::Format('UI:Audit:ErrorIn_Rule_Reason', $oAuditRule->GetHyperlink(), $e->getMessage());
|
||||
$oP->p("<img style=\"vertical-align:middle\" src=\"../images/stop-mid.png\"/> ".$sMessage);
|
||||
}
|
||||
}
|
||||
$aResults[] = $aRow;
|
||||
$iTotalErrors = count($aObjectsWithErrors);
|
||||
$sOverallPercentOk = ($iCount == 0) ? '100.00' : sprintf('%.2f', 100.0 * (($iCount - $iTotalErrors) / $iCount));
|
||||
$sClass = GetReportColor($iCount, $iTotalErrors);
|
||||
|
||||
}
|
||||
}
|
||||
$aResults = array();
|
||||
$oDefinitionSet = new CMDBObjectSet($oDefinitionFilter);
|
||||
$iCount = $oDefinitionSet->Count();
|
||||
$oRulesFilter = new CMDBSearchFilter('AuditRule');
|
||||
$oRulesFilter->AddCondition('category_id', $oAuditCategory->GetKey(), '=');
|
||||
$oRulesSet = new DBObjectSet($oRulesFilter);
|
||||
while($oAuditRule = $oRulesSet->fetch() )
|
||||
catch(Exception $e)
|
||||
{
|
||||
$aRow = array();
|
||||
$aRow['description'] = $oAuditRule->GetName();
|
||||
if ($iCount == 0)
|
||||
{
|
||||
// nothing to check, really !
|
||||
$aRow['nb_errors'] = "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."\">0</a>";
|
||||
$aRow['percent_ok'] = '100.00';
|
||||
$aRow['class'] = GetReportColor($iCount, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRuleFilter = DBObjectSearch::FromOQL($oAuditRule->Get('query'));
|
||||
$oErrorObjectSet = GetRuleResultSet($oAuditRule->GetKey(), $oDefinitionFilter, $oAppContext);
|
||||
$iErrorsCount = $oErrorObjectSet->Count();
|
||||
while($oObj = $oErrorObjectSet->Fetch())
|
||||
{
|
||||
$aObjectsWithErrors[$oObj->GetKey()] = true;
|
||||
}
|
||||
$aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount</a>";
|
||||
$aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount));
|
||||
$aRow['class'] = GetReportColor($iCount, $iErrorsCount);
|
||||
}
|
||||
$aResults[] = $aRow;
|
||||
$iTotalErrors = count($aObjectsWithErrors);
|
||||
$sOverallPercentOk = ($iCount == 0) ? '100.00' : sprintf('%.2f', 100.0 * (($iCount - $iTotalErrors) / $iCount));
|
||||
$sClass = GetReportColor($iCount, $iTotalErrors);
|
||||
|
||||
$aRow['description'] = "OQL error";
|
||||
$aRow['nb_errors'] = "n/a";
|
||||
$aRow['percent_ok'] = '';
|
||||
$aRow['class'] = 'red';
|
||||
$sMessage = Dict::Format('UI:Audit:ErrorIn_Category_Reason', $oAuditCategory->GetHyperlink(), $e->getMessage());
|
||||
$oP->p("<img style=\"vertical-align:middle\" src=\"../images/stop-mid.png\"/> ".$sMessage);
|
||||
$aResults[] = $aRow;
|
||||
}
|
||||
$oP->add("<tr>\n");
|
||||
$oP->add("<th><img src=\"../images/minus.gif\"></th><th class=\"alignLeft\">".$oAuditCategory->GetName()."</th><th class=\"alignRight\">$iCount</th><th class=\"alignRight\">$iTotalErrors</th><th class=\"alignRight $sClass\">$sOverallPercentOk %</th>\n");
|
||||
|
||||
1120
portal/index.php
1120
portal/index.php
File diff suppressed because it is too large
Load Diff
@@ -7,98 +7,72 @@ html, body {
|
||||
height: 100%;
|
||||
}
|
||||
#content {
|
||||
margin: auto;
|
||||
margin: 10px;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
text-align: center;
|
||||
overflow-y: auto;
|
||||
no.max-width: 90%;
|
||||
min-width: 960px;
|
||||
position: relative;
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
div#portal #welcome {
|
||||
display: none;
|
||||
background: url("./images/dockbar_bg.png") repeat-x scroll 0 0 #97A1AE;
|
||||
border-bottom: 1px solid #636364;
|
||||
font-size: 13px;
|
||||
padding: 1px 5px;
|
||||
position: relative;
|
||||
z-index: 300;
|
||||
text-align:right;
|
||||
color: #2C2F34;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px #FFFFFF;
|
||||
}
|
||||
div#portal #banner {
|
||||
background-color: #F6F6F1;
|
||||
display: block;
|
||||
height: 60px;
|
||||
vertical-align: middle;
|
||||
width: 100%;
|
||||
}
|
||||
div#portal #logo {
|
||||
background: url("../images/itop-logo.png") no-repeat scroll 0 0 transparent;
|
||||
border: 0 none;
|
||||
display: inline-block;
|
||||
height: 116px;
|
||||
line-height: 48px;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
padding-right: 50px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
width: 240px;
|
||||
height: 60px;
|
||||
display: block;
|
||||
vertical-align:middle;
|
||||
background-color: #f6f6f1;
|
||||
}
|
||||
|
||||
div#portal #logo {
|
||||
width: 126px;
|
||||
background: url(../images/itop-logo.png) 0 0 no-repeat;
|
||||
margin-left:20px;
|
||||
margin-right:20px;
|
||||
height: 60px;
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
line-height: 48px;
|
||||
padding-right:50px;
|
||||
}
|
||||
div#menu {
|
||||
display: block;
|
||||
height: 48px;
|
||||
left: 200px;
|
||||
line-height: 48px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
right: 0px;
|
||||
line-height: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
#portal_menu {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
#change_pwd {
|
||||
background: url("../images/password.png") no-repeat scroll 0 0 transparent;
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
|
||||
#logoff {
|
||||
background: url("../images/logoff.png") no-repeat scroll 0 0 transparent;
|
||||
display: block;
|
||||
float: right;
|
||||
}
|
||||
#logoff span {
|
||||
}
|
||||
|
||||
div.button {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
}
|
||||
a.button, a.button:visited {
|
||||
color: #1C94C4;
|
||||
margin-left:20px;
|
||||
margin-right:20px;
|
||||
height: 60px;
|
||||
border: 0;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
a.button , a.button:visited {
|
||||
color: #1C94C4;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
a.button span {
|
||||
margin-left: 50px;
|
||||
vertical-align:middle;
|
||||
margin-right: 20px;
|
||||
vertical-align: middle;
|
||||
margin-left: 50px;
|
||||
}
|
||||
|
||||
#close_form_table {
|
||||
@@ -106,117 +80,66 @@ a.button span {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
#request_details td {
|
||||
text-align:left;
|
||||
#logoff {
|
||||
display: block;
|
||||
float: right;
|
||||
background: url(../images/logoff.png) right center no-repeat;
|
||||
}
|
||||
|
||||
#request_details td fieldset{
|
||||
xxxheight:100%;
|
||||
#logoff span {
|
||||
margin-right: 50px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
#cancel {
|
||||
background: url(../images/stop-mid.png) 0 0 no-repeat;
|
||||
}
|
||||
|
||||
#create {
|
||||
background: url(../modules/itop-request-mgmt-1.0.0/images/user-request.png) 0 0 no-repeat;
|
||||
}
|
||||
#user_info {
|
||||
background: url(../images/clean-mid.png) 0 0 no-repeat;
|
||||
}
|
||||
|
||||
#change_pwd {
|
||||
background: url(../images/password.png) 0 0 no-repeat;
|
||||
}
|
||||
#back {
|
||||
background: url(../images/back.png) 0 0 no-repeat;
|
||||
}
|
||||
#back span {
|
||||
margin-left: 54px;
|
||||
}
|
||||
#refresh {
|
||||
background: url(../images/refresh.png) 0 0 no-repeat;
|
||||
margin-right: 40px;
|
||||
}
|
||||
#refresh span {
|
||||
margin-left: 54px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
#request_details {
|
||||
display: inline-block;
|
||||
width:800px;
|
||||
text-align: left;
|
||||
}
|
||||
#form_close_request {
|
||||
display: inline-block;
|
||||
width:800px;
|
||||
text-align: left;
|
||||
}
|
||||
#request_details_log {
|
||||
width:774px;
|
||||
}
|
||||
#request_details table {
|
||||
border: #f1f1f6 2px solid;
|
||||
text-align: left;
|
||||
}
|
||||
#form_details {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.wizContainer table {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#user_request_comment {
|
||||
width: 30em;
|
||||
height: 20em;
|
||||
}
|
||||
|
||||
#buttons {
|
||||
margin-top: 1em;
|
||||
}
|
||||
div#buttons #btn_cancel {
|
||||
margin-right: 50px;
|
||||
}
|
||||
|
||||
div#buttons #btn_back {
|
||||
margin-left: 50px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
div#buttons #btn_next {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
div#buttons #btn_finish {
|
||||
margin-left: 5px;
|
||||
}
|
||||
table.listContainer {
|
||||
clear: both;
|
||||
width: 100%;
|
||||
}
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
div.DrawerHandle {
|
||||
display:none;
|
||||
}
|
||||
div.HRDrawer {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
height: 0.5em;
|
||||
}
|
||||
|
||||
.SearchDrawer {
|
||||
background-color: #F9EDBF;
|
||||
border: 0;
|
||||
-moz-border-radius: 4px 4px 4px 4px;
|
||||
}
|
||||
.SearchDrawer label {
|
||||
background: transparent;
|
||||
}
|
||||
#open_incidents, #open_requests, #open_changes, #request_details {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
legend {
|
||||
background: url("./images/header_bg.png") repeat-x scroll 0 0 #D4D4D4;
|
||||
border-color: #C8C9CA #9E9E9E #9E9E9E #C8C9CA;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
color: #222222;
|
||||
font-weight: bold;
|
||||
text-shadow: 1px 1px #FFFFFF;
|
||||
padding: 5px;
|
||||
-moz-border-radius: 4px 4px 4px 4px;
|
||||
margin-top:0;
|
||||
}
|
||||
table.details > tbody > tr > td {
|
||||
padding-bottom: 5px;
|
||||
padding-top: 3px;
|
||||
padding-right: 5px;
|
||||
border: 0;
|
||||
}
|
||||
.label {
|
||||
font-weight: bold;
|
||||
}
|
||||
.caselog {
|
||||
display:block;
|
||||
width: 100%;
|
||||
}
|
||||
.caselog textarea {
|
||||
resize: none;
|
||||
}
|
||||
.edit_item {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
div.edit_item span div table {
|
||||
width: 100%;
|
||||
}
|
||||
div.edit_item span div table tbody tr td textarea{
|
||||
width: 99%;
|
||||
}
|
||||
div#ticket_shortcuts form {
|
||||
display: inline-block;
|
||||
}
|
||||
@@ -37,7 +37,7 @@ define('FINAL_CONFIG_FILE', APPROOT.'/config-itop.php');
|
||||
define('PHP_MIN_VERSION', '5.2.0');
|
||||
define('MYSQL_MIN_VERSION', '5.0.0');
|
||||
define('MIN_MEMORY_LIMIT', 32*1024*1024);
|
||||
define('SUHOSIN_GET_MAX_VALUE_LENGTH', 1024);
|
||||
define('SUHOSIN_GET_MAX_VALUE_LENGTH', 2048);
|
||||
|
||||
$sOperation = Utils::ReadParam('operation', 'step0');
|
||||
$oP = new SetupWebPage('iTop configuration wizard');
|
||||
|
||||
@@ -53,6 +53,9 @@ try
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'oql'));
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
$oBlock1 = new DisplayBlock($oFilter, 'search', false, array('menu'=>false));
|
||||
$oBlock1->Display($oP, 0);
|
||||
$oP->add('<p class="page-header">'.MetaModel::GetClassIcon('SynchroReplica').Dict::S('Core:SynchroReplica:ListOfReplicas').'</p>');
|
||||
$iSourceId = utils::ReadParam('datasource', null);
|
||||
if ($iSourceId != null)
|
||||
@@ -60,7 +63,6 @@ try
|
||||
$oSource = MetaModel::GetObject('SynchroDataSource', $iSourceId);
|
||||
$oP->p(Dict::Format('Core:SynchroReplica:BackToDataSource', $oSource->GetHyperlink()).'</a>');
|
||||
}
|
||||
$oFilter = DBObjectSearch::FromOQL($sOQL);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false, array('menu'=>false));
|
||||
$oBlock->Display($oP, 1);
|
||||
break;
|
||||
|
||||
@@ -166,12 +166,12 @@ foreach(explode(',', $sDataSourcesList) as $iSDS)
|
||||
$oP->p("Objects deletion errors: ".$oStatLog->Get('stats_nb_obj_deleted_errors'));
|
||||
$oP->p("Objects obsoleted: ".$oStatLog->Get('stats_nb_obj_obsoleted'));
|
||||
$oP->p("Objects obsolescence errors: ".$oStatLog->Get('stats_nb_obj_obsoleted_errors'));
|
||||
$oP->p("Objects created: ".$oStatLog->Get('stats_nb_obj_created'));
|
||||
$oP->p("Objects created: ".$oStatLog->Get('stats_nb_obj_created')." (".$oStatLog->Get('stats_nb_obj_created_warnings')." warnings)");
|
||||
$oP->p("Objects creation errors: ".$oStatLog->Get('stats_nb_obj_created_errors'));
|
||||
$oP->p("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated'));
|
||||
$oP->p("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated')." (".$oStatLog->Get('stats_nb_obj_updated_warnings')." warnings)");
|
||||
$oP->p("Objects update errors: ".$oStatLog->Get('stats_nb_obj_updated_errors'));
|
||||
$oP->p("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated'));
|
||||
$oP->p("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged'));
|
||||
$oP->p("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
|
||||
$oP->p("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
|
||||
$oP->p("Objects reconciliation errors: ".$oStatLog->Get('stats_nb_replica_reconciled_errors'));
|
||||
$oP->p("Replica disappeared, no action taken: ".$oStatLog->Get('stats_nb_replica_disappeared_no_action'));
|
||||
}
|
||||
|
||||
@@ -633,12 +633,12 @@ try
|
||||
$oP->add_comment("Objects deletion errors: ".$oStatLog->Get('stats_nb_obj_deleted_errors'));
|
||||
$oP->add_comment("Objects obsoleted: ".$oStatLog->Get('stats_nb_obj_obsoleted'));
|
||||
$oP->add_comment("Objects obsolescence errors: ".$oStatLog->Get('stats_nb_obj_obsoleted_errors'));
|
||||
$oP->add_comment("Objects created: ".$oStatLog->Get('stats_nb_obj_created'));
|
||||
$oP->add_comment("Objects created: ".$oStatLog->Get('stats_nb_obj_created')." (".$oStatLog->Get('stats_nb_obj_created_warnings')." warnings)");
|
||||
$oP->add_comment("Objects creation errors: ".$oStatLog->Get('stats_nb_obj_created_errors'));
|
||||
$oP->add_comment("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated'));
|
||||
$oP->add_comment("Objects updated: ".$oStatLog->Get('stats_nb_obj_updated')." (".$oStatLog->Get('stats_nb_obj_updated_warnings')." warnings)");
|
||||
$oP->add_comment("Objects update errors: ".$oStatLog->Get('stats_nb_obj_updated_errors'));
|
||||
$oP->add_comment("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated'));
|
||||
$oP->add_comment("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged'));
|
||||
$oP->add_comment("Objects reconciled (updated): ".$oStatLog->Get('stats_nb_obj_new_updated')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
|
||||
$oP->add_comment("Objects reconciled (unchanged): ".$oStatLog->Get('stats_nb_obj_new_unchanged')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)");
|
||||
$oP->add_comment("Objects reconciliation errors: ".$oStatLog->Get('stats_nb_replica_reconciled_errors'));
|
||||
$oP->add_comment("Replica disappeared, no action taken: ".$oStatLog->Get('stats_nb_replica_disappeared_no_action'));
|
||||
}
|
||||
|
||||
@@ -251,6 +251,19 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
$sEndDate = $oLastLog->Get('end_date');
|
||||
$iLastLog = $oLastLog->GetKey();
|
||||
$oPage->p('<h2>'.Dict::Format('Core:Synchro:SynchroEndedOn_Date', $sEndDate).'</h2>');
|
||||
$sOQL = "SELECT SynchroReplica WHERE sync_source_id=$iDSid";
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
|
||||
$iCountAllReplicas = $oSet->Count();
|
||||
$sAllReplicas = "<a href=\"../synchro/replica.php?operation=oql&datasource=$iDSid&oql=$sOQL\">$iCountAllReplicas</a>";
|
||||
$sOQL = "SELECT SynchroReplica WHERE sync_source_id=$iDSid AND status_last_error !=''";
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
|
||||
$iCountAllErrors = $oSet->Count();
|
||||
$sAllErrors = "<a href=\"../synchro/replica.php?operation=oql&datasource=$iDSid&oql=$sOQL\">$iCountAllErrors</a>";
|
||||
$sOQL = "SELECT SynchroReplica WHERE sync_source_id=$iDSid AND status_last_warning !=''";
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL));
|
||||
$iCountAllWarnings = $oSet->Count();
|
||||
$sAllWarnings = "<a href=\"../synchro/replica.php?operation=oql&datasource=$iDSid&oql=$sOQL\">$iCountAllWarnings</a>";
|
||||
$oPage->p('<h2>'.Dict::Format('Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings', $sAllReplicas, $sAllErrors, $sAllWarnings).'</h2>');
|
||||
}
|
||||
|
||||
$oPage->add('<table class="synoptics"><tr><td style="color:#333;vertical-align:top">');
|
||||
@@ -273,6 +286,18 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
$sScript .= "};\n";
|
||||
$sScript .= <<<EOF
|
||||
var sLastLog = '$iLastLog';
|
||||
function ToggleSynoptics(sId, bShow)
|
||||
{
|
||||
if (bShow)
|
||||
{
|
||||
$(sId).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(sId).hide();
|
||||
}
|
||||
}
|
||||
|
||||
function UpdateSynoptics(id)
|
||||
{
|
||||
var aValues = aSynchroLog[id];
|
||||
@@ -310,6 +335,12 @@ class SynchroDataSource extends cmdbAbstractObject
|
||||
{
|
||||
$('#disappeared_errors_link').hide();
|
||||
}
|
||||
|
||||
ToggleSynoptics('#cw_obj_created_warnings', aValues['obj_created_warnings'] > 0);
|
||||
ToggleSynoptics('#cw_obj_new_updated_warnings', aValues['obj_new_updated_warnings'] > 0);
|
||||
ToggleSynoptics('#cw_obj_new_unchanged_warnings', aValues['obj_new_unchanged_warnings'] > 0);
|
||||
ToggleSynoptics('#cw_obj_updated_warnings', aValues['obj_updated_warnings'] > 0);
|
||||
ToggleSynoptics('#cw_obj_unchanged_warnings', aValues['obj_unchanged_warnings'] > 0);
|
||||
}
|
||||
EOF
|
||||
;
|
||||
@@ -375,6 +406,10 @@ EOF
|
||||
$sCount = "<span id=\"c_{$sId}\">$iCount</span>";
|
||||
$sLabel = Dict::Format('Core:Synchro:label_'.$sId, $sCount);
|
||||
$sOpacity = ($iCount==0) ? "opacity:0.3;" : "";
|
||||
if (isset($aData[$sId.'_warnings']))
|
||||
{
|
||||
$sLabel .= " <span id=\"cw_{$sId}_warnings\"><img src=\"../images/error.png\" style=\"vertical-align:middle\"/> (<span id=\"c_{$sId}_warnings\">".$aData[$sId.'_warnings']."</span>)</span>";
|
||||
}
|
||||
|
||||
return "<td id=\"$sId\" style=\"background-color:$sColor;$sOpacity;\" {$sHTMLAttribs}>{$sLabel}{$sErrorLink}</td>";
|
||||
}
|
||||
@@ -387,11 +422,15 @@ EOF
|
||||
'obj_disappeared_errors' => $oLastLog->Get('stats_nb_obj_obsoleted_errors') + $oLastLog->Get('stats_nb_obj_deleted_errors'),
|
||||
'obj_disappeared_no_action' => $oLastLog->Get('stats_nb_replica_disappeared_no_action'),
|
||||
'obj_updated' => $oLastLog->Get('stats_nb_obj_updated'),
|
||||
'obj_updated_warnings' => $oLastLog->Get('stats_nb_obj_updated_warnings'),
|
||||
'obj_updated_errors' => $oLastLog->Get('stats_nb_obj_updated_errors'),
|
||||
'obj_new_updated' => $oLastLog->Get('stats_nb_obj_new_updated'),
|
||||
'obj_new_updated_warnings' => $oLastLog->Get('stats_nb_obj_new_updated_warnings'),
|
||||
'obj_new_unchanged' => $oLastLog->Get('stats_nb_obj_new_unchanged'),
|
||||
'obj_created' => $oLastLog->Get('stats_nb_obj_created'),
|
||||
'obj_created_warnings' => $oLastLog->Get('stats_nb_obj_created_warnings'),
|
||||
'obj_created_errors' => $oLastLog->Get('stats_nb_obj_created_errors'),
|
||||
'obj_unchanged_warnings' => $oLastLog->Get('stats_nb_obj_unchanged_warnings'),
|
||||
);
|
||||
$iReconciledErrors = $oLastLog->Get('stats_nb_replica_reconciled_errors');
|
||||
$iDisappeared = $aData['obj_disappeared_errors'] + $aData['obj_obsoleted'] + $aData['obj_deleted'] + $aData['obj_disappeared_no_action'];
|
||||
@@ -949,13 +988,18 @@ EOF
|
||||
$oStatLog->Set('stats_nb_obj_obsoleted_errors', 0);
|
||||
$oStatLog->Set('stats_nb_obj_created', 0);
|
||||
$oStatLog->Set('stats_nb_obj_created_errors', 0);
|
||||
$oStatLog->Set('stats_nb_obj_created_warnings', 0);
|
||||
$oStatLog->Set('stats_nb_obj_updated', 0);
|
||||
$oStatLog->Set('stats_nb_obj_updated_warnings', 0);
|
||||
$oStatLog->Set('stats_nb_obj_updated_errors', 0);
|
||||
// $oStatLog->Set('stats_nb_replica_reconciled', 0);
|
||||
$oStatLog->Set('stats_nb_obj_unchanged_warnings', 0);
|
||||
// $oStatLog->Set('stats_nb_replica_reconciled', 0);
|
||||
$oStatLog->Set('stats_nb_replica_reconciled_errors', 0);
|
||||
$oStatLog->Set('stats_nb_replica_disappeared_no_action', 0);
|
||||
$oStatLog->Set('stats_nb_obj_new_updated', 0);
|
||||
$oStatLog->Set('stats_nb_obj_new_updated_warnings', 0);
|
||||
$oStatLog->Set('stats_nb_obj_new_unchanged',0);
|
||||
$oStatLog->Set('stats_nb_obj_new_unchanged_warnings',0);
|
||||
|
||||
$sSelectTotal = "SELECT SynchroReplica WHERE sync_source_id = :source_id";
|
||||
$oSetTotal = new DBObjectSet(DBObjectSearch::FromOQL($sSelectTotal), array() /* order by*/, array('source_id' => $this->GetKey()));
|
||||
@@ -989,14 +1033,14 @@ EOF
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_deleted_errors').": ".$oStatLog->Get('stats_nb_obj_deleted_errors')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_obsoleted').": ".$oStatLog->Get('stats_nb_obj_obsoleted')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_obsoleted_errors').": ".$oStatLog->Get('stats_nb_obj_obsoleted_errors')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_created').": ".$oStatLog->Get('stats_nb_obj_created')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_created').": ".$oStatLog->Get('stats_nb_obj_created')." (".$oStatLog->Get('stats_nb_obj_created_warnings')." warnings)"."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_created_errors').": ".$oStatLog->Get('stats_nb_obj_created_errors')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_updated').": ".$oStatLog->Get('stats_nb_obj_updated')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_updated').": ".$oStatLog->Get('stats_nb_obj_updated')." (".$oStatLog->Get('stats_nb_obj_updated_warnings')." warnings)"."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_updated_errors').": ".$oStatLog->Get('stats_nb_obj_updated_errors')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_replica_reconciled_errors').": ".$oStatLog->Get('stats_nb_replica_reconciled_errors')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_replica_disappeared_no_action').": ".$oStatLog->Get('stats_nb_replica_disappeared_no_action')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_updated').": ".$oStatLog->Get('stats_nb_obj_new_updated')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_unchanged').": ".$oStatLog->Get('stats_nb_obj_new_unchanged')."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_updated').": ".$oStatLog->Get('stats_nb_obj_new_updated')." (".$oStatLog->Get('stats_nb_obj_new_updated_warnings')." warnings)"."</li>\n";
|
||||
$sStatistics .= "<li>".$oStatLog->GetLabel('stats_nb_obj_new_unchanged').": ".$oStatLog->Get('stats_nb_obj_new_unchanged')." (".$oStatLog->Get('stats_nb_obj_new_unchanged_warnings')." warnings)"."</li>\n";
|
||||
$sStatistics .= "</ul>\n";
|
||||
|
||||
$this->SendNotification("errors ($iErrors)", "<p>The synchronization has been executed, $iErrors errors have been encountered. Click <a href=\"$sIssuesURL\">here</a> to see the records being currently in error.</p>".$sStatistics);
|
||||
@@ -1180,10 +1224,10 @@ EOF
|
||||
$oSetSeen = new DBObjectSet(DBObjectSearch::FromOQL($sSelectSeen), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sLimitDate));
|
||||
$oStatLog->Set('stats_nb_replica_seen', $oSetSeen->Count());
|
||||
|
||||
// Get all the replicas that are 'new' or modified
|
||||
// Get all the replicas that are 'new' or modified or synchronized with a warning
|
||||
//
|
||||
$sSelectToSync = "SELECT SynchroReplica WHERE (status = 'new' OR status = 'modified') AND sync_source_id = :source_id";
|
||||
$oSetToSync = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToSync), array() /* order by*/, array('source_id' => $this->GetKey()) /* aArgs */, $aExtDataSpec, 0 /* limitCount */, 0 /* limitStart */);
|
||||
$sSelectToSync = "SELECT SynchroReplica WHERE (status = 'new' OR status = 'modified' OR (status = 'synchronized' AND status_last_warning != '')) AND sync_source_id = :source_id AND status_last_seen >= :last_import";
|
||||
$oSetToSync = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToSync), array() /* order by*/, array('source_id' => $this->GetKey(), 'last_import' => $sLimitDate) /* aArgs */, $aExtDataSpec, 0 /* limitCount */, 0 /* limitStart */);
|
||||
|
||||
while($oReplica = $oSetToSync->Fetch())
|
||||
{
|
||||
@@ -1484,15 +1528,20 @@ class SynchroLog extends DBObject
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_obsoleted_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_obsoleted_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_created", array("allowed_values"=>null, "sql"=>"stats_nb_obj_created", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_created_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_created_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_created_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_created_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_updated", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_updated_errors", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
// MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_updated_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_updated_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_unchanged_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_unchanged_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
// MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_reconciled_errors", array("allowed_values"=>null, "sql"=>"stats_nb_replica_reconciled_errors", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_replica_disappeared_no_action", array("allowed_values"=>null, "sql"=>"stats_nb_replica_disappeared_no_action", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_updated", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_updated", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_updated_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_updated_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_unchanged", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_unchanged", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("stats_nb_obj_new_unchanged_warnings", array("allowed_values"=>null, "sql"=>"stats_nb_obj_new_unchanged_warnings", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("last_error", array("allowed_values"=>null, "sql"=>"last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("traces", array("allowed_values"=>null, "sql"=>"traces", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
@@ -1596,6 +1645,7 @@ class SynchroLog extends DBObject
|
||||
class SynchroReplica extends DBObject implements iDisplay
|
||||
{
|
||||
static $aSearches = array(); // Cache of OQL queries used for reconciliation (per data source)
|
||||
protected $aWarnings;
|
||||
|
||||
public static function Init()
|
||||
{
|
||||
@@ -1624,7 +1674,8 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("status", array("allowed_values"=>new ValueSetEnum('new,synchronized,modified,orphan,obsolete'), "sql"=>"status", "default_value"=>"new", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeBoolean("status_dest_creator", array("allowed_values"=>null, "sql"=>"status_dest_creator", "default_value"=>0, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("status_last_error", array("allowed_values"=>null, "sql"=>"status_last_error", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("status_last_warning", array("allowed_values"=>null, "sql"=>"status_last_warning", "default_value"=>'', "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("info_creation_date", array("allowed_values"=>null, "sql"=>"info_creation_date", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("info_last_modified", array("allowed_values"=>null, "sql"=>"info_last_modified", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
@@ -1632,17 +1683,65 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
MetaModel::Init_SetZListItems('details', array('' .
|
||||
'col:0'=> array(
|
||||
'fieldset:SynchroDataSource:Definition' => array('sync_source_id','dest_id','dest_class'),
|
||||
'fieldset:SynchroDataSource:Status' => array('status','status_last_seen','status_dest_creator','status_last_error'),
|
||||
'fieldset:SynchroDataSource:Status' => array('status','status_last_seen','status_dest_creator','status_last_error','status_last_warning'),
|
||||
'fieldset:SynchroDataSource:Information' => array('info_creation_date','info_last_modified'))
|
||||
)
|
||||
);
|
||||
MetaModel::Init_SetZListItems('list', array('sync_source_id', 'dest_id', 'dest_class', 'status_last_seen', 'status', 'status_dest_creator', 'status_last_error')); // Attributes to be displayed for a list
|
||||
MetaModel::Init_SetZListItems('list', array('sync_source_id', 'dest_id', 'dest_class', 'status_last_seen', 'status', 'status_dest_creator', 'status_last_error', 'status_last_warning')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('sync_source_id', 'status_last_seen', 'status', 'status_dest_creator', 'dest_class', 'dest_id', 'status_last_error')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('standard_search', array('sync_source_id', 'status_last_seen', 'status', 'status_dest_creator', 'dest_class', 'dest_id', 'status_last_error', 'status_last_warning')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
public function __construct($aRow = null, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
|
||||
{
|
||||
parent::__construct($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
$this->aWarnings = array();
|
||||
}
|
||||
|
||||
public function DBInsert()
|
||||
protected function AddWarning($sWarningMessage)
|
||||
{
|
||||
$this->aWarnings[] = $sWarningMessage;
|
||||
}
|
||||
|
||||
protected function ResetWarnings()
|
||||
{
|
||||
$this->aWarnings = array();
|
||||
}
|
||||
|
||||
protected function HasWarnings()
|
||||
{
|
||||
return (count($this->aWarnings) > 0);
|
||||
}
|
||||
|
||||
protected function RecordWarnings()
|
||||
{
|
||||
$sWarningMessage = '';
|
||||
$MAX_WARNING_LENGTH = 255;
|
||||
switch(count($this->aWarnings))
|
||||
{
|
||||
case 0:
|
||||
$sWarningMessage = '';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
$sWarningMessage = $this->aWarnings[0];
|
||||
break;
|
||||
|
||||
default:
|
||||
$sWarningMessage = count($this->aWarnings)." warnings: ".implode(' ', $this->aWarnings);
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen($sWarningMessage) > $MAX_WARNING_LENGTH)
|
||||
{
|
||||
$sWarningMessage = substr($sWarningMessage, 0, $MAX_WARNING_LENGTH - 3).'...';
|
||||
}
|
||||
|
||||
$this->Set('status_last_warning', $sWarningMessage);
|
||||
}
|
||||
|
||||
public function DBInsert()
|
||||
{
|
||||
throw new CoreException('A synchronization replica must be created only by the mean of triggers');
|
||||
}
|
||||
@@ -1688,6 +1787,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
|
||||
public function Synchro($oDataSource, $aReconciliationKeys, $aAttributes, $oChange, &$oStatLog)
|
||||
{
|
||||
$this->ResetWarnings();
|
||||
switch($this->Get('status'))
|
||||
{
|
||||
case 'new':
|
||||
@@ -1714,6 +1814,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
}
|
||||
else
|
||||
{
|
||||
// TO DO: can we retry this ??
|
||||
// Reconciliation could not be performed - log and EXIT
|
||||
$oStatLog->AddTrace("Could not reconcile on null value for attribute '$sFilterCode'", $this);
|
||||
$this->SetLastError("Could not reconcile on null value for attribute '$sFilterCode'");
|
||||
@@ -1736,7 +1837,19 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$oStatLog->AddTrace("Nothing found on: $sConditionDesc", $this);
|
||||
if ($oDataSource->Get('action_on_zero') == 'create')
|
||||
{
|
||||
$this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog);
|
||||
$bCreated = $this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog);
|
||||
if ($bCreated)
|
||||
{
|
||||
if ($this->HasWarnings())
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_created_warnings');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Creation error has precedence over any warning
|
||||
$this->ResetWarnings();
|
||||
}
|
||||
}
|
||||
else // assumed to be 'error'
|
||||
{
|
||||
@@ -1751,9 +1864,20 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
if ($oDataSource->Get('action_on_one') == 'update')
|
||||
{
|
||||
$oDestObj = $oDestSet->Fetch();
|
||||
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
|
||||
$bModified = $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
|
||||
$this->Set('dest_id', $oDestObj->GetKey());
|
||||
$this->Set('dest_class', get_class($oDestObj));
|
||||
if ($this->HasWarnings())
|
||||
{
|
||||
if ($bModified)
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_new_updated_warnings');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_new_unchanged_warnings');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1774,21 +1898,46 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
}
|
||||
elseif ($oDataSource->Get('action_on_multiple') == 'create')
|
||||
{
|
||||
$this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog);
|
||||
$bCreated = $this->CreateObjectFromReplica($oDataSource->GetTargetClass(), $aAttributes, $oChange, $oStatLog);
|
||||
if ($bCreated)
|
||||
{
|
||||
if ($this->HasWarnings())
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_created_warnings');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Creation error has precedence over any warning
|
||||
$this->ResetWarnings();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// assumed to be 'take_first'
|
||||
$oDestObj = $oDestSet->Fetch();
|
||||
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
|
||||
$bModified = $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj_new', 'stats_nb_replica_reconciled_errors');
|
||||
$this->Set('dest_id', $oDestObj->GetKey());
|
||||
$this->Set('dest_class', get_class($oDestObj));
|
||||
if ($this->HasWarnings())
|
||||
{
|
||||
if ($bModified)
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_new_updated_warnings');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_new_unchanged_warnings');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->RecordWarnings();
|
||||
break;
|
||||
|
||||
case 'synchronized': // try to recover synchronized replicas with warnings
|
||||
case 'modified':
|
||||
$oDestObj = MetaModel::GetObject($oDataSource->GetTargetClass(), $this->Get('dest_id'));
|
||||
$oDestObj = MetaModel::GetObject($oDataSource->GetTargetClass(), $this->Get('dest_id'));
|
||||
if ($oDestObj == null)
|
||||
{
|
||||
$this->Set('status', 'orphan'); // The destination object has been deleted !
|
||||
@@ -1797,8 +1946,20 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj', 'stats_nb_obj_updated_errors');
|
||||
$bModified = $this->UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, $oStatLog, 'stats_nb_obj', 'stats_nb_obj_updated_errors');
|
||||
if ($this->HasWarnings())
|
||||
{
|
||||
if ($bModified)
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_updated_warnings');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oStatLog->Inc('stats_nb_obj_unchanged_warnings');
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->RecordWarnings();
|
||||
break;
|
||||
|
||||
default: // Do nothing in all other cases
|
||||
@@ -1811,6 +1972,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
protected function UpdateObjectFromReplica($oDestObj, $aAttributes, $oChange, &$oStatLog, $sStatsCode, $sStatsCodeError)
|
||||
{
|
||||
$aValueTrace = array();
|
||||
$bModified = false;
|
||||
try
|
||||
{
|
||||
foreach($aAttributes as $sAttCode => $oSyncAtt)
|
||||
@@ -1826,6 +1988,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
if ($oDestObj->IsModified())
|
||||
{
|
||||
$oDestObj->DBUpdateTracked($oChange);
|
||||
$bModified = true;
|
||||
$oStatLog->AddTrace('Updated object - Values: {'.implode(', ', $aValueTrace).'}', $this);
|
||||
if (($sStatsCode != '') &&(MetaModel::IsValidAttCode(get_class($oStatLog), $sStatsCode.'_updated')))
|
||||
{
|
||||
@@ -1851,13 +2014,16 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$this->SetLastError('Unable to update destination object: ', $e);
|
||||
$oStatLog->Inc($sStatsCodeError);
|
||||
}
|
||||
return $bModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the destination object populating it with the Extended data found in the synchro_data_XXXX table
|
||||
* @return bool Whether or not the object was created
|
||||
*/
|
||||
protected function CreateObjectFromReplica($sClass, $aAttributes, $oChange, &$oStatLog)
|
||||
{
|
||||
$bCreated = false;
|
||||
$oDestObj = MetaModel::NewObject($sClass);
|
||||
try
|
||||
{
|
||||
@@ -1879,6 +2045,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$this->Set('status_last_error', '');
|
||||
$this->Set('status', 'synchronized');
|
||||
$this->Set('info_creation_date', date('Y-m-d H:i:s'));
|
||||
$bCreated = true;
|
||||
|
||||
$oStatLog->AddTrace("Created (".implode(', ', $aValueTrace).")", $this);
|
||||
$oStatLog->Inc('stats_nb_obj_created');
|
||||
@@ -1889,6 +2056,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
$this->SetLastError('Unable to create destination object: ', $e);
|
||||
$oStatLog->Inc('stats_nb_obj_created_errors');
|
||||
}
|
||||
return $bCreated;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1983,6 +2151,7 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
// $sExtAttCode is a valid attribute code
|
||||
//
|
||||
$sClass = $this->Get('base_class');
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sExtAttCode);
|
||||
|
||||
if (!is_null($oSyncAtt) && ($oSyncAtt instanceof SynchroAttExtKey))
|
||||
@@ -2005,8 +2174,12 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: differs from null (in which case the value would be left unchanged)
|
||||
$oStatLog->AddTrace("Could not find [unique] object for '$sExtAttCode': searched on $sReconcAttCode = '$rawValue'", $this);
|
||||
if ($rawValue != '')
|
||||
{
|
||||
// Note: differs from null (in which case the value would be left unchanged)
|
||||
$oStatLog->AddTrace("Could not find [unique] object for '$sExtAttCode': searched on $sReconcAttCode = '$rawValue'", $this);
|
||||
$this->AddWarning("Could not find [unique] object for '$sExtAttCode': searched on $sReconcAttCode = '$rawValue'");
|
||||
}
|
||||
$retValue = 0;
|
||||
}
|
||||
}
|
||||
@@ -2108,6 +2281,14 @@ class SynchroReplica extends DBObject implements iDisplay
|
||||
}
|
||||
$oPage->Details($aDetails);
|
||||
$oPage->add('</fieldset>');
|
||||
$oDestObj = MetaModel::GetObject($this->Get('dest_class'), $this->Get('dest_id'), false);
|
||||
if (is_object($oDestObj))
|
||||
{
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>'.Dict::Format('Core:SynchroReplica:TargetObject', $oDestObj->GetHyperlink()).'</legend>');
|
||||
$oDestObj->DisplayBareProperties($oPage, false, $aExtraParams);
|
||||
$oPage->add('<fieldset>');
|
||||
}
|
||||
$oPage->add('</td><td>');
|
||||
$oPage->add('<fieldset>');
|
||||
$oPage->add('<legend>'.Dict::S('Core:SynchroReplica:PublicData').'</legend>');
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
<!-- Added the following import tag to pass the Eclipse validation -->
|
||||
<xsd:import namespace="http://schemas.xmlsoap.org/soap/encoding/" />
|
||||
<xsd:complexType name="SearchCondition">
|
||||
<wsdl:documentation>
|
||||
<!--wsdl:documentation>
|
||||
A criteria to restrict a search (strict search is performed)
|
||||
Example: name = 'myserver.combodo.fr'
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="attcode" type="xsd:string"/>
|
||||
<xsd:element name="value" type="xsd:string"/> <!-- should be anyType but this one is not well supported by Eclipse -->
|
||||
@@ -25,20 +25,20 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="ExternalKeySearch">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Specifies [how to find] a value for an external key.
|
||||
the class of object to search for will depend on the usage that is being made, therefore the search conditions that may be used will vary depending on the parameter that is concerned.
|
||||
If one criteria is not relevant, then the match will not be attempted and warning will be logged (or an error if the target external key is mandatory)
|
||||
Example: match on customer = 'Demo' and type = 'Router'
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="conditions" type="typens:ArrayOfSearchCondition"/>
|
||||
</xsd:all>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="AttributeValue">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Specifies a value to set
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="attcode" type="xsd:string"/>
|
||||
<xsd:element name="value" type="xsd:string"/> <!-- should be anyType but this one is not well supported by Eclipse -->
|
||||
@@ -52,9 +52,9 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="LinkCreationSpec">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Specifies [how to match] one item to attach and what values should be set on the newly created link.
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="class" type="xsd:string"/>
|
||||
<xsd:element name="conditions" type="typens:ArrayOfSearchCondition"/>
|
||||
@@ -69,9 +69,9 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="LogMessage">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
An event that happened during the execution of the web service
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="text" type="xsd:string"/>
|
||||
</xsd:all>
|
||||
@@ -84,9 +84,9 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="ResultLog">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
A Log of events of the same category
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="messages" type="typens:ArrayOfLogMessage"/>
|
||||
</xsd:all>
|
||||
@@ -105,10 +105,10 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="ResultMessage">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Output expected, depending on the operation invoked.
|
||||
Example: CreateIncidentTicket will return 'created' => basic information on the created ticket
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="label" type="xsd:string"/>
|
||||
<xsd:element name="values" type="typens:ArrayOfResultData"/>
|
||||
@@ -122,12 +122,12 @@
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="Result">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Standard result structure returned by all of the operations, excepted GetVersion (returning a string)
|
||||
result holds returned data if the status is set to true
|
||||
errors, warnings and infos will help in understanding what happened (unknown identifiers, object matching issues/results)
|
||||
This resulting structure is being tracked into the application log as well.
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<xsd:all>
|
||||
<xsd:element name="status" type="xsd:boolean"/>
|
||||
<xsd:element name="result" type="typens:ArrayOfResultMessage"/>
|
||||
@@ -189,31 +189,31 @@
|
||||
</message>
|
||||
<portType name="WebServicePortType">
|
||||
<operation name="GetVersion">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Get the current version of Itop
|
||||
As this service is very simple, it is a test to get trained for more complex operations
|
||||
</wsdl:documentation> -->
|
||||
</wsdl:documentation --> -->
|
||||
<input message="typens:GetVersion"/>
|
||||
<output message="typens:GetVersionResponse"/>
|
||||
</operation>
|
||||
<operation name="CreateRequestTicket">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Create a ticket, return information about reconciliation on external keys and the created ticket
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<input message="typens:CreateRequestTicket"/>
|
||||
<output message="typens:CreateRequestTicketResponse"/>
|
||||
</operation>
|
||||
<operation name="CreateIncidentTicket">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Create a ticket, return information about reconciliation on external keys and the created ticket
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<input message="typens:CreateIncidentTicket"/>
|
||||
<output message="typens:CreateIncidentTicketResponse"/>
|
||||
</operation>
|
||||
<operation name="SearchObjects">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
Create a ticket, return information about reconciliation on external keys and the created ticket
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<input message="typens:SearchObjects"/>
|
||||
<output message="typens:SearchObjectsResponse"/>
|
||||
</operation>
|
||||
@@ -258,9 +258,9 @@
|
||||
</operation>
|
||||
</binding>
|
||||
<service name="ITopService">
|
||||
<wsdl:documentation>
|
||||
<!-- wsdl:documentation>
|
||||
ITop is the central solution for managing your IT infrastructure
|
||||
</wsdl:documentation>
|
||||
</wsdl:documentation -->
|
||||
<port name="WebServicePort" binding="typens:WebServiceBinding">
|
||||
<soap:address location="___SOAP_SERVER_URI___"/>
|
||||
</port>
|
||||
|
||||
Reference in New Issue
Block a user