N°5655 - Refactor object modification logic to a dedicated controller for both page / modal modes

This commit is contained in:
Molkobain
2022-11-05 00:14:25 +01:00
parent dcdce52608
commit f5b216fd9a
8 changed files with 143 additions and 38 deletions

View File

@@ -1838,7 +1838,7 @@ class MenuBlock extends DisplayBlock
if ($bIsModifyAllowed) {
$aRegularActions['UI:Menu:Modify'] = array(
'label' => Dict::S('UI:Menu:Modify'),
'url' => "{$sRootUrl}pages/$sUIPage?operation=modify&class=$sClass&id=$id{$sContext}#",
'url' => "{$sRootUrl}pages/$sUIPage?operation=object.modify&class=$sClass&id=$id{$sContext}#",
) + $aActionParams;
}
if ($bIsCreationAllowed) {

View File

@@ -349,6 +349,7 @@ return array(
'Combodo\\iTop\\Controller\\AbstractController' => $baseDir . '/sources/Controller/AbstractController.php',
'Combodo\\iTop\\Controller\\AjaxRenderController' => $baseDir . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => $baseDir . '/sources/Controller/Base/Layout/ActivityPanelController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => $baseDir . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\OAuth\\OAuthLandingController' => $baseDir . '/sources/Controller/OAuth/OAuthLandingController.php',
'Combodo\\iTop\\Controller\\PreferencesController' => $baseDir . '/sources/Controller/PreferencesController.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\IOAuthClientProvider' => $baseDir . '/sources/Core/Authentication/Client/OAuth/IOAuthClientProvider.php',

View File

@@ -714,6 +714,7 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
'Combodo\\iTop\\Controller\\AbstractController' => __DIR__ . '/../..' . '/sources/Controller/AbstractController.php',
'Combodo\\iTop\\Controller\\AjaxRenderController' => __DIR__ . '/../..' . '/sources/Controller/AjaxRenderController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ActivityPanelController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ActivityPanelController.php',
'Combodo\\iTop\\Controller\\Base\\Layout\\ObjectController' => __DIR__ . '/../..' . '/sources/Controller/Base/Layout/ObjectController.php',
'Combodo\\iTop\\Controller\\OAuth\\OAuthLandingController' => __DIR__ . '/../..' . '/sources/Controller/OAuth/OAuthLandingController.php',
'Combodo\\iTop\\Controller\\PreferencesController' => __DIR__ . '/../..' . '/sources/Controller/PreferencesController.php',
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\IOAuthClientProvider' => __DIR__ . '/../..' . '/sources/Core/Authentication/Client/OAuth/IOAuthClientProvider.php',

View File

@@ -19,6 +19,7 @@ use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Controller\Base\Layout\ObjectController;
/**
* Displays a popup welcome message, once per session at maximum
@@ -301,7 +302,7 @@ require_once(APPROOT.'/application/startup.inc.php');
try
{
$operation = utils::ReadParam('operation', '');
$operation = utils::ReadParam('operation', '', false, utils::ENUM_SANITIZATION_FILTER_OPERATION);
$bPrintable = (utils::ReadParam('printable', 0) == '1');
$oKPI = new ExecutionKPI();
@@ -321,22 +322,16 @@ try
switch($operation)
{
case 'new': // Form to create a new object
case 'modify': // Form to modify an object
case 'apply_new': // Creation of a new object
case 'apply_modify': // Applying the modifications to an existing object
case 'form_for_modify_all': // Form to modify multiple objects (bulk modify)
case 'bulk_stimulus': // For to apply a stimulus to multiple objects
case 'stimulus': // Form displayed when applying a stimulus (state change)
case 'apply_stimulus': // Form displayed when applying a stimulus (state change)
$oP->add_linked_script("../js/json.js");
$oP->add_linked_script("../js/forms-json-utils.js");
$oP->add_linked_script("../js/wizardhelper.js");
$oP->add_linked_script("../js/wizard.utils.js");
$oP->add_linked_script("../js/linkswidget.js");
$oP->add_linked_script("../js/linksdirectwidget.js");
$oP->add_linked_script("../js/extkeywidget.js");
$oP->add_linked_script("../js/jquery.blockUI.js");
break;
foreach (ObjectController::EnumRequiredForModificationJsFilesRelPaths() as $sJsFileRelPath) {
$oP->add_linked_script("../$sJsFileRelPath");
}
break;
}
switch($operation)
@@ -659,29 +654,10 @@ EOF
///////////////////////////////////////////////////////////////////////////////////////////
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));
}
$oP->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObj, cmdbAbstractObject::ENUM_DISPLAY_MODE_EDIT));
// 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 title above the form
}
case 'modify': // Legacy operation
case 'object.modify': // New operation
$oController = new ObjectController();
$oP = $oController->Modify();
break;
///////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -11,6 +11,7 @@ use Combodo\iTop\Application\UI\Base\Component\Html\Html;
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
use Combodo\iTop\Controller\AjaxRenderController;
use Combodo\iTop\Controller\Base\Layout\ActivityPanelController;
use Combodo\iTop\Controller\Base\Layout\ObjectController;
use Combodo\iTop\Controller\PreferencesController;
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
@@ -2668,6 +2669,14 @@ EOF
$oAjaxRenderController->GetMenusCount($oPage);
break;
//--------------------------------
// Object
//--------------------------------
case 'object.modify':
$oController = new ObjectController();
$oPage = $oController->Modify();
break;
default:
$oPage->p("Invalid query.");
}

View File

@@ -529,9 +529,9 @@ JS
*/
public function SetContentLayout(PageContent $oLayout)
{
$oPrevContentLayout=$this->oContentLayout;
$oPrevContentLayout = $this->oContentLayout;
$this->oContentLayout = $oLayout;
foreach ($oPrevContentLayout->GetSubBlocks() as $oBlock){
foreach ($oPrevContentLayout->GetSubBlocks() as $oBlock) {
$this->AddUiBlock($oBlock);
}

View File

@@ -17,5 +17,16 @@ namespace Combodo\iTop\Controller;
*/
class AbstractController
{
// Empty stub for now, factorized needs might come later
/**
* It works if your JavaScript library sets an X-Requested-With HTTP header.
* It is known to work with common JavaScript frameworks: {@link https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript}
*
* @see \Symfony\Component\HttpFoundation\Request::isXmlHttpRequest() Inspired by
*
* @return bool True if the current request is an XmlHttpRequest (eg. an AJAX request)
*/
public function IsHandlingXmlHttpRequest(): bool
{
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
}
}

View File

@@ -0,0 +1,107 @@
<?php
/*
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Controller\Base\Layout;
use AjaxPage;
use ApplicationException;
use cmdbAbstractObject;
use CMDBObjectSet;
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
use Dict;
use iTopWebPage;
use MetaModel;
use SecurityException;
use utils;
use UserRights;
use WebPage;
/**
* Class ObjectController
*
* @internal
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
* @since 3.1.0
* @package Combodo\iTop\Controller\Base\Layout
*/
class ObjectController extends \Combodo\iTop\Controller\AbstractController
{
public function View()
{
}
/**
* @return \iTopWebPage|\AjaxPage Object edit form in its webpage
* @throws \ApplicationException
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \SecurityException
*/
public function Modify()
{
$bPrintable = utils::ReadParam('printable', '0') === '1';
$sClass = utils::ReadParam('class', '', false, 'class');
$sId = utils::ReadParam('id', '');
$sClass = 'Person';
$sId = 6;
// Check parameters
if (utils::IsNullOrEmptyString($sClass) || utils::IsNullOrEmptyString($sId))
{
throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
}
$oObj = MetaModel::GetObject($sClass, $sId, false);
// Check user permissions
// - Is allowed to view it?
if (is_null($oObj)) {
throw new ApplicationException(Dict::S('UI:ObjectDoesNotExist'));
}
// - Is allowed to edit 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' => $sId));
}
// Prepare web page (should more likely be some kind of response object like for Symfony)
if ($this->IsHandlingXmlHttpRequest()) {
$oPage = new AjaxPage('');
} else {
$oPage = new iTopWebPage('', $bPrintable);
$oPage->DisableBreadCrumb();
$oPage->SetContentLayout(PageContentFactory::MakeForObjectDetails($oObj, cmdbAbstractObject::ENUM_DISPLAY_MODE_EDIT));
}
// - JS files
foreach (static::EnumRequiredForModificationJsFilesRelPaths() as $sJsFileRelPath) {
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().$sJsFileRelPath);
}
// Note: Code duplicated to the case 'apply_modify' in UI.php when a data integrity issue has been found
$oObj->DisplayModifyForm($oPage, array('wizard_container' => 1)); // wizard_container: Display the title above the form
return $oPage;
}
/**
* @return string[] Rel. paths (to iTop root folder) of required JS files for object modification (create, edit, stimulus, ...)
*/
public static function EnumRequiredForModificationJsFilesRelPaths(): array
{
return [
'js/json.js',
'js/forms-json-utils.js',
'js/wizardhelper.js',
'js/wizard.utils.js',
'js/linkswidget.js',
'js/linksdirectwidget.js',
'js/extkeywidget.js',
'js/jquery.blockUI.js',
];
}
}