/** * Main page of iTop * * @copyright Copyright (C) 2010-2012 Combodo SARL * @license http://opensource.org/licenses/AGPL-3.0 */ /** * Displays a popup welcome message, once per session at maximum * until the user unchecks the "Display welcome at startup" * @param WebPage $oP The current web page for the display * @return void */ function DisplayWelcomePopup(WebPage $oP) { if (!isset($_SESSION['welcome'])) { // Check, only once per session, if the popup should be displayed... // If the user did not already ask for hiding it forever $bPopup = appUserPreferences::GetPref('welcome_popup', true); if ($bPopup) { $sTemplate = @file_get_contents('../application/templates/welcome_popup.html'); if ($sTemplate !== false) { $oTemplate = new DisplayTemplate($sTemplate); $oP->add("
\n"); $oP->add("
Missing Attributes
".print_r($aExpectedAttributes, true)."\n"; $oP->add_header('Location: '.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=stimulus&class='.get_class($oObj).'&stimulus='.$sNextAction.'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink()); } } function ReloadAndDisplay($oPage, $oObj, $sMessageId = '', $sMessage = '', $sSeverity = null) { $oAppContext = new ApplicationContext(); if ($sMessageId != '') { cmdbAbstractObject::SetSessionMessage(get_class($oObj), $oObj->GetKey(), $sMessageId, $sMessage, $sSeverity, 0, true /* must not exist */); } $oPage->add_header('Location: '.utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.get_class($oObj).'&id='.$oObj->getKey().'&'.$oAppContext->GetForLink()); } /** * Displays the details of an object * @param $oP WebPage Page for the output * @param $sClass string The name of the class of the object * @param $oObj DBObject The object to display * @param $id mixed Identifier of the object (name or ID) */ function DisplayDetails($oP, $sClass, $oObj, $id) { $sClassLabel = MetaModel::GetName($sClass); $oSearch = new DBObjectSearch($sClass); $oBlock = new DisplayBlock($oSearch, 'search', false); $oBlock->Display($oP, 0); // The object could be listed, check if it is actually allowed to view it $oSet = CMDBObjectSet::FromObject($oObj); if (UserRights::IsActionAllowed($sClass, UR_ACTION_READ, $oSet) == UR_ALLOWED_NO) { throw new SecurityException('User not allowed to view this object', array('class' => $sClass, 'id' => $id)); } $oP->set_title(Dict::Format('UI:DetailsPageTitle', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding $oObj->DisplayDetails($oP); } /** * Displays the result of a search request * @param $oP WebPage Web page for the output * @param $oFilter DBObjectSearch The search of objects to display * @param $bSearchForm boolean Whether or not to display the search form at the top the page * @param $sBaseClass string The base class for the search (can be different from the actual class of the results) * @param $sFormat string The format to use for the output: csv or html */ function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '', $sFormat = '') { if ($bSearchForm) { $aParams = array('open' => true); if (!empty($sBaseClass)) { $aParams['baseClass'] = $sBaseClass; } $oBlock = new DisplayBlock($oFilter, 'search', false /* Asynchronous */, $aParams); $oBlock->Display($oP, 0); } if (strtolower($sFormat) == 'csv') { $oBlock = new DisplayBlock($oFilter, 'csv', false); $oBlock->Display($oP, 1); // Adjust the size of the Textarea containing the CSV to fit almost all the remaining space $oP->add_ready_script(" $('#1>textarea').height($('#1').parent().height() - $('#0').outerHeight() - 30).width( $('#1').parent().width() - 20);"); // adjust the size of the block } else { $oBlock = new DisplayBlock($oFilter, 'list', false); $oBlock->Display($oP, 1); } } /** * Displays a form (checkboxes) to select the objects for which to apply a given action * Only the objects for which the action is valid can be checked. By default all valid objects are checked * @param $oP WebPage The page for output * @param $oFilter DBObjectSearch The filter that defines the list of objects * @param $sNextOperation string The next operation (code) to be executed when the form is submitted * @param $oChecker ActionChecker The helper class/instance used to check for which object the action is valid * @return none */ function DisplayMultipleSelectionForm($oP, $oFilter, $sNextOperation, $oChecker, $aExtraFormParams = array()) { $oAppContext = new ApplicationContext(); $iBulkActionAllowed = $oChecker->IsAllowed(); $sClass = $oFilter->GetClass(); $aExtraParams = array('selection_type' => 'multiple', 'selection_mode' => true, 'display_limit' => false, 'menu' => false); if ($iBulkActionAllowed == UR_ALLOWED_DEPENDS) { $aAllowed = array(); $aExtraParams['selection_enabled'] = $oChecker->GetAllowedIDs(); } else if(UR_ALLOWED_NO) { throw new ApplicationException(Dict::Format('UI:ActionNotAllowed')); } $oBlock = new DisplayBlock($oFilter, 'list', false); $oP->add("\n"); $oP->add_ready_script("$('#1 table.listResults').trigger('check_all');"); } function DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj) { $oP->SetCurrentTab(Dict::S('UI:RelationshipList')); $oP->add("
".Dict::Format('UI:BulkModify_Count_DistinctValues', count($aValues[$sAttCode]))."
'.implode('
',$aErrors)."\n"; } } else { $sStatus = Dict::S('UI:BulkModifyStatusSkipped'); $sError = ''.Dict::S('UI:FailedToApplyStimuli')."
\n"; } } else { $sStatus = Dict::S('UI:BulkModifyStatusSkipped'); $sError = '
'.implode('
',$aErrors)."\n"; } } } catch(Exception $e) { $sError = $e->getMessage(); $sStatus = Dict::S('UI:BulkModifyStatusSkipped'); } $aRows[] = array( 'object' => $oObj->GetHyperlink(), 'status' => $sStatus, 'errors' => $sError, ); } $oP->Table($aHeaders, $aRows); // Back to the list $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink(); $oP->add(''); } break; case 'stimulus': // Form displayed when applying a stimulus (state change) $sClass = utils::ReadParam('class', '', false, 'class'); $id = utils::ReadParam('id', ''); $sStimulus = utils::ReadParam('stimulus', ''); if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid ! { throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus')); } $oObj = MetaModel::GetObject($sClass, $id, false); if ($oObj != null) { $oObj->DisplayStimulusForm($oP, $sStimulus); } else { $oP->set_title(Dict::S('UI:ErrorPageTitle')); $oP->P(Dict::S('UI:ObjectDoesNotExist')); } break; /////////////////////////////////////////////////////////////////////////////////////////// case 'apply_stimulus': // Actual state change $sClass = utils::ReadPostedParam('class', ''); $id = utils::ReadPostedParam('id', ''); $sTransactionId = utils::ReadPostedParam('transaction_id', ''); $sStimulus = utils::ReadPostedParam('stimulus', ''); if ( empty($sClass) || empty($id) || empty($sStimulus) ) // TO DO: check that the class name is valid ! { throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus')); } $oObj = MetaModel::GetObject($sClass, $id, false); if ($oObj != null) { $aTransitions = $oObj->EnumTransitions(); $aStimuli = MetaModel::EnumStimuli($sClass); $sMessage = ''; $sSeverity = 'ok'; $bDisplayDetails = true; if (!isset($aTransitions[$sStimulus])) { throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sStimulus, $oObj->GetName(), $oObj->GetStateLabel())); } if (!utils::IsTransactionValid($sTransactionId)) { $sMessage = Dict::S('UI:Error:ObjectAlreadyUpdated'); $sSeverity = 'info'; } else { $sActionLabel = $aStimuli[$sStimulus]->GetLabel(); $sActionDetails = $aStimuli[$sStimulus]->GetDescription(); $aTransition = $aTransitions[$sStimulus]; $sTargetState = $aTransition['target_state']; $aTargetStates = MetaModel::EnumStates($sClass); $aTargetState = $aTargetStates[$sTargetState]; $aExpectedAttributes = $aTargetState['attribute_list']; $aDetails = array(); $aErrors = array(); foreach($aExpectedAttributes as $sAttCode => $iExpectCode) { $iFlags = $oObj->GetAttributeFlags($sAttCode); if (($iExpectCode & (OPT_ATT_MUSTCHANGE|OPT_ATT_MUSTPROMPT)) || ($oObj->Get($sAttCode) == '') ) { $paramValue = utils::ReadPostedParam("attr_$sAttCode", '', 'raw_data'); if ( ($iFlags & OPT_ATT_SLAVE) && ($paramValue != $oObj->Get($sAttCode))) { $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $aErrors[] = Dict::Format('UI:AttemptingToChangeASlaveAttribute_Name', $oAttDef->GetLabel()); unset($aExpectedAttributes[$sAttCode]); } } } $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $sTargetState); if (count($aErrors) == 0) { $sIssues = ''; $bApplyStimulus = true; list($bRes, $aIssues) = $oObj->CheckToWrite(); // Check before trying to write the object if ($bRes) { try { $bApplyStimulus = $oObj->ApplyStimulus($sStimulus); // will write the object in the DB } catch(CoreException $e) { // Rollback to the previous state... by reloading the object from the database and applying the modifications again $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey()); $oObj->UpdateObjectFromPostedForm('', array_keys($aExpectedAttributes), $sTargetState); $aData = $e->getContextData(); $sIssues = (array_key_exists('issues', $aData)) ? $aData['issues'] : 'Unknown error...'; } } else { $sIssues = implode(' ', $aIssues); } if (!$bApplyStimulus) { $sMessage = Dict::S('UI:FailedToApplyStimuli'); $sSeverity = 'error'; } else if ($sIssues != '') { $bDisplayDetails = false; // Found issues, explain and give the user a second chance // $oObj->DisplayStimulusForm($oP, $sStimulus); $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten',$sIssues); $oP->add_ready_script("alert('".addslashes($sIssueDesc)."');"); } else { $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName()); $sSeverity = 'ok'; utils::RemoveTransaction($sTransactionId); } } else { $sMessage = implode('', $aErrors); $sSeverity = 'error'; } } if ($bDisplayDetails) { ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity); } } else { $oP->set_title(Dict::S('UI:ErrorPageTitle')); $oP->P(Dict::S('UI:ObjectDoesNotExist')); } break; /////////////////////////////////////////////////////////////////////////////////////////// case 'swf_navigator': // Graphical display of the relations "impact" / "depends on" $sClass = utils::ReadParam('class', '', false, 'class'); $id = utils::ReadParam('id', 0); $sRelation = utils::ReadParam('relation', 'impact'); $aResults = array(); $oObj = MetaModel::GetObject($sClass, $id); $iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20); $oObj->GetRelatedObjects($sRelation, $iMaxRecursionDepth /* iMaxDepth */, $aResults); $oP->AddTabContainer('Navigator'); $oP->SetCurrentTabContainer('Navigator'); $sFirstTab = MetaModel::GetConfig()->Get('impact_analysis_first_tab'); if ($sFirstTab == 'list') { DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj); DisplayNavigatorGraphicsTab($oP, $aResults, $sClass, $id, $sRelation, $oAppContext); } else { DisplayNavigatorGraphicsTab($oP, $aResults, $sClass, $id, $sRelation, $oAppContext); DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj); } $oP->SetCurrentTab(''); break; /////////////////////////////////////////////////////////////////////////////////////////// case 'cancel': // An action was cancelled $oP->set_title(Dict::S('UI:OperationCancelled')); $oP->add('