public static function GetProfileActionGrant($iProfileId, $sClass, $sAction) { $bLegacyBehavior = MetaModel::GetConfig()->Get('user_rights_legacy'); // Search for a grant, stoping if any deny is encountered (allowance implies the verification of all paths) $bAllow = null; // 1 - The class itself // $sGrantKey = $iProfileId . '_' . $sClass . '_' . $sAction; if (isset(self::$aGRANTS[$sGrantKey])) { $bAllow = self::$aGRANTS[$sGrantKey]; if ($bLegacyBehavior) { return $bAllow; } if (!$bAllow) { return false; } } // 2 - The parent classes, up to the root class // foreach (MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_EXCLUDELEAF, false) as $sParent) { $sGrantKey = $iProfileId . '_' . $sParent . '+_' . $sAction; if (isset(self::$aGRANTS[$sGrantKey])) { $bAllow = self::$aGRANTS[$sGrantKey]; if ($bLegacyBehavior) { return $bAllow; } if (!$bAllow) { return false; } } } // 3 - The related classes (if the current is an N-N link with DEL_AUTO/DEL_SILENT) // $bGrant = self::GetLinkActionGrant($iProfileId, $sClass, $sAction); if (!is_null($bGrant)) { $bAllow = $bGrant; if ($bLegacyBehavior) { return $bAllow; } if (!$bAllow) { return false; } } // 4 - All // $sGrantKey = $iProfileId . '_*_' . $sAction; if (isset(self::$aGRANTS[$sGrantKey])) { $bAllow = self::$aGRANTS[$sGrantKey]; if ($bLegacyBehavior) { return $bAllow; } if (!$bAllow) { return false; } } // null or true return $bAllow; }
public static function MakeObjectURL($sClass, $iId) { if (strpos(MetaModel::GetConfig()->Get('portal_tickets'), $sClass) !== false) { $sAbsoluteUrl = utils::GetAbsoluteUrlAppRoot(); $sUrl = "{$sAbsoluteUrl}portal/index.php?operation=details&class={$sClass}&id={$iId}"; } else { $sUrl = ''; } return $sUrl; }
public function GetURL() { $aOverloads = MetaModel::GetConfig()->Get('portal_dispatch_urls'); if (array_key_exists($this->sPortalid, $aOverloads)) { $sRet = $aOverloads[$this->sPortalid]; } else { $sRet = utils::GetAbsoluteUrlAppRoot() . $this->aData['url']; } return $sRet; }
public function ComputeResults() { $this->m_iToDelete = 0; $this->m_iToUpdate = 0; foreach ($this->m_aToDelete as $sClass => $aToDelete) { foreach ($aToDelete as $iId => $aData) { $this->m_iToDelete++; if (isset($aData['issue'])) { $this->m_bFoundStopper = true; $this->m_bFoundManualOperation = true; if (isset($aData['issue_security'])) { $this->m_bFoundSecurityIssue = true; } } if ($aData['mode'] == DEL_MANUAL) { $this->m_aToDelete[$sClass][$iId]['issue'] = $sClass . '::' . $iId . ' ' . Dict::S('UI:Delete:MustBeDeletedManually'); $this->m_bFoundStopper = true; $this->m_bFoundManualDelete = true; } } } // Getting and setting time limit are not symetric: // www.php.net/manual/fr/function.set-time-limit.php#72305 $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); foreach ($this->m_aToUpdate as $sClass => $aToUpdate) { foreach ($aToUpdate as $iId => $aData) { set_time_limit($iLoopTimeLimit); $this->m_iToUpdate++; $oObject = $aData['to_reset']; $aExtKeyLabels = array(); foreach ($aData['attributes'] as $sRemoteExtKey => $aRemoteAttDef) { $oObject->Set($sRemoteExtKey, $aData['values'][$sRemoteExtKey]); $aExtKeyLabels[] = $aRemoteAttDef->GetLabel(); } $this->m_aToUpdate[$sClass][$iId]['attributes_list'] = implode(', ', $aExtKeyLabels); list($bRes, $aIssues, $bSecurityIssues) = $oObject->CheckToWrite(); if (!$bRes) { $this->m_aToUpdate[$sClass][$iId]['issue'] = implode(', ', $aIssues); $this->m_bFoundStopper = true; if ($bSecurityIssues) { $this->m_aToUpdate[$sClass][$iId]['issue_security'] = true; $this->m_bFoundSecurityIssue = true; } } } } set_time_limit($iPreviousTimeLimit); }
/** * Get the related objects through the given relation, output in XML * @param DBObject $oObj The current object * @param string $sRelation The name of the relation to search with */ function GetRelatedObjectsAsXml(DBObject $oObj, $sRelationName, &$oLinks, &$oXmlDoc, &$oXmlNode, $iDepth = 0, $aExcludedClasses) { global $G_aCachedObjects; $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20); $aResults = array(); $bAddLinks = false; if ($iDepth > $iMaxRecursionDepth - 1) { return; } $sIdxKey = get_class($oObj) . ':' . $oObj->GetKey(); if (!array_key_exists($sIdxKey, $G_aCachedObjects)) { $oObj->GetRelatedObjects($sRelationName, 1, $aResults); $G_aCachedObjects[$sIdxKey] = true; } else { return; //$aResults = $G_aCachedObjects[$sIdxKey]; } foreach ($aResults as $sRelatedClass => $aObjects) { foreach ($aObjects as $id => $oTargetObj) { if (is_object($oTargetObj)) { if (in_array(get_class($oTargetObj), $aExcludedClasses)) { GetRelatedObjectsAsXml($oTargetObj, $sRelationName, $oLinks, $oXmlDoc, $oXmlNode, $iDepth + 1, $aExcludedClasses); } else { $oLinkingNode = $oXmlDoc->CreateElement('link'); $oLinkingNode->SetAttribute('relation', $sRelationName); $oLinkingNode->SetAttribute('arrow', 1); // Such relations have a direction, display an arrow $oLinkedNode = $oXmlDoc->CreateElement('node'); $oLinkedNode->SetAttribute('id', $oTargetObj->GetKey()); $oLinkedNode->SetAttribute('obj_class', get_class($oTargetObj)); $oLinkedNode->SetAttribute('obj_class_name', htmlspecialchars(MetaModel::GetName(get_class($oTargetObj)))); $oLinkedNode->SetAttribute('name', htmlspecialchars($oTargetObj->GetRawName())); // htmlentities is too much for XML $oLinkedNode->SetAttribute('icon', BuildIconPath($oTargetObj->GetIcon(false))); AddNodeDetails($oLinkedNode, $oTargetObj); $oSubLinks = $oXmlDoc->CreateElement('links'); // Recurse GetRelatedObjectsAsXml($oTargetObj, $sRelationName, $oSubLinks, $oXmlDoc, $oLinkedNode, $iDepth + 1, $aExcludedClasses); $oLinkingNode->AppendChild($oLinkedNode); $oLinks->AppendChild($oLinkingNode); $bAddLinks = true; } } } } if ($bAddLinks) { $oXmlNode->AppendChild($oLinks); } }
/** * Helper to determine the supported types of tickets */ function GetTicketClasses() { $aClasses = array(); foreach (explode(',', MetaModel::GetConfig()->Get('portal_tickets')) as $sRawClass) { $sRawClass = trim($sRawClass); if (!MetaModel::IsValidClass($sRawClass)) { throw new Exception("Class '{$sRawClass}' is not a valid class, please review your configuration (portal_tickets)"); } if (!MetaModel::IsParentClass('Ticket', $sRawClass)) { throw new Exception("Class '{$sRawClass}' does not inherit from Ticket, please review your configuration (portal_tickets)"); } $aClasses[] = $sRawClass; } return $aClasses; }
function CronExec($oP, $aProcesses, $bVerbose) { $iStarted = time(); $iMaxDuration = MetaModel::GetConfig()->Get('cron_max_execution_time'); $iTimeLimit = $iStarted + $iMaxDuration; if ($bVerbose) { $oP->p("Planned duration = {$iMaxDuration} seconds"); } // Reset the next planned execution to take into account new settings $oSearch = new DBObjectSearch('BackgroundTask'); $oTasks = new DBObjectSet($oSearch); while ($oTask = $oTasks->Fetch()) { $sTaskClass = $oTask->Get('class_name'); $oRefClass = new ReflectionClass($sTaskClass); $oNow = new DateTime(); if ($oRefClass->implementsInterface('iScheduledProcess') && ($oTask->Get('status') != 'active' || $oTask->Get('next_run_date') > $oNow->format('Y-m-d H:i:s'))) { if ($bVerbose) { $oP->p("Resetting the next run date for {$sTaskClass}"); } $oProcess = $aProcesses[$sTaskClass]; $oNextOcc = $oProcess->GetNextOccurrence(); $oTask->Set('next_run_date', $oNextOcc->format('Y-m-d H:i:s')); $oTask->DBUpdate(); } } $iCronSleep = MetaModel::GetConfig()->Get('cron_sleep'); $oSearch = new DBObjectSearch('BackgroundTask'); while (time() < $iTimeLimit) { $oTasks = new DBObjectSet($oSearch); $aTasks = array(); while ($oTask = $oTasks->Fetch()) { $aTasks[$oTask->Get('class_name')] = $oTask; } foreach ($aProcesses as $oProcess) { $sTaskClass = get_class($oProcess); $oNow = new DateTime(); if (!array_key_exists($sTaskClass, $aTasks)) { // New entry, let's create a new BackgroundTask record, and plan the first execution $oTask = new BackgroundTask(); $oTask->Set('class_name', get_class($oProcess)); $oTask->Set('total_exec_count', 0); $oTask->Set('min_run_duration', 99999.999); $oTask->Set('max_run_duration', 0); $oTask->Set('average_run_duration', 0); $oRefClass = new ReflectionClass($sTaskClass); if ($oRefClass->implementsInterface('iScheduledProcess')) { $oNextOcc = $oProcess->GetNextOccurrence(); $oTask->Set('next_run_date', $oNextOcc->format('Y-m-d H:i:s')); } else { // Background processes do start asap, i.e. "now" $oTask->Set('next_run_date', $oNow->format('Y-m-d H:i:s')); } if ($bVerbose) { $oP->p('Creating record for: ' . $sTaskClass); $oP->p('First execution planned at: ' . $oTask->Get('next_run_date')); } $oTask->DBInsert(); $aTasks[$oTask->Get('class_name')] = $oTask; } if ($aTasks[$sTaskClass]->Get('status') == 'active' && $aTasks[$sTaskClass]->Get('next_run_date') <= $oNow->format('Y-m-d H:i:s')) { // Run the task and record its next run time if ($bVerbose) { $oP->p(">> === " . $oNow->format('Y-m-d H:i:s') . sprintf(" Starting:%-'=40s", ' ' . $sTaskClass . ' ')); } $sMessage = RunTask($oProcess, $aTasks[$sTaskClass], $oNow, $iTimeLimit); if ($bVerbose) { if (!empty($sMessage)) { $oP->p("{$sTaskClass}: {$sMessage}"); } $oEnd = new DateTime(); $oP->p("<< === " . $oEnd->format('Y-m-d H:i:s') . sprintf(" End of: %-'=40s", ' ' . $sTaskClass . ' ')); } } else { // will run later if ($aTasks[$sTaskClass]->Get('status') == 'active' && $bVerbose) { $oP->p("Skipping asynchronous task: {$sTaskClass} until " . $aTasks[$sTaskClass]->Get('next_run_date')); } } } if ($bVerbose) { $oP->p("Sleeping"); } sleep($iCronSleep); } if ($bVerbose) { $oP->p("Reached normal execution time limit (exceeded by " . (time() - $iTimeLimit) . "s)"); } }
public static function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists) { $oSettings = new DataTableSettings($aClassAliases); // Retrieve the class specific settings for each class/alias based on the 'list' ZList //TODO let the caller pass some other default settings (another Zlist, extre fields...) $aColumns = array(); foreach ($aClassAliases as $sAlias => $sClass) { if ($aDefaultLists == null) { $aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list')); } else { $aList = $aDefaultLists[$sAlias]; } $aSortOrder = MetaModel::GetOrderByDefault($sClass); if ($bViewLink) { $sSort = 'none'; if (array_key_exists('friendlyname', $aSortOrder)) { $sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc'; } $aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true, $sSort); } foreach ($aList as $sAttCode) { $sSort = 'none'; if (array_key_exists($sAttCode, $aSortOrder)) { $sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc'; } $oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode); $aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true, $sSort); if ($aFieldData) { $aColumns[$sAlias][$sAttCode] = $aFieldData; } } } $iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns); return $oSettings; }
/** * Outputs (via some echo) the complete HTML page by assembling all its elements */ public function output() { $sAbsURLAppRoot = addslashes($this->m_sRootUrl); //$this->set_base($this->m_sRootUrl.'pages/'); $sForm = $this->GetSiloSelectionForm(); $this->DisplayMenu(); // Compute the menu // Call the extensions to add content to the page, so that they can also add styles or scripts $sBannerExtraHtml = ''; foreach (MetaModel::EnumPlugins('iPageUIExtension') as $oExtensionInstance) { $sBannerExtraHtml .= $oExtensionInstance->GetBannerHtml($this); } $sNorthPane = ''; foreach (MetaModel::EnumPlugins('iPageUIExtension') as $oExtensionInstance) { $sNorthPane .= $oExtensionInstance->GetNorthPaneHtml($this); } if (UserRights::IsAdministrator() && ExecutionKPI::IsEnabled()) { $sNorthPane .= '<div id="admin-banner"><span style="padding:5px;">' . ExecutionKPI::GetDescription() . '<span></div>'; } //$sSouthPane = '<p>Peak memory Usage: '.sprintf('%.3f MB', memory_get_peak_usage(true) / (1024*1024)).'</p>'; $sSouthPane = ''; foreach (MetaModel::EnumPlugins('iPageUIExtension') as $oExtensionInstance) { $sSouthPane .= $oExtensionInstance->GetSouthPaneHtml($this); } // Put here the 'ready scripts' that must be executed after all others $aMultiselectOptions = array('header' => true, 'checkAllText' => Dict::S('UI:SearchValue:CheckAll'), 'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'), 'noneSelectedText' => Dict::S('UI:SearchValue:Any'), 'selectedText' => Dict::S('UI:SearchValue:NbSelected'), 'selectedList' => 1); $sJSMultiselectOptions = json_encode($aMultiselectOptions); $this->add_ready_script(<<<EOF \t\t// Since the event is only triggered when the hash changes, we need to trigger \t\t// the event now, to handle the hash the page may have loaded with. \t\t\$(window).trigger( 'hashchange' ); \t\t \t\t// Some table are sort-able, some are not, let's fix this \t\t\$('table.listResults').each( function() { FixTableSorter(\$(this)); } ); \t\t \t\t\$('.multiselect').multiselect({$sJSMultiselectOptions}); \t\tFixSearchFormsDisposition(); EOF ); if ($this->GetOutputFormat() == 'html') { foreach ($this->a_headers as $s_header) { header($s_header); } } $s_captured_output = $this->ob_get_clean_safe(); $sHtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"; $sHtml .= "<html>\n"; $sHtml .= "<head>\n"; // Make sure that Internet Explorer renders the page using its latest/highest/greatest standards ! $sHtml .= "<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n"; $sHtml .= "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n"; $sHtml .= "<title>" . htmlentities($this->s_title, ENT_QUOTES, 'UTF-8') . "</title>\n"; $sHtml .= $this->get_base_tag(); // Stylesheets MUST be loaded before any scripts otherwise // jQuery scripts may face some spurious problems (like failing on a 'reload') foreach ($this->a_linked_stylesheets as $a_stylesheet) { if ($a_stylesheet['condition'] != "") { $sHtml .= "<!--[if {$a_stylesheet['condition']}]>\n"; } $sHtml .= "<link rel=\"stylesheet\" type=\"text/css\" href=\"{$a_stylesheet['link']}\" />\n"; if ($a_stylesheet['condition'] != "") { $sHtml .= "<![endif]-->\n"; } } // special stylesheet for printing, hides the navigation gadgets $sHtml .= "<link rel=\"stylesheet\" media=\"print\" type=\"text/css\" href=\"../css/print.css\" />\n"; if ($this->GetOutputFormat() == 'html') { $sHtml .= $this->output_dict_entries(true); // before any script so that they can benefit from the translations foreach ($this->a_linked_scripts as $s_script) { // 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) { $s_script .= "?itopversion=" . ITOP_VERSION; } else { $s_script .= "&itopversion=" . ITOP_VERSION; } $sHtml .= "<script type=\"text/javascript\" src=\"{$s_script}\"></script>\n"; } $this->add_script("var iPaneVisWatchDog = window.setTimeout('FixPaneVis()',5000);\n\$(document).ready(function() {\n{$this->m_sInitScript};\nwindow.setTimeout('onDelayedReady()',10)\n});"); if (count($this->m_aReadyScripts) > 0) { $this->add_script("\nonDelayedReady = function() {\n" . implode("\n", $this->m_aReadyScripts) . "\n}\n"); } if (count($this->a_scripts) > 0) { $sHtml .= "<script type=\"text/javascript\">\n"; foreach ($this->a_scripts as $s_script) { $sHtml .= "{$s_script}\n"; } $sHtml .= "</script>\n"; } } if (count($this->a_styles) > 0) { $sHtml .= "<style>\n"; foreach ($this->a_styles as $s_style) { $sHtml .= "{$s_style}\n"; } $sHtml .= "</style>\n"; } $sHtml .= "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"" . utils::GetAbsoluteUrlAppRoot() . "pages/opensearch.xml.php\" />\n"; $sHtml .= "<link rel=\"shortcut icon\" href=\"" . utils::GetAbsoluteUrlAppRoot() . "images/favicon.ico\" />\n"; $sHtml .= "</head>\n"; $sHtml .= "<body>\n"; // Render the revision number if (ITOP_REVISION == '$WCREV$') { // This is NOT a version built using the buil system, just display the main version $sVersionString = Dict::Format('UI:iTopVersion:Short', ITOP_VERSION); } else { // This is a build made from SVN, let display the full information $sVersionString = Dict::Format('UI:iTopVersion:Long', ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE); } // Render the text of the global search form $sText = htmlentities(utils::ReadParam('text', '', false, 'raw_data'), ENT_QUOTES, 'UTF-8'); $sOnClick = ""; if (empty($sText)) { // if no search text is supplied then // 1) the search text is filled with "your search" // 2) clicking on it will erase it $sText = Dict::S("UI:YourSearch"); $sOnClick = " onclick=\"this.value='';this.onclick=null;\""; } // Render the tabs in the page (if any) $this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content); if ($this->GetOutputFormat() == 'html') { $oAppContext = new ApplicationContext(); $sUserName = UserRights::GetUser(); $sIsAdmin = UserRights::IsAdministrator() ? '(Administrator)' : ''; if (UserRights::IsAdministrator()) { $sLogonMessage = Dict::Format('UI:LoggedAsMessage+Admin', $sUserName); } else { $sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName); } $sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>"; $sLogOffMenu .= "<li><span>{$sLogonMessage}</span></li>\n"; $aActions = array(); $oPrefs = new URLPopupMenuItem('UI:Preferences', Dict::S('UI:Preferences'), utils::GetAbsoluteUrlAppRoot() . "pages/preferences.php?" . $oAppContext->GetForLink()); $aActions[$oPrefs->GetUID()] = $oPrefs->GetMenuItem(); if (utils::CanLogOff()) { $oLogOff = new URLPopupMenuItem('UI:LogOffMenu', Dict::S('UI:LogOffMenu'), utils::GetAbsoluteUrlAppRoot() . 'pages/logoff.php?operation=do_logoff'); $aActions[$oLogOff->GetUID()] = $oLogOff->GetMenuItem(); } if (UserRights::CanChangePassword()) { $oChangePwd = new URLPopupMenuItem('UI:ChangePwdMenu', Dict::S('UI:ChangePwdMenu'), utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?loginop=change_pwd'); $aActions[$oChangePwd->GetUID()] = $oChangePwd->GetMenuItem(); } utils::GetPopupMenuItems($this, iPopupMenuExtension::MENU_USER_ACTIONS, null, $aActions); $oAbout = new JSPopupMenuItem('UI:AboutBox', Dict::S('UI:AboutBox'), 'return ShowAboutBox();'); $aActions[$oAbout->GetUID()] = $oAbout->GetMenuItem(); $sLogOffMenu .= $this->RenderPopupMenuItems($aActions); $sRestrictions = ''; if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE)) { if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE)) { $sRestrictions = Dict::S('UI:AccessRO-All'); } } elseif (!MetaModel::DBHasAccess(ACCESS_USER_WRITE)) { $sRestrictions = Dict::S('UI:AccessRO-Users'); } $sApplicationBanner = ''; if (strlen($sRestrictions) > 0) { $sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message')); $sApplicationBanner .= '<div id="admin-banner">'; $sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">'; $sApplicationBanner .= ' <b>' . $sRestrictions . '</b>'; if (strlen($sAdminMessage) > 0) { $sApplicationBanner .= ' <b>' . $sAdminMessage . '</b>'; } $sApplicationBanner .= '</div>'; } if (strlen($this->m_sMessage)) { $sApplicationBanner .= '<div id="admin-banner"><span style="padding:5px;">' . $this->m_sMessage . '<span></div>'; } $sApplicationBanner .= $sBannerExtraHtml; if (!empty($sNorthPane)) { $sNorthPane = '<div id="bottom-pane" class="ui-layout-north">' . $sNorthPane . '</div>'; } if (!empty($sSouthPane)) { $sSouthPane = '<div id="bottom-pane" class="ui-layout-south">' . $sSouthPane . '</div>'; } $sIconUrl = Utils::GetConfig()->Get('app_icon_url'); $sOnlineHelpUrl = MetaModel::GetConfig()->Get('online_help'); //$sLogOffMenu = "<span id=\"logOffBtn\" style=\"height:55px;padding:0;margin:0;\"><img src=\"../images/onOffBtn.png\"></span>"; $sDisplayIcon = utils::GetAbsoluteUrlAppRoot() . 'images/itop-logo.png'; if (file_exists(MODULESROOT . 'branding/main-logo.png')) { $sDisplayIcon = utils::GetAbsoluteUrlModulesRoot() . 'branding/main-logo.png'; } $sHtml .= $sNorthPane; $sHtml .= '<div id="left-pane" class="ui-layout-west">'; $sHtml .= '<!-- Beginning of the left pane -->'; $sHtml .= ' <div class="ui-layout-north">'; $sHtml .= ' <div id="header-logo">'; $sHtml .= ' <div id="top-left"></div><div id="logo"><a href="' . htmlentities($sIconUrl, ENT_QUOTES, 'UTF-8') . '"><img src="' . $sDisplayIcon . '" title="' . htmlentities($sVersionString, ENT_QUOTES, 'UTF-8') . '" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>'; $sHtml .= ' </div>'; $sHtml .= ' <div class="header-menu">'; if (!MetaModel::GetConfig()->Get('demo_mode')) { $sHtml .= ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>'; } $sHtml .= ' <div style="text-align:center;">' . self::FilterXSS($sForm) . '</div>'; $sHtml .= ' </div>'; $sHtml .= ' </div>'; $sHtml .= ' <div id="menu" class="ui-layout-center">'; $sHtml .= ' <div id="inner_menu">'; $sHtml .= ' <div id="accordion">'; $sHtml .= self::FilterXSS($this->m_sMenu); $sHtml .= ' <!-- Beginning of the accordion menu -->'; $sHtml .= ' <!-- End of the accordion menu-->'; $sHtml .= ' </div>'; $sHtml .= ' </div> <!-- /inner menu -->'; $sHtml .= ' </div> <!-- /menu -->'; $sHtml .= ' <div class="footer ui-layout-south"><div id="combodo_logo"><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logo-combodo.png"/></a></div></div>'; $sHtml .= '<!-- End of the left pane -->'; $sHtml .= '</div>'; $sHtml .= '<div class="ui-layout-center">'; $sHtml .= ' <div id="top-bar" style="width:100%">'; $sHtml .= self::FilterXSS($sApplicationBanner); $sHtml .= ' <div id="global-search"><form action="' . utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="' . $sText . '"' . $sOnClick . '/></td>'; $sHtml .= '<td><input type="image" src="../images/searchBtn.png"/></a></td>'; $sHtml .= '<td><a style="background:transparent;" href="' . $sOnlineHelpUrl . '" target="_blank"><img style="border:0;padding-left:20px;padding-right:10px;" title="' . Dict::S('UI:Help') . '" src="../images/help.png"/></td>'; $sHtml .= '<td style="padding-right:20px;padding-left:10px;">' . self::FilterXSS($sLogOffMenu) . '</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>'; //echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>'; $sHtml .= ' </div>'; $sHtml .= ' <div class="ui-layout-content" style="overflow:auto;">'; $sHtml .= ' <!-- Beginning of page content -->'; $sHtml .= self::FilterXSS($this->s_content); $sHtml .= ' <!-- End of page content -->'; $sHtml .= ' </div>'; $sHtml .= '</div>'; $sHtml .= $sSouthPane; // Add the captured output if (trim($s_captured_output) != "") { $sHtml .= "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">" . self::FilterXSS($s_captured_output) . "</div></div>\n"; } $sHtml .= "<div id=\"at_the_end\">" . self::FilterXSS($this->s_deferred_content) . "</div>"; $sHtml .= "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window $sHtml .= "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>"; $sHtml .= "<div style=\"display:none\" id=\"ajax_content\"></div>"; } else { $sHtml .= self::FilterXSS($this->s_content); } $sHtml .= "</body>\n"; $sHtml .= "</html>\n"; if ($this->GetOutputFormat() == 'html') { $oKPI = new ExecutionKPI(); echo $sHtml; $oKPI->ComputeAndReport('Echoing (' . round(strlen($sHtml) / 1024) . ' Kb)'); } else { if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf')) { if (@is_readable(APPROOT . 'lib/MPDF/mpdf.php')) { require_once APPROOT . 'lib/MPDF/mpdf.php'; $oMPDF = new mPDF('c'); $oMPDF->mirroMargins = false; if ($this->a_base['href'] != '') { $oMPDF->setBasePath($this->a_base['href']); // Seems that the <BASE> tag is not recognized by mPDF... } $oMPDF->showWatermarkText = true; if ($this->GetOutputOption('pdf', 'template_path')) { $oMPDF->setImportUse(); // Allow templates $oMPDF->SetDocTemplate($this->GetOutputOption('pdf', 'template_path'), 1); } $oMPDF->WriteHTML($sHtml); $sOutputName = $this->s_title . '.pdf'; if ($this->GetOutputOption('pdf', 'output_name')) { $sOutputName = $this->GetOutputOption('pdf', 'output_name'); } $oMPDF->Output($sOutputName, 'I'); } } } DBSearch::RecordQueryTrace(); ExecutionKPI::ReportStats(); }
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null) { if ($bForceSynchronous) { return $this->SendSynchronous($aIssues, $oLog); } else { $bConfigASYNC = MetaModel::GetConfig()->Get('email_asynchronous'); if ($bConfigASYNC) { return $this->SendAsynchronous($aIssues, $oLog); } else { return $this->SendSynchronous($aIssues, $oLog); } } }
public static function ReportStats() { if (!self::IsEnabled()) { return; } global $fItopStarted; $sExecId = microtime(); // id to differentiate the hrefs! $aBeginTimes = array(); foreach (self::$m_aExecData as $aOpStats) { $aBeginTimes[] = $aOpStats['time_begin']; } array_multisort($aBeginTimes, self::$m_aExecData); $sTableStyle = 'background-color: #ccc; margin: 10px;'; self::Report("<hr/>"); self::Report("<div style=\"background-color: grey; padding: 10px;\">"); self::Report("<h3><a name=\"" . md5($sExecId) . "\">KPIs</a> - " . $_SERVER['REQUEST_URI'] . " (" . $_SERVER['REQUEST_METHOD'] . ")</h3>"); self::Report("<p>" . date('Y-m-d H:i:s', $fItopStarted) . "</p>"); self::Report("<p>log_kpi_user_id: " . MetaModel::GetConfig()->Get('log_kpi_user_id') . "</p>"); self::Report("<div>"); self::Report("<table border=\"1\" style=\"{$sTableStyle}\">"); self::Report("<thead>"); self::Report(" <th>Operation</th><th>Begin</th><th>End</th><th>Duration</th><th>Memory start</th><th>Memory end</th><th>Memory peak</th>"); self::Report("</thead>"); foreach (self::$m_aExecData as $aOpStats) { $sOperation = $aOpStats['op']; $sBegin = $sEnd = $sDuration = $sMemBegin = $sMemEnd = $sMemPeak = '?'; $sBegin = round($aOpStats['time_begin'], 3); $sEnd = round($aOpStats['time_end'], 3); $fDuration = $aOpStats['time_end'] - $aOpStats['time_begin']; $sDuration = round($fDuration, 3); if (isset($aOpStats['mem_begin'])) { $sMemBegin = self::MemStr($aOpStats['mem_begin']); $sMemEnd = self::MemStr($aOpStats['mem_end']); if (isset($aOpStats['mem_peak'])) { $sMemPeak = self::MemStr($aOpStats['mem_peak']); } } self::Report("<tr>"); self::Report(" <td>{$sOperation}</td><td>{$sBegin}</td><td>{$sEnd}</td><td>{$sDuration}</td><td>{$sMemBegin}</td><td>{$sMemEnd}</td><td>{$sMemPeak}</td>"); self::Report("</tr>"); } self::Report("</table>"); self::Report("</div>"); $aConsolidatedStats = array(); foreach (self::$m_aStats as $sOperation => $aOpStats) { $fTotalOp = 0; $iTotalOp = 0; $fMinOp = null; $fMaxOp = 0; $sMaxOpArguments = null; foreach ($aOpStats as $sArguments => $aEvents) { foreach ($aEvents as $aEventData) { $fDuration = $aEventData['time']; $fTotalOp += $fDuration; $iTotalOp++; $fMinOp = is_null($fMinOp) ? $fDuration : min($fMinOp, $fDuration); if ($fDuration > $fMaxOp) { $sMaxOpArguments = $sArguments; $fMaxOp = $fDuration; } } } $aConsolidatedStats[$sOperation] = array('count' => $iTotalOp, 'duration' => $fTotalOp, 'min' => $fMinOp, 'max' => $fMaxOp, 'avg' => $fTotalOp / $iTotalOp, 'max_args' => $sMaxOpArguments); } self::Report("<div>"); self::Report("<table border=\"1\" style=\"{$sTableStyle}\">"); self::Report("<thead>"); self::Report(" <th>Operation</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th><th>Avg</th>"); self::Report("</thead>"); foreach ($aConsolidatedStats as $sOperation => $aOpStats) { $sOperation = '<a href="#' . md5($sExecId . $sOperation) . '">' . $sOperation . '</a>'; $sCount = $aOpStats['count']; $sDuration = round($aOpStats['duration'], 3); $sMin = round($aOpStats['min'], 3); $sMax = '<a href="#' . md5($sExecId . $aOpStats['max_args']) . '">' . round($aOpStats['max'], 3) . '</a>'; $sAvg = round($aOpStats['avg'], 3); self::Report("<tr>"); self::Report(" <td>{$sOperation}</td><td>{$sCount}</td><td>{$sDuration}</td><td>{$sMin}</td><td>{$sMax}</td><td>{$sAvg}</td>"); self::Report("</tr>"); } self::Report("</table>"); self::Report("</div>"); self::Report("</div>"); // Report operation details foreach (self::$m_aStats as $sOperation => $aOpStats) { $sOperationHtml = '<a name="' . md5($sExecId . $sOperation) . '">' . $sOperation . '</a>'; self::Report("<h4>{$sOperationHtml}</h4>"); self::Report("<p><a href=\"#" . md5($sExecId) . "\">Back to page stats</a></p>"); self::Report("<table border=\"1\" style=\"{$sTableStyle}\">"); self::Report("<thead>"); self::Report(" <th>Operation details (+ blame caller if log_kpi_duration = 2)</th><th>Count</th><th>Duration</th><th>Min</th><th>Max</th>"); self::Report("</thead>"); foreach ($aOpStats as $sArguments => $aEvents) { $sHtmlArguments = '<a name="' . md5($sExecId . $sArguments) . '"><div style="white-space: pre-wrap;">' . $sArguments . '</div></a>'; if ($aConsolidatedStats[$sOperation]['max_args'] == $sArguments) { $sHtmlArguments = '<span style="color: red;">' . $sHtmlArguments . '</span>'; } if (isset($aEvents[0]['callers'])) { $sHtmlArguments .= '<div style="padding: 10px;">'; $sHtmlArguments .= '<table border="1" bgcolor="#cfc">'; $sHtmlArguments .= '<tr><td colspan="2" bgcolor="#e9b96">Call stack for the <b>FIRST</b> caller</td></tr>'; foreach ($aEvents[0]['callers'] as $aCall) { $sHtmlArguments .= '<tr>'; $sHtmlArguments .= '<td>' . $aCall['Function'] . '</td>'; $sHtmlArguments .= '<td>' . $aCall['File'] . ':' . $aCall['Line'] . '</td>'; $sHtmlArguments .= '</tr>'; } $sHtmlArguments .= '</table>'; $sHtmlArguments .= '</div>'; } $fTotalInter = 0; $fMinInter = null; $fMaxInter = 0; foreach ($aEvents as $aEventData) { $fDuration = $aEventData['time']; $fTotalInter += $fDuration; $fMinInter = is_null($fMinInter) ? $fDuration : min($fMinInter, $fDuration); $fMaxInter = max($fMaxInter, $fDuration); } $iCountInter = count($aEvents); $sTotalInter = round($fTotalInter, 3); $sMinInter = round($fMinInter, 3); $sMaxInter = round($fMaxInter, 3); self::Report("<tr>"); self::Report(" <td>{$sHtmlArguments}</td><td>{$iCountInter}</td><td>{$sTotalInter}</td><td>{$sMinInter}</td><td>{$sMaxInter}</td>"); self::Report("</tr>"); } self::Report("</table>"); } }
public function CreateZip($sZipFile, $sSourceConfigFile = null) { // Note: the file is created by tempnam and might not be writeable by another process (Windows/IIS) // (delete it before spawning a process) $sDataFile = tempnam(SetupUtils::GetTmpDir(), 'itop-'); $this->LogInfo("Data file: '{$sDataFile}'"); $aContents = array(); $aContents[] = array('source' => $sDataFile, 'dest' => 'itop-dump.sql'); if (is_null($sSourceConfigFile)) { $sSourceConfigFile = MetaModel::GetConfig()->GetLoadedFile(); } if (!empty($sSourceConfigFile)) { $aContents[] = array('source' => $sSourceConfigFile, 'dest' => 'config-itop.php'); } $this->DoBackup($sDataFile); $sDeltaFile = APPROOT . 'data/' . utils::GetCurrentEnvironment() . '.delta.xml'; if (file_exists($sDeltaFile)) { $aContents[] = array('source' => $sDeltaFile, 'dest' => 'delta.xml'); } $sExtraDir = APPROOT . 'data/' . utils::GetCurrentEnvironment() . '-modules/'; if (is_dir($sExtraDir)) { $aContents[] = array('source' => $sExtraDir, 'dest' => utils::GetCurrentEnvironment() . '-modules/'); } $this->DoZip($aContents, $sZipFile); // Windows/IIS: the data file has been created by the spawned process... // trying to delete it will issue a warning, itself stopping the setup abruptely @unlink($sDataFile); }
private function MakeDeletionPlan(&$oDeletionPlan, $aVisited = array(), $iDeleteOption = null) { static $iLoopTimeLimit = null; if ($iLoopTimeLimit == null) { $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); } $sClass = get_class($this); $iThisId = $this->GetKey(); $iDeleteOption = $oDeletionPlan->AddToDelete($this, $iDeleteOption); if (array_key_exists($sClass, $aVisited)) { if (in_array($iThisId, $aVisited[$sClass])) { return; } } $aVisited[$sClass] = $iThisId; if ($iDeleteOption == DEL_MANUAL) { // Stop the recursion here return; } // Check the node itself $this->DoCheckToDelete($oDeletionPlan); $oDeletionPlan->SetDeletionIssues($this, $this->m_aDeleteIssues, $this->m_bSecurityIssue); $aDependentObjects = $this->GetReferencingObjects(true); // Getting and setting time limit are not symetric: // www.php.net/manual/fr/function.set-time-limit.php#72305 $iPreviousTimeLimit = ini_get('max_execution_time'); foreach ($aDependentObjects as $sRemoteClass => $aPotentialDeletes) { foreach ($aPotentialDeletes as $sRemoteExtKey => $aData) { set_time_limit($iLoopTimeLimit); $oAttDef = $aData['attribute']; $iDeletePropagationOption = $oAttDef->GetDeletionPropagationOption(); $oDepSet = $aData['objects']; $oDepSet->Rewind(); while ($oDependentObj = $oDepSet->fetch()) { $iId = $oDependentObj->GetKey(); if ($oAttDef->IsNullAllowed()) { // Optional external key, list to reset if ($iDeletePropagationOption == DEL_MOVEUP && $oAttDef->IsHierarchicalKey()) { // Move the child up one level i.e. set the same parent as the current object $iParentId = $this->Get($oAttDef->GetCode()); $oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef, $iParentId); } else { $oDeletionPlan->AddToUpdate($oDependentObj, $oAttDef); } } else { // Mandatory external key, list to delete $oDependentObj->MakeDeletionPlan($oDeletionPlan, $aVisited, $iDeletePropagationOption); } } } } set_time_limit($iPreviousTimeLimit); }
/** * Renders the "Actions" popup menu for the given set of objects * * Note that the menu links containing (or ending) with a hash (#) will have their fragment * part (whatever is after the hash) dynamically replaced (by javascript) when the menu is * displayed, to correspond to the current hash/fragment in the page. This allows modifying * an object in with the same tab active by default as the tab that was active when selecting * the "Modify..." action. */ public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId) { if ($this->m_sStyle == 'popup') { $this->m_sStyle = 'list'; } $sHtml = ''; $oAppContext = new ApplicationContext(); $sContext = $oAppContext->GetForLink(); if (!empty($sContext)) { $sContext = '&' . $sContext; } $sClass = $this->m_oFilter->GetClass(); $oReflectionClass = new ReflectionClass($sClass); $oSet = new CMDBObjectSet($this->m_oFilter); $sFilter = $this->m_oFilter->serialize(); $sFilterDesc = $this->m_oFilter->ToOql(true); $aActions = array(); $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass); $sRootUrl = utils::GetAbsoluteUrlAppRoot(); // 1:n links, populate the target object as a default value when creating a new linked object if (isset($aExtraParams['target_attr'])) { $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id']; } $sDefault = ''; if (!empty($aExtraParams['default'])) { foreach ($aExtraParams['default'] as $sKey => $sValue) { $sDefault .= "&default[{$sKey}]={$sValue}"; } } $bIsCreationAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); switch ($oSet->Count()) { case 0: // No object in the set, the only possible action is "new" if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}"); } break; case 1: $oObj = $oSet->Fetch(); $id = $oObj->GetKey(); $bLocked = false; if (MetaModel::GetConfig()->Get('concurrent_lock_enabled')) { $aLockInfo = iTopOwnershipLock::IsLocked(get_class($oObj), $id); if ($aLockInfo['locked']) { $bLocked = true; //$this->AddMenuSeparator($aActions); //$aActions['concurrent_lock_unlock'] = array ('label' => Dict::S('UI:Menu:ReleaseConcurrentLock'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}"); } } $bRawModifiedAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); $bIsModifyAllowed = !$bLocked && $bRawModifiedAllowed; $bIsDeleteAllowed = !$bLocked && UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet); // Just one object in the set, possible actions are "new / clone / modify and delete" if (!isset($aExtraParams['link_attr'])) { if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify&class={$sClass}&id={$id}{$sContext}#"); } if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}"); } if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=delete&class={$sClass}&id={$id}{$sContext}"); } // Transitions / Stimuli if (!$bLocked) { $aTransitions = $oObj->EnumTransitions(); if (count($aTransitions)) { $this->AddMenuSeparator($aActions); $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; switch ($iActionAllowed) { case UR_ALLOWED_YES: $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus={$sStimulusCode}&class={$sClass}&id={$id}{$sContext}"); break; default: // Do nothing } } } } // Relations... $aRelations = MetaModel::EnumRelationsEx($sClass); if (count($aRelations)) { $this->AddMenuSeparator($aActions); foreach ($aRelations as $sRelationCode => $aRelationInfo) { if (array_key_exists('down', $aRelationInfo)) { $aActions[$sRelationCode . '_down'] = array('label' => $aRelationInfo['down'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=down&class={$sClass}&id={$id}{$sContext}"); } if (array_key_exists('up', $aRelationInfo)) { $aActions[$sRelationCode . '_up'] = array('label' => $aRelationInfo['up'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=up&class={$sClass}&id={$id}{$sContext}"); } } } if ($bLocked && $bRawModifiedAllowed) { // Add a special menu to kill the lock, but only to allowed users who can also modify this object $aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles'); $bCanKill = false; $oUser = UserRights::GetUserObject(); $aUserProfiles = array(); if (!is_null($oUser)) { $oProfileSet = $oUser->Get('profile_list'); while ($oProfile = $oProfileSet->Fetch()) { $aUserProfiles[$oProfile->Get('profile')] = true; } } foreach ($aAllowedProfiles as $sProfile) { if (array_key_exists($sProfile, $aUserProfiles)) { $bCanKill = true; break; } } if ($bCanKill) { $this->AddMenuSeparator($aActions); $aActions['concurrent_lock_unlock'] = array('label' => Dict::S('UI:Menu:KillConcurrentLock'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=kill_lock&class={$sClass}&id={$id}{$sContext}"); } } /* $this->AddMenuSeparator($aActions); // Static menus: Email this page & CSV Export $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id); $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl)); $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}"); // The style tells us whether the menu is displayed on a list of one object, or on the details of the given object if ($this->m_sStyle == 'list') { // Actions specific to the list $sOQL = addslashes($sFilterDesc); $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')"); } */ } $this->AddMenuSeparator($aActions); foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) { $oSet->Rewind(); foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) { $aActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl); } } break; default: // Check rights // New / Modify $bIsModifyAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); $bIsBulkModifyAllowed = !MetaModel::IsAbstract($sClass) && UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); $bIsBulkDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, $oSet); if (isset($aExtraParams['link_attr'])) { $id = $aExtraParams['object_id']; $sTargetAttr = $aExtraParams['target_attr']; $oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr); $sTargetClass = $oAttDef->GetTargetClass(); $bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet); if ($bIsModifyAllowed) { $aActions['UI:Menu:Add'] = array('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}&addObjects=true{$sContext}"); } if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:Manage'] = array('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}{$sContext}"); } //if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); } } else { // many objects in the set, possible actions are: new / modify all / delete all if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}"); } if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_modify_all&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}"); } if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_deletion&filter=" . urlencode($sFilter) . "{$sContext}"); } // Stimuli $aStates = MetaModel::EnumStates($sClass); // Do not perform time consuming computations if there are too may objects in the list $iLimit = MetaModel::GetConfig()->Get('complex_actions_limit'); if (count($aStates) > 0 && ($iLimit == 0 || $oSet->Count() < $iLimit)) { // Life cycle actions may be available... if all objects are in the same state // // Group by <state> $oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias()); $aGroupBy = array('__state__' => $oGroupByExp); $aQueryParams = array(); if (isset($aExtraParams['query_params'])) { $aQueryParams = $aExtraParams['query_params']; } $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy); $aRes = CMDBSource::QueryToArray($sSql); if (count($aRes) == 1) { // All objects are in the same state... $sState = $aRes[0]['__state__']; $aTransitions = Metamodel::EnumTransitions($sClass, $sState); if (count($aTransitions)) { $this->AddMenuSeparator($aActions); $aStimuli = Metamodel::EnumStimuli($sClass); foreach ($aTransitions as $sStimulusCode => $aTransitionDef) { $oSet->Rewind(); // As soon as the user rights implementation will browse the object set, // then we might consider using OptimizeColumnLoad() here $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet); $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? $iActionAllowed : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: case UR_ALLOWED_DEPENDS: $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus={$sStimulusCode}&state={$sState}&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}"); break; default: // Do nothing } } } } } /* $this->AddMenuSeparator($aActions); $sUrl = utils::GetAbsoluteUrlAppRoot(); $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}")); $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}"); $sOQL = addslashes($sFilterDesc); $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')"); */ } } $this->AddMenuSeparator($aActions); foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) { $oSet->Rewind(); foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) { if (is_array($data)) { // New plugins can provide javascript handlers via the 'onclick' property //TODO: enable extension of different menus by checking the 'target' property ?? $aActions[$sLabel] = array('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : ''); } else { // Backward compatibility with old plugins $aActions[$sLabel] = array('label' => $sLabel, 'url' => $data); } } } // New extensions based on iPopupMenuItem interface switch ($this->m_sStyle) { case 'list': $oSet->Rewind(); $param = $oSet; $iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS; break; case 'details': $oSet->Rewind(); $param = $oSet->Fetch(); $iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS; break; } utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions); $aFavoriteActions = array(); $aCallSpec = array($sClass, 'GetShortcutActions'); if (is_callable($aCallSpec)) { $aShortcutActions = call_user_func($aCallSpec, $sClass); foreach ($aActions as $key => $aAction) { if (in_array($key, $aShortcutActions)) { $aFavoriteActions[] = $aAction; unset($aActions[$key]); } } } else { $aShortcutActions = array(); } if (count($aFavoriteActions) > 0) { $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:OtherActions') . "\n<ul>\n"; } else { $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:Actions') . "\n<ul>\n"; } $sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions); static $bPopupScript = false; if (!$bPopupScript) { // Output this once per page... $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n"); $bPopupScript = true; } return $sHtml; }
// Build the ordered list of classes to search into // if (empty($sClassName)) { $aSearchClasses = MetaModel::GetClasses('searchable'); } else { // Search is limited to a given class and its subclasses $aSearchClasses = MetaModel::EnumChildClasses($sClassName, ENUM_CHILD_CLASSES_ALL); } // Skip abstract classes, since we search in all the child classes anyway foreach ($aSearchClasses as $idx => $sClass) { if (MetaModel::IsAbstract($sClass)) { unset($aSearchClasses[$idx]); } } $sMaxChunkDuration = MetaModel::GetConfig()->Get('full_text_chunk_duration'); $aAccelerators = MetaModel::GetConfig()->Get('full_text_accelerators'); foreach (array_reverse($aAccelerators) as $sClass => $aRestriction) { $bSkip = false; $iPos = array_search($sClass, $aSearchClasses); if ($iPos !== false) { unset($aSearchClasses[$iPos]); } else { $bSkip = true; } $bSkip |= array_key_exists('skip', $aRestriction) ? $aRestriction['skip'] : false; if (!in_array($sClass, $aSearchClasses)) { if ($sClass == $sClassName) { // Class explicitely requested, do NOT skip it // beware: there may not be a 'query' defined for a skipped class ! $bSkip = false; }
/** * Applies the defined parameters into the SQL query * @return string the SQL query to execute */ public function BuildQuery() { $oAppContext = new ApplicationContext(); $sQuery = $this->m_sQuery; $sQuery = str_replace('$DB_PREFIX$', MetaModel::GetConfig()->GetDBSubname(), $sQuery); // put the tables DB prefix (if any) foreach ($this->m_aParams as $sName => $aParam) { if ($aParam['type'] == 'context') { $sSearchPattern = '/\\$CONDITION\\(' . $sName . ',([^\\)]+)\\)\\$/'; $value = $oAppContext->GetCurrentValue($aParam['mapping']); if (empty($value)) { $sSQLExpr = '(1)'; } else { // Special case for managing the hierarchy of organizations if ($aParam['mapping'] == 'org_id' && MetaModel::IsValidClass('Organization')) { $sHierarchicalKeyCode = MetaModel::IsHierarchicalClass('Organization'); if ($sHierarchicalKeyCode != false) { // organizations are in hierarchy... gather all the orgs below the given one... $sOQL = "SELECT Organization AS node JOIN Organization AS root ON node.{$sHierarchicalKeyCode} BELOW root.id WHERE root.id = :value"; $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array(), array('value' => $value)); $aOrgIds = array(); while ($oOrg = $oSet->Fetch()) { $aOrgIds[] = $oOrg->GetKey(); } $sSQLExpr = '($1 IN(' . implode(',', $aOrgIds) . '))'; } else { $sSQLExpr = '($1 = ' . CMDBSource::Quote($value) . ')'; } } else { $sSQLExpr = '($1 = ' . CMDBSource::Quote($value) . ')'; } } $sQuery = preg_replace($sSearchPattern, $sSQLExpr, $sQuery); } } return $sQuery; }
// Therefore we don't use the standard "search_oql" operation of UI.php to display the CSV $iCategory = utils::ReadParam('category', ''); $iRuleIndex = utils::ReadParam('rule', 0); $oAuditCategory = MetaModel::GetObject('AuditCategory', $iCategory); $oDefinitionFilter = DBObjectSearch::FromOQL($oAuditCategory->Get('definition_set')); FilterByContext($oDefinitionFilter, $oAppContext); $oDefinitionSet = new CMDBObjectSet($oDefinitionFilter); $oFilter = GetRuleResultFilter($iRuleIndex, $oDefinitionFilter, $oAppContext); $oErrorObjectSet = new CMDBObjectSet($oFilter); $oAuditRule = MetaModel::GetObject('AuditRule', $iRuleIndex); $sFileName = utils::ReadParam('filename', null, true, 'string'); $bAdvanced = utils::ReadParam('advanced', false); $sAdvanced = $bAdvanced ? '&advanced=1' : ''; if ($sFileName != null) { $oP = new CSVPage("iTop - Export"); $sCharset = MetaModel::GetConfig()->Get('csv_file_default_charset'); $sCSVData = cmdbAbstractObject::GetSetAsCSV($oErrorObjectSet, array('localize_values' => true, 'fields_advanced' => $bAdvanced), $sCharset); if ($sCharset == 'UTF-8') { $sOutputData = UTF8_BOM . $sCSVData; } else { $sOutputData = $sCSVData; } if ($sFileName == '') { // Plain text => Firefox will NOT propose to download the file $oP->add_header("Content-type: text/plain; charset={$sCharset}"); } else { $oP->add_header("Content-type: text/csv; charset={$sCharset}"); } $oP->add($sOutputData); $oP->TrashUnexpectedOutput(); $oP->output();
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $aSelectedClasses = $this->oSearch->GetSelectedClasses(); $aAliases = array_keys($aSelectedClasses); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $aAliasByField = array(); $aColumnsToLoad = array(); // Prepare the list of aliases / columns to load foreach ($this->aStatusInfo['fields'] as $sExtendedAttCode) { if (preg_match('/^([^\\.]+)\\.(.+)$/', $sExtendedAttCode, $aMatches)) { $sAlias = $aMatches[1]; $sAttCode = $aMatches[2]; } else { $sAlias = reset($aAliases); $sAttCode = $sExtendedAttCode; } if (!in_array($sAlias, $aAliases)) { throw new Exception("Invalid alias '{$sAlias}' for the column '{$sExtendedAttCode}'. Availables aliases: '" . implode("', '", $aAliases) . "'"); } if (!array_key_exists($sAlias, $aColumnsToLoad)) { $aColumnsToLoad[$sAlias] = array(); } if ($sAttCode != 'id') { // id is not a real attribute code and, moreover, is always loaded $aColumnsToLoad[$sAlias][] = $sAttCode; } $aAliasByField[$sExtendedAttCode] = array('alias' => $sAlias, 'attcode' => $sAttCode); } $iCount = 0; $sData = ''; $oSet->OptimizeColumnLoad($aColumnsToLoad); $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $sFirstAlias = reset($aAliases); $sHilightClass = $aRow[$sFirstAlias]->GetHilightClass(); if ($sHilightClass != '') { $sData .= "<tr class=\"{$sHilightClass}\">"; } else { $sData .= "<tr>"; } foreach ($aAliasByField as $aAttCode) { $sField = ''; switch ($aAttCode['attcode']) { case 'id': $sField = $aRow[$aAttCode['alias']]->GetHyperlink(); break; default: $sField = $aRow[$aAttCode['alias']]->GetAsHtml($aAttCode['attcode']); } $sValue = $sField === '' ? ' ' : $sField; $sData .= "<td>{$sValue}</td>"; } $sData .= "</tr>"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
} if ($bPortal) { $sUrl .= 'portal/'; } else { $sUrl .= 'pages/UI.php'; } if (isset($_SESSION['auth_user'])) { $sAuthUser = $_SESSION['auth_user']; UserRights::Login($sAuthUser); // Set the user's language } $sLoginMode = isset($_SESSION['login_mode']) ? $_SESSION['login_mode'] : ''; LoginWebPage::ResetSession(); switch ($sLoginMode) { case 'cas': $sCASLogoutUrl = MetaModel::GetConfig()->Get('cas_logout_redirect_service'); if (empty($sCASLogoutUrl)) { $sCASLogoutUrl = $sUrl; } utils::InitCASClient(); phpCAS::logoutWithRedirectService($sCASLogoutUrl); // Redirects to the CAS logout page break; } $oPage = LoginWebPage::NewLoginWebPage(); $oPage->no_cache(); $oPage->DisplayLoginHeader(); $oPage->add("<div id=\"login\">\n"); $oPage->add("<h1>" . Dict::S('UI:LogOff:ThankYou') . "</h1>\n"); $oPage->add("<p><a href=\"{$sUrl}\">" . Dict::S('UI:LogOff:ClickHereToLoginAgain') . "</a></p>"); $oPage->add("</div>\n");
/** * Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...) * for the given attribute in the current state of the object * @param $sAttCode string $sAttCode The code of the attribute * @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas) * @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used * @return integer Flags: the binary combination of the flags applicable to this attribute */ public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '') { $iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState); if (MetaModel::GetConfig()->Get('demo_mode')) { $aReasons[] = 'Sorry, profiles are read-only in the demonstration mode!'; $iFlags |= OPT_ATT_READONLY; } return $iFlags; }
public function GetMaxRetries() { $iMaxRetries = 0; $aRetries = MetaModel::GetConfig()->Get('async_task_retries', array()); if (is_array($aRetries) && array_key_exists(get_class($this), $aRetries)) { $aConfig = $aRetries[get_class($this)]; $iMaxRetries = $aConfig['max_retries']; } }
/** * Generates the javascript code handle the "watchdog" associated with the concurrent access locking mechanism * @param Webpage $oPage * @param string $sOwnershipToken */ protected function GetOwnershipJSHandler($oPage, $sOwnershipToken) { $iInterval = max(MIN_WATCHDOG_INTERVAL, MetaModel::GetConfig()->Get('concurrent_lock_expiration_delay')) * 1000 / 2; // Minimum interval for the watchdog is MIN_WATCHDOG_INTERVAL $sJSClass = json_encode(get_class($this)); $iKey = (int) $this->GetKey(); $sJSToken = json_encode($sOwnershipToken); $sJSTitle = json_encode(Dict::S('UI:DisconnectedDlgTitle')); $sJSOk = json_encode(Dict::S('UI:Button:Ok')); $oPage->add_ready_script(<<<EOF \t\twindow.setInterval(function() { \t\t\tif (window.bInSubmit || window.bInCancel) return; \t\t\t \t\t\t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'extend_lock', obj_class: {$sJSClass}, obj_key: {$iKey}, token: {$sJSToken} }, function(data) { \t\t\t\tif (!data.status) \t\t\t\t{ \t\t\t\t\tif (\$('.lock_owned').length == 0) \t\t\t\t\t{ \t\t\t\t\t\t\$('.ui-layout-content').prepend('<div class="header_message message_error lock_owned">'+data.message+'</div>'); \t\t\t\t\t\t\$('<div>'+data.popup_message+'</div>').dialog({title: {$sJSTitle}, modal: true, autoOpen: true, buttons:[ {text: {$sJSOk}, click: function() { \$(this).dialog('close'); } }], close: function() { \$(this).remove(); }}); \t\t\t\t\t} \t\t\t\t\t\$('.wizContainer form button.action:not(.cancel)').attr('disabled', 'disabled'); \t\t\t\t} \t\t\t\telse if ((data.operation == 'lost') || (data.operation == 'expired')) \t\t\t\t{ \t\t\t\t\tif (\$('.lock_owned').length == 0) \t\t\t\t\t{ \t\t\t\t\t\t\$('.ui-layout-content').prepend('<div class="header_message message_error lock_owned">'+data.message+'</div>'); \t\t\t\t\t\t\$('<div>'+data.popup_message+'</div>').dialog({title: {$sJSTitle}, modal: true, autoOpen: true, buttons:[ {text: {$sJSOk}, click: function() { \$(this).dialog('close'); } }], close: function() { \$(this).remove(); }}); \t\t\t\t\t} \t\t\t\t\t\$('.wizContainer form button.action:not(.cancel)').attr('disabled', 'disabled'); \t\t\t\t} \t\t\t}, 'json'); \t\t}, {$iInterval}); EOF ); }
protected static function Write($sText) { $bLogEnabled = MetaModel::GetConfig()->Get('log_transactions'); if ($bLogEnabled) { $hLogFile = @fopen(APPROOT . 'log/transactions.log', 'a'); if ($hLogFile !== false) { flock($hLogFile, LOCK_EX); $sDate = date('Y-m-d H:i:s'); fwrite($hLogFile, "{$sDate} | {$sText}\n"); fflush($hLogFile); flock($hLogFile, LOCK_UN); fclose($hLogFile); } } }
} } } ///////////////////////////////////////////////////////////////////// // Main program // LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin) //$sOperation = utils::ReadParam('operation', 'menu'); //$oAppContext = new ApplicationContext(); $oP = new iTopWebPage(Dict::S('config-edit-title')); $oP->set_base(utils::GetAbsoluteUrlAppRoot() . 'pages/'); try { $sOperation = utils::ReadParam('operation', ''); $oP->add("<h1>" . Dict::S('config-edit-title') . "</h1>"); if (MetaModel::GetConfig()->Get('demo_mode')) { $oP->add("<div class=\"header_message message_info\">Sorry, iTop is in <b>demonstration mode</b>: the configuration file cannot be edited.</div>"); } else { $oP->add_style(<<<EOF textarea { \t-webkit-box-sizing: border-box; \t-moz-box-sizing: border-box; \tbox-sizing: border-box; \twidth: 100%; \theight: 550px; } .current_line { \tdisplay: none; \tmargin-left: 20px; }
protected static function HandleOperations($operation) { $sMessage = ''; // most of the operations never return, but some can return a message to be displayed if ($operation == 'logoff') { if (isset($_SESSION['login_mode'])) { $sLoginMode = $_SESSION['login_mode']; } else { $aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes(); if (count($aAllowedLoginTypes) > 0) { $sLoginMode = $aAllowedLoginTypes[0]; } else { $sLoginMode = 'form'; } } self::ResetSession(); $oPage = self::NewLoginWebPage(); $oPage->DisplayLoginForm($sLoginMode, false); $oPage->output(); exit; } else { if ($operation == 'forgot_pwd') { $oPage = self::NewLoginWebPage(); $oPage->DisplayForgotPwdForm(); $oPage->output(); exit; } else { if ($operation == 'forgot_pwd_go') { $oPage = self::NewLoginWebPage(); $oPage->ForgotPwdGo(); $oPage->output(); exit; } else { if ($operation == 'reset_pwd') { $oPage = self::NewLoginWebPage(); $oPage->DisplayResetPwdForm(); $oPage->output(); exit; } else { if ($operation == 'do_reset_pwd') { $oPage = self::NewLoginWebPage(); $oPage->DoResetPassword(); $oPage->output(); exit; } else { if ($operation == 'change_pwd') { $sAuthUser = $_SESSION['auth_user']; UserRights::Login($sAuthUser); // Set the user's language $oPage = self::NewLoginWebPage(); $oPage->DisplayChangePwdForm(); $oPage->output(); exit; } } } } } } if ($operation == 'do_change_pwd') { $sAuthUser = $_SESSION['auth_user']; UserRights::Login($sAuthUser); // Set the user's language $sOldPwd = utils::ReadPostedParam('old_pwd', '', false, 'raw_data'); $sNewPwd = utils::ReadPostedParam('new_pwd', '', false, 'raw_data'); if (UserRights::CanChangePassword() && (!UserRights::CheckCredentials($sAuthUser, $sOldPwd) || !UserRights::ChangePassword($sOldPwd, $sNewPwd))) { $oPage = self::NewLoginWebPage(); $oPage->DisplayChangePwdForm(true); // old pwd was wrong $oPage->output(); exit; } $sMessage = Dict::S('UI:Login:PasswordChanged'); } return $sMessage; }
/** * Get the context definitions from the parameters / configuration. The format of the "key" string is: * <module>/relation_context/<class>/<relation>/<direction> * The values will be retrieved for the given class and all its parents and merged together as a single array. * Entries with an invalid query are removed from the list. * @param string $sContextKey The key to fetch the queries in the configuration. Example: itop-tickets/relation_context/UserRequest/impacts/down * @param bool $bDevelopParams Whether or not to substitute the parameters inside the queries with the supplied "context params" * @param array $aContextParams Arguments for the queries (via ToArgs()) if $bDevelopParams == true * @return multitype:multitype:string */ public static function GetContextDefinitions($sContextKey, $bDevelopParams = true, $aContextParams = array()) { $aContextDefs = array(); $aLevels = explode('/', $sContextKey); if (count($aLevels) < 5) { IssueLog::Warning("GetContextDefinitions: invalid 'sContextKey' = '{$sContextKey}'. 5 levels of / are expected !"); } else { $sLeafClass = $aLevels[2]; if (!MetaModel::IsValidClass($sLeafClass)) { IssueLog::Warning("GetContextDefinitions: invalid 'sLeafClass' = '{$sLeafClass}'. A valid class name is expected in 3rd position inside '{$sContextKey}' !"); } else { $aRelationContext = MetaModel::GetConfig()->GetModuleSetting($aLevels[0], $aLevels[1], array()); foreach (MetaModel::EnumParentClasses($sLeafClass, ENUM_PARENT_CLASSES_ALL) as $sClass) { if (isset($aRelationContext[$sClass][$aLevels[3]][$aLevels[4]]['items'])) { $aContextDefs = array_merge($aContextDefs, $aRelationContext[$sClass][$aLevels[3]][$aLevels[4]]['items']); } } // Check if the queries are valid foreach ($aContextDefs as $sKey => $sDefs) { $sOQL = $aContextDefs[$sKey]['oql']; try { // Expand the parameters. If anything goes wrong, then the query is considered as invalid and removed from the list $oSearch = DBObjectSearch::FromOQL($sOQL); $aContextDefs[$sKey]['oql'] = $oSearch->ToOQL($bDevelopParams, $aContextParams); } catch (Exception $e) { IssueLog::Warning('Invalid OQL query: ' . $sOQL . ' in the parameter ' . $sContextKey); unset($aContextDefs[$sKey]); } } } } return $aContextDefs; }
/** * Updates the object form POSTED arguments, and writes it into the DB (applies a stimuli if requested) * @param DBObject $oObj The object to update * $param array $aAttList If set, this will limit the list of updated attributes * @return void */ public function DoUpdateObjectFromPostedForm(DBObject $oObj, $aAttList = null) { $sTransactionId = utils::ReadPostedParam('transaction_id', ''); if (!utils::IsTransactionValid($sTransactionId)) { throw new TransactionException(); } $sClass = get_class($oObj); $sStimulus = trim(utils::ReadPostedParam('apply_stimulus', '')); $sTargetState = ''; if (!empty($sStimulus)) { // Compute the target state $aTransitions = $oObj->EnumTransitions(); if (!isset($aTransitions[$sStimulus])) { throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel())); } $sTargetState = $aTransitions[$sStimulus]['target_state']; } $oObj->UpdateObjectFromPostedForm('', $aAttList, $sTargetState); // Optional: apply a stimulus // if (!empty($sStimulus)) { if (!$oObj->ApplyStimulus($sStimulus)) { throw new Exception("Cannot apply stimulus '{$sStimulus}' to {$oObj->GetName()}"); } } if ($oObj->IsModified()) { // Record the change // $oObj->DBUpdate(); // Trigger ? // $aClasses = MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL); $sClassList = implode(", ", CMDBSource::Quote($aClasses)); $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnPortalUpdate AS t WHERE t.target_class IN ({$sClassList})")); while ($oTrigger = $oSet->Fetch()) { $oTrigger->DoActivate($oObj->ToArgs('this')); } $this->p("<h1>" . Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName()) . "</h1>\n"); } $bLockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled'); if ($bLockEnabled) { // Release the concurrent lock, if any $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, false, 'raw_data'); if ($sOwnershipToken !== null) { // We're done, let's release the lock iTopOwnershipLock::ReleaseLock(get_class($oObj), $oObj->GetKey(), $sOwnershipToken); } } }
public function AllowTargetCreation() { return $this->GetOptional('allow_target_creation', MetaModel::GetConfig()->Get('allow_target_creation')); }
public function GetNextChunk(&$aStatus) { $sRetCode = 'run'; $iPercentage = 0; $oSet = new DBObjectSet($this->oSearch); $oSet->SetLimit($this->iChunkSize, $this->aStatusInfo['position']); $this->OptimizeColumnLoad($oSet); $iCount = 0; $sData = ''; $iPreviousTimeLimit = ini_get('max_execution_time'); $iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop'); while ($aRow = $oSet->FetchAssoc()) { set_time_limit($iLoopTimeLimit); $aData = array(); foreach ($this->aStatusInfo['fields'] as $iCol => $aFieldSpec) { $sAlias = $aFieldSpec['sAlias']; $sAttCode = $aFieldSpec['sAttCode']; $sField = ''; $oObj = $aRow[$sAlias]; if ($oObj != null) { switch ($sAttCode) { case 'id': $sField = $oObj->GetKey(); break; default: $sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput); } } if ($this->aStatusInfo['charset'] != 'UTF-8') { // Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string // and thus to convert field by field and not the whole row or file at once (see ticket #991) $aData[] = iconv('UTF-8', $this->aStatusInfo['charset'] . '//IGNORE//TRANSLIT', $sField); } else { $aData[] = $sField; } } $sData .= implode($this->aStatusInfo['separator'], $aData) . "\n"; $iCount++; } set_time_limit($iPreviousTimeLimit); $this->aStatusInfo['position'] += $this->iChunkSize; if ($this->aStatusInfo['total'] == 0) { $iPercentage = 100; } else { $iPercentage = floor(min(100.0, 100.0 * $this->aStatusInfo['position'] / $this->aStatusInfo['total'])); } if ($iCount < $this->iChunkSize) { $sRetCode = 'done'; } $aStatus = array('code' => $sRetCode, 'message' => Dict::S('Core:BulkExport:RetrievingData'), 'percentage' => $iPercentage); return $sData; }
/** * Do the synchronization job #1: Obsolete replica "untouched" for some time * @param integer $iMaxReplica Limit the number of replicas to process * @param integer $iCurrPos Current position where to resume the processing * @return true if the process must be continued */ protected function DoJob1($iMaxReplica = null, $iCurrPos = -1) { $sLimitDate = $this->m_oLastFullLoadStartDate->Format('Y-m-d H:i:s'); // Get all the replicas that were not seen in the last import and mark them as obsolete $sDeletePolicy = $this->m_oDataSource->Get('delete_policy'); if ($sDeletePolicy != 'ignore') { $sSelectToObsolete = "SELECT SynchroReplica WHERE id > :curr_pos AND sync_source_id = :source_id AND status IN ('new', 'synchronized', 'modified', 'orphan') AND status_last_seen < :last_import"; $oSetScope = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToObsolete), array(), array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sLimitDate, 'curr_pos' => $iCurrPos)); $iCountScope = $oSetScope->Count(); if ($this->m_iCountAllReplicas > 10 && $this->m_iCountAllReplicas == $iCountScope && MetaModel::GetConfig()->Get('synchro_prevent_delete_all')) { throw new SynchroExceptionNotStarted(Dict::S('Core:SyncTooManyMissingReplicas')); } if ($iMaxReplica) { // Consider a given subset, starting from replica iCurrPos, limited to the count of iMaxReplica // The replica have to be ordered by id $oSetToProcess = new DBObjectSet(DBObjectSearch::FromOQL($sSelectToObsolete), array('id' => true), array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sLimitDate, 'curr_pos' => $iCurrPos)); $oSetToProcess->SetLimit($iMaxReplica); } else { $oSetToProcess = $oSetScope; } $iLastReplicaProcessed = -1; while ($oReplica = $oSetToProcess->Fetch()) { $iLastReplicaProcessed = $oReplica->GetKey(); switch ($sDeletePolicy) { case 'update': case 'update_then_delete': $this->m_oStatLog->AddTrace("Destination object to be updated", $oReplica); $aToUpdate = array(); $aToUpdateSpec = explode(';', $this->m_oDataSource->Get('delete_policy_update')); //ex: 'status:obsolete;description:stopped', foreach ($aToUpdateSpec as $sUpdateSpec) { $aUpdateSpec = explode(':', $sUpdateSpec); if (count($aUpdateSpec) == 2) { $sAttCode = $aUpdateSpec[0]; $sValue = $aUpdateSpec[1]; $aToUpdate[$sAttCode] = $sValue; } } $oReplica->Set('status_last_error', ''); if ($oReplica->Get('dest_id') == '') { $oReplica->Set('status', 'obsolete'); $this->m_oStatLog->Inc('stats_nb_replica_disappeared_no_action'); } else { $oReplica->UpdateDestObject($aToUpdate, $this->m_oChange, $this->m_oStatLog); if ($oReplica->Get('status_last_error') == '') { // Change the status of the replica IIF $oReplica->Set('status', 'obsolete'); } } $oReplica->DBUpdateTracked($this->m_oChange); break; case 'delete': default: $this->m_oStatLog->AddTrace("Destination object to be DELETED", $oReplica); $oReplica->DeleteDestObject($this->m_oChange, $this->m_oStatLog); } } if ($iMaxReplica) { if ($iMaxReplica < $iCountScope) { // Continue with this job! $this->m_oStatLog->Set('status_curr_pos', $iLastReplicaProcessed); return true; } } } // if ($sDeletePolicy != 'ignore' //Count "seen" objects $sSelectSeen = "SELECT SynchroReplica WHERE sync_source_id = :source_id AND status IN ('new', 'synchronized', 'modified', 'orphan') AND status_last_seen >= :last_import"; $oSetSeen = new DBObjectSet(DBObjectSearch::FromOQL($sSelectSeen), array(), array('source_id' => $this->m_oDataSource->GetKey(), 'last_import' => $sLimitDate)); $this->m_oStatLog->Set('stats_nb_replica_seen', $oSetSeen->Count()); // Job complete! $this->m_oStatLog->Set('status_curr_job', 2); $this->m_oStatLog->Set('status_curr_pos', -1); return false; }