mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-19 15:22:17 +02:00
WIP
- Add access rights management - Manage mass updates - Add tooltips to buttons
This commit is contained in:
132
sources/Controller/Links/SynchroReplicaController.php
Normal file
132
sources/Controller/Links/SynchroReplicaController.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Controller\Links;
|
||||
|
||||
use ApplicationContext;
|
||||
use ApplicationException;
|
||||
use Combodo\iTop\Application\TwigBase\Controller\Controller;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use DBObjectSearch;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use iTopWebPage;
|
||||
use MetaModel;
|
||||
use utils;
|
||||
|
||||
class SynchroReplicaController extends Controller
|
||||
{
|
||||
public const ROUTE_NAMESPACE = 'synchroreplica';
|
||||
|
||||
public function __construct($sViewPath = '', $sModuleName = 'core', $aAdditionalPaths = [])
|
||||
{
|
||||
$sViewPath = APPROOT.'synchro';
|
||||
parent::__construct($sViewPath, $sModuleName, $aAdditionalPaths);
|
||||
|
||||
// Previously in index.php
|
||||
$this->DisableInDemoMode();
|
||||
$this->AllowOnlyAdmin();
|
||||
$this->CheckAccess();
|
||||
}
|
||||
|
||||
public static function OperationUnlinkAll(iTopWebPage $oP, ApplicationContext $oAppContext, $sOperation = 'unlink'): void
|
||||
{
|
||||
$oP->DisableBreadCrumb();
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sFilter = utils::ReadPostedParam('filter', '', 'raw_data');
|
||||
$oFullSetFilter = DBObjectSearch::unserialize($sFilter);
|
||||
// Add user filter
|
||||
$oFullSetFilter->UpdateContextFromUser();
|
||||
$aSelectObject = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
if ( empty($sClass) || empty($aSelectObject)) // TO DO: check that the class name is valid !
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObject[]'));
|
||||
}
|
||||
$sCancelUrl = "./UI.php?operation=search&filter=".urlencode($sFilter)."&".$oAppContext->GetForLink();
|
||||
$aContext = array(
|
||||
'filter' => utils::EscapeHtml($sFilter),
|
||||
'selectObj' => $aSelectObject,
|
||||
);
|
||||
|
||||
$aHeaders = array(
|
||||
'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();
|
||||
|
||||
|
||||
$sHeaderTitle = Dict::Format('UI:Modify_N_ObjectsOf_Class', count($aSelectObject), MetaModel::GetName($sClass));
|
||||
$sClassIcon = MetaModel::GetClassIcon($sClass, false);
|
||||
|
||||
// Not in preview mode, do the update for real
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', '', 'transaction_id');
|
||||
if (!utils::IsTransactionValid($sTransactionId, false)) {
|
||||
throw new Exception(Dict::S('UI:Error:ObjectAlreadyUpdated'));
|
||||
}
|
||||
utils::RemoveTransaction($sTransactionId);
|
||||
|
||||
// Avoid too many events
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
|
||||
$aErrors = [];
|
||||
foreach ($aSelectObject as $iId) {
|
||||
set_time_limit(intval($iLoopTimeLimit));
|
||||
/** @var \cmdbAbstractObject $oObj */
|
||||
$oReplica = MetaModel::GetObject('SynchroReplica', $iId);
|
||||
$bResult = true;
|
||||
try {
|
||||
if (in_array($sOperation, ['unlink', 'unlinksynchro'])) {
|
||||
\IssueLog::Error('unlinking replica '.$oReplica->GetKey());
|
||||
$oReplica->UnLink();
|
||||
}
|
||||
if (in_array($sOperation, ['synchro', 'unlinksynchro'])) {
|
||||
\IssueLog::Error('synchro replica '.$oReplica->GetKey());
|
||||
$oStatLog = $oReplica->ReSynchro();
|
||||
$aErrors = $oStatLog->GetTraces();
|
||||
}
|
||||
}
|
||||
catch (Exception $e) {
|
||||
$bResult = false;
|
||||
$aErrors[] = $e->getMessage();
|
||||
}
|
||||
catch (Error $e) {
|
||||
$bResult = false;
|
||||
$aErrors[] = $e->getMessage();
|
||||
}
|
||||
|
||||
$sStatus = $bResult ? Dict::S('UI:BulkModifyStatusModified') : Dict::S('UI:BulkModifyStatusSkipped');
|
||||
|
||||
$aErrorsToDisplay = array_map(function ($sError) {
|
||||
return utils::HtmlEntities($sError);
|
||||
}, $aErrors);
|
||||
$aRows[] = array(
|
||||
'object' => $oReplica->GetHyperlink(),
|
||||
'status' => $sStatus,
|
||||
'errors' => '<p>'.($bResult ? '' : implode('</p><p>', $aErrorsToDisplay)).'</p>',
|
||||
);
|
||||
}
|
||||
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
$oTable = DataTableUIBlockFactory::MakeForForm('BulkModify', $aHeaders, $aRows);
|
||||
$oTable->AddOption("bFullscreen", true);
|
||||
|
||||
$oPanel = PanelUIBlockFactory::MakeForClass($sClass, '');
|
||||
$oPanel->SetIcon($sClassIcon);
|
||||
$oPanel->SetTitle($sHeaderTitle);
|
||||
$oPanel->AddCSSClass('ibo-datatable-panel');
|
||||
$oPanel->AddSubBlock($oTable);
|
||||
|
||||
$oP->AddUiBlock($oPanel);
|
||||
$oP->AddSubBlock(ButtonUIBlockFactory::MakeForSecondaryAction(Dict::S('UI:Button:Done')))->SetOnClickJsCode("window.location.href='$sCancelUrl'")->AddCSSClass('mt-5');
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
170
sources/Controller/UI.php
Normal file
170
sources/Controller/UI.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Form\Form;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
class UI
|
||||
{
|
||||
|
||||
/**
|
||||
* Operation select_for_modify_all
|
||||
*
|
||||
* @param iTopWebPage $oP
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function OperationSelectForModifyAll(iTopWebPage $oP, $sTitleTab = 'UI:ModifyAllPageTitle', $sTitleCode = 'UI:Modify_ObjectsOf_Class', $sNextOperation = 'form_for_modify_all'): void
|
||||
{
|
||||
$oP->DisableBreadCrumb();
|
||||
IssueLog::Error('OperationSelectForModifyAll'.$sTitleCode);
|
||||
$oP->set_title(Dict::S($sTitleTab));
|
||||
$sFilter = utils::ReadParam('filter', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
if (empty($sFilter)) {
|
||||
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'filter'));
|
||||
}
|
||||
$oFilter = DBObjectSearch::unserialize($sFilter); //TODO : check that the filter is valid
|
||||
// Add user filter
|
||||
$oFilter->UpdateContextFromUser();
|
||||
$oChecker = new ActionChecker($oFilter, UR_ACTION_BULK_MODIFY);
|
||||
$sClass = $oFilter->GetClass();
|
||||
$sClassName = MetaModel::GetName($sClass);
|
||||
|
||||
$aDisplayParams = [
|
||||
'icon' => MetaModel::GetClassIcon($sClass, false),
|
||||
'title' => Dict::Format('UI:Modify_ObjectsOf_Class', $sClassName),
|
||||
];
|
||||
IssueLog::Error('OperationSelectForModifyAll');
|
||||
self::DisplayMultipleSelectionForm($oP, $oFilter, $sNextOperation, $oChecker, [], $aDisplayParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation form_for_modify_all
|
||||
*
|
||||
* @param iTopWebPage $oP
|
||||
* @param \ApplicationContext $oAppContext
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function OperationFormForModifyAll(iTopWebPage $oP, ApplicationContext $oAppContext): void
|
||||
{
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$sClass = utils::ReadParam('class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$oFullSetFilter = DBObjectSearch::unserialize($sFilter);
|
||||
// Add user filter
|
||||
$oFullSetFilter->UpdateContextFromUser();
|
||||
$aSelectedObj = utils::ReadMultipleSelection($oFullSetFilter);
|
||||
$sCancelUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&filter=' . urlencode($sFilter) . '&' . $oAppContext->GetForLink();
|
||||
$aContext = array('filter' => utils::EscapeHtml($sFilter));
|
||||
cmdbAbstractObject::DisplayBulkModifyForm($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $sCancelUrl, array(), $aContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Operation preview_or_modify_all
|
||||
*
|
||||
* @param iTopWebPage $oP
|
||||
* @param \ApplicationContext $oAppContext
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function OperationPreviewOrModifyAll(iTopWebPage $oP, ApplicationContext $oAppContext): void
|
||||
{
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
$oFilter = DBObjectSearch::unserialize($sFilter); // TO DO : check that the filter is valid
|
||||
// Add user filter
|
||||
$oFilter->UpdateContextFromUser();
|
||||
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$bPreview = utils::ReadParam('preview_mode', '');
|
||||
$sSelectedObj = utils::ReadParam('selectObj', '', false, 'raw_data');
|
||||
if (empty($sClass) || empty($sSelectedObj)) // TO DO: check that the class name is valid !
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'selectObj'));
|
||||
}
|
||||
$aSelectedObj = explode(',', $sSelectedObj);
|
||||
$sCancelUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&filter=' . urlencode($sFilter) . '&' . $oAppContext->GetForLink();
|
||||
$aContext = array(
|
||||
'filter' => utils::EscapeHtml($sFilter),
|
||||
'selectObj' => $sSelectedObj,
|
||||
);
|
||||
cmdbAbstractObject::DoBulkModify($oP, $sClass, $aSelectedObj, 'preview_or_modify_all', $bPreview, $sCancelUrl, $aContext);
|
||||
}/**
|
||||
* Displays a form (checkboxes) to select the objects for which to apply a given action
|
||||
* Only the objects for which the action is valid can be checked. By default all valid objects are checked
|
||||
*
|
||||
* @param WebPage $oP WebPage The page for output
|
||||
* @param \DBSearch $oFilter DBSearch The filter that defines the list of objects
|
||||
* @param string $sNextOperation string The next operation (code) to be executed when the form is submitted
|
||||
* @param ActionChecker $oChecker ActionChecker The helper class/instance used to check for which object the action is valid
|
||||
* @param array $aExtraFormParams
|
||||
* @param array $aDisplayParams
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
*@since 3.0.0 $aDisplayParams parameter
|
||||
*
|
||||
*/
|
||||
public static function DisplayMultipleSelectionForm(WebPage $oP, DBSearch $oFilter, string $sNextOperation, ActionChecker $oChecker, array $aExtraFormParams = [], array $aDisplayParams = [])
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iBulkActionAllowed = $oChecker->IsAllowed();
|
||||
$aExtraParams = array('selection_type' => 'multiple', 'selection_mode' => true, 'display_limit' => false, 'menu' => false);
|
||||
if ($iBulkActionAllowed == UR_ALLOWED_DEPENDS) {
|
||||
$aExtraParams['selection_enabled'] = $oChecker->GetAllowedIDs();
|
||||
} else {
|
||||
if (UR_ALLOWED_NO) {
|
||||
throw new ApplicationException(Dict::Format('UI:ActionNotAllowed'));
|
||||
}
|
||||
}
|
||||
|
||||
$oForm = new Form();
|
||||
$oForm->SetAction( utils::GetAbsoluteUrlAppRoot().'pages/UI.php');
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('operation', $sNextOperation));
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('class', $oFilter->GetClass()));
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('filter', utils::HtmlEntities($oFilter->Serialize())));
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden('transaction_id', utils::GetNewTransactionId()));
|
||||
foreach ($aExtraFormParams as $sName => $sValue) {
|
||||
$oForm->AddSubBlock(InputUIBlockFactory::MakeForHidden($sName, $sValue));
|
||||
}
|
||||
IssueLog::Error('DisplayMultipleSelectionForm');
|
||||
$oForm->AddSubBlock($oAppContext->GetForFormBlock());
|
||||
$oDisplayBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
//by default all the elements are selected
|
||||
$aExtraParams['selectionMode'] = 'negative';
|
||||
if (array_key_exists('icon', $aDisplayParams) || array_key_exists('title', $aDisplayParams)) {
|
||||
$aExtraParams['surround_with_panel'] = true;
|
||||
if (array_key_exists('icon', $aDisplayParams)) {
|
||||
$aExtraParams['panel_icon'] = $aDisplayParams['icon'];
|
||||
}
|
||||
if (array_key_exists('title', $aDisplayParams)) {
|
||||
$aExtraParams['panel_title'] = $aDisplayParams['title'];
|
||||
}
|
||||
}
|
||||
$oForm->AddSubBlock($oDisplayBlock->GetDisplay($oP, 1, $aExtraParams));
|
||||
$oToolbarButtons = ToolbarUIBlockFactory::MakeStandard(null);
|
||||
$oToolbarButtons->AddCSSClass('ibo-toolbar--button');
|
||||
$oForm->AddSubBlock($oToolbarButtons);
|
||||
$oToolbarButtons->AddSubBlock(ButtonUIBlockFactory::MakeForCancel(Dict::S('UI:Button:Cancel'), 'cancel')->SetOnClickJsCode('window.history.back()'));
|
||||
$oToolbarButtons->AddSubBlock(ButtonUIBlockFactory::MakeForPrimaryAction(Dict::S('UI:Button:Next'), 'next', Dict::S('UI:Button:Next'), true));
|
||||
|
||||
$oP->AddUiBlock($oForm);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user