\n");
- $sTitle = addslashes(Dict::S('UI:WelcomeMenu:Title'));
- $oP->add_ready_script(
-<< ($(window).height()-70))
- {
- $('#welcome_popup').height($(window).height()-70);
- }
-EOF
-);
- $_SESSION['welcome'] = 'ok';
- }
- }
- }
-}
-
-/**
- * Apply the 'next-action' to the given object or redirect to the page that prompts for additional information if needed
- * @param $oP WebPage The page for the output
- * @param $oObj CMDBObject The object to process
- * @param $sNextAction string The code of the stimulus for the 'action' (i.e. Transition) to apply
- */
-function ApplyNextAction(Webpage $oP, CMDBObject $oObj, $sNextAction)
-{
- // Here handle the apply stimulus
- $aTransitions = $oObj->EnumTransitions();
- $aStimuli = MetaModel::EnumStimuli(get_class($oObj));
- if (!isset($aTransitions[$sNextAction]))
- {
- // Invalid stimulus
- throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sNextAction, $oObj->GetName(), $oObj->GetStateLabel()));
- }
- // Get the list of missing mandatory fields for the target state, considering only the changes from the previous form (i.e don't prompt twice)
- $aExpectedAttributes = $oObj->GetTransitionAttributes($sNextAction);
-
- if (count($aExpectedAttributes) == 0)
- {
- // If all the mandatory fields are already present, just apply the transition silently...
- if ($oObj->ApplyStimulus($sNextAction))
- {
- $oObj->DBUpdate();
- }
- ReloadAndDisplay($oP, $oObj);
- }
- else
- {
- // redirect to the 'stimulus' action
- $oAppContext = new ApplicationContext();
-//echo "
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);
-}
-
-/**
- * Display the session messages relative to the object identified by its "message key" (class::id)
- * @param string $sMessageKey
- * @param WebPage $oPage
- */
-function DisplayMessages($sMessageKey, WebPage $oPage)
-{
- if (array_key_exists('obj_messages', $_SESSION) && array_key_exists($sMessageKey, $_SESSION['obj_messages']))
- {
- $aMessages = array();
- $aRanks = array();
- foreach ($_SESSION['obj_messages'][$sMessageKey] as $sMessageId => $aMessageData)
- {
- $sMsgClass = 'message_'.$aMessageData['severity'];
- $aMessages[] = "
".$aMessageData['message']."
";
- $aRanks[] = $aMessageData['rank'];
- }
- unset($_SESSION['obj_messages'][$sMessageKey]);
- array_multisort($aRanks, $aMessages);
- foreach ($aMessages as $sMessage)
- {
- $oPage->add($sMessage);
- }
- }
-}
-
-/**
- * Helper to update the breadrumb for the current object
- * @param DBObject $oObj
- * @param WebPage $oPage
- */
-function SetObjectBreadCrumbEntry(DBObject $oObj, WebPage $oPage)
-{
- $sClass = get_class($oObj); // get the leaf class
- $sIcon = MetaModel::GetClassIcon($sClass, false);
- if ($sIcon == '')
- {
- $sIcon = utils::GetAbsoluteUrlAppRoot().'images/breadcrumb_object.png';
- }
- $oPage->SetBreadCrumbEntry("ui-details-$sClass-".$oObj->GetKey(), $oObj->Get('friendlyname'), MetaModel::GetName($sClass).': '.$oObj->Get('friendlyname'), '', $sIcon);
-}
-
-/**
- * Displays the result of a search request
- * @param $oP WebPage Web page for the output
- * @param $oFilter DBSearch 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
- * @param $bDoSearch bool True to display the search results below the search form
- * @param $bSearchFormOpen bool True to display the search form fully expanded (only if $bSearchForm of course)
- */
-function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '', $sFormat = '', $bDoSearch = true, $bSearchFormOpen = false)
-{
- if ($bSearchForm)
- {
- $aParams = array('open' => $bSearchFormOpen);
- if (!empty($sBaseClass))
- {
- $aParams['baseClass'] = $sBaseClass;
- }
- $oBlock = new DisplayBlock($oFilter, 'search', false /* Asynchronous */, $aParams);
- $oBlock->Display($oP, 0);
- }
- if ($bDoSearch)
- {
- 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);
-
- // Breadcrumb
- //$iCount = $oBlock->GetDisplayedCount();
- $sPageId = "ui-search-".$oFilter->GetClass();
- $sLabel = MetaModel::GetName($oFilter->GetClass());
- $oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', '../images/breadcrumb-search.png');
- }
- }
-}
-
-/**
- * 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 DBSearch 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, $sDirection, $oObj)
-{
- $oP->SetCurrentTab(Dict::S('UI:RelationshipList'));
- $oP->add("
\n");
- $sJSClass = addslashes($sClassName);
- $sJSNeedles = json_encode($aFullTextNeedles);
- $oP->add_ready_script(
-<< 0)
- {
- $oP->add_script("var oTimeStatistics = {};");
- }
- }
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'modify': // Form to modify an object
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $id = utils::ReadParam('id', '');
- if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
- }
- // Check if the user can modify this object
- $oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
- if (is_null($oObj))
- {
- $oP->set_title(Dict::S('UI:ErrorPageTitle'));
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
- }
- else
- {
- // The object could be read - check if it is allowed to modify it
- $oSet = CMDBObjectSet::FromObject($oObj);
- if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_NO)
- {
- throw new SecurityException('User not allowed to modify this object', array('class' => $sClass, 'id' => $id));
- }
- // Note: code duplicated to the case 'apply_modify' when a data integrity issue has been found
- $oObj->DisplayModifyForm($oP, array('wizard_container' => 1)); // wizard_container: Display the blue borders and the title above the form
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'select_for_modify_all': // Select the list of objects to be modified (bulk modify)
- $oP->DisableBreadCrumb();
- $oP->set_title(Dict::S('UI:ModifyAllPageTitle'));
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- if (empty($sFilter))
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
- }
- $oFilter = DBObjectSearch::unserialize($sFilter); // TO DO : check that the filter is valid
- // Add user filter
- $oFilter->UpdateContextFromUser();
- $sClass = $oFilter->GetClass();
- $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_MODIFY);
- $oP->add("
".Dict::S('UI:ModifyAllPageTitle')."
\n");
-
- DisplayMultipleSelectionForm($oP, $oFilter, 'form_for_modify_all', $oChecker);
- break;
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
- $oP->DisableBreadCrumb();
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $sClass = utils::ReadParam('class', '', false, 'class');
- $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
- // Add user filter
- $oFullSetFilter->UpdateContextFromUser();
- $aSelectedObj = utils::ReadMultipleSelection($oFullSetFilter);
- $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
- $aContext = array('filter' => $sFilter);
- cmdbAbstractObject::DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $sCancelUrl, array(), $aContext);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'preview_or_modify_all': // Preview or apply bulk modify
- $oP->DisableBreadCrumb();
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- $oFilter = DBObjectSearch::unserialize($sFilter); // TO DO : check that the filter is valid
- // Add user filter
- $oFilter->UpdateContextFromUser();
- $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_MODIFY);
-
- $sClass = utils::ReadParam('class', '', false, 'class');
- $bPreview = utils::ReadParam('preview_mode', '');
- $sSelectedObj = utils::ReadParam('selectObj', '', false, 'raw_data');
- if ( empty($sClass) || empty($sSelectedObj)) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObj'));
- }
- $aSelectedObj = explode(',', $sSelectedObj);
- $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
- $aContext = array(
- 'filter' => $sFilter,
- 'selectObj' => $sSelectedObj,
- );
- cmdbAbstractObject::DoBulkModify($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $bPreview, $sCancelUrl, $aContext);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'new': // Form to create a new object
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sStateCode = utils::ReadParam('state', '');
- $bCheckSubClass = utils::ReadParam('checkSubclass', true);
- if ( empty($sClass) )
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
- }
-
-/*
- $aArgs = utils::ReadParam('default', array(), false, 'raw_data');
- $aContext = $oAppContext->GetAsHash();
- foreach( $oAppContext->GetNames() as $key)
- {
- $aArgs[$key] = $oAppContext->GetCurrentValue($key);
- }
-*/
- // If the specified class has subclasses, ask the user an instance of which class to create
- $aSubClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
- $aPossibleClasses = array();
- $sRealClass = '';
- if ($bCheckSubClass)
- {
- foreach($aSubClasses as $sCandidateClass)
- {
- if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
- {
- $aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
- }
- }
- // Only one of the subclasses can be instantiated...
- if (count($aPossibleClasses) == 1)
- {
- $aKeys = array_keys($aPossibleClasses);
- $sRealClass = $aKeys[0];
- }
- }
- else
- {
- $sRealClass = $sClass;
- }
-
- if (!empty($sRealClass))
- {
- // Display the creation form
- $sClassLabel = MetaModel::GetName($sRealClass);
- // Note: some code has been duplicated to the case 'apply_new' when a data integrity issue has been found
- $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
- $oP->add("
\n");
-
- // Set all the default values in an object and clone this "default" object
- $oObjToClone = MetaModel::NewObject($sRealClass);
-
- // 1st - set context values
- $oAppContext->InitObjectFromContext($oObjToClone);
-
- // 2nd - set values from the page argument 'default'
- $oObjToClone->UpdateObjectFromArg('default');
-
- cmdbAbstractObject::DisplayCreationForm($oP, $sRealClass, $oObjToClone, array());
- $oP->add("
\n");
- }
- else
- {
- // Select the derived class to create
- $sClassLabel = MetaModel::GetName($sClass);
- $oP->add("
\n");
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'apply_modify': // Applying the modifications to an existing object
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadPostedParam('class', '');
- $sClassLabel = MetaModel::GetName($sClass);
- $id = utils::ReadPostedParam('id', '');
- $sTransactionId = utils::ReadPostedParam('transaction_id', '');
- if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
- }
- $bDisplayDetails = true;
- $oObj = MetaModel::GetObject($sClass, $id, false);
- if ($oObj == null)
- {
- $bDisplayDetails = false;
- $oP->set_title(Dict::S('UI:ErrorPageTitle'));
- $oP->P(Dict::S('UI:ObjectDoesNotExist'));
- }
- elseif (!utils::IsTransactionValid($sTransactionId, false))
- {
- $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
- $oP->p("".Dict::S('UI:Error:ObjectAlreadyUpdated')."\n");
- }
- else
- {
- $oObj->UpdateObjectFromPostedForm();
- $sMessage = '';
- $sSeverity = 'ok';
-
- if (!$oObj->IsModified())
- {
- $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
- $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'info';
- }
- else
- {
- list($bRes, $aIssues) = $oObj->CheckToWrite();
- if ($bRes)
- {
- try
- {
- CMDBSource::Query('START TRANSACTION');
- $oObj->DBUpdate();
- CMDBSource::Query('COMMIT');
- $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'ok';
- }
- catch(DeleteException $e)
- {
- CMDBSource::Query('ROLLBACK');
- // Say two things: 1) Don't be afraid nothing was modified
- $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
- $sSeverity = 'info';
- cmdbAbstractObject::SetSessionMessage(get_class($oObj), $oObj->GetKey(), 'UI:Class_Object_NotUpdated', $sMessage, $sSeverity, 0, true /* must not exist */);
- // 2) Ok, there was some trouble indeed
- $sMessage = $e->getMessage();
- $sSeverity = 'error';
- $bDisplayDetails = true;
- }
- utils::RemoveTransaction($sTransactionId);
-
- }
- else
- {
- $bDisplayDetails = false;
- // Found issues, explain and give the user a second chance
- //
- $oObj->DisplayModifyForm($oP, array('wizard_container' => true)); // wizard_container: display the wizard border and the title
- $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten', implode(', ', $aIssues));
- $oP->add_ready_script("alert('".addslashes($sIssueDesc)."');");
- }
- }
- }
- if ($bDisplayDetails)
- {
- $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey()); //Workaround: reload the object so that the linkedset are displayed properly
- $sNextAction = utils::ReadPostedParam('next_action', '');
- if (!empty($sNextAction))
- {
- ApplyNextAction($oP, $oObj, $sNextAction);
- }
- else
- {
- // Nothing more to do
- ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
- }
-
- $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);
- }
- }
- }
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'select_for_deletion': // Select multiple objects for deletion
- $oP->DisableBreadCrumb();
- $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
- if (empty($sFilter))
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
- }
- $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
- $oP->add("
".Dict::S('UI:BulkDeleteTitle')."
\n");
- $oFilter = DBSearch::unserialize($sFilter); // TO DO : check that the filter is valid
- $oFilter->UpdateContextFromUser();
- $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_DELETE);
- DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_delete', $oChecker);
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'bulk_delete_confirmed': // Confirm bulk deletion of objects
- $oP->DisableBreadCrumb();
- $sTransactionId = utils::ReadPostedParam('transaction_id', '');
- if (!utils::IsTransactionValid($sTransactionId))
- {
- throw new ApplicationException(Dict::S('UI:Error:ObjectsAlreadyDeleted'));
- }
- // Fall through
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'delete':
- case 'bulk_delete': // Actual bulk deletion (if confirmed)
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadParam('class', '', false, 'class');
- $sClassLabel = MetaModel::GetName($sClass);
- $aObjects = array();
- if ($operation == 'delete')
- {
- // Single object
- $id = utils::ReadParam('id', '');
- $oObj = MetaModel::GetObject($sClass, $id);
- $aObjects[] = $oObj;
- if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromObject($oObj)))
- {
- throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClassLabel));
- }
- }
- else
- {
- // Several objects
- $sFilter = utils::ReadPostedParam('filter', '');
- $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
- // Add user filter
- $oFullSetFilter->UpdateContextFromUser();
- $aSelectObject = utils::ReadMultipleSelection($oFullSetFilter);
- if ( empty($sClass) || empty($aSelectObject)) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObject[]'));
- }
- foreach($aSelectObject as $iId)
- {
- $aObjects[] = MetaModel::GetObject($sClass, $iId);
- }
- if (count($aObjects) == 1)
- {
- if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
- {
- throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
- }
- }
- else
- {
- if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
- {
- throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
- }
- $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
- }
- }
- // Go for the common part... (delete single, delete bulk, delete confirmed)
- cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed');
- break;
-
- ///////////////////////////////////////////////////////////////////////////////////////////
-
- case 'apply_new': // Creation of a new object
- $oP->DisableBreadCrumb();
- $sClass = utils::ReadPostedParam('class', '', 'class');
- $sClassLabel = MetaModel::GetName($sClass);
- $sTransactionId = utils::ReadPostedParam('transaction_id', '');
- if ( empty($sClass) ) // TO DO: check that the class name is valid !
- {
- throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
- }
- if (!utils::IsTransactionValid($sTransactionId, false))
- {
- $oP->p("".Dict::S('UI:Error:ObjectAlreadyCreated')."\n");
- }
- else
- {
- $oObj = MetaModel::NewObject($sClass);
- $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
- if (!empty($sStateAttCode))
- {
- $sTargetState = utils::ReadPostedParam('obj_state', '');
- if ($sTargetState != '')
- {
- $oObj->Set($sStateAttCode, $sTargetState);
- }
- }
- $oObj->UpdateObjectFromPostedForm();
- }
- if (isset($oObj) && is_object($oObj))
- {
- $sClass = get_class($oObj);
- $sClassLabel = MetaModel::GetName($sClass);
-
- list($bRes, $aIssues) = $oObj->CheckToWrite();
- if ($bRes)
- {
- $oObj->DBInsertNoReload(); // No need to reload
- utils::RemoveTransaction($sTransactionId);
- $oP->set_title(Dict::S('UI:PageTitle:ObjectCreated'));
-
- // Compute the name, by reloading the object, even if it disappeared from the silo
- $oObj = MetaModel::GetObject($sClass, $oObj->GetKey(), true /* Must be found */, true /* Allow All Data*/);
- $sName = $oObj->GetName();
- $sMessage = Dict::Format('UI:Title:Object_Of_Class_Created', $sName, $sClassLabel);
-
- $sNextAction = utils::ReadPostedParam('next_action', '');
- if (!empty($sNextAction))
- {
- $oP->add("
$sMessage
");
- ApplyNextAction($oP, $oObj, $sNextAction);
- }
- else
- {
- // Nothing more to do
- ReloadAndDisplay($oP, $oObj, 'create', $sMessage, 'ok');
- }
- }
- else
- {
- // Found issues, explain and give the user a second chance
- //
- $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
- $oP->add("
\n");
- }
- $oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc()));
- $oP->output();
-
- if (MetaModel::IsLogEnabledIssue())
- {
- if (MetaModel::IsValidClass('EventIssue'))
- {
- try
- {
- $oLog = new EventIssue();
-
- $oLog->Set('message', $e->getMessage());
- $oLog->Set('userinfo', '');
- $oLog->Set('issue', $e->GetIssue());
- $oLog->Set('impact', 'Page could not be displayed');
- $oLog->Set('callstack', $e->getTrace());
- $oLog->Set('data', $e->getContextData());
- $oLog->DBInsertNoReload();
- }
- catch(Exception $e)
- {
- IssueLog::Error("Failed to log issue into the DB");
- }
- }
-
- IssueLog::Error($e->getMessage());
- }
-
- // For debugging only
- //throw $e;
-}
-catch(Exception $e)
-{
- require_once(APPROOT.'/setup/setuppage.class.inc.php');
- $oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
- $oP->add("
".Dict::S('UI:FatalErrorMessage')."
\n");
- $oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
- $oP->output();
-
- if (MetaModel::IsLogEnabledIssue())
- {
- if (MetaModel::IsValidClass('EventIssue'))
- {
- try
- {
- $oLog = new EventIssue();
-
- $oLog->Set('message', $e->getMessage());
- $oLog->Set('userinfo', '');
- $oLog->Set('issue', 'PHP Exception');
- $oLog->Set('impact', 'Page could not be displayed');
- $oLog->Set('callstack', $e->getTrace());
- $oLog->Set('data', array());
- $oLog->DBInsertNoReload();
- }
- catch(Exception $e)
- {
- IssueLog::Error("Failed to log issue into the DB");
- }
- }
-
- IssueLog::Error($e->getMessage());
- }
+
+
+
+/**
+ * Main page of iTop
+ *
+ * @copyright Copyright (C) 2010-2017 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");
+ $sTitle = addslashes(Dict::S('UI:WelcomeMenu:Title'));
+ $oP->add_ready_script(
+<< ($(window).height()-70))
+ {
+ $('#welcome_popup').height($(window).height()-70);
+ }
+EOF
+);
+ $_SESSION['welcome'] = 'ok';
+ }
+ }
+ }
+}
+
+/**
+ * Apply the 'next-action' to the given object or redirect to the page that prompts for additional information if needed
+ * @param $oP WebPage The page for the output
+ * @param $oObj CMDBObject The object to process
+ * @param $sNextAction string The code of the stimulus for the 'action' (i.e. Transition) to apply
+ */
+function ApplyNextAction(Webpage $oP, CMDBObject $oObj, $sNextAction)
+{
+ // Here handle the apply stimulus
+ $aTransitions = $oObj->EnumTransitions();
+ $aStimuli = MetaModel::EnumStimuli(get_class($oObj));
+ if (!isset($aTransitions[$sNextAction]))
+ {
+ // Invalid stimulus
+ throw new ApplicationException(Dict::Format('UI:Error:Invalid_Stimulus_On_Object_In_State', $sNextAction, $oObj->GetName(), $oObj->GetStateLabel()));
+ }
+ // Get the list of missing mandatory fields for the target state, considering only the changes from the previous form (i.e don't prompt twice)
+ $aExpectedAttributes = $oObj->GetTransitionAttributes($sNextAction);
+
+ if (count($aExpectedAttributes) == 0)
+ {
+ // If all the mandatory fields are already present, just apply the transition silently...
+ if ($oObj->ApplyStimulus($sNextAction))
+ {
+ $oObj->DBUpdate();
+ }
+ ReloadAndDisplay($oP, $oObj);
+ }
+ else
+ {
+ // redirect to the 'stimulus' action
+ $oAppContext = new ApplicationContext();
+//echo "
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);
+}
+
+/**
+ * Display the session messages relative to the object identified by its "message key" (class::id)
+ * @param string $sMessageKey
+ * @param WebPage $oPage
+ */
+function DisplayMessages($sMessageKey, WebPage $oPage)
+{
+ if (array_key_exists('obj_messages', $_SESSION) && array_key_exists($sMessageKey, $_SESSION['obj_messages']))
+ {
+ $aMessages = array();
+ $aRanks = array();
+ foreach ($_SESSION['obj_messages'][$sMessageKey] as $sMessageId => $aMessageData)
+ {
+ $sMsgClass = 'message_'.$aMessageData['severity'];
+ $aMessages[] = "
".$aMessageData['message']."
";
+ $aRanks[] = $aMessageData['rank'];
+ }
+ unset($_SESSION['obj_messages'][$sMessageKey]);
+ array_multisort($aRanks, $aMessages);
+ foreach ($aMessages as $sMessage)
+ {
+ $oPage->add($sMessage);
+ }
+ }
+}
+
+/**
+ * Helper to update the breadrumb for the current object
+ * @param DBObject $oObj
+ * @param WebPage $oPage
+ */
+function SetObjectBreadCrumbEntry(DBObject $oObj, WebPage $oPage)
+{
+ $sClass = get_class($oObj); // get the leaf class
+ $sIcon = MetaModel::GetClassIcon($sClass, false);
+ if ($sIcon == '')
+ {
+ $sIcon = utils::GetAbsoluteUrlAppRoot().'images/breadcrumb_object.png';
+ }
+ $oPage->SetBreadCrumbEntry("ui-details-$sClass-".$oObj->GetKey(), $oObj->Get('friendlyname'), MetaModel::GetName($sClass).': '.$oObj->Get('friendlyname'), '', $sIcon);
+}
+
+/**
+ * Displays the result of a search request
+ * @param $oP WebPage Web page for the output
+ * @param $oFilter DBSearch 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
+ * @param $bDoSearch bool True to display the search results below the search form
+ * @param $bSearchFormOpen bool True to display the search form fully expanded (only if $bSearchForm of course)
+ */
+function DisplaySearchSet($oP, $oFilter, $bSearchForm = true, $sBaseClass = '', $sFormat = '', $bDoSearch = true, $bSearchFormOpen = false)
+{
+ if ($bSearchForm)
+ {
+ $aParams = array('open' => $bSearchFormOpen);
+ if (!empty($sBaseClass))
+ {
+ $aParams['baseClass'] = $sBaseClass;
+ }
+ $oBlock = new DisplayBlock($oFilter, 'search', false /* Asynchronous */, $aParams);
+ $oBlock->Display($oP, 0);
+ }
+ if ($bDoSearch)
+ {
+ 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);
+
+ // Breadcrumb
+ //$iCount = $oBlock->GetDisplayedCount();
+ $sPageId = "ui-search-".$oFilter->GetClass();
+ $sLabel = MetaModel::GetName($oFilter->GetClass());
+ $oP->SetBreadCrumbEntry($sPageId, $sLabel, '', '', '../images/breadcrumb-search.png');
+ }
+ }
+}
+
+/**
+ * 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 \WebPage $oP WebPage The page for output
+ * @param \DBSearch $oFilter DBSearch The filter that defines the list of objects
+ * @param string $sNextOperation string The next operation (code) to be executed when the form is submitted
+ * @param ActionChecker $oChecker ActionChecker The helper class/instance used to check for which object the action is valid
+ * @param array $aExtraFormParams
+ *
+ * @throws \ApplicationException
+ */
+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, $sDirection, $oObj)
+{
+ $oP->SetCurrentTab(Dict::S('UI:RelationshipList'));
+ $oP->add("
\n");
+ $sJSClass = addslashes($sClassName);
+ $sJSNeedles = json_encode($aFullTextNeedles);
+ $oP->add_ready_script(
+<< 0)
+ {
+ $oP->add_script("var oTimeStatistics = {};");
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'modify': // Form to modify an object
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $id = utils::ReadParam('id', '');
+ if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
+ }
+ // Check if the user can modify this object
+ $oObj = MetaModel::GetObject($sClass, $id, false /* MustBeFound */);
+ if (is_null($oObj))
+ {
+ $oP->set_title(Dict::S('UI:ErrorPageTitle'));
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
+ }
+ else
+ {
+ // The object could be read - check if it is allowed to modify it
+ $oSet = CMDBObjectSet::FromObject($oObj);
+ if (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_NO)
+ {
+ throw new SecurityException('User not allowed to modify this object', array('class' => $sClass, 'id' => $id));
+ }
+ // Note: code duplicated to the case 'apply_modify' when a data integrity issue has been found
+ $oObj->DisplayModifyForm($oP, array('wizard_container' => 1)); // wizard_container: Display the blue borders and the title above the form
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'select_for_modify_all': // Select the list of objects to be modified (bulk modify)
+ $oP->DisableBreadCrumb();
+ $oP->set_title(Dict::S('UI:ModifyAllPageTitle'));
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ if (empty($sFilter))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
+ }
+ $oFilter = DBObjectSearch::unserialize($sFilter); // TO DO : check that the filter is valid
+ // Add user filter
+ $oFilter->UpdateContextFromUser();
+ $sClass = $oFilter->GetClass();
+ $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_MODIFY);
+ $oP->add("
".Dict::S('UI:ModifyAllPageTitle')."
\n");
+
+ DisplayMultipleSelectionForm($oP, $oFilter, 'form_for_modify_all', $oChecker);
+ break;
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
+ $oP->DisableBreadCrumb();
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
+ // Add user filter
+ $oFullSetFilter->UpdateContextFromUser();
+ $aSelectedObj = utils::ReadMultipleSelection($oFullSetFilter);
+ $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $aContext = array('filter' => $sFilter);
+ cmdbAbstractObject::DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $sCancelUrl, array(), $aContext);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'preview_or_modify_all': // Preview or apply bulk modify
+ $oP->DisableBreadCrumb();
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ $oFilter = DBObjectSearch::unserialize($sFilter); // TO DO : check that the filter is valid
+ // Add user filter
+ $oFilter->UpdateContextFromUser();
+ $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_MODIFY);
+
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $bPreview = utils::ReadParam('preview_mode', '');
+ $sSelectedObj = utils::ReadParam('selectObj', '', false, 'raw_data');
+ if ( empty($sClass) || empty($sSelectedObj)) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObj'));
+ }
+ $aSelectedObj = explode(',', $sSelectedObj);
+ $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
+ $aContext = array(
+ 'filter' => $sFilter,
+ 'selectObj' => $sSelectedObj,
+ );
+ cmdbAbstractObject::DoBulkModify($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $bPreview, $sCancelUrl, $aContext);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'new': // Form to create a new object
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sStateCode = utils::ReadParam('state', '');
+ $bCheckSubClass = utils::ReadParam('checkSubclass', true);
+ if ( empty($sClass) )
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
+ }
+
+/*
+ $aArgs = utils::ReadParam('default', array(), false, 'raw_data');
+ $aContext = $oAppContext->GetAsHash();
+ foreach( $oAppContext->GetNames() as $key)
+ {
+ $aArgs[$key] = $oAppContext->GetCurrentValue($key);
+ }
+*/
+ // If the specified class has subclasses, ask the user an instance of which class to create
+ $aSubClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL); // Including the specified class itself
+ $aPossibleClasses = array();
+ $sRealClass = '';
+ if ($bCheckSubClass)
+ {
+ foreach($aSubClasses as $sCandidateClass)
+ {
+ if (!MetaModel::IsAbstract($sCandidateClass) && (UserRights::IsActionAllowed($sCandidateClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES))
+ {
+ $aPossibleClasses[$sCandidateClass] = MetaModel::GetName($sCandidateClass);
+ }
+ }
+ // Only one of the subclasses can be instantiated...
+ if (count($aPossibleClasses) == 1)
+ {
+ $aKeys = array_keys($aPossibleClasses);
+ $sRealClass = $aKeys[0];
+ }
+ }
+ else
+ {
+ $sRealClass = $sClass;
+ }
+
+ if (!empty($sRealClass))
+ {
+ // Display the creation form
+ $sClassLabel = MetaModel::GetName($sRealClass);
+ // Note: some code has been duplicated to the case 'apply_new' when a data integrity issue has been found
+ $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
+ $oP->add("
\n");
+
+ // Set all the default values in an object and clone this "default" object
+ $oObjToClone = MetaModel::NewObject($sRealClass);
+
+ // 1st - set context values
+ $oAppContext->InitObjectFromContext($oObjToClone);
+
+ // 2nd - set values from the page argument 'default'
+ $oObjToClone->UpdateObjectFromArg('default');
+
+ cmdbAbstractObject::DisplayCreationForm($oP, $sRealClass, $oObjToClone, array());
+ $oP->add("
\n");
+ }
+ else
+ {
+ // Select the derived class to create
+ $sClassLabel = MetaModel::GetName($sClass);
+ $oP->add("
\n");
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'apply_modify': // Applying the modifications to an existing object
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadPostedParam('class', '');
+ $sClassLabel = MetaModel::GetName($sClass);
+ $id = utils::ReadPostedParam('id', '');
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '');
+ if ( empty($sClass) || empty($id)) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
+ }
+ $bDisplayDetails = true;
+ $oObj = MetaModel::GetObject($sClass, $id, false);
+ if ($oObj == null)
+ {
+ $bDisplayDetails = false;
+ $oP->set_title(Dict::S('UI:ErrorPageTitle'));
+ $oP->P(Dict::S('UI:ObjectDoesNotExist'));
+ }
+ elseif (!utils::IsTransactionValid($sTransactionId, false))
+ {
+ $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
+ $oP->p("".Dict::S('UI:Error:ObjectAlreadyUpdated')."\n");
+ }
+ else
+ {
+ $oObj->UpdateObjectFromPostedForm();
+ $sMessage = '';
+ $sSeverity = 'ok';
+
+ if (!$oObj->IsModified())
+ {
+ $oP->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
+ $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'info';
+ }
+ else
+ {
+ list($bRes, $aIssues) = $oObj->CheckToWrite();
+ if ($bRes)
+ {
+ try
+ {
+ CMDBSource::Query('START TRANSACTION');
+ $oObj->DBUpdate();
+ CMDBSource::Query('COMMIT');
+ $sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'ok';
+ }
+ catch(DeleteException $e)
+ {
+ CMDBSource::Query('ROLLBACK');
+ // Say two things: 1) Don't be afraid nothing was modified
+ $sMessage = Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
+ $sSeverity = 'info';
+ cmdbAbstractObject::SetSessionMessage(get_class($oObj), $oObj->GetKey(), 'UI:Class_Object_NotUpdated', $sMessage, $sSeverity, 0, true /* must not exist */);
+ // 2) Ok, there was some trouble indeed
+ $sMessage = $e->getMessage();
+ $sSeverity = 'error';
+ $bDisplayDetails = true;
+ }
+ utils::RemoveTransaction($sTransactionId);
+
+ }
+ else
+ {
+ $bDisplayDetails = false;
+ // Found issues, explain and give the user a second chance
+ //
+ $oObj->DisplayModifyForm($oP, array('wizard_container' => true)); // wizard_container: display the wizard border and the title
+ $sIssueDesc = Dict::Format('UI:ObjectCouldNotBeWritten', implode(', ', $aIssues));
+ $oP->add_ready_script("alert('".addslashes($sIssueDesc)."');");
+ }
+ }
+ }
+ if ($bDisplayDetails)
+ {
+ $oObj = MetaModel::GetObject(get_class($oObj), $oObj->GetKey()); //Workaround: reload the object so that the linkedset are displayed properly
+ $sNextAction = utils::ReadPostedParam('next_action', '');
+ if (!empty($sNextAction))
+ {
+ ApplyNextAction($oP, $oObj, $sNextAction);
+ }
+ else
+ {
+ // Nothing more to do
+ ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity);
+ }
+
+ $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);
+ }
+ }
+ }
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'select_for_deletion': // Select multiple objects for deletion
+ $oP->DisableBreadCrumb();
+ $sFilter = utils::ReadParam('filter', '', false, 'raw_data');
+ if (empty($sFilter))
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
+ }
+ $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
+ $oP->add("
".Dict::S('UI:BulkDeleteTitle')."
\n");
+ $oFilter = DBSearch::unserialize($sFilter); // TO DO : check that the filter is valid
+ $oFilter->UpdateContextFromUser();
+ $oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_DELETE);
+ DisplayMultipleSelectionForm($oP, $oFilter, 'bulk_delete', $oChecker);
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'bulk_delete_confirmed': // Confirm bulk deletion of objects
+ $oP->DisableBreadCrumb();
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '');
+ if (!utils::IsTransactionValid($sTransactionId))
+ {
+ throw new ApplicationException(Dict::S('UI:Error:ObjectsAlreadyDeleted'));
+ }
+ // Fall through
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'delete':
+ case 'bulk_delete': // Actual bulk deletion (if confirmed)
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadParam('class', '', false, 'class');
+ $sClassLabel = MetaModel::GetName($sClass);
+ $aObjects = array();
+ if ($operation == 'delete')
+ {
+ // Single object
+ $id = utils::ReadParam('id', '');
+ $oObj = MetaModel::GetObject($sClass, $id);
+ $aObjects[] = $oObj;
+ if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromObject($oObj)))
+ {
+ throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClassLabel));
+ }
+ }
+ else
+ {
+ // Several objects
+ $sFilter = utils::ReadPostedParam('filter', '');
+ $oFullSetFilter = DBObjectSearch::unserialize($sFilter);
+ // Add user filter
+ $oFullSetFilter->UpdateContextFromUser();
+ $aSelectObject = utils::ReadMultipleSelection($oFullSetFilter);
+ if ( empty($sClass) || empty($aSelectObject)) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObject[]'));
+ }
+ foreach($aSelectObject as $iId)
+ {
+ $aObjects[] = MetaModel::GetObject($sClass, $iId);
+ }
+ if (count($aObjects) == 1)
+ {
+ if (!UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
+ {
+ throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
+ }
+ }
+ else
+ {
+ if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects)))
+ {
+ throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClassLabel));
+ }
+ $oP->set_title(Dict::S('UI:BulkDeletePageTitle'));
+ }
+ }
+ // Go for the common part... (delete single, delete bulk, delete confirmed)
+ cmdbAbstractObject::DeleteObjects($oP, $sClass, $aObjects, ($operation != 'bulk_delete_confirmed'), 'bulk_delete_confirmed');
+ break;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////
+
+ case 'apply_new': // Creation of a new object
+ $oP->DisableBreadCrumb();
+ $sClass = utils::ReadPostedParam('class', '', 'class');
+ $sClassLabel = MetaModel::GetName($sClass);
+ $sTransactionId = utils::ReadPostedParam('transaction_id', '');
+ if ( empty($sClass) ) // TO DO: check that the class name is valid !
+ {
+ throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
+ }
+ if (!utils::IsTransactionValid($sTransactionId, false))
+ {
+ $oP->p("".Dict::S('UI:Error:ObjectAlreadyCreated')."\n");
+ }
+ else
+ {
+ $oObj = MetaModel::NewObject($sClass);
+ $sStateAttCode = MetaModel::GetStateAttributeCode($sClass);
+ if (!empty($sStateAttCode))
+ {
+ $sTargetState = utils::ReadPostedParam('obj_state', '');
+ if ($sTargetState != '')
+ {
+ $oObj->Set($sStateAttCode, $sTargetState);
+ }
+ }
+ $oObj->UpdateObjectFromPostedForm();
+ }
+ if (isset($oObj) && is_object($oObj))
+ {
+ $sClass = get_class($oObj);
+ $sClassLabel = MetaModel::GetName($sClass);
+
+ list($bRes, $aIssues) = $oObj->CheckToWrite();
+ if ($bRes)
+ {
+ $oObj->DBInsertNoReload(); // No need to reload
+ utils::RemoveTransaction($sTransactionId);
+ $oP->set_title(Dict::S('UI:PageTitle:ObjectCreated'));
+
+ // Compute the name, by reloading the object, even if it disappeared from the silo
+ $oObj = MetaModel::GetObject($sClass, $oObj->GetKey(), true /* Must be found */, true /* Allow All Data*/);
+ $sName = $oObj->GetName();
+ $sMessage = Dict::Format('UI:Title:Object_Of_Class_Created', $sName, $sClassLabel);
+
+ $sNextAction = utils::ReadPostedParam('next_action', '');
+ if (!empty($sNextAction))
+ {
+ $oP->add("
$sMessage
");
+ ApplyNextAction($oP, $oObj, $sNextAction);
+ }
+ else
+ {
+ // Nothing more to do
+ ReloadAndDisplay($oP, $oObj, 'create', $sMessage, 'ok');
+ }
+ }
+ else
+ {
+ // Found issues, explain and give the user a second chance
+ //
+ $oP->set_title(Dict::Format('UI:CreationPageTitle_Class', $sClassLabel));
+ $oP->add("