/** * Tells whether the menu is enabled (i.e. displayed) for the current user * @return bool True if enabled, false otherwise */ public function IsEnabled() { foreach ($this->m_aEnableClasses as $index => $sClass) { if ($sClass != null) { if (MetaModel::IsValidClass($sClass)) { if ($this->m_aEnableStimuli[$index] != null) { if (!UserRights::IsStimulusAllowed($sClass, $this->m_aEnableStimuli[$index])) { return false; } } if ($this->m_aEnableActions[$index] != null) { $iResult = UserRights::IsActionAllowed($sClass, $this->m_aEnableActions[$index]); if (!($iResult & $this->m_aEnableActionResults[$index])) { return false; } } } else { return false; } } } return true; }
public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { $sOwnershipToken = null; $iKey = $this->GetKey(); $sClass = get_class($this); if ($iKey > 0) { // The concurrent access lock makes sense only for already existing objects $LockEnabled = MetaModel::GetConfig()->Get('concurrent_lock_enabled'); if ($LockEnabled) { $sOwnershipToken = utils::ReadPostedParam('ownership_token', null, false, 'raw_data'); if ($sOwnershipToken !== null) { // We're probably inside something like "apply_modify" where the validation failed and we must prompt the user again to edit the object // let's extend our lock $aLockInfo = iTopOwnershipLock::ExtendLock($sClass, $iKey, $sOwnershipToken); $sOwnershipDate = $aLockInfo['acquired']; } else { $aLockInfo = iTopOwnershipLock::AcquireLock($sClass, $iKey); if ($aLockInfo['success']) { $sOwnershipToken = $aLockInfo['token']; $sOwnershipDate = $aLockInfo['acquired']; } else { $oOwner = $aLockInfo['lock']->GetOwner(); // If the object is locked by the current user, it's worth trying again, since // the lock may be released by 'onunload' which is called AFTER loading the current page. //$bTryAgain = $oOwner->GetKey() == UserRights::GetUserId(); self::ReloadAndDisplay($oPage, $this, array('operation' => 'modify')); return; } } } } if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) { $sClassLabel = MetaModel::GetName($sClass); $oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $this->GetRawName(), $sClassLabel)); // Set title will take care of the encoding $oPage->add("<div class=\"page_header\">\n"); $oPage->add("<h1>" . $this->GetIcon() . " " . Dict::Format('UI:ModificationTitle_Class_Object', $sClassLabel, $this->GetName()) . "</h1>\n"); $oPage->add("</div>\n"); $oPage->add("<div class=\"wizContainer\">\n"); } self::$iGlobalFormId++; $this->aFieldsMap = array(); $sPrefix = ''; if (isset($aExtraParams['formPrefix'])) { $sPrefix = $aExtraParams['formPrefix']; } $aFieldsComments = isset($aExtraParams['fieldsComments']) ? $aExtraParams['fieldsComments'] : array(); $this->m_iFormId = $sPrefix . self::$iGlobalFormId; $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $aDetails = array(); $aFieldsMap = array(); if (!isset($aExtraParams['action'])) { $sFormAction = utils::GetAbsoluteUrlAppRoot() . 'pages/' . $this->GetUIPage(); // No parameter in the URL, the only parameter will be the ones passed through the form } else { $sFormAction = $aExtraParams['action']; } // Custom label for the apply button ? if (isset($aExtraParams['custom_button'])) { $sApplyButton = $aExtraParams['custom_button']; } else { if ($iKey > 0) { $sApplyButton = Dict::S('UI:Button:Apply'); } else { $sApplyButton = Dict::S('UI:Button:Create'); } } // Custom operation for the form ? if (isset($aExtraParams['custom_operation'])) { $sOperation = $aExtraParams['custom_operation']; } else { if ($iKey > 0) { $sOperation = 'apply_modify'; } else { $sOperation = 'apply_new'; } } if ($iKey > 0) { // The object already exists in the database, it's a modification $sButtons = "<input id=\"{$sPrefix}_id\" type=\"hidden\" name=\"id\" value=\"{$iKey}\">\n"; $sButtons .= "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\"><span>" . Dict::S('UI:Button:Cancel') . "</span></button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } else { // The object does not exist in the database it's a creation $sButtons = "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\">" . Dict::S('UI:Button:Cancel') . "</button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } $aTransitions = $this->EnumTransitions(); if (!isset($aExtraParams['custom_operation']) && count($aTransitions)) { // transitions are displayed only for the standard new/modify actions, not for modify_all or any other case... $oSetToCheckRights = DBObjectSet::FromObject($this); $aStimuli = Metamodel::EnumStimuli($sClass); foreach ($aTransitions as $sStimulusCode => $aTransitionDef) { $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: $sButtons .= "<button type=\"submit\" name=\"next_action\" value=\"{$sStimulusCode}\" class=\"action\"><span>" . $aStimuli[$sStimulusCode]->GetLabel() . "</span></button>\n"; break; default: // Do nothing } } } $sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position'); $iTransactionId = isset($aExtraParams['transaction_id']) ? $aExtraParams['transaction_id'] : utils::GetNewTransactionId(); $oPage->SetTransactionId($iTransactionId); $oPage->add("<form action=\"{$sFormAction}\" id=\"form_{$this->m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return OnSubmit('form_{$this->m_iFormId}');\">\n"); $sStatesSelection = ''; if (!isset($aExtraParams['custom_operation']) && $this->IsNew()) { $aInitialStates = MetaModel::EnumInitialStates($sClass); //$aInitialStates = array('new' => 'foo', 'closed' => 'bar'); if (count($aInitialStates) > 1) { $sStatesSelection = Dict::Format('UI:Create_Class_InState', MetaModel::GetName($sClass)) . '<select name="obj_state" class="state_select_' . $this->m_iFormId . '">'; foreach ($aInitialStates as $sStateCode => $sStateData) { $sSelected = ''; if ($sStateCode == $this->GetState()) { $sSelected = ' selected'; } $sStatesSelection .= '<option value="' . $sStateCode . '"' . $sSelected . '>' . MetaModel::GetStateLabel($sClass, $sStateCode) . '</option>'; } $sStatesSelection .= '</select>'; $oPage->add_ready_script("\$('.state_select_{$this->m_iFormId}').change( function() { oWizardHelper{$sPrefix}.ReloadObjectCreationForm('form_{$this->m_iFormId}', \$(this).val()); } );"); } } $sConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $sJSToken = json_encode($sOwnershipToken); $oPage->add_ready_script(<<<EOF \t\$(window).unload(function() { return OnUnload('{$iTransactionId}', '{$sClass}', {$iKey}, {$sJSToken}) } ); \twindow.onbeforeunload = function() { \t\tif (!window.bInSubmit && !window.bInCancel) \t\t{ \t\t\treturn '{$sConfirmationMessage}';\t \t\t} \t\t// return nothing ! safer for IE \t}; EOF ); if ($sButtonsPosition != 'bottom') { // top or both, display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams); if ($iKey > 0) { $aFieldsMap['id'] = $sPrefix . '_id'; } // Now display the relations, one tab per relation if (!isset($aExtraParams['noRelations'])) { $this->DisplayBareRelations($oPage, true); // Edit mode, will fill $this->aFieldsMap $aFieldsMap = array_merge($aFieldsMap, $this->aFieldsMap); } $oPage->SetCurrentTab(''); $oPage->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n"); $oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"{$iTransactionId}\">\n"); foreach ($aExtraParams as $sName => $value) { if (is_scalar($value)) { $oPage->add("<input type=\"hidden\" name=\"{$sName}\" value=\"{$value}\">\n"); } } if ($sOwnershipToken !== null) { $oPage->add("<input type=\"hidden\" name=\"ownership_token\" value=\"" . htmlentities($sOwnershipToken, ENT_QUOTES, 'UTF-8') . "\">\n"); } $oPage->add($oAppContext->GetForForm()); if ($sButtonsPosition != 'top') { // bottom or both: display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } // Hook the cancel button via jQuery so that it can be unhooked easily as well if needed $sDefaultUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=cancel&' . $oAppContext->GetForLink(); $oPage->add_ready_script("\$('#form_{$this->m_iFormId} button.cancel').click( function() { BackToDetails('{$sClass}', {$iKey}, '{$sDefaultUrl}', {$sJSToken})} );"); $oPage->add("</form>\n"); if (isset($aExtraParams['wizard_container']) && $aExtraParams['wizard_container']) { $oPage->add("</div>\n"); } $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); $sState = $this->GetState(); $sSessionStorageKey = $sClass . '_' . $iKey; $oPage->add_script(<<<EOF \t\tsessionStorage.removeItem('{$sSessionStorageKey}'); \t\t \t\t// Create the object once at the beginning of the page... \t\tvar oWizardHelper{$sPrefix} = new WizardHelper('{$sClass}', '{$sPrefix}', '{$sState}'); \t\toWizardHelper{$sPrefix}.SetFieldsMap({$sJsonFieldsMap}); \t\toWizardHelper{$sPrefix}.SetFieldsCount({$iFieldsCount}); EOF ); $oPage->add_ready_script(<<<EOF \t\toWizardHelper{$sPrefix}.UpdateWizard(); \t\t// Starts the validation when the page is ready \t\tCheckFields('form_{$this->m_iFormId}', false); EOF ); if ($sOwnershipToken !== null) { $this->GetOwnershipJSHandler($oPage, $sOwnershipToken); } else { // Probably a new object (or no concurrent lock), let's add a watchdog so that the session is kept open while editing $iInterval = MetaModel::GetConfig()->Get('concurrent_lock_expiration_delay') * 1000 / 2; if ($iInterval > 0) { $iInterval = max(MIN_WATCHDOG_INTERVAL * 1000, $iInterval); // Minimum interval for the watchdog is MIN_WATCHDOG_INTERVAL $oPage->add_ready_script(<<<EOF \t\t\t\twindow.setInterval(function() { \t\t\t\t\t\$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'watchdog'}); \t\t\t\t}, {$iInterval}); EOF ); } } }
/** * Renders the "Actions" popup menu for the given set of objects * * Note that the menu links containing (or ending) with a hash (#) will have their fragment * part (whatever is after the hash) dynamically replaced (by javascript) when the menu is * displayed, to correspond to the current hash/fragment in the page. This allows modifying * an object in with the same tab active by default as the tab that was active when selecting * the "Modify..." action. */ public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId) { if ($this->m_sStyle == 'popup') { $this->m_sStyle = 'list'; } $sHtml = ''; $oAppContext = new ApplicationContext(); $sContext = $oAppContext->GetForLink(); if (!empty($sContext)) { $sContext = '&' . $sContext; } $sClass = $this->m_oFilter->GetClass(); $oReflectionClass = new ReflectionClass($sClass); $oSet = new CMDBObjectSet($this->m_oFilter); $sFilter = $this->m_oFilter->serialize(); $sFilterDesc = $this->m_oFilter->ToOql(true); $aActions = array(); $sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass); $sRootUrl = utils::GetAbsoluteUrlAppRoot(); // 1:n links, populate the target object as a default value when creating a new linked object if (isset($aExtraParams['target_attr'])) { $aExtraParams['default'][$aExtraParams['target_attr']] = $aExtraParams['object_id']; } $sDefault = ''; if (!empty($aExtraParams['default'])) { foreach ($aExtraParams['default'] as $sKey => $sValue) { $sDefault .= "&default[{$sKey}]={$sValue}"; } } $bIsCreationAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); switch ($oSet->Count()) { case 0: // No object in the set, the only possible action is "new" if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}"); } break; case 1: $oObj = $oSet->Fetch(); $id = $oObj->GetKey(); $bLocked = false; if (MetaModel::GetConfig()->Get('concurrent_lock_enabled')) { $aLockInfo = iTopOwnershipLock::IsLocked(get_class($oObj), $id); if ($aLockInfo['locked']) { $bLocked = true; //$this->AddMenuSeparator($aActions); //$aActions['concurrent_lock_unlock'] = array ('label' => Dict::S('UI:Menu:ReleaseConcurrentLock'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=kill_lock&class=$sClass&id=$id{$sContext}"); } } $bRawModifiedAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); $bIsModifyAllowed = !$bLocked && $bRawModifiedAllowed; $bIsDeleteAllowed = !$bLocked && UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet); // Just one object in the set, possible actions are "new / clone / modify and delete" if (!isset($aExtraParams['link_attr'])) { if ($bIsModifyAllowed) { $aActions['UI:Menu:Modify'] = array('label' => Dict::S('UI:Menu:Modify'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify&class={$sClass}&id={$id}{$sContext}#"); } if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}"); } if ($bIsDeleteAllowed) { $aActions['UI:Menu:Delete'] = array('label' => Dict::S('UI:Menu:Delete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=delete&class={$sClass}&id={$id}{$sContext}"); } // Transitions / Stimuli if (!$bLocked) { $aTransitions = $oObj->EnumTransitions(); if (count($aTransitions)) { $this->AddMenuSeparator($aActions); $aStimuli = Metamodel::EnumStimuli(get_class($oObj)); foreach ($aTransitions as $sStimulusCode => $aTransitionDef) { $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet) : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=stimulus&stimulus={$sStimulusCode}&class={$sClass}&id={$id}{$sContext}"); break; default: // Do nothing } } } } // Relations... $aRelations = MetaModel::EnumRelationsEx($sClass); if (count($aRelations)) { $this->AddMenuSeparator($aActions); foreach ($aRelations as $sRelationCode => $aRelationInfo) { if (array_key_exists('down', $aRelationInfo)) { $aActions[$sRelationCode . '_down'] = array('label' => $aRelationInfo['down'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=down&class={$sClass}&id={$id}{$sContext}"); } if (array_key_exists('up', $aRelationInfo)) { $aActions[$sRelationCode . '_up'] = array('label' => $aRelationInfo['up'], 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=swf_navigator&relation={$sRelationCode}&direction=up&class={$sClass}&id={$id}{$sContext}"); } } } if ($bLocked && $bRawModifiedAllowed) { // Add a special menu to kill the lock, but only to allowed users who can also modify this object $aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles'); $bCanKill = false; $oUser = UserRights::GetUserObject(); $aUserProfiles = array(); if (!is_null($oUser)) { $oProfileSet = $oUser->Get('profile_list'); while ($oProfile = $oProfileSet->Fetch()) { $aUserProfiles[$oProfile->Get('profile')] = true; } } foreach ($aAllowedProfiles as $sProfile) { if (array_key_exists($sProfile, $aUserProfiles)) { $bCanKill = true; break; } } if ($bCanKill) { $this->AddMenuSeparator($aActions); $aActions['concurrent_lock_unlock'] = array('label' => Dict::S('UI:Menu:KillConcurrentLock'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=kill_lock&class={$sClass}&id={$id}{$sContext}"); } } /* $this->AddMenuSeparator($aActions); // Static menus: Email this page & CSV Export $sUrl = ApplicationContext::MakeObjectUrl($sClass, $id); $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl)); $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}"); // The style tells us whether the menu is displayed on a list of one object, or on the details of the given object if ($this->m_sStyle == 'list') { // Actions specific to the list $sOQL = addslashes($sFilterDesc); $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')"); } */ } $this->AddMenuSeparator($aActions); foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) { $oSet->Rewind(); foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl) { $aActions[$sLabel] = array('label' => $sLabel, 'url' => $sUrl); } } break; default: // Check rights // New / Modify $bIsModifyAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); $bIsBulkModifyAllowed = !MetaModel::IsAbstract($sClass) && UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_MODIFY, $oSet) && $oReflectionClass->IsSubclassOf('cmdbAbstractObject'); $bIsBulkDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_BULK_DELETE, $oSet); if (isset($aExtraParams['link_attr'])) { $id = $aExtraParams['object_id']; $sTargetAttr = $aExtraParams['target_attr']; $oAttDef = MetaModel::GetAttributeDef($sClass, $sTargetAttr); $sTargetClass = $oAttDef->GetTargetClass(); $bIsDeleteAllowed = UserRights::IsActionAllowed($sClass, UR_ACTION_DELETE, $oSet); if ($bIsModifyAllowed) { $aActions['UI:Menu:Add'] = array('label' => Dict::S('UI:Menu:Add'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}&addObjects=true{$sContext}"); } if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:Manage'] = array('label' => Dict::S('UI:Menu:Manage'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=modify_links&class={$sClass}&link_attr=" . $aExtraParams['link_attr'] . "&target_class={$sTargetClass}&id={$id}{$sContext}"); } //if ($bIsBulkDeleteAllowed) { $aActions[] = array ('label' => 'Remove All...', 'url' => "#"); } } else { // many objects in the set, possible actions are: new / modify all / delete all if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=new&class={$sClass}{$sContext}{$sDefault}"); } if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_modify_all&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}"); } if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/{$sUIPage}?operation=select_for_deletion&filter=" . urlencode($sFilter) . "{$sContext}"); } // Stimuli $aStates = MetaModel::EnumStates($sClass); // Do not perform time consuming computations if there are too may objects in the list $iLimit = MetaModel::GetConfig()->Get('complex_actions_limit'); if (count($aStates) > 0 && ($iLimit == 0 || $oSet->Count() < $iLimit)) { // Life cycle actions may be available... if all objects are in the same state // // Group by <state> $oGroupByExp = new FieldExpression(MetaModel::GetStateAttributeCode($sClass), $this->m_oFilter->GetClassAlias()); $aGroupBy = array('__state__' => $oGroupByExp); $aQueryParams = array(); if (isset($aExtraParams['query_params'])) { $aQueryParams = $aExtraParams['query_params']; } $sSql = $this->m_oFilter->MakeGroupByQuery($aQueryParams, $aGroupBy); $aRes = CMDBSource::QueryToArray($sSql); if (count($aRes) == 1) { // All objects are in the same state... $sState = $aRes[0]['__state__']; $aTransitions = Metamodel::EnumTransitions($sClass, $sState); if (count($aTransitions)) { $this->AddMenuSeparator($aActions); $aStimuli = Metamodel::EnumStimuli($sClass); foreach ($aTransitions as $sStimulusCode => $aTransitionDef) { $oSet->Rewind(); // As soon as the user rights implementation will browse the object set, // then we might consider using OptimizeColumnLoad() here $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSet); $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? $iActionAllowed : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: case UR_ALLOWED_DEPENDS: $aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus={$sStimulusCode}&state={$sState}&class={$sClass}&filter=" . urlencode($sFilter) . "{$sContext}"); break; default: // Do nothing } } } } } /* $this->AddMenuSeparator($aActions); $sUrl = utils::GetAbsoluteUrlAppRoot(); $aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}")); $aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}"); $sOQL = addslashes($sFilterDesc); $aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')"); */ } } $this->AddMenuSeparator($aActions); foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance) { $oSet->Rewind(); foreach ($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data) { if (is_array($data)) { // New plugins can provide javascript handlers via the 'onclick' property //TODO: enable extension of different menus by checking the 'target' property ?? $aActions[$sLabel] = array('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : ''); } else { // Backward compatibility with old plugins $aActions[$sLabel] = array('label' => $sLabel, 'url' => $data); } } } // New extensions based on iPopupMenuItem interface switch ($this->m_sStyle) { case 'list': $oSet->Rewind(); $param = $oSet; $iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS; break; case 'details': $oSet->Rewind(); $param = $oSet->Fetch(); $iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS; break; } utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions); $aFavoriteActions = array(); $aCallSpec = array($sClass, 'GetShortcutActions'); if (is_callable($aCallSpec)) { $aShortcutActions = call_user_func($aCallSpec, $sClass); foreach ($aActions as $key => $aAction) { if (in_array($key, $aShortcutActions)) { $aFavoriteActions[] = $aAction; unset($aActions[$key]); } } } else { $aShortcutActions = array(); } if (count($aFavoriteActions) > 0) { $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:OtherActions') . "\n<ul>\n"; } else { $sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>" . Dict::S('UI:Menu:Actions') . "\n<ul>\n"; } $sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions); static $bPopupScript = false; if (!$bPopupScript) { // Output this once per page... $oPage->add_ready_script("\$(\"div.itop_popup>ul\").popupmenu();\n"); $bPopupScript = true; } return $sHtml; }
/** * Displays the details of a request * @param WebPage $oP The current web page * @param Object $oObj The target object * @return void */ function ShowDetailsRequest(WebPage $oP, $oObj) { $sClass = get_class($oObj); $sLogAttCode = GetConstant($sClass, 'PUBLIC_LOG'); $sUserCommentAttCode = GetConstant($sClass, 'USER_COMMENT'); $bIsReopenButton = false; $bIsCloseButton = false; $bIsEscalateButton = false; $bEditAttachments = false; $aEditAtt = array(); // List of attributes editable in the main form if (!MetaModel::DBIsReadOnly()) { switch ($oObj->GetState()) { case 'resolved': $aEditAtt = array(); $aTransitions = $oObj->EnumTransitions(); $oSet = DBObjectSet::FromObject($oObj); // Add the "Reopen" button if this is valid action if (array_key_exists('ev_reopen', $aTransitions) && UserRights::IsStimulusAllowed($sClass, 'ev_reopen', $oSet)) { $bIsReopenButton = true; MakeStimulusForm($oP, $oObj, 'ev_reopen', array($sLogAttCode)); } // Add the "Close" button if this is valid action if (array_key_exists('ev_close', $aTransitions) && UserRights::IsStimulusAllowed($sClass, 'ev_close', $oSet)) { $bIsCloseButton = true; MakeStimulusForm($oP, $oObj, 'ev_close', array('user_satisfaction', $sUserCommentAttCode)); } break; case 'closed': // By convention 'closed' is the final state of a ticket and nothing can be done in such a state break; default: // In all other states, the only possible action is to update the ticket (both the case log and the attachments) // This update is possible only if the case log field is not read-only or hidden in the current state $iFlags = $oObj->GetAttributeFlags($sLogAttCode); $bReadOnly = ($iFlags & (OPT_ATT_READONLY | OPT_ATT_HIDDEN)) != 0; if ($bReadOnly) { $aEditAtt = array(); $bEditAttachments = false; } else { $aEditAtt = array($sLogAttCode => '????'); $bEditAttachments = true; } break; } } // REFACTORISER LA MISE EN FORME $oP->add("<h1 id=\"title_request_details\">" . $oObj->GetIcon() . " " . Dict::Format('Portal:TitleRequestDetailsFor_Request', $oObj->GetName()) . "</h1>\n"); $aAttList = json_decode(GetConstant($sClass, 'DETAILS_ZLIST'), true); switch ($oObj->GetState()) { case 'closed': $aAttList['centered'][] = 'user_satisfaction'; $aAttList['centered'][] = $sUserCommentAttCode; } // Remove the edited attribute from the shown attributes // foreach ($aEditAtt as $sAttCode => $foo) { foreach ($aAttList as $col => $aColumn) { if (in_array($sAttCode, $aColumn)) { if (($index = array_search($sAttCode, $aColumn)) !== false) { unset($aAttList[$col][$index]); } } } } $oP->add("<div class=\"wizContainer\" id=\"form_commment_request\">\n"); $oP->WizardFormStart('request_form', null); $oP->add('<div id="request_details">'); $oP->add('<table id="request_details_table">'); $oP->add('<tr>'); $oP->add('<td style="vertical-align:top;">'); $oP->DisplayObjectDetails($oObj, $aAttList['col:left']); $oP->add('</td>'); $oP->add('<td style="vertical-align:top;">'); $oP->DisplayObjectDetails($oObj, $aAttList['col:right']); $oP->add('</td>'); $oP->add('</tr>'); if (array_key_exists('centered', $aAttList)) { $oP->add('<tr>'); $oP->add('<td style="vertical-align:top;" colspan="2">'); $oP->DisplayObjectDetails($oObj, $aAttList['centered']); $oP->add('</td>'); $oP->add('</tr>'); } // REFACTORISER $oP->add('<tr>'); $oP->add('<td colspan="2" style="vertical-align:top;">'); $oAttPlugin = new AttachmentPlugIn(); if ($bEditAttachments) { $oAttPlugin->EnableDelete(false); $oAttPlugin->OnDisplayRelations($oObj, $oP, true); } else { $oAttPlugin->OnDisplayRelations($oObj, $oP, false); } $oP->add('</td>'); $oP->add('</tr>'); $oP->add('<tr>'); $oP->add('<td colspan="2" style="vertical-align:top;">'); //$oP->add("<form action=\"../portal/index.php\" id=\"request_form\" method=\"post\">\n"); //$oP->add('<table id=""><tr><td style="vertical-align:top;">'); //$oP->add("<h1 id=\"title_request_details\">".Dict::Format('Portal:CommentsFor_Request', $oObj->GetName())."</h1>\n"); $oP->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">"); $oP->add("<input type=\"hidden\" name=\"id\" value=\"" . $oObj->GetKey() . "\">"); $oP->add("<input type=\"hidden\" name=\"operation\" value=\"update_request\">"); $oP->add("<input type=\"hidden\" id=\"stimulus_to_apply\" name=\"apply_stimulus\" value=\"\">\n"); $oP->add_script(<<<EOF \tfunction SetStimulusToApply(sStimulusCode) \t{ \t\t\$('#stimulus_to_apply').val(sStimulusCode); \t} EOF ); $aEditFields = array(); // Intermediate array to avoid code duplication while splitting btw ticket_log and the rest foreach ($aEditAtt as $sAttCode => $foo) { $sValue = $oObj->Get($sAttCode); $sDisplayValue = $oObj->GetEditValue($sAttCode); $aArgs = array('this' => $oObj, 'formPrefix' => ''); $oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode); $sInputId = 'input_' . $sAttCode; $sHTMLValue = "<span id=\"field_{$sInputId}\">" . cmdbAbstractObject::GetFormElementForField($oP, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', 0, $aArgs) . '</span>'; $aEditFields[$sAttCode] = array('label' => MetaModel::GetLabel($sClass, $sAttCode), 'value' => $sHTMLValue); } foreach ($aEditFields as $sAttCode => $aFieldSpec) { if ($sAttCode == $sLogAttCode) { // Skip, the public log will be displayed below the buttons continue; } $oP->add("<div class=\"edit_item\">"); $oP->add('<h1>' . $aFieldSpec['label'] . '</h1>'); $oP->add($aFieldSpec['value']); $oP->add('</div>'); } if ($bIsReopenButton) { $sStimulusCode = 'ev_reopen'; $sTitle = addslashes(Dict::S('Portal:Button:ReopenTicket')); $sOk = addslashes(Dict::S('UI:Button:Ok')); $oP->p('<input type="button" onClick="RunStimulusDialog(\'' . $sStimulusCode . '\', \'' . $sTitle . '\', \'' . $sOk . '\');" value="' . $sTitle . '...">'); } if ($bIsCloseButton) { $sStimulusCode = 'ev_close'; $sTitle = addslashes(Dict::S('Portal:Button:CloseTicket')); $sOk = addslashes(Dict::S('UI:Button:Ok')); $oP->p('<input type="button" onClick="RunStimulusDialog(\'' . $sStimulusCode . '\', \'' . $sTitle . '\', \'' . $sOk . '\');" value="' . $sTitle . '...">'); } elseif (count($aEditAtt) > 0) { $oP->p('<input type="submit" value="' . Dict::S('Portal:Button:UpdateRequest') . '">'); } if ($bIsEscalateButton) { $sStimulusCode = 'ev_timeout'; $oP->p('<input type="submit" onClick="SetStimulusToApply(\'' . $sStimulusCode . '\');" value="' . Dict::S('Portal:ButtonEscalate') . '">'); } $oP->add('</td>'); $oP->add('</tr>'); $oP->add('<tr>'); $oP->add('<td colspan="2" style="vertical-align:top;">'); if (isset($aEditFields[$sLogAttCode])) { $oP->add("<div class=\"edit_item\">"); $oP->add('<h1>' . $aEditFields[$sLogAttCode]['label'] . '</h1>'); $oP->add($aEditFields[$sLogAttCode]['value']); $oP->add('</div>'); } else { $oP->add('<h1>' . MetaModel::GetLabel($sClass, $sLogAttCode) . '</h1>'); $oP->add($oObj->GetAsHTML($sLogAttCode)); } $oP->add('</td>'); $oP->add('</tr>'); $oP->add('</table>'); $oP->add('</div>'); $oP->WizardFormEnd(); $oP->add('</div>'); }
public function DisplayModifyForm(WebPage $oPage, $aExtraParams = array()) { self::$iGlobalFormId++; $this->aFieldsMap = array(); $sPrefix = ''; if (isset($aExtraParams['formPrefix'])) { $sPrefix = $aExtraParams['formPrefix']; } $aFieldsComments = isset($aExtraParams['fieldsComments']) ? $aExtraParams['fieldsComments'] : array(); $this->m_iFormId = $sPrefix . self::$iGlobalFormId; $sClass = get_class($this); $oAppContext = new ApplicationContext(); $sStateAttCode = MetaModel::GetStateAttributeCode($sClass); $iKey = $this->GetKey(); $aDetails = array(); $aFieldsMap = array(); if (!isset($aExtraParams['action'])) { $sFormAction = $_SERVER['SCRIPT_NAME']; // No parameter in the URL, the only parameter will be the ones passed through the form } else { $sFormAction = $aExtraParams['action']; } // Custom label for the apply button ? if (isset($aExtraParams['custom_button'])) { $sApplyButton = $aExtraParams['custom_button']; } else { if ($iKey > 0) { $sApplyButton = Dict::S('UI:Button:Apply'); } else { $sApplyButton = Dict::S('UI:Button:Create'); } } // Custom operation for the form ? if (isset($aExtraParams['custom_operation'])) { $sOperation = $aExtraParams['custom_operation']; } else { if ($iKey > 0) { $sOperation = 'apply_modify'; } else { $sOperation = 'apply_new'; } } if ($iKey > 0) { // The object already exists in the database, it's a modification $sButtons = "<input id=\"{$sPrefix}_id\" type=\"hidden\" name=\"id\" value=\"{$iKey}\">\n"; $sButtons .= "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\"><span>" . Dict::S('UI:Button:Cancel') . "</span></button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } else { // The object does not exist in the database it's a creation $sButtons = "<input type=\"hidden\" name=\"operation\" value=\"{$sOperation}\">\n"; $sButtons .= "<button type=\"button\" class=\"action cancel\">" . Dict::S('UI:Button:Cancel') . "</button> \n"; $sButtons .= "<button type=\"submit\" class=\"action\"><span>{$sApplyButton}</span></button>\n"; } $aTransitions = $this->EnumTransitions(); if (!isset($aExtraParams['custom_operation']) && count($aTransitions)) { // transitions are displayed only for the standard new/modify actions, not for modify_all or any other case... $oSetToCheckRights = DBObjectSet::FromObject($this); $aStimuli = Metamodel::EnumStimuli($sClass); foreach ($aTransitions as $sStimulusCode => $aTransitionDef) { $iActionAllowed = get_class($aStimuli[$sStimulusCode]) == 'StimulusUserAction' ? UserRights::IsStimulusAllowed($sClass, $sStimulusCode, $oSetToCheckRights) : UR_ALLOWED_NO; switch ($iActionAllowed) { case UR_ALLOWED_YES: $sButtons .= "<button type=\"submit\" name=\"next_action\" value=\"{$sStimulusCode}\" class=\"action\"><span>" . $aStimuli[$sStimulusCode]->GetLabel() . "</span></button>\n"; break; default: // Do nothing } } } $sButtonsPosition = MetaModel::GetConfig()->Get('buttons_position'); $iTransactionId = isset($aExtraParams['transaction_id']) ? $aExtraParams['transaction_id'] : utils::GetNewTransactionId(); $oPage->SetTransactionId($iTransactionId); $oPage->add("<form action=\"{$sFormAction}\" id=\"form_{$this->m_iFormId}\" enctype=\"multipart/form-data\" method=\"post\" onSubmit=\"return OnSubmit('form_{$this->m_iFormId}');\">\n"); $sStatesSelection = ''; if (!isset($aExtraParams['custom_operation']) && $this->IsNew()) { $aInitialStates = MetaModel::EnumInitialStates($sClass); //$aInitialStates = array('new' => 'foo', 'closed' => 'bar'); if (count($aInitialStates) > 1) { $sStatesSelection = Dict::Format('UI:Create_Class_InState', MetaModel::GetName($sClass)) . '<select name="obj_state" class="state_select_' . $this->m_iFormId . '">'; foreach ($aInitialStates as $sStateCode => $sStateData) { $sSelected = ''; if ($sStateCode == $this->GetState()) { $sSelected = ' selected'; } $sStatesSelection .= '<option value="' . $sStateCode . '"' . $sSelected . '>' . MetaModel::GetStateLabel($sClass, $sStateCode) . '</option>'; } $sStatesSelection .= '</select>'; $oPage->add_ready_script("\$('.state_select_{$this->m_iFormId}').change( function() { oWizardHelper{$sPrefix}.ReloadObjectCreationForm('form_{$this->m_iFormId}', \$(this).val()); } );"); } } $sConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage')); $oPage->add_ready_script(<<<EOF \t\$(window).unload(function() { return OnUnload('{$iTransactionId}') } ); \twindow.onbeforeunload = function() { \t\tif (!window.bInSubmit && !window.bInCancel) \t\t{ \t\t\treturn '{$sConfirmationMessage}';\t \t\t} \t\t// return nothing ! safer for IE \t}; EOF ); if ($sButtonsPosition != 'bottom') { // top or both, display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } $oPage->AddTabContainer(OBJECT_PROPERTIES_TAB, $sPrefix); $oPage->SetCurrentTabContainer(OBJECT_PROPERTIES_TAB); $oPage->SetCurrentTab(Dict::S('UI:PropertiesTab')); $aFieldsMap = $this->DisplayBareProperties($oPage, true, $sPrefix, $aExtraParams); if ($iKey > 0) { $aFieldsMap['id'] = $sPrefix . '_id'; } // Now display the relations, one tab per relation if (!isset($aExtraParams['noRelations'])) { $this->DisplayBareRelations($oPage, true); // Edit mode, will fill $this->aFieldsMap $aFieldsMap = array_merge($aFieldsMap, $this->aFieldsMap); } $oPage->SetCurrentTab(''); $oPage->add("<input type=\"hidden\" name=\"class\" value=\"{$sClass}\">\n"); $oPage->add("<input type=\"hidden\" name=\"transaction_id\" value=\"{$iTransactionId}\">\n"); foreach ($aExtraParams as $sName => $value) { if (is_scalar($value)) { $oPage->add("<input type=\"hidden\" name=\"{$sName}\" value=\"{$value}\">\n"); } } $oPage->add($oAppContext->GetForForm()); if ($sButtonsPosition != 'top') { // bottom or both: display the buttons here $oPage->p($sStatesSelection); $oPage->add($sButtons); } // Hook the cancel button via jQuery so that it can be unhooked easily as well if needed $sDefaultUrl = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=cancel&' . $oAppContext->GetForLink(); $oPage->add_ready_script("\$('#form_{$this->m_iFormId} button.cancel').click( function() { BackToDetails('{$sClass}', {$iKey}, '{$sDefaultUrl}')} );"); $oPage->add("</form>\n"); $iFieldsCount = count($aFieldsMap); $sJsonFieldsMap = json_encode($aFieldsMap); $sState = $this->GetState(); $oPage->add_script(<<<EOF \t\t// Create the object once at the beginning of the page... \t\tvar oWizardHelper{$sPrefix} = new WizardHelper('{$sClass}', '{$sPrefix}', '{$sState}'); \t\toWizardHelper{$sPrefix}.SetFieldsMap({$sJsonFieldsMap}); \t\toWizardHelper{$sPrefix}.SetFieldsCount({$iFieldsCount}); EOF ); $oPage->add_ready_script(<<<EOF \t\toWizardHelper{$sPrefix}.UpdateWizard(); \t\t// Starts the validation when the page is ready \t\tCheckFields('form_{$this->m_iFormId}', false); EOF ); }
/** * Check if the speficied stimulus is allowed for the set of objects * @return UR_ALLOWED_YES, UR_ALLOWED_NO or UR_ALLOWED_DEPENDS */ public function IsAllowed() { $sClass = $this->oFilter->GetClass(); if (MetaModel::IsAbstract($sClass)) { return UR_ALLOWED_NO; } // Safeguard, not implemented if the base class of the set is abstract ! $oSet = new DBObjectSet($this->oFilter); $iActionAllowed = UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oSet); if ($iActionAllowed == UR_ALLOWED_NO) { $this->iAllowedCount = 0; $this->aAllowedIDs = array(); } else { // Hmmm, may not be needed right now because we limit the "multiple" action to object in // the same state... may be useful later on if we want to extend this behavior... // Check for each object if the action is allowed or not $this->aAllowedIDs = array(); $oSet->Rewind(); $iAllowedCount = 0; $iActionAllowed = UR_ALLOWED_DEPENDS; while ($oObj = $oSet->Fetch()) { $aTransitions = $oObj->EnumTransitions(); if (array_key_exists($this->iActionCode, $aTransitions)) { // Temporary optimization possible: since the current implementation // of IsActionAllowed does not perform a 'per instance' check, we could // skip this second validation phase and assume it would return UR_ALLOWED_YES $oObjSet = DBObjectSet::FromArray($sClass, array($oObj)); if (!UserRights::IsStimulusAllowed($sClass, $this->iActionCode, $oObjSet)) { $this->aAllowedIDs[$oObj->GetKey()] = false; } else { // Assume UR_ALLOWED_YES, since there is just one object ! $this->aAllowedIDs[$oObj->GetKey()] = true; $this->iState = $oObj->GetState(); $this->iAllowedCount++; } } else { $this->aAllowedIDs[$oObj->GetKey()] = false; } } } if ($this->iAllowedCount == $oSet->Count()) { $iActionAllowed = UR_ALLOWED_YES; } if ($this->iAllowedCount == 0) { $iActionAllowed = UR_ALLOWED_NO; } return $iActionAllowed; }
protected function DoExecute() { $sUser = '******'; echo "<p>Totor: " . (UserRights::CheckCredentials('Totor', 'toto') ? 'ok' : 'NO') . "</p>\n"; echo "<p>Romain: " . (UserRights::CheckCredentials('Romain', 'toto') ? 'ok' : 'NO') . "</p>\n"; echo "<p>User: "******"</p>\n"; echo "<p>On behalf of..." . UserRights::GetRealUser() . "</p>\n"; echo "<p>Denis (impersonate) : " . (UserRights::Impersonate('Denis', 'tutu') ? 'ok' : 'NO') . "</p>\n"; echo "<p>User: "******"</p>\n"; echo "<p>On behalf of..." . UserRights::GetRealUser() . "</p>\n"; $oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT bizOrganization")); echo "<p>IsActionAllowed..." . (UserRights::IsActionAllowed('bizOrganization', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO') . "</p>\n"; echo "<p>IsStimulusAllowed..." . (UserRights::IsStimulusAllowed('bizOrganization', 'myStimulus', $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO') . "</p>\n"; echo "<p>IsActionAllowedOnAttribute..." . (UserRights::IsActionAllowedOnAttribute('bizOrganization', 'myattribute', UR_ACTION_MODIFY, $oSet) == UR_ALLOWED_YES ? 'ok' : 'NO') . "</p>\n"; return true; }