From 80a8b63498877e0dba276a7d50c631d0f9009d2f Mon Sep 17 00:00:00 2001 From: Romain Quetiez Date: Fri, 8 Mar 2013 13:36:31 +0000 Subject: [PATCH] Modified the mechanism to display object dedicated messages (allows the plugin to add their message or replace standard ones) Factorized the code to bulk update / bulk delete objects in an interactive way. SVN:trunk[2610] --- application/cmdbabstract.class.inc.php | 624 +++++++++++++++++++++++- pages/UI.php | 628 ++----------------------- 2 files changed, 666 insertions(+), 586 deletions(-) diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index a981075b7..d6e522352 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -92,7 +92,38 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay { return 'UI.php'; } - + + /** + * Set a message diplayed to the end-user next time this object will be displayed + * Messages are uniquely identified so that plugins can override standard messages (the final work is given to the last plugin to set the message for a given message id) + * In practice, standard messages are recorded at the end but they will not overwrite existing messages + * + * @param string $sClass The class of the object (must be the final class) + * @param int $iKey The identifier of the object + * @param string $sMessageId Your id or one of the well-known ids: 'create', 'update' and 'apply_stimulus' + * @param string $sMessage The HTML message (must be correctly escaped) + * @param string $sSeverity Any of the following: ok, info, error. + * @param float $fRank Ordering of the message: smallest displayed first (can be negative) + * @param bool $bMustNotExist Do not alter any existing message (considering the id) + * + */ + public static function SetSessionMessage($sClass, $iKey, $sMessageId, $sMessage, $sSeverity, $fRank, $bMustNotExist = false) + { + $sMessageKey = $sClass.'::'.$iKey; + if (!isset($_SESSION['obj_messages'][$sMessageKey])) + { + $_SESSION['obj_messages'][$sMessageKey] = array(); + } + if (!$bMustNotExist || !array_key_exists($sMessageId, $_SESSION['obj_messages'][$sMessageKey])) + { + $_SESSION['obj_messages'][$sMessageKey][$sMessageId] = array( + 'rank' => $fRank, + 'severity' => $sSeverity, + 'message' => $sMessage + ); + } + } + function DisplayBareHeader(WebPage $oPage, $bEditMode = false) { // Standard Header with name, actions menu and history block @@ -102,8 +133,19 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay $sMessageKey = get_class($this).'::'.$this->GetKey(); if (array_key_exists('obj_messages', $_SESSION) && array_key_exists($sMessageKey, $_SESSION['obj_messages'])) { - $sMsgClass = 'message_'.$_SESSION['obj_messages'][$sMessageKey]['severity']; - $oPage->add("
".$_SESSION['obj_messages'][$sMessageKey]['message']."
"); + $aMessages = array(); + $aRanks = array(); + foreach ($_SESSION['obj_messages'][$sMessageKey] as $sMessageId => $aMessageData) + { + $sMsgClass = 'message_'.$aMessageData['severity']; + $aMessages[] = "
".$aMessageData['message']."
"; + $aRanks[] = $aMessageData['rank']; + } + array_multisort($aRanks, $aMessages); + foreach ($aMessages as $sMessage) + { + $oPage->add($sMessage); + } unset($_SESSION['obj_messages'][$sMessageKey]); } @@ -1754,7 +1796,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay } return "
{$sHTMLValue}
"; } - + public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { self::$iGlobalFormId++; @@ -2868,5 +2910,579 @@ EOF } return $aComputedAttributes; } + + /** + * Display a form for modifying several objects at once + * The form will be submitted to the current page, with the specified additional values + */ + public static function DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, $sCustomOperation, $sCancelUrl, $aExcludeAttributes = array(), $aContextData = array()) + { + if (count($aSelectedObj) > 0) + { + $iAllowedCount = count($aSelectedObj); + $sSelectedObj = implode(',', $aSelectedObj); + + $sOQL = "SELECT $sClass WHERE id IN (".$sSelectedObj.")"; + $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL)); + + // Compute the distribution of the values for each field to determine which of the "scalar" fields are homogenous + $aList = MetaModel::ListAttributeDefs($sClass); + $aValues = array(); + foreach($aList as $sAttCode => $oAttDef) + { + if ($oAttDef->IsScalar()) + { + $aValues[$sAttCode] = array(); + } + } + while($oObj = $oSet->Fetch()) + { + foreach($aList as $sAttCode => $oAttDef) + { + if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) + { + $currValue = $oObj->Get($sAttCode); + if ($oAttDef instanceof AttributeCaseLog) + { + $currValue = ' '; // Don't put an empty string, in case the field would be considered as mandatory... + } + if (is_object($currValue)) continue; // Skip non scalar values... + if(!array_key_exists($currValue, $aValues[$sAttCode])) + { + $aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode)); + } + else + { + $aValues[$sAttCode][$currValue]['count']++; + } + } + } + } + // Now create an object that has values for the homogenous values only + $oDummyObj = new $sClass(); // @@ What if the class is abstract ? + $aComments = array(); + function MyComparison($a, $b) // Sort descending + { + if ($a['count'] == $b['count']) + { + return 0; + } + return ($a['count'] > $b['count']) ? -1 : 1; + } + + $iFormId = cmdbAbstractObject::GetNextFormId(); // Identifier that prefixes all the form fields + $sReadyScript = ''; + $aDependsOn = array(); + $sFormPrefix = '2_'; + foreach($aList as $sAttCode => $oAttDef) + { + $aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one + if (count($aPrerequisites) > 0) + { + // When 'enabling' a field, all its prerequisites must be enabled too + $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aPrerequisites)."']"; + $oP->add_ready_script("$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, true); } );\n"); + } + $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one + if (count($aDependents) > 0) + { + // When 'disabling' a field, all its dependent fields must be disabled too + $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aDependents)."']"; + $oP->add_ready_script("$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, false); } );\n"); + } + if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) + { + if ($oAttDef->GetEditClass() == 'One Way Password') + { + + $sTip = "Unknown values"; + $sReadyScript .= "$('#multi_values_$sAttCode').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"; + + $oDummyObj->Set($sAttCode, null); + $aComments[$sAttCode] = ''; + $aComments[$sAttCode] .= '
?
'; + $sReadyScript .= 'ToogleField(false, \''.$iFormId.'_'.$sAttCode.'\');'."\n"; + } + else + { + $iCount = count($aValues[$sAttCode]); + if ($iCount == 1) + { + // Homogenous value + reset($aValues[$sAttCode]); + $aKeys = array_keys($aValues[$sAttCode]); + $currValue = $aKeys[0]; // The only value is the first key + //echo "

current value for $sAttCode : $currValue

"; + $oDummyObj->Set($sAttCode, $currValue); + $aComments[$sAttCode] = ''; + $aComments[$sAttCode] .= '
1
'; + } + else + { + // Non-homogenous value + $aMultiValues = $aValues[$sAttCode]; + uasort($aMultiValues, 'MyComparison'); + $iMaxCount = 5; + $sTip = "

".Dict::Format('UI:BulkModify_Count_DistinctValues', $iCount)."

"; + $sTip = addslashes($sTip); + $sReadyScript .= "$('#multi_values_$sAttCode').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"; + + $oDummyObj->Set($sAttCode, null); + $aComments[$sAttCode] = ''; + $aComments[$sAttCode] .= '
'.$iCount.'
'; + } + $sReadyScript .= 'ToogleField('.(($iCount == 1) ? 'true': 'false').', \''.$iFormId.'_'.$sAttCode.'\');'."\n"; + } + } + } + + $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); + if (($sStateAttCode != '') && ($oDummyObj->GetState() == '')) + { + // Hmmm, it's not gonna work like this ! Set a default value for the "state" + // Maybe we should use the "state" that is the most common among the objects... + $aMultiValues = $aValues[$sStateAttCode]; + uasort($aMultiValues, 'MyComparison'); + foreach($aMultiValues as $sCurrValue => $aVal) + { + $oDummyObj->Set($sStateAttCode, $sCurrValue); + break; + } + //$oStateAtt = MetaModel::GetAttributeDef($sClass, $sStateAttCode); + //$oDummyObj->Set($sStateAttCode, $oStateAtt->GetDefaultValue()); + } + $oP->add("
\n"); + $oP->add("

".$oDummyObj->GetIcon()." ".Dict::Format('UI:Modify_M_ObjectsOf_Class_OutOf_N', $iAllowedCount, $sClass, $iAllowedCount)."

\n"); + $oP->add("
\n"); + + $oP->add("
\n"); + $sDisableFields = json_encode($aExcludeAttributes); + + $aParams = array + ( + 'fieldsComments' => $aComments, + 'noRelations' => true, + 'custom_operation' => $sCustomOperation, + 'custom_button' => Dict::S('UI:Button:PreviewModifications'), + 'selectObj' => $sSelectedObj, + 'preview_mode' => true, + 'disabled_fields' => $sDisableFields, + 'disable_plugins' => true + ); + $aParams = $aParams + $aContextData; // merge keeping associations + + $oDummyObj->DisplayModifyForm($oP, $aParams); + $oP->add("
\n"); + $oP->add_ready_script($sReadyScript); + $oP->add_ready_script( +<<p("No object selected !, nothing to do"); + } + } + + /** + * Process the reply made from a form built with DisplayBulkModifyForm + */ + public static function DoBulkModify($oP, $sClass, $aSelectedObj, $sCustomOperation, $bPreview, $sCancelUrl, $aContextData = array()) + { + $aHeaders = array( + 'form::select' => array('label' => "", 'description' => Dict::S('UI:SelectAllToggle+')), + 'object' => array('label' => MetaModel::GetName($sClass), 'description' => Dict::S('UI:ModifiedObject')), + 'status' => array('label' => Dict::S('UI:BulkModifyStatus'), 'description' => Dict::S('UI:BulkModifyStatus+')), + 'errors' => array('label' => Dict::S('UI:BulkModifyErrors'), 'description' => Dict::S('UI:BulkModifyErrors+')), + ); + $aRows = array(); + + $oP->add("
\n"); + $oP->add("

".MetaModel::GetClassIcon($sClass)." ".Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), $sClass)."

\n"); + $oP->add("
\n"); + $oP->set_title(Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), $sClass)); + if (!$bPreview) + { + // Not in preview mode, do the update for real + $sTransactionId = utils::ReadPostedParam('transaction_id', ''); + if (!utils::IsTransactionValid($sTransactionId, false)) + { + throw new Exception(Dict::S('UI:Error:ObjectAlreadyUpdated')); + } + utils::RemoveTransaction($sTransactionId); + } + foreach($aSelectedObj as $iId) + { + $oObj = MetaModel::GetObject($sClass, $iId); + $aErrors = $oObj->UpdateObjectFromPostedForm(''); + $bResult = (count($aErrors) == 0); + if ($bResult) + { + list($bResult, $aErrors) = $oObj->CheckToWrite(true /* Enforce Read-only fields */); + } + if ($bPreview) + { + $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusOk') : Dict::S('UI:BulkModifyStatusError'); + } + else + { + $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusModified') : Dict::S('UI:BulkModifyStatusSkipped'); + } + $sCSSClass = $bResult ? HILIGHT_CLASS_NONE : HILIGHT_CLASS_CRITICAL; + $sChecked = $bResult ? 'checked' : ''; + $sDisabled = $bResult ? '' : 'disabled'; + $aRows[] = array( + 'form::select' => "", + 'object' => $oObj->GetHyperlink(), + 'status' => $sStatus, + 'errors' => '

'.($bResult ? '': implode('

', $aErrors)).'

', + '@class' => $sCSSClass, + ); + if ($bResult && (!$bPreview)) + { + $oObj->DBUpdate(); + } + } + $oP->Table($aHeaders, $aRows); + if ($bPreview) + { + $sFormAction = $_SERVER['SCRIPT_NAME']; // No parameter in the URL, the only parameter will be the ones passed through the form + // Form to submit: + $oP->add("
\n"); + $aDefaults = utils::ReadParam('default', array()); + $oAppContext = new ApplicationContext(); + $oP->add($oAppContext->GetForForm()); + foreach ($aContextData as $sKey => $value) + { + $oP->add("\n"); + } + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("    \n"); + $oP->add("\n"); + foreach($_POST as $sKey => $value) + { + if (preg_match('/attr_(.+)/', $sKey, $aMatches)) + { + // Beware: some values (like durations) are passed as arrays + if (is_array($value)) + { + foreach($value as $vKey => $vValue) + { + $oP->add("\n"); + } + } + else + { + $oP->add("\n"); + } + } + } + $oP->add("
\n"); + } + else + { + $oP->add("\n"); + } + } + + /** + * Perform all the needed checks to delete one (or more) objects + */ + public static function DeleteObjects(WebPage $oP, $sClass, $aObjects, $bPreview, $sCustomOperation, $aContextData = array()) + { + $oDeletionPlan = new DeletionPlan(); + + foreach($aObjects as $oObj) + { + if ($bPreview) + { + $oObj->CheckToDelete($oDeletionPlan); + } + else + { + $oObj->DBDeleteTracked(CMDBObject::GetCurrentChange(), null, $oDeletionPlan); + } + } + + if ($bPreview) + { + if (count($aObjects) == 1) + { + $oObj = $aObjects[0]; + $oP->add("

".Dict::Format('UI:Delete:ConfirmDeletionOf_Name', $oObj->GetName())."

\n"); + } + else + { + $oP->add("

".Dict::Format('UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass))."

\n"); + } + // Explain what should be done + // + $aDisplayData = array(); + foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) + { + foreach ($aDeletes as $iId => $aData) + { + $oToDelete = $aData['to_delete']; + $bAutoDel = (($aData['mode'] == DEL_SILENT) || ($aData['mode'] == DEL_AUTO)); + if (array_key_exists('issue', $aData)) + { + if ($bAutoDel) + { + if (isset($aData['requested_explicitely'])) + { + $sConsequence = Dict::Format('UI:Delete:CannotDeleteBecause', $aData['issue']); + } + else + { + $sConsequence = Dict::Format('UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible', $aData['issue']); + } + } + else + { + $sConsequence = Dict::Format('UI:Delete:MustBeDeletedManuallyButNotPossible', $aData['issue']); + } + } + else + { + if ($bAutoDel) + { + if (isset($aData['requested_explicitely'])) + { + $sConsequence = ''; // not applicable + } + else + { + $sConsequence = Dict::S('UI:Delete:WillBeDeletedAutomatically'); + } + } + else + { + $sConsequence = Dict::S('UI:Delete:MustBeDeletedManually'); + } + } + $aDisplayData[] = array( + 'class' => MetaModel::GetName(get_class($oToDelete)), + 'object' => $oToDelete->GetHyperLink(), + 'consequence' => $sConsequence, + ); + } + } + foreach ($oDeletionPlan->ListUpdates() as $sRemoteClass => $aToUpdate) + { + foreach ($aToUpdate as $iId => $aData) + { + $oToUpdate = $aData['to_reset']; + if (array_key_exists('issue', $aData)) + { + $sConsequence = Dict::Format('UI:Delete:CannotUpdateBecause_Issue', $aData['issue']); + } + else + { + $sConsequence = Dict::Format('UI:Delete:WillAutomaticallyUpdate_Fields', $aData['attributes_list']); + } + $aDisplayData[] = array( + 'class' => MetaModel::GetName(get_class($oToUpdate)), + 'object' => $oToUpdate->GetHyperLink(), + 'consequence' => $sConsequence, + ); + } + } + + $iImpactedIndirectly = $oDeletionPlan->GetTargetCount() - count($aObjects); + if ($iImpactedIndirectly > 0) + { + if (count($aObjects) == 1) + { + $oObj = $aObjects[0]; + $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencing_Object', $iImpactedIndirectly, $oObj->GetName())); + } + else + { + $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencingTheObjects', $iImpactedIndirectly)); + } + $oP->p(Dict::S('UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity')); + } + + if (($iImpactedIndirectly > 0) || $oDeletionPlan->FoundStopper()) + { + $aDisplayConfig = array(); + $aDisplayConfig['class'] = array('label' => 'Class', 'description' => ''); + $aDisplayConfig['object'] = array('label' => 'Object', 'description' => ''); + $aDisplayConfig['consequence'] = array('label' => 'Consequence', 'description' => Dict::S('UI:Delete:Consequence+')); + $oP->table($aDisplayConfig, $aDisplayData); + } + + if ($oDeletionPlan->FoundStopper()) + { + if ($oDeletionPlan->FoundSecurityIssue()) + { + $oP->p(Dict::S('UI:Delete:SorryDeletionNotAllowed')); + } + elseif ($oDeletionPlan->FoundManualOperation()) + { + $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations')); + } + else // $bFoundManualOp + { + $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations')); + } + $oAppContext = new ApplicationContext(); + $oP->add("
\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add("\n"); + $oP->add($oAppContext->GetForForm()); + $oP->add("
\n"); + } + else + { + if (count($aObjects) == 1) + { + $oObj = $aObjects[0]; + $id = $oObj->GetKey(); + $oP->p('

'.Dict::Format('UI:Delect:Confirm_Object', $oObj->GetHyperLink()).'

'); + } + else + { + $oP->p('

'.Dict::Format('UI:Delect:Confirm_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)).'

'); + } + foreach($aObjects as $oObj) + { + $aKeys[] = $oObj->GetKey(); + } + $oFilter = new DBObjectSearch($sClass); + $oFilter->AddCondition('id', $aKeys, 'IN'); + $oSet = new CMDBobjectSet($oFilter); + $oP->add('
'); + CMDBAbstractObject::DisplaySet($oP, $oSet, array('display_limit' => false, 'menu' => false)); + $oP->add("
\n"); + $oP->add("
\n"); + foreach ($aContextData as $sKey => $value) + { + $oP->add("\n"); + } + $oP->add("\n"); + $oP->add("\n"); + $oP->add("Serialize()."\">\n"); + $oP->add("\n"); + foreach($aObjects as $oObj) + { + $oP->add("GetKey()."\">\n"); + } + $oP->add("\n"); + $oP->add("\n"); + $oAppContext = new ApplicationContext(); + $oP->add($oAppContext->GetForForm()); + $oP->add("
\n"); + } + } + else // if ($bPreview)... + { + // Execute the deletion + // + if (count($aObjects) == 1) + { + $oObj = $aObjects[0]; + $oP->add("

".Dict::Format('UI:Title:DeletionOf_Object', $oObj->GetName())."

\n"); + } + else + { + $oP->add("

".Dict::Format('UI:Title:BulkDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass))."

\n"); + } + // Security - do not allow the user to force a forbidden delete by the mean of page arguments... + if ($oDeletionPlan->FoundSecurityIssue()) + { + throw new CoreException(Dict::S('UI:Error:NotEnoughRightsToDelete')); + } + if ($oDeletionPlan->FoundManualOperation()) + { + throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseManualOpNeeded')); + } + if ($oDeletionPlan->FoundManualDelete()) + { + throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseOfDepencies')); + } + + // Report deletions + // + $aDisplayData = array(); + foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) + { + foreach ($aDeletes as $iId => $aData) + { + $oToDelete = $aData['to_delete']; + + if (isset($aData['requested_explicitely'])) + { + $sMessage = Dict::S('UI:Delete:Deleted'); + } + else + { + $sMessage = Dict::S('UI:Delete:AutomaticallyDeleted'); + } + $aDisplayData[] = array( + 'class' => MetaModel::GetName(get_class($oToDelete)), + 'object' => $oToDelete->GetName(), + 'consequence' => $sMessage, + ); + } + } + + // Report updates + // + foreach ($oDeletionPlan->ListUpdates() as $sTargetClass => $aToUpdate) + { + foreach ($aToUpdate as $iId => $aData) + { + $oToUpdate = $aData['to_reset']; + $aDisplayData[] = array( + 'class' => MetaModel::GetName(get_class($oToUpdate)), + 'object' => $oToUpdate->GetHyperLink(), + 'consequence' => Dict::Format('UI:Delete:AutomaticResetOf_Fields', $aData['attributes_list']), + ); + } + } + + // Report automatic jobs + // + if ($oDeletionPlan->GetTargetCount() > 0) + { + if (count($aObjects) == 1) + { + $oObj = $aObjects[0]; + $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Object', $oObj->GetName())); + } + else + { + $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass))); + } + $aDisplayConfig = array(); + $aDisplayConfig['class'] = array('label' => 'Class', 'description' => ''); + $aDisplayConfig['object'] = array('label' => 'Object', 'description' => ''); + $aDisplayConfig['consequence'] = array('label' => 'Done', 'description' => Dict::S('UI:Delete:Done+')); + $oP->table($aDisplayConfig, $aDisplayData); + } + } + } } ?> diff --git a/pages/UI.php b/pages/UI.php index 8083960ec..d43710aeb 100644 --- a/pages/UI.php +++ b/pages/UI.php @@ -24,288 +24,6 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ -/** - * Perform all the needed checks to delete one (or more) objects - */ -function DeleteObjects(WebPage $oP, $sClass, $aObjects, $bDeleteConfirmed, $oFilter = null) -{ - $oDeletionPlan = new DeletionPlan(); - - foreach($aObjects as $oObj) - { - if ($bDeleteConfirmed) - { - $oObj->DBDeleteTracked(CMDBObject::GetCurrentChange(), null, $oDeletionPlan); - } - else - { - $oObj->CheckToDelete($oDeletionPlan); - } - } - - if ($bDeleteConfirmed) - { - if (count($aObjects) == 1) - { - $oObj = $aObjects[0]; - $oP->add("

".Dict::Format('UI:Title:DeletionOf_Object', $oObj->GetName())."

\n"); - } - else - { - $oP->add("

".Dict::Format('UI:Title:BulkDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass))."

\n"); - } - // Security - do not allow the user to force a forbidden delete by the mean of page arguments... - if ($oDeletionPlan->FoundSecurityIssue()) - { - throw new CoreException(Dict::S('UI:Error:NotEnoughRightsToDelete')); - } - if ($oDeletionPlan->FoundManualOperation()) - { - throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseManualOpNeeded')); - } - if ($oDeletionPlan->FoundManualDelete()) - { - throw new CoreException(Dict::S('UI:Error:CannotDeleteBecauseOfDepencies')); - } - - // Report deletions - // - $aDisplayData = array(); - foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) - { - foreach ($aDeletes as $iId => $aData) - { - $oToDelete = $aData['to_delete']; - - if (isset($aData['requested_explicitely'])) - { - $sMessage = Dict::S('UI:Delete:Deleted'); - } - else - { - $sMessage = Dict::S('UI:Delete:AutomaticallyDeleted'); - } - $aDisplayData[] = array( - 'class' => MetaModel::GetName(get_class($oToDelete)), - 'object' => $oToDelete->GetName(), - 'consequence' => $sMessage, - ); - } - } - - // Report updates - // - foreach ($oDeletionPlan->ListUpdates() as $sTargetClass => $aToUpdate) - { - foreach ($aToUpdate as $iId => $aData) - { - $oToUpdate = $aData['to_reset']; - $aDisplayData[] = array( - 'class' => MetaModel::GetName(get_class($oToUpdate)), - 'object' => $oToUpdate->GetHyperLink(), - 'consequence' => Dict::Format('UI:Delete:AutomaticResetOf_Fields', $aData['attributes_list']), - ); - } - } - - // Report automatic jobs - // - if ($oDeletionPlan->GetTargetCount() > 0) - { - if (count($aObjects) == 1) - { - $oObj = $aObjects[0]; - $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Object', $oObj->GetName())); - } - else - { - $oP->p(Dict::Format('UI:Delete:CleaningUpRefencesTo_Several_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass))); - } - $aDisplayConfig = array(); - $aDisplayConfig['class'] = array('label' => 'Class', 'description' => ''); - $aDisplayConfig['object'] = array('label' => 'Object', 'description' => ''); - $aDisplayConfig['consequence'] = array('label' => 'Done', 'description' => Dict::S('UI:Delete:Done+')); - $oP->table($aDisplayConfig, $aDisplayData); - } - } - else - { - if (count($aObjects) == 1) - { - $oObj = $aObjects[0]; - $oP->add("

".Dict::Format('UI:Delete:ConfirmDeletionOf_Name', $oObj->GetName())."

\n"); - } - else - { - $oP->add("

".Dict::Format('UI:Delete:ConfirmDeletionOf_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass))."

\n"); - } - // Explain what should be done - // - $aDisplayData = array(); - foreach ($oDeletionPlan->ListDeletes() as $sTargetClass => $aDeletes) - { - foreach ($aDeletes as $iId => $aData) - { - $oToDelete = $aData['to_delete']; - $bAutoDel = (($aData['mode'] == DEL_SILENT) || ($aData['mode'] == DEL_AUTO)); - if (array_key_exists('issue', $aData)) - { - if ($bAutoDel) - { - if (isset($aData['requested_explicitely'])) - { - $sConsequence = Dict::Format('UI:Delete:CannotDeleteBecause', $aData['issue']); - } - else - { - $sConsequence = Dict::Format('UI:Delete:ShouldBeDeletedAtomaticallyButNotPossible', $aData['issue']); - } - } - else - { - $sConsequence = Dict::Format('UI:Delete:MustBeDeletedManuallyButNotPossible', $aData['issue']); - } - } - else - { - if ($bAutoDel) - { - if (isset($aData['requested_explicitely'])) - { - $sConsequence = ''; // not applicable - } - else - { - $sConsequence = Dict::S('UI:Delete:WillBeDeletedAutomatically'); - } - } - else - { - $sConsequence = Dict::S('UI:Delete:MustBeDeletedManually'); - } - } - $aDisplayData[] = array( - 'class' => MetaModel::GetName(get_class($oToDelete)), - 'object' => $oToDelete->GetHyperLink(), - 'consequence' => $sConsequence, - ); - } - } - foreach ($oDeletionPlan->ListUpdates() as $sRemoteClass => $aToUpdate) - { - foreach ($aToUpdate as $iId => $aData) - { - $oToUpdate = $aData['to_reset']; - if (array_key_exists('issue', $aData)) - { - $sConsequence = Dict::Format('UI:Delete:CannotUpdateBecause_Issue', $aData['issue']); - } - else - { - $sConsequence = Dict::Format('UI:Delete:WillAutomaticallyUpdate_Fields', $aData['attributes_list']); - } - $aDisplayData[] = array( - 'class' => MetaModel::GetName(get_class($oToUpdate)), - 'object' => $oToUpdate->GetHyperLink(), - 'consequence' => $sConsequence, - ); - } - } - - $iImpactedIndirectly = $oDeletionPlan->GetTargetCount() - count($aObjects); - if ($iImpactedIndirectly > 0) - { - if (count($aObjects) == 1) - { - $oObj = $aObjects[0]; - $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencing_Object', $iImpactedIndirectly, $oObj->GetName())); - } - else - { - $oP->p(Dict::Format('UI:Delete:Count_Objects/LinksReferencingTheObjects', $iImpactedIndirectly)); - } - $oP->p(Dict::S('UI:Delete:ReferencesMustBeDeletedToEnsureIntegrity')); - } - - if (($iImpactedIndirectly > 0) || $oDeletionPlan->FoundStopper()) - { - $aDisplayConfig = array(); - $aDisplayConfig['class'] = array('label' => 'Class', 'description' => ''); - $aDisplayConfig['object'] = array('label' => 'Object', 'description' => ''); - $aDisplayConfig['consequence'] = array('label' => 'Consequence', 'description' => Dict::S('UI:Delete:Consequence+')); - $oP->table($aDisplayConfig, $aDisplayData); - } - - if ($oDeletionPlan->FoundStopper()) - { - if ($oDeletionPlan->FoundSecurityIssue()) - { - $oP->p(Dict::S('UI:Delete:SorryDeletionNotAllowed')); - } - elseif ($oDeletionPlan->FoundManualOperation()) - { - $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations')); - } - else // $bFoundManualOp - { - $oP->p(Dict::S('UI:Delete:PleaseDoTheManualOperations')); - } - $oAppContext = new ApplicationContext(); - $oP->add("
\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add($oAppContext->GetForForm()); - $oP->add("
\n"); - } - else - { - $oAppContext = new ApplicationContext(); - if (count($aObjects) == 1) - { - $oObj = $aObjects[0]; - $id = $oObj->GetKey(); - $oP->p('

'.Dict::Format('UI:Delect:Confirm_Object', $oObj->GetHyperLink()).'

'); - $oP->add("
\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add($oAppContext->GetForForm()); - $oP->add("
\n"); - } - else - { - $oP->p('

'.Dict::Format('UI:Delect:Confirm_Count_ObjectsOf_Class', count($aObjects), MetaModel::GetName($sClass)).'

'); - foreach($aObjects as $oObj) - { - $aKeys[] = $oObj->GetKey(); - } - $oFilter = new DBObjectSearch($sClass); - $oFilter->AddCondition('id', $aKeys, 'IN'); - $oSet = new CMDBobjectSet($oFilter); - $oP->add('
'); - CMDBAbstractObject::DisplaySet($oP, $oSet, array('display_limit' => false, 'menu' => false)); - $oP->add("
\n"); - $oP->add("
\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("Serialize()."\">\n"); - $oP->add("\n"); - foreach($aObjects as $oObj) - { - $oP->add("GetKey()."\">\n"); - } - $oP->add("\n"); - $oP->add("\n"); - $oP->add($oAppContext->GetForForm()); - $oP->add("
\n"); - } - } - } -} /** * Displays a popup welcome message, once per session at maximum @@ -390,13 +108,12 @@ function ApplyNextAction(Webpage $oP, CMDBObject $oObj, $sNextAction) } } -function ReloadAndDisplay($oPage, $oObj, $sMessage = '', $sSeverity) +function ReloadAndDisplay($oPage, $oObj, $sMessageId = '', $sMessage = '', $sSeverity = null) { $oAppContext = new ApplicationContext(); - $sMessageKey = get_class($oObj).'::'.$oObj->GetKey(); - if ($sMessage != '') + if ($sMessageId != '') { - $_SESSION['obj_messages'][$sMessageKey] = array('severity' => $sSeverity, 'message' => $sMessage); + 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()); } @@ -959,174 +676,9 @@ try $sClass = utils::ReadParam('class', '', false, 'class'); $oFullSetFilter = DBObjectSearch::unserialize($sFilter); $aSelectedObj = utils::ReadMultipleSelection($oFullSetFilter); - if (count($aSelectedObj) > 0) - { - $iAllowedCount = count($aSelectedObj); - $sSelectedObj = implode(',', $aSelectedObj); - - $sOQL = "SELECT $sClass WHERE id IN (".$sSelectedObj.")"; - $oSet = new CMDBObjectSet(DBObjectSearch::FromOQL($sOQL)); - - // Compute the distribution of the values for each field to determine which of the "scalar" fields are homogenous - $aList = MetaModel::ListAttributeDefs($sClass); - $aValues = array(); - foreach($aList as $sAttCode => $oAttDef) - { - if ($oAttDef->IsScalar()) - { - $aValues[$sAttCode] = array(); - } - } - while($oObj = $oSet->Fetch()) - { - foreach($aList as $sAttCode => $oAttDef) - { - if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) - { - $currValue = $oObj->Get($sAttCode); - if ($oAttDef instanceof AttributeCaseLog) - { - $currValue = ' '; // Don't put an empty string, in case the field would be considered as mandatory... - } - if (is_object($currValue)) continue; // Skip non scalar values... - if(!array_key_exists($currValue, $aValues[$sAttCode])) - { - $aValues[$sAttCode][$currValue] = array('count' => 1, 'display' => $oObj->GetAsHTML($sAttCode)); - } - else - { - $aValues[$sAttCode][$currValue]['count']++; - } - } - } - } - // Now create an object that has values for the homogenous values only - $oDummyObj = new $sClass(); // @@ What if the class is abstract ? - $aComments = array(); - function MyComparison($a, $b) // Sort descending - { - if ($a['count'] == $b['count']) - { - return 0; - } - return ($a['count'] > $b['count']) ? -1 : 1; - } - - $iFormId = cmdbAbstractObject::GetNextFormId(); // Identifier that prefixes all the form fields - $sReadyScript = ''; - $aDependsOn = array(); - $sFormPrefix = '2_'; - foreach($aList as $sAttCode => $oAttDef) - { - $aPrerequisites = MetaModel::GetPrequisiteAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one - if (count($aPrerequisites) > 0) - { - // When 'enabling' a field, all its prerequisites must be enabled too - $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aPrerequisites)."']"; - $oP->add_ready_script("$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, true); } );\n"); - } - $aDependents = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that are needed for the current one - if (count($aDependents) > 0) - { - // When 'disabling' a field, all its dependent fields must be disabled too - $sFieldList = "['{$sFormPrefix}".implode("','{$sFormPrefix}", $aDependents)."']"; - $oP->add_ready_script("$('#enable_{$sFormPrefix}{$sAttCode}').bind('change', function(evt, sFormId) { return PropagateCheckBox( this.checked, $sFieldList, false); } );\n"); - } - if ($oAttDef->IsScalar() && $oAttDef->IsWritable()) - { - if ($oAttDef->GetEditClass() == 'One Way Password') - { - - $sTip = "Unknown values"; - $sReadyScript .= "$('#multi_values_$sAttCode').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"; - - $oDummyObj->Set($sAttCode, null); - $aComments[$sAttCode] = ''; - $aComments[$sAttCode] .= '
?
'; - $sReadyScript .= 'ToogleField(false, \''.$iFormId.'_'.$sAttCode.'\');'."\n"; - } - else - { - $iCount = count($aValues[$sAttCode]); - if ($iCount == 1) - { - // Homogenous value - reset($aValues[$sAttCode]); - $aKeys = array_keys($aValues[$sAttCode]); - $currValue = $aKeys[0]; // The only value is the first key - //echo "

current value for $sAttCode : $currValue

"; - $oDummyObj->Set($sAttCode, $currValue); - $aComments[$sAttCode] = ''; - $aComments[$sAttCode] .= '
1
'; - } - else - { - // Non-homogenous value - $aMultiValues = $aValues[$sAttCode]; - uasort($aMultiValues, 'MyComparison'); - $iMaxCount = 5; - $sTip = "

".Dict::Format('UI:BulkModify_Count_DistinctValues', $iCount)."

"; - $sTip = addslashes($sTip); - $sReadyScript .= "$('#multi_values_$sAttCode').qtip( { content: '$sTip', show: 'mouseover', hide: 'mouseout', style: { name: 'dark', tip: 'leftTop' }, position: { corner: { target: 'rightMiddle', tooltip: 'leftTop' }} } );"; - - $oDummyObj->Set($sAttCode, null); - $aComments[$sAttCode] = ''; - $aComments[$sAttCode] .= '
'.$iCount.'
'; - } - $sReadyScript .= 'ToogleField('.(($iCount == 1) ? 'true': 'false').', \''.$iFormId.'_'.$sAttCode.'\');'."\n"; - } - } - } - - $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); - if (($sStateAttCode != '') && ($oDummyObj->GetState() == '')) - { - // Hmmm, it's not gonna work like this ! Set a default value for the "state" - // Maybe we should use the "state" that is the most common among the objects... - $aMultiValues = $aValues[$sStateAttCode]; - uasort($aMultiValues, 'MyComparison'); - foreach($aMultiValues as $sCurrValue => $aVal) - { - $oDummyObj->Set($sStateAttCode, $sCurrValue); - break; - } - //$oStateAtt = MetaModel::GetAttributeDef($sClass, $sStateAttCode); - //$oDummyObj->Set($sStateAttCode, $oStateAtt->GetDefaultValue()); - } - $oP->add("
\n"); - $oP->add("

".$oDummyObj->GetIcon()." ".Dict::Format('UI:Modify_M_ObjectsOf_Class_OutOf_N', $iAllowedCount, $sClass, $iAllowedCount)."

\n"); - $oP->add("
\n"); - - $oP->add("
\n"); - $oDummyObj->DisplayModifyForm($oP, array('fieldsComments' => $aComments, 'noRelations' => true, 'custom_operation' => 'preview_or_modify_all', 'custom_button' => Dict::S('UI:Button:PreviewModifications'), 'selectObj' => $sSelectedObj, 'filter' => $sFilter, 'preview_mode' => true, 'disabled_fields' => '{}', 'disable_plugins' => true)); - $oP->add("
\n"); - $oP->add_ready_script($sReadyScript); - $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink(); - $oP->add_ready_script( -<<p("No object selected !, nothing to do"); - } + $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; /////////////////////////////////////////////////////////////////////////////////////////// @@ -1145,101 +697,12 @@ EOF throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObj')); } $aSelectedObj = explode(',', $sSelectedObj); - $aHeaders = array( - 'form::select' => array('label' => "", 'description' => Dict::S('UI:SelectAllToggle+')), - 'object' => array('label' => MetaModel::GetName($sClass), 'description' => Dict::S('UI:ModifiedObject')), - 'status' => array('label' => Dict::S('UI:BulkModifyStatus'), 'description' => Dict::S('UI:BulkModifyStatus+')), - 'errors' => array('label' => Dict::S('UI:BulkModifyErrors'), 'description' => Dict::S('UI:BulkModifyErrors+')), + $sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink(); + $aContext = array( + 'filter' => $sFilter, + 'selectObj' => $sSelectedObj, ); - $aRows = array(); - - $oP->add("
\n"); - $oP->add("

".MetaModel::GetClassIcon($sClass)." ".Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), $sClass)."

\n"); - $oP->add("
\n"); - $oP->set_title(Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectedObj), $sClass)); - if (!$bPreview) - { - // Not in preview mode, do the update for real - $sTransactionId = utils::ReadPostedParam('transaction_id', ''); - if (!utils::IsTransactionValid($sTransactionId, false)) - { - throw new Exception(Dict::S('UI:Error:ObjectAlreadyUpdated')); - } - utils::RemoveTransaction($sTransactionId); - } - foreach($aSelectedObj as $iId) - { - $oObj = MetaModel::GetObject($sClass, $iId); - $aErrors = $oObj->UpdateObjectFromPostedForm(''); - $bResult = (count($aErrors) == 0); - if ($bResult) - { - list($bResult, $aErrors) = $oObj->CheckToWrite(true /* Enforce Read-only fields */); - } - if ($bPreview) - { - $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusOk') : Dict::S('UI:BulkModifyStatusError'); - } - else - { - $sStatus = $bResult ? Dict::S('UI:BulkModifyStatusModified') : Dict::S('UI:BulkModifyStatusSkipped'); - } - $sCSSClass = $bResult ? HILIGHT_CLASS_NONE : HILIGHT_CLASS_CRITICAL; - $sChecked = $bResult ? 'checked' : ''; - $sDisabled = $bResult ? '' : 'disabled'; - $aRows[] = array( - 'form::select' => "", - 'object' => $oObj->GetHyperlink(), - 'status' => $sStatus, - 'errors' => '

'.($bResult ? '': implode('

', $aErrors)).'

', - '@class' => $sCSSClass, - ); - if ($bResult && (!$bPreview)) - { - $oObj->DBUpdate(); - } - } - $oP->Table($aHeaders, $aRows); - $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink(); - if ($bPreview) - { - // Form to submit: - $oP->add("
\n"); - $aDefaults = utils::ReadParam('default', array()); - $oP->add($oAppContext->GetForForm()); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("\n"); - $oP->add("    \n"); - $oP->add("\n"); - foreach($_POST as $sKey => $value) - { - if (preg_match('/attr_(.+)/', $sKey, $aMatches)) - { - // Beware: some values (like durations) are passed as arrays - if (is_array($value)) - { - foreach($value as $vKey => $vValue) - { - $oP->add("\n"); - } - } - else - { - $oP->add("\n"); - } - } - } - $oP->add("
\n"); - } - else - { - $sURL = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink(); - $oP->add("\n"); - } + cmdbAbstractObject::DoBulkModify($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $bPreview, $sCancelUrl, $aContext); break; /////////////////////////////////////////////////////////////////////////////////////////// @@ -1431,7 +894,7 @@ EOF else { // Nothing more to do - ReloadAndDisplay($oP, $oObj, $sMessage, $sSeverity); + ReloadAndDisplay($oP, $oObj, 'update', $sMessage, $sSeverity); } } break; @@ -1464,47 +927,48 @@ EOF /////////////////////////////////////////////////////////////////////////////////////////// + case 'delete': case 'bulk_delete': // Actual bulk deletion (if confirmed) - $sClass = utils::ReadPostedParam('class', ''); + $sClass = utils::ReadParam('class', '', false, 'class'); $sClassLabel = MetaModel::GetName($sClass); - $sFilter = utils::ReadPostedParam('filter', ''); - $oFullSetFilter = DBObjectSearch::unserialize($sFilter); - $aSelectObject = utils::ReadMultipleSelection($oFullSetFilter); $aObjects = array(); - if ( empty($sClass) || empty($aSelectObject)) // TO DO: check that the class name is valid ! + if ($operation == 'delete') { - throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObject[]')); + // Single object + $id = utils::ReadParam('id', ''); + $oObj = MetaModel::GetObject($sClass, $id); + $aObjects[] = $oObj; + if (!UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, DBObjectSet::FromObject($oObj))) + { + throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClass)); + } } - foreach($aSelectObject as $iId) + else { - $aObjects[] = MetaModel::GetObject($sClass, $iId); + // Several objects + $sFilter = utils::ReadPostedParam('filter', ''); + $oFullSetFilter = DBObjectSearch::unserialize($sFilter); + $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 (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects))) + { + throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClass)); + } + $oP->set_title(Dict::S('UI:BulkDeletePageTitle')); } - if (!UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, DBObjectSet::FromArray($sClass, $aObjects))) - { - throw new SecurityException(Dict::Format('UI:Error:BulkDeleteNotAllowedOn_Class', $sClass)); - } - $oP->set_title(Dict::S('UI:BulkDeletePageTitle')); - DeleteObjects($oP, $sClass, $aObjects, ($operation == 'bulk_delete_confirmed'), $oFullSetFilter); - break; + // 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 'delete': // Deletion (preview) - case 'delete_confirmed': // Deletion (confirmed) - $sClass = utils::ReadParam('class', '', false, 'class'); - $sClassLabel = MetaModel::GetName($sClass); - $id = utils::ReadParam('id', ''); - $oObj = MetaModel::GetObject($sClass, $id); - - if (!UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, DBObjectSet::FromObject($oObj))) - { - throw new SecurityException(Dict::Format('UI:Error:DeleteNotAllowedOn_Class', $sClass)); - } - DeleteObjects($oP, $sClass, array($oObj), ($operation == 'delete_confirmed')); - break; - - /////////////////////////////////////////////////////////////////////////////////////////// - case 'apply_new': // Creation of a new object $sClass = utils::ReadPostedParam('class', '', 'class'); $sClassLabel = MetaModel::GetName($sClass); @@ -1555,7 +1019,7 @@ EOF else { // Nothing more to do - ReloadAndDisplay($oP, $oObj, $sMessage, 'ok'); + ReloadAndDisplay($oP, $oObj, 'create', $sMessage, 'ok'); } } else @@ -2116,7 +1580,7 @@ EOF $sSeverity = 'error'; } } - ReloadAndDisplay($oP, $oObj, $sMessage, $sSeverity); + ReloadAndDisplay($oP, $oObj, 'apply_stimulus', $sMessage, $sSeverity); } else {