mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-02 07:34:13 +01:00
Compare commits
9 Commits
test_eric
...
feature/69
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94fb23d366 | ||
|
|
4e4b6c1ec2 | ||
|
|
451bab6957 | ||
|
|
85003e89eb | ||
|
|
5fb5f093e7 | ||
|
|
4c48b65e6b | ||
|
|
43d3a3bc67 | ||
|
|
1fee4372eb | ||
|
|
a4434afa0d |
@@ -79,6 +79,10 @@ gitGraph
|
||||
commit id: "2023-08-10" tag: "2.7.9"
|
||||
checkout support/3.1
|
||||
commit id: "2023-12-20" tag: "3.1.1"
|
||||
checkout support/2.7
|
||||
commit id: "2024-01-17a" tag: "2.7.10"
|
||||
checkout support/3.0
|
||||
commit id: "2024-01-17b" tag: "3.0.4"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
|
||||
@@ -563,8 +563,8 @@ JS
|
||||
}
|
||||
|
||||
if (!$bEditMode) {
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/dashlet.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/dashboard.js');
|
||||
}
|
||||
|
||||
return $oDashboard;
|
||||
|
||||
@@ -326,6 +326,7 @@ class DataTable
|
||||
$sPagesLinks = implode('', $aPagesToDisplay);
|
||||
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
|
||||
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
|
||||
$sHtml =
|
||||
<<<EOF
|
||||
@@ -333,11 +334,11 @@ class DataTable
|
||||
<div $sPagerStyle>
|
||||
<table id="pager{$this->iListId}" class="pager"><tr>
|
||||
<td>$sPages</td>
|
||||
<td><img src="../images/first.png" class="first"/></td>
|
||||
<td><img src="../images/prev.png" class="prev"/></td>
|
||||
<td><img src="{$sAppRootUrl}images/first.png" class="first"/>AAAA</td>
|
||||
<td><img src="{$sAppRootUrl}images/prev.png" class="prev"/></td>
|
||||
<td><span id="index">$sPagesLinks</span></td>
|
||||
<td><img src="../images/next.png" class="next"/></td>
|
||||
<td><img src="../images/last.png" class="last"/></td>
|
||||
<td><img src="{$sAppRootUrl}images/next.png" class="next"/></td>
|
||||
<td><img src="{$sAppRootUrl}images/last.png" class="last"/></td>
|
||||
<td>$sPageSizeCombo</td>
|
||||
<td><span id="loading"> </span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
|
||||
</td>
|
||||
|
||||
@@ -26,7 +26,6 @@ use Combodo\iTop\Application\UI\DisplayBlock\BlockCsv\BlockCsv;
|
||||
use Combodo\iTop\Application\UI\DisplayBlock\BlockList\BlockList;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
|
||||
@@ -570,7 +569,7 @@ class DisplayBlock
|
||||
} else {
|
||||
// render it as an Ajax (asynchronous) call
|
||||
$oHtml->AddCSSClass("loading");
|
||||
$oHtml->AddHtml("<p><img src=\"../images/indicator_arrows.gif\"> ".Dict::S('UI:Loading').'</p>');
|
||||
$oHtml->AddHtml("<p><img src=\"".utils::GetAbsoluteUrlAppRoot()."images/indicator_arrows.gif\"> ".Dict::S('UI:Loading').'</p>');
|
||||
$oPage->add_script('
|
||||
$.post("ajax.render.php?style='.$this->m_sStyle.'",
|
||||
{ operation: "ajax", filter: "'.$sFilter.'", extra_params: "'.$sExtraParams.'" },
|
||||
@@ -1848,7 +1847,6 @@ class MenuBlock extends DisplayBlock
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$oRenderBlock = new UIContentBlock();
|
||||
|
||||
if ($this->m_sStyle == 'popup') // popup is a synonym of 'list' for backward compatibility
|
||||
@@ -2068,7 +2066,8 @@ class MenuBlock extends DisplayBlock
|
||||
if ($bIsModifyAllowed) {
|
||||
$aRegularActions['UI:Menu:Modify'] = array(
|
||||
'label' => Dict::S('UI:Menu:Modify'),
|
||||
'url' => $oRouter->GenerateUrl('object.modify', ['class' => $sClass, 'id' => $id]) . "{$sContext}#",
|
||||
// Can't use URL Generator (`$this->oUrlGenerator->generate("b_object_summary", [$sObjClass, $sObjKey])`) yet as we have to find how to inject it here
|
||||
'url' => "{$sRootUrl}app.php/object/modify/{$sClass}/{$id}{$sContext}#",
|
||||
) + $aActionParams;
|
||||
}
|
||||
if ($bIsDeleteAllowed) {
|
||||
|
||||
@@ -303,7 +303,7 @@ class ExcelExporter
|
||||
{
|
||||
if ($this->sOutputFilePath == null)
|
||||
{
|
||||
return APPROOT.'data/bulk_export/'.$this->sToken.'.xlsx';
|
||||
return utils::GetDataPath().'bulk_export/'.$this->sToken.'.xlsx';
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -313,14 +313,14 @@ class ExcelExporter
|
||||
|
||||
public static function GetExcelFileFromToken($sToken)
|
||||
{
|
||||
return @file_get_contents(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
|
||||
return @file_get_contents(utils::GetDataPath().'bulk_export/'.$sToken.'.xlsx');
|
||||
}
|
||||
|
||||
public static function CleanupFromToken($sToken)
|
||||
{
|
||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.status');
|
||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.data');
|
||||
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
|
||||
@unlink(utils::GetDataPath().'bulk_export/'.$sToken.'.status');
|
||||
@unlink(utils::GetDataPath().'bulk_export/'.$sToken.'.data');
|
||||
@unlink(utils::GetDataPath().'bulk_export/'.$sToken.'.xlsx');
|
||||
}
|
||||
|
||||
public function Cleanup()
|
||||
@@ -334,7 +334,7 @@ class ExcelExporter
|
||||
*/
|
||||
public static function CleanupOldFiles()
|
||||
{
|
||||
$aFiles = glob(APPROOT.'data/bulk_export/*.*');
|
||||
$aFiles = glob(utils::GetDataPath().'bulk_export/*.*');
|
||||
$iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay');
|
||||
|
||||
if($iDelay > 0)
|
||||
@@ -416,14 +416,14 @@ class ExcelExporter
|
||||
|
||||
protected function CheckDataDir()
|
||||
{
|
||||
if(!is_dir(APPROOT."data/bulk_export"))
|
||||
if(!is_dir(utils::GetDataPath()."bulk_export"))
|
||||
{
|
||||
@mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */);
|
||||
@mkdir(utils::GetDataPath()."bulk_export", 0777, true /* recursive */);
|
||||
clearstatcache();
|
||||
}
|
||||
if (!is_writable(APPROOT."data/bulk_export"))
|
||||
if (!is_writable(utils::GetDataPath()."bulk_export"))
|
||||
{
|
||||
throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.');
|
||||
throw new Exception('Data directory "'.utils::GetDataPath().'bulk_export" could not be written.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,12 +433,12 @@ class ExcelExporter
|
||||
{
|
||||
$sToken = $this->sToken;
|
||||
}
|
||||
return APPROOT."data/bulk_export/$sToken.status";
|
||||
return utils::GetDataPath()."bulk_export/$sToken.status";
|
||||
}
|
||||
|
||||
protected function GetDataFile()
|
||||
{
|
||||
return APPROOT.'data/bulk_export/'.$this->sToken.'.data';
|
||||
return utils::GetDataPath().'bulk_export/'.$this->sToken.'.data';
|
||||
}
|
||||
|
||||
protected function GetNewToken()
|
||||
|
||||
@@ -232,12 +232,13 @@ class DisplayTemplate
|
||||
static public function UnitTest()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sTemplate = '<div class="page_header">
|
||||
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
</div>
|
||||
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<img src="'.$sAppRootUrl.'images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<itoptabs>
|
||||
<itoptab name="Interfaces">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
|
||||
@@ -350,7 +351,8 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
if ($iFlags & OPT_ATT_SLAVE)
|
||||
{
|
||||
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sAppRooturl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"{$sAppRooturl}images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
|
||||
@@ -228,7 +228,7 @@ class privUITransactionFile
|
||||
*/
|
||||
public static function GetNewTransactionId()
|
||||
{
|
||||
if (!is_dir(APPROOT.'data/transactions'))
|
||||
if (!is_dir(utils::GetDataPath().'transactions'))
|
||||
{
|
||||
if (!is_writable(APPROOT.'data'))
|
||||
{
|
||||
@@ -236,22 +236,22 @@ class privUITransactionFile
|
||||
}
|
||||
// condition avoids race condition N°2345
|
||||
// See https://github.com/kalessil/phpinspectionsea/blob/master/docs/probable-bugs.md#mkdir-race-condition
|
||||
if (!mkdir($concurrentDirectory = APPROOT.'data/transactions') && !is_dir($concurrentDirectory))
|
||||
if (!mkdir($concurrentDirectory = utils::GetDataPath().'transactions') && !is_dir($concurrentDirectory))
|
||||
{
|
||||
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
|
||||
throw new Exception('Failed to create the directory "'.utils::GetDataPath().'transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_writable(APPROOT.'data/transactions'))
|
||||
if (!is_writable(utils::GetDataPath().'transactions'))
|
||||
{
|
||||
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
|
||||
throw new Exception('The directory "'.utils::GetDataPath().'transactions" must be writable to the application.');
|
||||
}
|
||||
|
||||
$iCurrentUserId = static::GetCurrentUserId();
|
||||
|
||||
self::CleanupOldTransactions();
|
||||
|
||||
$sTransactionIdFullPath = tempnam(APPROOT.'data/transactions', static::GetUserPrefix());
|
||||
$sTransactionIdFullPath = tempnam(utils::GetDataPath().'transactions', static::GetUserPrefix());
|
||||
file_put_contents($sTransactionIdFullPath, $iCurrentUserId, LOCK_EX);
|
||||
|
||||
$sTransactionIdFileName = basename($sTransactionIdFullPath);
|
||||
@@ -274,8 +274,8 @@ class privUITransactionFile
|
||||
*/
|
||||
public static function IsTransactionValid($id, $bRemoveTransaction = true)
|
||||
{
|
||||
// Constraint the transaction file within APPROOT.'data/transactions'
|
||||
$sTransactionDir = realpath(APPROOT.'data/transactions');
|
||||
// Constraint the transaction file within utils::GetDataPath().'transactions'
|
||||
$sTransactionDir = realpath(utils::GetDataPath().'transactions');
|
||||
$sFilepath = utils::RealPath($sTransactionDir.'/'.$id, $sTransactionDir);
|
||||
if (($sFilepath === false) || (strlen($sTransactionDir) == strlen($sFilepath)))
|
||||
{
|
||||
@@ -348,7 +348,7 @@ class privUITransactionFile
|
||||
|
||||
clearstatcache();
|
||||
$iLimit = time() - 24*3600;
|
||||
$sPattern = $sTransactionDir ? "$sTransactionDir/*" : APPROOT.'data/transactions/*';
|
||||
$sPattern = $sTransactionDir ? "$sTransactionDir/*" : utils::GetDataPath().'transactions/*';
|
||||
$aTransactions = glob($sPattern);
|
||||
foreach($aTransactions as $sFileName)
|
||||
{
|
||||
@@ -368,7 +368,7 @@ class privUITransactionFile
|
||||
{
|
||||
clearstatcache();
|
||||
$aResult = array();
|
||||
$aTransactions = glob(APPROOT.'data/transactions/'.self::GetUserPrefix().'*');
|
||||
$aTransactions = glob(utils::GetDataPath().'transactions/'.self::GetUserPrefix().'*');
|
||||
foreach($aTransactions as $sFileName)
|
||||
{
|
||||
$aResult[] = date('Y-m-d H:i:s', filemtime($sFileName)).' - '.basename($sFileName);
|
||||
|
||||
@@ -161,8 +161,8 @@ class UIExtKeyWidget
|
||||
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), &$sInputType = '')
|
||||
{
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/extkeywidget.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
@@ -368,7 +368,7 @@ JS
|
||||
*/
|
||||
public function DisplayRadio(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, DBObjectset $oAllowedValues, $value, $sFieldName, $sDisplayStyle)
|
||||
{
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
@@ -477,8 +477,8 @@ JS
|
||||
$this->bSearchMode = $bSearchMode;
|
||||
}
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/extkeywidget.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
|
||||
@@ -1446,7 +1446,7 @@ EOF
|
||||
<<<EOF
|
||||
function OnTruncatedHistoryToggle(bShowAll)
|
||||
{
|
||||
$('#csv_history_reload').html('<img src="../images/indicator.gif"/>');
|
||||
$('#csv_history_reload').html('<img src="' + GetAbsoluteUrlAppRoot() + 'images/indicator.gif"/>');
|
||||
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
|
||||
{
|
||||
$('#$sAjaxDivId').html(data);
|
||||
|
||||
@@ -474,14 +474,14 @@ abstract class BulkExport
|
||||
*/
|
||||
protected function MakeTmpFile($sExtension)
|
||||
{
|
||||
if(!is_dir(APPROOT."data/bulk_export"))
|
||||
if(!is_dir(utils::GetDataPath()."bulk_export"))
|
||||
{
|
||||
@mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */);
|
||||
@mkdir(utils::GetDataPath()."bulk_export", 0777, true /* recursive */);
|
||||
clearstatcache();
|
||||
}
|
||||
if (!is_writable(APPROOT."data/bulk_export"))
|
||||
if (!is_writable(utils::GetDataPath()."bulk_export"))
|
||||
{
|
||||
throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.');
|
||||
throw new Exception('Data directory "'.utils::GetDataPath().'bulk_export" could not be written.');
|
||||
}
|
||||
|
||||
$iNum = rand();
|
||||
@@ -489,7 +489,7 @@ abstract class BulkExport
|
||||
{
|
||||
$iNum++;
|
||||
$sToken = sprintf("%08x", $iNum);
|
||||
$sFileName = APPROOT."data/bulk_export/$sToken.".$sExtension;
|
||||
$sFileName = utils::GetDataPath()."bulk_export/$sToken.".$sExtension;
|
||||
$hFile = @fopen($sFileName, 'x');
|
||||
}
|
||||
while($hFile === false);
|
||||
|
||||
@@ -1552,13 +1552,13 @@ abstract class DBSearch
|
||||
}
|
||||
|
||||
$sLogFile = 'queries.latest';
|
||||
file_put_contents(APPROOT.'data/'.$sLogFile.'.html', $sHtml);
|
||||
file_put_contents(utils::GetDataPath().$sLogFile.'.html', $sHtml);
|
||||
|
||||
$sLog = "<?php\n\$aQueriesLog = ".var_export(self::$m_aQueriesLog, true).";";
|
||||
file_put_contents(APPROOT.'data/'.$sLogFile.'.log', $sLog);
|
||||
file_put_contents(utils::GetDataPath().$sLogFile.'.log', $sLog);
|
||||
|
||||
// Cumulate the queries
|
||||
$sAllQueries = APPROOT.'data/queries.log';
|
||||
$sAllQueries = utils::GetDataPath().'queries.log';
|
||||
if (file_exists($sAllQueries))
|
||||
{
|
||||
// Merge the new queries into the existing log
|
||||
|
||||
@@ -217,7 +217,7 @@ class ormStopWatch
|
||||
}
|
||||
else
|
||||
{
|
||||
$aProperties['Elapsed'] = 'running <img src="../images/indicator.gif">';
|
||||
$aProperties['Elapsed'] = 'running <img src="' . utils::GetAbsoluteUrlAppRoot() . 'images/indicator.gif">';
|
||||
}
|
||||
|
||||
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
|
||||
|
||||
@@ -500,17 +500,17 @@ EOF
|
||||
if (file_exists($sDotExecutable))
|
||||
{
|
||||
// create the file with Graphviz
|
||||
if (!is_dir(APPROOT."data"))
|
||||
if (!is_dir(utils::GetDataPath()))
|
||||
{
|
||||
@mkdir(APPROOT."data");
|
||||
@mkdir(utils::GetDataPath());
|
||||
}
|
||||
if (!is_dir(APPROOT."data/tmp"))
|
||||
if (!is_dir(utils::GetDataPath()."tmp"))
|
||||
{
|
||||
@mkdir(APPROOT."data/tmp");
|
||||
@mkdir(utils::GetDataPath()."tmp");
|
||||
}
|
||||
$sImageFilePath = tempnam(APPROOT."data/tmp", 'png-');
|
||||
$sImageFilePath = tempnam(utils::GetDataPath()."tmp", 'png-');
|
||||
$sDotDescription = $this->GetDotDescription();
|
||||
$sDotFilePath = tempnam(APPROOT."data/tmp", 'dot-');
|
||||
$sDotFilePath = tempnam(utils::GetDataPath()."tmp", 'dot-');
|
||||
|
||||
$rFile = @fopen($sDotFilePath, "w");
|
||||
@fwrite($rFile, $sDotDescription);
|
||||
@@ -556,17 +556,17 @@ EOF
|
||||
if (file_exists($sDotExecutable))
|
||||
{
|
||||
// create the file with Graphviz
|
||||
if (!is_dir(APPROOT."data"))
|
||||
if (!is_dir(utils::GetDataPath()))
|
||||
{
|
||||
@mkdir(APPROOT."data");
|
||||
@mkdir(utils::GetDataPath());
|
||||
}
|
||||
if (!is_dir(APPROOT."data/tmp"))
|
||||
if (!is_dir(utils::GetDataPath()."tmp"))
|
||||
{
|
||||
@mkdir(APPROOT."data/tmp");
|
||||
@mkdir(utils::GetDataPath()."tmp");
|
||||
}
|
||||
$sXdotFilePath = tempnam(APPROOT."data/tmp", 'xdot-');
|
||||
$sXdotFilePath = tempnam(utils::GetDataPath()."tmp", 'xdot-');
|
||||
$sDotDescription = $this->GetDotDescription(true); // true => don't put (localized) labels in the file, since it makes it harder to parse
|
||||
$sDotFilePath = tempnam(APPROOT."data/tmp", 'dot-');
|
||||
$sDotFilePath = tempnam(utils::GetDataPath()."tmp", 'dot-');
|
||||
|
||||
$rFile = @fopen($sDotFilePath, "w");
|
||||
@fwrite($rFile, $sDotDescription);
|
||||
|
||||
@@ -185,6 +185,7 @@ abstract class AbstractAttachmentsRenderer
|
||||
{
|
||||
$sClass = $this->sObjClass;
|
||||
$sId = $this->iObjKey;
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$iMaxUploadInBytes = AttachmentPlugIn::GetMaxUploadSize();
|
||||
$sMaxUploadLabel = AttachmentPlugIn::GetMaxUpload();
|
||||
$sFileTooBigLabel = Dict::Format('Attachments:Error:FileTooLarge', $sMaxUploadLabel);
|
||||
@@ -195,7 +196,7 @@ abstract class AbstractAttachmentsRenderer
|
||||
$oAddButton = FileSelectUIBlockFactory::MakeStandard('file', 'file');
|
||||
$oAddButton->SetShowFilename(false);
|
||||
$this->oPage->AddUiBlock($oAddButton);
|
||||
$this->oPage->add('<span style="display:none;" id="attachment_loading"><img src="../images/indicator.gif"></span> '.$sMaxUploadLabel);
|
||||
$this->oPage->add('<span style="display:none;" id="attachment_loading"><img src="' . $sAppRootUrl . 'images/indicator.gif"></span> ' . $sMaxUploadLabel);
|
||||
$this->oPage->add('</div>');
|
||||
$this->oPage->add('<div class="ibo-attachment--upload-file--drop-zone-hint ibo-svg-illustration--container">');
|
||||
$this->oPage->add(file_get_contents(APPROOT.'images/illustrations/undraw_upload.svg'));
|
||||
@@ -342,7 +343,7 @@ abstract class AbstractAttachmentsRenderer
|
||||
$('.attachment a[href="'+sSrc+'"]').parent().addClass('image-in-use').find('img').wrap('<div class="image-in-use-wrapper" style="position:relative;display:inline-block;"></div>');
|
||||
});
|
||||
});
|
||||
$('.image-in-use-wrapper').append('<div style="position:absolute;top:0;left:0;"><img src="../images/transp-lock.png"></div>');
|
||||
$('.image-in-use-wrapper').append('<div style="position:absolute;top:0;left:0;"><img src="' + GetAbsoluteUrlModulesRoot() + 'images/transp-lock.png"></div>');
|
||||
}, 200 );
|
||||
JS
|
||||
);
|
||||
|
||||
@@ -120,7 +120,7 @@ try
|
||||
try
|
||||
{
|
||||
set_time_limit(0);
|
||||
$oBB = new BackupExec(APPROOT.'data/backups/manual/', 0 /*iRetentionCount*/);
|
||||
$oBB = new BackupExec(utils::GetDataPath().'backups/manual/', 0 /*iRetentionCount*/);
|
||||
$sRes = $oBB->Process(time() + 36000); // 10 hours to complete should be sufficient!
|
||||
}
|
||||
catch (Exception $e)
|
||||
@@ -185,7 +185,7 @@ try
|
||||
$oDBRS = new DBRestore($oItopConfig);
|
||||
$oDBRS->SetMySQLBinDir($sMySQLBinDir);
|
||||
|
||||
$sBackupDir = APPROOT.'data/backups/';
|
||||
$sBackupDir = utils::GetDataPath().'backups/';
|
||||
$sBackupFile = $sBackupDir.$sFile;
|
||||
$sRes = $oDBRS->RestoreFromCompressedBackup($sBackupFile, $sEnvironment);
|
||||
|
||||
@@ -210,7 +210,7 @@ try
|
||||
}
|
||||
$sFile = utils::ReadParam('file', '', false, 'raw_data');
|
||||
$oBackup = new DBBackupScheduled();
|
||||
$sBackupDir = APPROOT.'data/backups/';
|
||||
$sBackupDir = utils::GetDataPath().'backups/';
|
||||
$sBackupFilePath = utils::RealPath($sBackupDir.$sFile, $sBackupDir);
|
||||
if ($sBackupFilePath === false)
|
||||
{
|
||||
|
||||
@@ -154,7 +154,7 @@ class DBRestore extends DBBackup
|
||||
|
||||
// Load the database
|
||||
//
|
||||
$sDataDir = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax());
|
||||
$sDataDir = utils::GetDataPath().'tmp-backup-'.rand(10000, getrandmax());
|
||||
|
||||
SetupUtils::builddir($sDataDir); // Here is the directory
|
||||
$oArchive->extractTo($sDataDir);
|
||||
@@ -164,7 +164,7 @@ class DBRestore extends DBBackup
|
||||
|
||||
// Update the code
|
||||
//
|
||||
$sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml';
|
||||
$sDeltaFile = utils::GetDataPath().$sEnvironment.'.delta.xml';
|
||||
|
||||
if (is_file($sDataDir.'/delta.xml')) {
|
||||
// Extract and rename delta.xml => <env>.delta.xml;
|
||||
@@ -172,15 +172,15 @@ class DBRestore extends DBBackup
|
||||
} else {
|
||||
@unlink($sDeltaFile);
|
||||
}
|
||||
if (is_dir(APPROOT.'data/production-modules/')) {
|
||||
if (is_dir(utils::GetDataPath().'production-modules/')) {
|
||||
try {
|
||||
SetupUtils::rrmdir(APPROOT.'data/production-modules/');
|
||||
SetupUtils::rrmdir(utils::GetDataPath().'production-modules/');
|
||||
} catch (Exception $e) {
|
||||
throw new BackupException("Can't remove production-modules dir", 0, $e);
|
||||
}
|
||||
}
|
||||
if (is_dir($sDataDir.'/production-modules')) {
|
||||
rename($sDataDir.'/production-modules', APPROOT.'data/production-modules/');
|
||||
rename($sDataDir.'/production-modules', utils::GetDataPath().'production-modules/');
|
||||
}
|
||||
|
||||
$sConfigFile = APPROOT.'conf/'.$sEnvironment.'/config-itop.php';
|
||||
|
||||
@@ -109,7 +109,7 @@ class BackupExec extends AbstractWeeklyScheduledProcess
|
||||
{
|
||||
if (is_null($sBackupDir))
|
||||
{
|
||||
$this->sBackupDir = APPROOT.'data/backups/auto/';
|
||||
$this->sBackupDir = utils::GetDataPath().'backups/auto/';
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -131,7 +131,7 @@ try {
|
||||
// Destination directory
|
||||
//
|
||||
// Make sure the target directory exists and is writeable
|
||||
$sBackupDir = realpath(APPROOT.'data/backups/');
|
||||
$sBackupDir = realpath(utils::GetDataPath().'backups/');
|
||||
SetupUtils::builddir($sBackupDir);
|
||||
if (!is_dir($sBackupDir)) {
|
||||
$oBlockForChecks->AddSubBlock(
|
||||
|
||||
@@ -486,7 +486,7 @@ final class CoreUpdater
|
||||
*/
|
||||
private static function GetItopArchiveName()
|
||||
{
|
||||
$sItopArchiveName = APPROOT.'data/backups/itop';
|
||||
$sItopArchiveName = utils::GetDataPath().'backups/itop';
|
||||
return $sItopArchiveName;
|
||||
}
|
||||
|
||||
@@ -504,7 +504,7 @@ final class CoreUpdater
|
||||
*/
|
||||
private static function GetBackupName()
|
||||
{
|
||||
$sBackupName = APPROOT.'data/backups/manual/backup-core-update';
|
||||
$sBackupName = utils::GetDataPath().'backups/manual/backup-core-update';
|
||||
return $sBackupName;
|
||||
}
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ try
|
||||
require_once (APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
|
||||
|
||||
$sDBBackupPath = APPROOT.'data/backups/manual';
|
||||
$sDBBackupPath = utils::GetDataPath().'backups/manual';
|
||||
$aChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath);
|
||||
$bFailed = false;
|
||||
foreach ($aChecks as $oCheckResult)
|
||||
@@ -258,7 +258,7 @@ try
|
||||
case 'compile':
|
||||
SetupLog::Info('Deployment starts...');
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
if (!file_exists(APPROOT.'data/hub/compile_authent') || $sAuthent !== file_get_contents(APPROOT.'data/hub/compile_authent'))
|
||||
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent'))
|
||||
{
|
||||
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
|
||||
}
|
||||
@@ -301,11 +301,11 @@ try
|
||||
{
|
||||
SetupLog::Info('Move to production starts...');
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
if (!file_exists(APPROOT.'data/hub/compile_authent') || $sAuthent !== file_get_contents(APPROOT.'data/hub/compile_authent'))
|
||||
if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent'))
|
||||
{
|
||||
throw new SecurityException(Dict::S('iTopHub:FailAuthent'));
|
||||
}
|
||||
unlink(APPROOT.'data/hub/compile_authent');
|
||||
unlink(utils::GetDataPath().'hub/compile_authent');
|
||||
// Load the "production" config file to clone & update it
|
||||
$oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE);
|
||||
SetupUtils::EnterReadOnlyMode($oConfig);
|
||||
@@ -370,9 +370,9 @@ try
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if(file_exists(APPROOT.'data/hub/compile_authent'))
|
||||
if(file_exists(utils::GetDataPath().'hub/compile_authent'))
|
||||
{
|
||||
unlink(APPROOT.'data/hub/compile_authent');
|
||||
unlink(utils::GetDataPath().'hub/compile_authent');
|
||||
}
|
||||
// Note: at this point, the dictionnary is not necessarily loaded
|
||||
SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage());
|
||||
|
||||
@@ -78,7 +78,7 @@ class HubNewsroomProvider extends NewsroomProviderBase
|
||||
$sBaseUrl = $this->oConfig->GetModuleSetting('itop-hub-connector', 'url').MetaModel::GetModuleSetting('itop-hub-connector', $sRouteCode);
|
||||
|
||||
$sParameters = 'uuid[bdd]='.urlencode((string) trim(DBProperty::GetProperty('database_uuid', ''), '{}'));
|
||||
$sParameters .= '&uuid[file]='.urlencode((string) trim(@file_get_contents(APPROOT."data/instance.txt"), "{} \n"));
|
||||
$sParameters .= '&uuid[file]='.urlencode((string) trim(@file_get_contents(utils::GetDataPath()."instance.txt"), "{} \n"));
|
||||
$sParameters .= '&uuid[user]='.urlencode(UserRights::GetUserId());
|
||||
|
||||
return $sBaseUrl.'?'.$sParameters;
|
||||
|
||||
@@ -15,7 +15,7 @@ function DisplayStatus(WebPage $oPage)
|
||||
|
||||
$oPage->add('<div class="module-selection-body">');
|
||||
// Now scan the extensions and display a report of the extensions brought by the hub
|
||||
$sPath = APPROOT.'data/downloaded-extensions/';
|
||||
$sPath = utils::GetDataPath().'downloaded-extensions/';
|
||||
$aExtraDirs = array();
|
||||
if (is_dir($sPath)) {
|
||||
$aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory
|
||||
@@ -84,7 +84,7 @@ function DoLanding(WebPage $oPage)
|
||||
throw new Exception("Inconsistent version '$sVersion', expecting ".ITOP_VERSION."'");
|
||||
}
|
||||
|
||||
$sFileUUID = (string)trim(@file_get_contents(APPROOT."data/instance.txt"), "{} \n");
|
||||
$sFileUUID = (string)trim(@file_get_contents(utils::GetDataPath()."instance.txt"), "{} \n");
|
||||
if ($sInstanceUUID != $sFileUUID) {
|
||||
throw new Exception("Inconsistent file UUID '$sInstanceUUID', expecting ".$sFileUUID."'");
|
||||
}
|
||||
@@ -97,7 +97,7 @@ function DoLanding(WebPage $oPage)
|
||||
// Uncompression of extensions in data/downloaded-extensions
|
||||
// only newly downloaded extensions reside in this folder
|
||||
$i = 0;
|
||||
$sPath = APPROOT.'data/downloaded-extensions/';
|
||||
$sPath = utils::GetDataPath().'downloaded-extensions/';
|
||||
if (!is_dir($sPath)) {
|
||||
if (!mkdir($sPath)) {
|
||||
throw new Exception("ERROR: Unable to create the directory '$sPath'. Cannot download any extension. Check the access rights on '".dirname('data/downloaded-extensions/')."'");
|
||||
@@ -112,7 +112,7 @@ function DoLanding(WebPage $oPage)
|
||||
|
||||
$sZipArchiveFile = $sPath."/extension-{$i}.zip";
|
||||
file_put_contents($sZipArchiveFile, $sArchive);
|
||||
// Expand the content of extension-x.zip into APPROOT.'data/downloaded-extensions/'
|
||||
// Expand the content of extension-x.zip into utils::GetDataPath().'downloaded-extensions/'
|
||||
// where the installation will load the extension automatically
|
||||
$oZip = new ZipArchive();
|
||||
if (!$oZip->open($sZipArchiveFile)) {
|
||||
@@ -136,7 +136,7 @@ function DoLanding(WebPage $oPage)
|
||||
function DoInstall(WebPage $oPage)
|
||||
{
|
||||
$sUID = hash('sha256', rand());
|
||||
file_put_contents(APPROOT.'data/hub/compile_authent', $sUID);
|
||||
file_put_contents(utils::GetDataPath().'hub/compile_authent', $sUID);
|
||||
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/css/hub.css');
|
||||
$oPage->add('<table class="module-selection-banner"><tr>');
|
||||
@@ -151,7 +151,7 @@ function DoInstall(WebPage $oPage)
|
||||
|
||||
// Now scan the extensions and display a report of the extensions brought by the hub
|
||||
// Now scan the extensions and display a report of the extensions brought by the hub
|
||||
$sPath = APPROOT.'data/downloaded-extensions/';
|
||||
$sPath = utils::GetDataPath().'downloaded-extensions/';
|
||||
$aExtraDirs = array();
|
||||
if (is_dir($sPath)) {
|
||||
$aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory
|
||||
@@ -283,8 +283,8 @@ CSS
|
||||
break;
|
||||
|
||||
case 'install':
|
||||
if (!file_exists(APPROOT.'data/hub')) {
|
||||
mkdir(APPROOT.'data/hub');
|
||||
if (!file_exists(utils::GetDataPath().'hub')) {
|
||||
mkdir(utils::GetDataPath().'hub');
|
||||
}
|
||||
DoInstall($oPage);
|
||||
break;
|
||||
|
||||
@@ -231,7 +231,7 @@ function MakeDataToPost($sTargetRoute)
|
||||
'itop_hub_target_route' => $sTargetRoute,
|
||||
'itop_stack' => array(
|
||||
"uuidBdd" => (string)trim(DBProperty::GetProperty('database_uuid', ''), '{}'), // TODO check if empty and... regenerate a new UUID ??
|
||||
"uuidFile" => (string)trim(@file_get_contents(APPROOT."data/instance.txt"), "{} \n"), // TODO check if empty and... regenerate a new UUID ??
|
||||
"uuidFile" => (string)trim(@file_get_contents(utils::GetDataPath()."instance.txt"), "{} \n"), // TODO check if empty and... regenerate a new UUID ??
|
||||
'instance_friendly_name' => (string)$_SERVER['SERVER_NAME'],
|
||||
'instance_host' => (string)utils::GetAbsoluteUrlAppRoot(),
|
||||
'application_name' => (string)ITOP_APPLICATION,
|
||||
|
||||
@@ -389,7 +389,6 @@ return array(
|
||||
'Combodo\\iTop\\Application\\WebPage\\iTopWebPage' => $baseDir . '/sources/Application/WebPage/iTopWebPage.php',
|
||||
'Combodo\\iTop\\Application\\WebPage\\iTopWizardWebPage' => $baseDir . '/sources/Application/WebPage/iTopWizardWebPage.php',
|
||||
'Combodo\\iTop\\Composer\\iTopComposer' => $baseDir . '/sources/Composer/iTopComposer.php',
|
||||
'Combodo\\iTop\\Controller\\AbstractAppController' => $baseDir . '/sources/Controller/AbstractAppController.php',
|
||||
'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',
|
||||
|
||||
@@ -764,7 +764,6 @@ class ComposerStaticInit7f81b4a2a468a061c306af5e447a9a9f
|
||||
'Combodo\\iTop\\Application\\WebPage\\iTopWebPage' => __DIR__ . '/../..' . '/sources/Application/WebPage/iTopWebPage.php',
|
||||
'Combodo\\iTop\\Application\\WebPage\\iTopWizardWebPage' => __DIR__ . '/../..' . '/sources/Application/WebPage/iTopWizardWebPage.php',
|
||||
'Combodo\\iTop\\Composer\\iTopComposer' => __DIR__ . '/../..' . '/sources/Composer/iTopComposer.php',
|
||||
'Combodo\\iTop\\Controller\\AbstractAppController' => __DIR__ . '/../..' . '/sources/Controller/AbstractAppController.php',
|
||||
'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',
|
||||
|
||||
168
pages/UI.php
168
pages/UI.php
@@ -6,14 +6,12 @@
|
||||
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
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\Form\Form;
|
||||
use Combodo\iTop\Application\UI\Base\Component\GlobalSearch\GlobalSearchHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\Title;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
|
||||
@@ -23,7 +21,9 @@ use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Controller\Base\Layout\ObjectController;
|
||||
use Combodo\iTop\Kernel;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Displays a popup welcome message, once per session at maximum
|
||||
@@ -319,6 +319,7 @@ try
|
||||
$oKPI->ComputeAndReport('User login');
|
||||
|
||||
// First check if we can redirect the route to a dedicated controller
|
||||
// IMPORTANT: Even though iTop router is deprecated, we must ensure old URLs keep working (for a while) as they can be used in received notifications, bookmarks, extensions, ...
|
||||
$sRoute = utils::ReadParam('route', '', false, utils::ENUM_SANITIZATION_FILTER_ROUTE);
|
||||
$oRouter = Router::GetInstance();
|
||||
if ($oRouter->CanDispatchRoute($sRoute)) {
|
||||
@@ -341,7 +342,131 @@ try
|
||||
$oP = new iTopWebPage(Dict::S('UI:WelcomeToITop'), $bPrintable);
|
||||
$oP->SetMessage($sLoginMessage);
|
||||
|
||||
// All the following actions use advanced forms that require more javascript to be loaded
|
||||
//-----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Mind that the following backward compatibility pattern is also present in the `pages/ajax.render.php` endpoint
|
||||
//
|
||||
//-----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Kept for backward compatibility with iTop 3.1.x notification URLs, don't remove
|
||||
// Non-dispatchable "routes" (iTop 3.1) are mapped to their old corresponding "operation" (iTop 3.0 and older), in order to be later redirected to the proper new URLs (iTop 3.2 and newer)
|
||||
switch ($sRoute) {
|
||||
case 'object.new':
|
||||
case 'object.apply_new':
|
||||
case 'object.modify':
|
||||
case 'object.apply_modify':
|
||||
$operation = str_ireplace("object.", "", $sRoute);
|
||||
break;
|
||||
}
|
||||
|
||||
if (utils::IsNotNullOrEmptyString($sRoute)) {
|
||||
DeprecatedCallsLog::Debug("Calling UI.php with a deprecated \"route\" parameter that was migrated to Symfony router, redirecting to fallback \"operation\" parameter. If URI comes from a custom code, migrate it. If URI comes from an old notification, mind that it may not work in future versions.", LogChannels::ROUTER, [
|
||||
"request_uri" => $_SERVER["REQUEST_URI"],
|
||||
"route" => $sRoute,
|
||||
"fallback_operation" => $operation,
|
||||
]);
|
||||
}
|
||||
|
||||
// Kept for backward compatibility with iTop 3.0 and older notification URLs, don't remove
|
||||
// These operations have been migrated to Symfony router, we need to redirect to the proper new URLs
|
||||
switch ($operation) {
|
||||
/** @deprecated 3.1.0 Use the "b_object_new" Symfony route instead */
|
||||
case 'new':
|
||||
/** @deprecated 3.1.0 Use the "b_object_apply_new" Symfony route instead */
|
||||
case 'apply_new':
|
||||
/** @deprecated 3.1.0 Use the "b_object_modify" Symfony route instead */
|
||||
case 'modify':
|
||||
/** @deprecated 3.1.0 Use the "b_object_apply_new" Symfony route instead */
|
||||
case 'apply_modify':
|
||||
// Start a Symfony kernel and redirect to the corresponding route / controller
|
||||
$oKernel = new Kernel("prod", false);
|
||||
$oRequest = Request::createFromGlobals();
|
||||
|
||||
/** @var string $sRouteName Route name to redirect to */
|
||||
$sRouteName = '';
|
||||
/** @var string[] $aPath Parts of the Symfony route path (eg. for "/object/{sCLass}/{sId}", ["sClass" => "UserRequest", "sId" => "123"]) */
|
||||
$aPath = [];
|
||||
/** @var string[] $aQuery Query parameters of the request -parameters after the "?" of the URI- (eg. for "/object/UserRequest/123?a=1&b=2", ["a" => 1, "b" => 2]) */
|
||||
$aQuery = $oRequest->query->all();
|
||||
|
||||
// Find controller corresponding to the old "operation"
|
||||
switch ($operation) {
|
||||
case 'new':
|
||||
$sRouteName = 'b_object_new';
|
||||
$aPath['_controller'] = ObjectController::class . "::OperationNew";
|
||||
$aPath['sClass'] = utils::ReadParam('class', null, false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
break;
|
||||
|
||||
case 'apply_new':
|
||||
$sRouteName = 'b_object_apply_new';
|
||||
$aPath['_controller'] = ObjectController::class . "::OperationApplyNew";
|
||||
break;
|
||||
|
||||
case 'modify':
|
||||
$sRouteName = 'b_object_modify';
|
||||
$aPath['_controller'] = ObjectController::class . "::OperationModify";
|
||||
$aPath['sClass'] = utils::ReadParam('class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$aPath['sId'] = utils::ReadParam('id', '');
|
||||
break;
|
||||
|
||||
case 'apply_modify':
|
||||
$sRouteName = 'b_object_apply_modify';
|
||||
$aPath['_controller'] = ObjectController::class . "::OperationApplyModify";
|
||||
break;
|
||||
}
|
||||
|
||||
// Redirect
|
||||
///** @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface $oUrlGenerator */
|
||||
//$oResponse = $oKernel->handle($oRequest);
|
||||
//$oUrlGenerator = $oKernel->getContainer()->get('router');
|
||||
|
||||
// - Solution 1: Simplement redirection
|
||||
// Pros:
|
||||
// - Redirects to the new URL
|
||||
// - Keeps query parameters
|
||||
// - Uses the real Symfony kernel as it will be a complete new process
|
||||
// Cons:
|
||||
// - Loose posted parameters if any (but could be ok as we essentially do this for notifications / bookmarks); extensions will be migrated
|
||||
// - Makes an HTTP redirection, could be an issue in some infras? I don't think so, we already do it in several places
|
||||
/*$sRedirectUrl = $oUrlGenerator->generate($sRouteName, $aPath + $aQuery);
|
||||
// Generated URL is based on the script the Kernel is instantiated in, so we have to correct it to point to the new unique endpoint
|
||||
$sRedirectUrl = str_ireplace("pages/UI.php", "app.php", $sRedirectUrl);
|
||||
header("location: $sRedirectUrl");
|
||||
die();*/
|
||||
|
||||
// - Solution 2: Symfony redirection
|
||||
// Pros:
|
||||
// - Redirects to the new URL
|
||||
// - Keeps query parameters
|
||||
// - Uses the real Symfony kernel as it will be a complete new process
|
||||
// - Keeps redirection working even though there are deprecated messages printed before headers are send (unlike with solution 1)
|
||||
// Cons:
|
||||
// - Loose posted parameters if any (but could be ok as we essentially do this for notifications / bookmarks); extensions will be migrated
|
||||
// - Makes an HTTP redirection, could be an issue in some infras? I don't think so, we already do it in several places
|
||||
/*$sRedirectUrl = $oUrlGenerator->generate($sRouteName, $aPath + $aQuery);
|
||||
// Generated URL is based on the script the Kernel is instantiated in, so we have to correct it to point to the new unique endpoint
|
||||
$sRedirectUrl = str_ireplace("pages/UI.php", "app.php", $sRedirectUrl);
|
||||
$oResponse = new RedirectResponse($sRedirectUrl);
|
||||
$oResponse->send();
|
||||
$oKernel->terminate($oRequest, $oResponse);
|
||||
die();*/
|
||||
|
||||
|
||||
// - Solution 3: Internal redirection
|
||||
// Pros:
|
||||
// - Keeps query parameters
|
||||
// - Keeps posted parameters (essential for submission URLs)
|
||||
// Cons:
|
||||
// - Still displays the old URL
|
||||
// - Uses a not so well-formed Symfony kernel?
|
||||
$oSubRequest = $oRequest->duplicate($aQuery, null, $aPath);
|
||||
$oResponse = $oKernel->handle($oSubRequest, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);
|
||||
$oResponse->send();
|
||||
$oKernel->terminate($oSubRequest, $oResponse);
|
||||
die();
|
||||
}
|
||||
|
||||
// All the following operations use advanced forms that require more javascript to be loaded
|
||||
switch($operation)
|
||||
{
|
||||
case 'new': // Form to create a new object
|
||||
@@ -350,7 +475,7 @@ try
|
||||
case 'stimulus': // Form displayed when applying a stimulus (state change)
|
||||
case 'apply_stimulus': // Form displayed when applying a stimulus (state change)
|
||||
foreach (ObjectController::EnumRequiredForModificationJsFilesRelPaths() as $sJsFileRelPath) {
|
||||
$oP->add_linked_script("../$sJsFileRelPath");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "$sJsFileRelPath");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -651,7 +776,7 @@ try
|
||||
$oP->SetBreadCrumbEntry($sPageId, $sLabel, $sDescription, '', 'fas fa-search', iTopWebPage::ENUM_BREADCRUMB_ENTRY_ICON_TYPE_CSS_CLASSES);
|
||||
$oP->add("<div style=\"padding: 10px;\">\n");
|
||||
$oP->add("<div class=\"header_message\" id=\"full_text_progress\" style=\"position: fixed; background-color: #cccccc; opacity: 0.7; padding: 1.5em;\">\n");
|
||||
$oP->add('<img id="full_text_indicator" src="../images/indicator.gif"> <span style="padding: 1.5em;">'.Dict::Format('UI:Search:Ongoing', utils::EscapeHtml($sFullText)).'</span>');
|
||||
$oP->add('<img id="full_text_indicator" src="' . utils::GetAbsoluteUrlAppRoot() . 'images/indicator.gif"> <span style="padding: 1.5em;">'.Dict::Format('UI:Search:Ongoing', utils::EscapeHtml($sFullText)).'</span>');
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<div id=\"full_text_results\">\n");
|
||||
$oP->add("<div id=\"full_text_progress_placeholder\" style=\"padding: 1.5em;\"> </div>\n");
|
||||
@@ -678,15 +803,6 @@ try
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** @deprecated 3.1.0 Use the "object.modify" route instead */
|
||||
// Kept for backward compatibility with notification URLs, don't remove
|
||||
case 'modify': // Legacy operation
|
||||
$oController = new ObjectController();
|
||||
$oP = $oController->OperationModify();
|
||||
break;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'select_for_modify_all': // Select the list of objects to be modified (bulk modify)
|
||||
UI::OperationSelectForModifyAll($oP);
|
||||
break;
|
||||
@@ -703,22 +819,6 @@ try
|
||||
break;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** @deprecated 3.1.0 Use the "object.new" route instead */
|
||||
// Kept for backward compatibility
|
||||
case 'new': // Form to create a new object
|
||||
$oController = new ObjectController();
|
||||
$oP = $oController->OperationNew();
|
||||
break;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'apply_modify': // Applying the modifications to an existing object
|
||||
$oController = new ObjectController();
|
||||
$oP = $oController->OperationApplyModify();
|
||||
break;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'select_for_deletion': // Select multiple objects for deletion
|
||||
$oP->DisableBreadCrumb();
|
||||
@@ -813,14 +913,6 @@ try
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'apply_new': // Creation of a new object
|
||||
|
||||
$oController = new ObjectController();
|
||||
$oP = $oController->OperationApplyNew();
|
||||
break;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
case 'select_bulk_stimulus': // Form displayed when applying a stimulus to many objects
|
||||
$oP->DisableBreadCrumb();
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
|
||||
@@ -33,11 +33,11 @@ ApplicationMenu::CheckMenuIdEnabled('UniversalSearchMenu');
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
$oP = new iTopWebPage(Dict::S('UI:UniversalSearchTitle'));
|
||||
$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/extkeywidget.js");
|
||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/forms-json-utils.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/wizardhelper.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/wizard.utils.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/extkeywidget.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/jquery.blockUI.js");
|
||||
|
||||
// From now on the context is limited to the the selected organization ??
|
||||
|
||||
|
||||
@@ -21,8 +21,10 @@ use Combodo\iTop\Controller\Base\Layout\ObjectController;
|
||||
use Combodo\iTop\Controller\PreferencesController;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer;
|
||||
use Combodo\iTop\Renderer\Console\ConsoleFormRenderer;
|
||||
use Combodo\iTop\Kernel;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
use Combodo\iTop\Service\TemporaryObjects\TemporaryObjectManager;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
require_once('../approot.inc.php');
|
||||
|
||||
@@ -44,7 +46,6 @@ try
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
$sRoute = utils::ReadParam('route', '', false, utils::ENUM_SANITIZATION_FILTER_ROUTE);
|
||||
$operation = utils::ReadParam('operation', '', false, utils::ENUM_SANITIZATION_FILTER_OPERATION);
|
||||
|
||||
// Only allow export functions to portal users
|
||||
@@ -78,6 +79,7 @@ try
|
||||
}
|
||||
|
||||
// First check if we can redirect the route to a dedicated controller
|
||||
// IMPORTANT: Even though iTop router is deprecated, we must ensure old URLs keep working (for a while) as they can be used in received notifications, bookmarks, extensions, ...
|
||||
$sRoute = utils::ReadParam('route', '', false, utils::ENUM_SANITIZATION_FILTER_ROUTE);
|
||||
$oRouter = Router::GetInstance();
|
||||
if ($oRouter->CanDispatchRoute($sRoute)) {
|
||||
@@ -97,12 +99,82 @@ try
|
||||
// Default for most operations, but can be switch to a JsonPage, DownloadPage or else if the operation requires it
|
||||
$oPage = new AjaxPage("");
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Mind that the following backward compatibility pattern is also present in the `pages/UI.php` endpoint
|
||||
//
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Kept for backward compatibility with iTop 3.1.x notification URLs, don't remove
|
||||
// Non-dispatchable "routes" (iTop 3.1) are mapped to their old corresponding "operation" (iTop 3.0 and older), in order to be later redirected to the proper new URLs (iTop 3.2 and newer)
|
||||
switch ($sRoute) {
|
||||
case 'object.new':
|
||||
case 'object.modify':
|
||||
$operation = str_ireplace("object.", "", $sRoute);
|
||||
break;
|
||||
}
|
||||
|
||||
if (utils::IsNotNullOrEmptyString($sRoute)) {
|
||||
DeprecatedCallsLog::Debug("Calling UI.php with a deprecated \"route\" parameter that was migrated to Symfony router, redirecting to fallback \"operation\" parameter. If URI comes from a custom code, migrate it. If URI comes from an old notification, mind that it may not work in future versions.", LogChannels::ROUTER, [
|
||||
"request_uri" => $_SERVER["REQUEST_URI"],
|
||||
"route" => $sRoute,
|
||||
"fallback_operation" => $operation,
|
||||
]);
|
||||
}
|
||||
|
||||
// Kept for backward compatibility with iTop 3.0 and older notification URLs, don't remove
|
||||
// These operations have been migrated to Symfony router, we need to redirect to the proper new URLs
|
||||
switch ($operation) {
|
||||
/** @deprecated 3.1.0 Use the "b_object_new" Symfony route instead */
|
||||
case 'new':
|
||||
/** @deprecated 3.1.0 Use the "b_object_modify" Symfony route instead */
|
||||
case 'modify':
|
||||
// Start a Symfony kernel and redirect to the corresponding route / controller
|
||||
$oKernel = new Kernel("prod", false);
|
||||
$oRequest = Request::createFromGlobals();
|
||||
|
||||
/** @var string $sRouteName Route name to redirect to */
|
||||
$sRouteName = '';
|
||||
/** @var string[] $aPath Parts of the Symfony route path (eg. for "/object/{sCLass}/{sId}", ["sClass" => "UserRequest", "sId" => "123"]) */
|
||||
$aPath = [];
|
||||
/** @var string[] $aQuery Query parameters of the request -parameters after the "?" of the URI- (eg. for "/object/UserRequest/123?a=1&b=2", ["a" => 1, "b" => 2]) */
|
||||
$aQuery = $oRequest->query->all();
|
||||
|
||||
// Find controller corresponding to the old "operation"
|
||||
switch ($operation) {
|
||||
case 'new':
|
||||
$sRouteName = 'b_object_new';
|
||||
$aPath['_controller'] = ObjectController::class . "::OperationNew";
|
||||
$aPath['sClass'] = utils::ReadParam('class', null, false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
break;
|
||||
|
||||
case 'modify':
|
||||
$sRouteName = 'b_object_modify';
|
||||
$aPath['_controller'] = ObjectController::class . "::OperationModify";
|
||||
$aPath['sClass'] = utils::ReadParam('class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$aPath['sId'] = utils::ReadParam('id', '');
|
||||
break;
|
||||
}
|
||||
|
||||
// Internal Symfony redirection
|
||||
// Pros:
|
||||
// - Keeps query parameters
|
||||
// - Keeps posted parameters (essential for submission URLs)
|
||||
// Cons:
|
||||
// - Still displays the old URL
|
||||
// - Uses a not so well-formed Symfony kernel?
|
||||
$oSubRequest = $oRequest->duplicate($aQuery, null, $aPath);
|
||||
$oResponse = $oKernel->handle($oSubRequest, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);
|
||||
$oResponse->send();
|
||||
$oKernel->terminate($oSubRequest, $oResponse);
|
||||
die();
|
||||
}
|
||||
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
$sEncoding = utils::ReadParam('encoding', 'serialize');
|
||||
$sClass = utils::ReadParam('class', 'MissingAjaxParam', false, 'class');
|
||||
$sStyle = utils::ReadParam('style', 'list');
|
||||
|
||||
|
||||
$oAjaxRenderController = new AjaxRenderController();
|
||||
|
||||
switch ($operation) {
|
||||
@@ -1375,7 +1447,7 @@ JS
|
||||
<<<EOF
|
||||
$('.search-class-$sClassName button').prop('disabled', true);
|
||||
|
||||
$('.search-class-$sClassName h2').append(' <img id="indicator" src="../images/indicator.gif">');
|
||||
$('.search-class-$sClassName h2').append(' <img id="indicator" src="' + GetAbsoluteUrlAppRoot() + 'images/indicator.gif">');
|
||||
var oParams = {operation: 'full_text_search_enlarge', class: '$sClassName', text: '$sFullTextJS'};
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
|
||||
$('.search-class-$sClassName').html(data);
|
||||
@@ -1532,6 +1604,7 @@ EOF
|
||||
case 'xlsx_export_dialog':
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpEndpoint('Use "export_*" operations instead of "'.$operation.'"');
|
||||
$sFilter = utils::ReadParam('filter', '', false, 'raw_data');
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$oPage->SetContentType('text/html');
|
||||
$oPage->add(
|
||||
<<<EOF
|
||||
@@ -1561,11 +1634,11 @@ EOF
|
||||
padding-left: 16px;
|
||||
cursor: pointer;
|
||||
font-size: 10pt;
|
||||
background: url(../images/minus.gif) 0 2px no-repeat;
|
||||
background: url({$sAppRootUrl}images/minus.gif) 0 2px no-repeat;
|
||||
}
|
||||
.statistics > div.closed {
|
||||
padding-left: 16px;
|
||||
background: url(../images/plus.gif) 0 2px no-repeat;
|
||||
background: url({$sAppRootUrl}images/plus.gif) 0 2px no-repeat;
|
||||
}
|
||||
|
||||
.statistics .closed .stats-data {
|
||||
@@ -1594,7 +1667,7 @@ EOF
|
||||
);
|
||||
$sJSLabels = json_encode($aLabels);
|
||||
$sFilter = addslashes($sFilter);
|
||||
$sJSPageUrl = addslashes(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php');
|
||||
$sJSPageUrl = addslashes($sAppRootUrl.'pages/ajax.render.php');
|
||||
$oPage->add_ready_script("$('#XlsxExportDlg').xlsxexporter({filter: '$sFilter', labels: $sJSLabels, ajax_page_url: '$sJSPageUrl'});");
|
||||
break;
|
||||
|
||||
@@ -2208,7 +2281,8 @@ EOF
|
||||
$oPage = new NiceWebPage(Dict::S('UI:BrowseInlineImages'));
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/magnific-popup.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.magnific-popup.min.js');
|
||||
$sImgUrl = utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL;
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sImgUrl = $sAppRootUrl.INLINEIMAGE_DOWNLOAD_URL;
|
||||
|
||||
/** @noinspection SuspiciousAssignmentsInspection cke_upload_and_browse and cke_browse are chained */
|
||||
$sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
|
||||
@@ -2236,7 +2310,7 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
$sPostUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?CKEditorFuncNum='.$sCKEditorFuncNum;
|
||||
$sPostUrl = $sAppRootUrl.'pages/ajax.render.php?CKEditorFuncNum='.$sCKEditorFuncNum;
|
||||
|
||||
$oPage->add_style(
|
||||
<<<EOF
|
||||
@@ -2304,7 +2378,7 @@ EOF
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#upload_button').on('change', function() {
|
||||
$('#upload_status').html('<img src="../images/indicator.gif">');
|
||||
$('#upload_status').html('<img src="{$sAppRootUrl}images/indicator.gif">');
|
||||
$('#upload_form').submit();
|
||||
$(this).prop('disabled', true);
|
||||
});
|
||||
|
||||
@@ -281,7 +281,7 @@ try
|
||||
$oAllCategoriesDashlet
|
||||
->AddCSSClasses(['ibo-dashlet--is-inline', 'ibo-dashlet-badge'])
|
||||
->AddSubBlock(DashletFactory::MakeForDashletBadge(
|
||||
'../images/icons/icons8-audit.svg',
|
||||
utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-audit.svg',
|
||||
utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=audit",
|
||||
$iCategoryCount,
|
||||
Dict::S('UI:Audit:Interactive:Selection:BadgeAll')
|
||||
@@ -304,7 +304,7 @@ try
|
||||
/** @var AuditDomain $oAuditDomain */
|
||||
while($oAuditDomain = $oDomainSet->Fetch()) {
|
||||
$sDomainUrl = utils::GetAbsoluteUrlAppRoot()."pages/audit.php?operation=audit&domain=".$oAuditDomain->GetKey();
|
||||
$sIconUrl = '../images/icons/icons8-puzzle.svg';
|
||||
$sIconUrl = utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-puzzle.svg';
|
||||
/** @var \ormDocument $oImage */
|
||||
$oImage = $oAuditDomain->Get('icon');
|
||||
if (!$oImage->IsEmpty()) {
|
||||
@@ -357,9 +357,9 @@ try
|
||||
$oP->AddUiBlock(TitleUIBlockFactory::MakeForPage($sTitle));
|
||||
$oP->AddUiBlock(new Text($sSubTitle));
|
||||
|
||||
$oTotalBlock = DashletFactory::MakeForDashletBadge('../images/icons/icons8-audit.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsAudited'));
|
||||
$oErrorBlock = DashletFactory::MakeForDashletBadge('../images/icons/icons8-delete.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsInError'));
|
||||
$oWorkingBlock = DashletFactory::MakeForDashletBadge('../images/icons/icons8-checkmark.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsValidated'));
|
||||
$oTotalBlock = DashletFactory::MakeForDashletBadge(utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-audit.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsAudited'));
|
||||
$oErrorBlock = DashletFactory::MakeForDashletBadge(utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-delete.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsInError'));
|
||||
$oWorkingBlock = DashletFactory::MakeForDashletBadge(utils::GetAbsoluteUrlAppRoot().'images/icons/icons8-checkmark.svg', '#', 0, Dict::S('UI:Audit:Dashboard:ObjectsValidated'));
|
||||
|
||||
$aCSSClasses = ['ibo-dashlet--is-inline', 'ibo-dashlet-badge'];
|
||||
|
||||
@@ -436,7 +436,7 @@ try
|
||||
foreach ($aErrors as $aErrorRow) {
|
||||
$aObjectsWithErrors[$aErrorRow['id']] = true;
|
||||
}
|
||||
$aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount</a> <a href=\"?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\"><img src=\"../images/icons/icons8-export-csv.svg\" class=\"ibo-audit--audit-line--csv-download\"></a>";
|
||||
$aRow['nb_errors'] = ($iErrorsCount == 0) ? '0' : "<a href=\"?operation=errors&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\">$iErrorsCount</a> <a href=\"?operation=csv&category=".$oAuditCategory->GetKey()."&rule=".$oAuditRule->GetKey()."&".$oAppContext->GetForLink()."\"><img src=\"" . utils::GetAbsoluteUrlAppRoot() . "images/icons/icons8-export-csv.svg\" class=\"ibo-audit--audit-line--csv-download\"></a>";
|
||||
$aRow['percent_ok'] = sprintf('%.2f', 100.0 * (($iCount - $iErrorsCount) / $iCount));
|
||||
$aRow['class'] = $oAuditCategory->GetReportColor($iCount, $iErrorsCount);
|
||||
}
|
||||
|
||||
@@ -400,6 +400,7 @@ try {
|
||||
$iUnchanged = 0;
|
||||
|
||||
$aTableData = [];
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
foreach ($aRes as $iLine => $aResRow) {
|
||||
$aTableRow = [];
|
||||
@@ -414,7 +415,7 @@ try {
|
||||
$sFinalClass = $aResRow['finalclass'];
|
||||
$oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue());
|
||||
$sUrl = $oObj->GetHyperlink();
|
||||
$sStatus = '<img src="../images/unchanged.png" title="'.Dict::S('UI:CSVReport-Icon-Unchanged').'">';
|
||||
$sStatus = '<img src="' . $sAppRootUrl . 'images/unchanged.png" title="'.Dict::S('UI:CSVReport-Icon-Unchanged').'">';
|
||||
$sCSSRowClass = 'ibo-csv-import--row-unchanged';
|
||||
break;
|
||||
|
||||
@@ -423,7 +424,7 @@ try {
|
||||
$sFinalClass = $aResRow['finalclass'];
|
||||
$oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue());
|
||||
$sUrl = $oObj->GetHyperlink();
|
||||
$sStatus = '<img src="../images/modified.png" title="'.Dict::S('UI:CSVReport-Icon-Modified').'">';
|
||||
$sStatus = '<img src="' . $sAppRootUrl . 'images/modified.png" title="'.Dict::S('UI:CSVReport-Icon-Modified').'">';
|
||||
$sCSSRowClass = 'ibo-csv-import--row-modified';
|
||||
break;
|
||||
|
||||
@@ -432,7 +433,7 @@ try {
|
||||
$sFinalClass = $aResRow['finalclass'];
|
||||
$oObj = MetaModel::GetObject($sFinalClass, $aResRow['id']->GetPureValue());
|
||||
$sUrl = $oObj->GetHyperlink();
|
||||
$sStatus = '<img src="../images/delete.png" title="'.Dict::S('UI:CSVReport-Icon-Missing').'">';
|
||||
$sStatus = '<img src="' . $sAppRootUrl . 'images/delete.png" title="'.Dict::S('UI:CSVReport-Icon-Missing').'">';
|
||||
$sCSSRowClass = 'ibo-csv-import--row-modified';
|
||||
if ($bSimulate) {
|
||||
$sMessage = Dict::S('UI:CSVReport-Object-MissingToUpdate');
|
||||
@@ -443,7 +444,7 @@ try {
|
||||
|
||||
case 'RowStatus_NewObj':
|
||||
$iCreated++;
|
||||
$sStatus = '<img src="../images/added.png" title="'.Dict::S('UI:CSVReport-Icon-Created').'">';
|
||||
$sStatus = '<img src="' . $sAppRootUrl . 'images/added.png" title="'.Dict::S('UI:CSVReport-Icon-Created').'">';
|
||||
$sCSSRowClass = 'ibo-csv-import--row-added';
|
||||
if ($bSimulate) {
|
||||
$sMessage = Dict::S('UI:CSVReport-Object-ToCreate');
|
||||
@@ -585,21 +586,21 @@ HTML;
|
||||
$oMulticolumn->AddCSSClass('ml-1');
|
||||
$oForm->AddSubBlock($oMulticolumn);
|
||||
|
||||
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="../images/unchanged.png"> '.sprintf($aDisplayFilters['unchanged'], $iUnchanged), '', "1", "show_unchanged", "checkbox");
|
||||
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="' . $sAppRootUrl . 'images/unchanged.png"> '.sprintf($aDisplayFilters['unchanged'], $iUnchanged), '', "1", "show_unchanged", "checkbox");
|
||||
$oCheckBoxUnchanged->GetInput()->SetIsChecked(true);
|
||||
$oCheckBoxUnchanged->SetBeforeInput(false);
|
||||
$oCheckBoxUnchanged->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oCheckBoxUnchanged));
|
||||
$oPage->add_ready_script("$('#show_unchanged').on('click', function(){ToggleRows('ibo-csv-import--row-unchanged')})");
|
||||
|
||||
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="../images/modified.png"> '.sprintf($aDisplayFilters['modified'], $iModified), '', "1", "show_modified", "checkbox");
|
||||
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="' . $sAppRootUrl . 'images/modified.png"> '.sprintf($aDisplayFilters['modified'], $iModified), '', "1", "show_modified", "checkbox");
|
||||
$oCheckBoxUnchanged->GetInput()->SetIsChecked(true);
|
||||
$oCheckBoxUnchanged->SetBeforeInput(false);
|
||||
$oCheckBoxUnchanged->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oCheckBoxUnchanged));
|
||||
$oPage->add_ready_script("$('#show_modified').on('click', function(){ToggleRows('ibo-csv-import--row-modified')})");
|
||||
|
||||
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="../images/added.png"> '.sprintf($aDisplayFilters['added'], $iCreated), '', "1", "show_created", "checkbox");
|
||||
$oCheckBoxUnchanged = InputUIBlockFactory::MakeForInputWithLabel('<img src="' . $sAppRootUrl . 'images/added.png"> '.sprintf($aDisplayFilters['added'], $iCreated), '', "1", "show_created", "checkbox");
|
||||
$oCheckBoxUnchanged->GetInput()->SetIsChecked(true);
|
||||
$oCheckBoxUnchanged->SetBeforeInput(false);
|
||||
$oCheckBoxUnchanged->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
|
||||
@@ -81,8 +81,8 @@ if (is_link($sPageEnvFullPath)) {
|
||||
$aPossibleBasePaths = [
|
||||
APPROOT.$sSourceDir,
|
||||
APPROOT.'extensions',
|
||||
APPROOT.'data/'.$sEnvironment.'-modules',
|
||||
APPROOT.'data/downloaded-extensions', // Hub connector
|
||||
utils::GetDataPath().$sEnvironment.'-modules',
|
||||
utils::GetDataPath().'downloaded-extensions', // Hub connector
|
||||
];
|
||||
} else {
|
||||
$aPossibleBasePaths = [$sEnvFullPath];
|
||||
|
||||
@@ -111,17 +111,17 @@ $sDotExecutable = MetaModel::GetConfig()->Get('graphviz_path');
|
||||
if (file_exists($sDotExecutable))
|
||||
{
|
||||
// create the file with Graphviz
|
||||
$sImageFilePath = APPROOT."data/lifecycle/".$sClass.".svg";
|
||||
if (!is_dir(APPROOT."data"))
|
||||
$sImageFilePath = utils::GetDataPath()."lifecycle/".$sClass.".svg";
|
||||
if (!is_dir(utils::GetDataPath()))
|
||||
{
|
||||
@mkdir(APPROOT."data");
|
||||
@mkdir(utils::GetDataPath());
|
||||
}
|
||||
if (!is_dir(APPROOT."data/lifecycle"))
|
||||
if (!is_dir(utils::GetDataPath()."lifecycle"))
|
||||
{
|
||||
@mkdir(APPROOT."data/lifecycle");
|
||||
@mkdir(utils::GetDataPath()."lifecycle");
|
||||
}
|
||||
$sDotDescription = GraphvizLifecycle($sClass);
|
||||
$sDotFilePath = APPROOT."data/lifecycle/{$sClass}.dot";
|
||||
$sDotFilePath = utils::GetDataPath()."lifecycle/{$sClass}.dot";
|
||||
|
||||
$rFile = @fopen($sDotFilePath, "w");
|
||||
@fwrite($rFile, $sDotDescription);
|
||||
|
||||
@@ -133,7 +133,7 @@ function ValidateOtherSettings()
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#v_default_page_size').html('<img src="../images/validation_error.png"/>');
|
||||
$('#v_default_page_size').html('<img src="' + GetAbsoluteUrlAppRoot() + 'images/validation_error.png"/>');
|
||||
$('#ibo-misc-settings-submit').prop('disabled', true);
|
||||
return false;
|
||||
}
|
||||
@@ -417,7 +417,7 @@ JS
|
||||
|
||||
$oUserPicturePlaceHolderBlock = new Panel(Dict::S('UI:Preferences:ChooseAPlaceholder'), array(), 'grey', 'ibo-user-picture-placeholder');
|
||||
|
||||
$sUserPicturesFolder = '../images/user-pictures/';
|
||||
$sUserPicturesFolder = utils::GetAbsoluteUrlAppRoot() . 'images/user-pictures/';
|
||||
$sUserDefaultPicture = appUserPreferences::GetPref('user_picture_placeholder', 'default-placeholder.png');
|
||||
$sUserPicturePlaceHolderHtml = '';
|
||||
$sUserPicturePlaceHolderHtml .= '<p>'.Dict::S('UI:Preferences:ChooseAPlaceholder+').'</p> <div class="ibo-preferences--user-preferences--picture-placeholder">';
|
||||
|
||||
@@ -37,11 +37,11 @@ try
|
||||
// Main program
|
||||
//
|
||||
$oP = new iTopWebPage(Dict::S('Menu:TagAdminMenu+'));
|
||||
$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/extkeywidget.js");
|
||||
$oP->add_linked_script("../js/jquery.blockUI.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/forms-json-utils.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/wizardhelper.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/wizard.utils.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/extkeywidget.js");
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/jquery.blockUI.js");
|
||||
|
||||
$sBaseClass = 'TagSetFieldData';
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
|
||||
@@ -626,14 +626,14 @@ class ApplicationInstaller
|
||||
}
|
||||
}
|
||||
// Dump the "reference" model, just before loading any actual delta
|
||||
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$sEnvironment.'.xml');
|
||||
$oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'.xml');
|
||||
|
||||
$sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml';
|
||||
$sDeltaFile = utils::GetDataPath().$sEnvironment.'.delta.xml';
|
||||
if (file_exists($sDeltaFile))
|
||||
{
|
||||
$oDelta = new MFDeltaModule($sDeltaFile);
|
||||
$oFactory->LoadModule($oDelta);
|
||||
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$sEnvironment.'-with-delta.xml');
|
||||
$oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'-with-delta.xml');
|
||||
}
|
||||
|
||||
$oMFCompiler = new MFCompiler($oFactory, $sEnvironment);
|
||||
@@ -658,8 +658,8 @@ class ApplicationInstaller
|
||||
}
|
||||
|
||||
// Set an "Instance UUID" identifying this machine based on a file located in the data directory
|
||||
$sInstanceUUIDFile = APPROOT.'data/instance.txt';
|
||||
SetupUtils::builddir(APPROOT.'data');
|
||||
$sInstanceUUIDFile = utils::GetDataPath().'instance.txt';
|
||||
SetupUtils::builddir(utils::GetDataPath());
|
||||
if (!file_exists($sInstanceUUIDFile))
|
||||
{
|
||||
$sIntanceUUID = utils::CreateUUID('filesystem');
|
||||
|
||||
@@ -201,7 +201,7 @@ class DBBackup
|
||||
|
||||
$oArchive = new ITopArchiveTar($sTargetFile.'.tar.gz');
|
||||
|
||||
$sTmpFolder = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax());
|
||||
$sTmpFolder = utils::GetDataPath().'tmp-backup-'.rand(10000, getrandmax());
|
||||
$aFiles = $this->PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder);
|
||||
|
||||
$sFilesList = var_export($aFiles, true);
|
||||
@@ -248,7 +248,7 @@ class DBBackup
|
||||
$aRet[] = $sFile;
|
||||
}
|
||||
|
||||
$sDeltaFile = APPROOT.'data/'.utils::GetCurrentEnvironment().'.delta.xml';
|
||||
$sDeltaFile = utils::GetDataPath().utils::GetCurrentEnvironment().'.delta.xml';
|
||||
if (file_exists($sDeltaFile))
|
||||
{
|
||||
$sFile = $sTmpFolder.'/delta.xml';
|
||||
@@ -256,7 +256,7 @@ class DBBackup
|
||||
copy($sDeltaFile, $sFile);
|
||||
$aRet[] = $sFile;
|
||||
}
|
||||
$sExtraDir = APPROOT.'data/'.utils::GetCurrentEnvironment().'-modules/';
|
||||
$sExtraDir = utils::GetDataPath().utils::GetCurrentEnvironment().'-modules/';
|
||||
if (is_dir($sExtraDir))
|
||||
{
|
||||
$sModules = utils::GetCurrentEnvironment().'-modules';
|
||||
|
||||
@@ -380,7 +380,7 @@ class RunTimeEnvironment
|
||||
{
|
||||
$aDirsToCompile[] = APPROOT.'extensions';
|
||||
}
|
||||
$sExtraDir = APPROOT.'data/'.$this->sTargetEnv.'-modules/';
|
||||
$sExtraDir = utils::GetDataPath().$this->sTargetEnv.'-modules/';
|
||||
if (is_dir($sExtraDir))
|
||||
{
|
||||
$aDirsToCompile[] = $sExtraDir;
|
||||
@@ -475,7 +475,7 @@ class RunTimeEnvironment
|
||||
}
|
||||
while($bModuleAdded);
|
||||
|
||||
$sDeltaFile = APPROOT.'data/'.$this->sTargetEnv.'.delta.xml';
|
||||
$sDeltaFile = utils::GetDataPath().$this->sTargetEnv.'.delta.xml';
|
||||
if (file_exists($sDeltaFile))
|
||||
{
|
||||
$oDelta = new MFDeltaModule($sDeltaFile);
|
||||
@@ -512,7 +512,7 @@ class RunTimeEnvironment
|
||||
{
|
||||
// Just before loading the delta, let's save an image of the datamodel
|
||||
// in case there is no delta the operation will be done after the end of the loop
|
||||
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$this->sTargetEnv.'.xml');
|
||||
$oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'.xml');
|
||||
}
|
||||
$oFactory->LoadModule($oModule);
|
||||
}
|
||||
@@ -520,10 +520,10 @@ class RunTimeEnvironment
|
||||
|
||||
if ($oModule instanceof MFDeltaModule) {
|
||||
// A delta was loaded, let's save a second copy of the datamodel
|
||||
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$this->sTargetEnv.'-with-delta.xml');
|
||||
$oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'-with-delta.xml');
|
||||
} else {
|
||||
// No delta was loaded, let's save the datamodel now
|
||||
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$this->sTargetEnv.'.xml');
|
||||
$oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'.xml');
|
||||
}
|
||||
|
||||
$sTargetDir = APPROOT.'env-'.$this->sTargetEnv;
|
||||
@@ -532,7 +532,7 @@ class RunTimeEnvironment
|
||||
$oMFCompiler = new MFCompiler($oFactory, $this->sFinalEnv);
|
||||
$oMFCompiler->Compile($sTargetDir, null, $bUseSymLinks, $bSkipTempDir);
|
||||
|
||||
$sCacheDir = APPROOT.'data/cache-'.$this->sTargetEnv;
|
||||
$sCacheDir = utils::GetDataPath().'cache-'.$this->sTargetEnv;
|
||||
SetupUtils::builddir($sCacheDir);
|
||||
SetupUtils::tidydir($sCacheDir);
|
||||
|
||||
@@ -942,38 +942,38 @@ class RunTimeEnvironment
|
||||
{
|
||||
if ($this->sFinalEnv != $this->sTargetEnv)
|
||||
{
|
||||
if (file_exists(APPROOT.'data/'.$this->sTargetEnv.'.delta.xml'))
|
||||
if (file_exists(utils::GetDataPath().$this->sTargetEnv.'.delta.xml'))
|
||||
{
|
||||
if (file_exists(APPROOT.'data/'.$this->sFinalEnv.'.delta.xml'))
|
||||
if (file_exists(utils::GetDataPath().$this->sFinalEnv.'.delta.xml'))
|
||||
{
|
||||
// Make a "previous" file
|
||||
copy(
|
||||
APPROOT.'data/'.$this->sFinalEnv.'.delta.xml',
|
||||
APPROOT.'data/'.$this->sFinalEnv.'.delta.prev.xml'
|
||||
utils::GetDataPath().$this->sFinalEnv.'.delta.xml',
|
||||
utils::GetDataPath().$this->sFinalEnv.'.delta.prev.xml'
|
||||
);
|
||||
}
|
||||
$this->CommitFile(
|
||||
APPROOT.'data/'.$this->sTargetEnv.'.delta.xml',
|
||||
APPROOT.'data/'.$this->sFinalEnv.'.delta.xml'
|
||||
utils::GetDataPath().$this->sTargetEnv.'.delta.xml',
|
||||
utils::GetDataPath().$this->sFinalEnv.'.delta.xml'
|
||||
);
|
||||
}
|
||||
$this->CommitFile(
|
||||
APPROOT.'data/datamodel-'.$this->sTargetEnv.'.xml',
|
||||
APPROOT.'data/datamodel-'.$this->sFinalEnv.'.xml'
|
||||
utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'.xml',
|
||||
utils::GetDataPath().'datamodel-'.$this->sFinalEnv.'.xml'
|
||||
);
|
||||
$this->CommitFile(
|
||||
APPROOT.'data/datamodel-'.$this->sTargetEnv.'-with-delta.xml',
|
||||
APPROOT.'data/datamodel-'.$this->sFinalEnv.'-with-delta.xml',
|
||||
utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'-with-delta.xml',
|
||||
utils::GetDataPath().'datamodel-'.$this->sFinalEnv.'-with-delta.xml',
|
||||
false
|
||||
);
|
||||
$this->CommitDir(
|
||||
APPROOT.'data/'.$this->sTargetEnv.'-modules/',
|
||||
APPROOT.'data/'.$this->sFinalEnv.'-modules/',
|
||||
utils::GetDataPath().$this->sTargetEnv.'-modules/',
|
||||
utils::GetDataPath().$this->sFinalEnv.'-modules/',
|
||||
false
|
||||
);
|
||||
$this->CommitDir(
|
||||
APPROOT.'data/cache-'.$this->sTargetEnv,
|
||||
APPROOT.'data/cache-'.$this->sFinalEnv,
|
||||
utils::GetDataPath().'cache-'.$this->sTargetEnv,
|
||||
utils::GetDataPath().'cache-'.$this->sFinalEnv,
|
||||
false
|
||||
);
|
||||
$this->CommitDir(
|
||||
|
||||
@@ -39,10 +39,10 @@ class SetupPage extends NiceWebPage
|
||||
public function __construct($sTitle)
|
||||
{
|
||||
parent::__construct($sTitle);
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/jquery.blockUI.js");
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'node_modules/@popperjs/core/dist/umd/popper.js');
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'node_modules/tippy.js/dist/tippy-bundle.umd.js');
|
||||
$this->add_linked_script("../setup/setup.js");
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "setup/setup.js");
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-combodo/font-combodo.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'node_modules/tippy.js/dist/tippy.css');
|
||||
|
||||
@@ -1581,7 +1581,7 @@ JS
|
||||
if (is_dir($oWizard->GetParameter('copy_extensions_from'))) {
|
||||
$aDirsToScan[] = $oWizard->GetParameter('copy_extensions_from');
|
||||
}
|
||||
$sExtraDir = APPROOT.'data/production-modules/';
|
||||
$sExtraDir = utils::GetDataPath().'production-modules/';
|
||||
if (is_dir($sExtraDir))
|
||||
{
|
||||
$aDirsToScan[] = $sExtraDir;
|
||||
@@ -1935,7 +1935,7 @@ JS
|
||||
if (empty($sEnv)) {
|
||||
$aLicenceFiles = array_merge($aLicenceFiles, glob(APPROOT.'datamodels/*/*/license.*.xml'));
|
||||
$aLicenceFiles = array_merge($aLicenceFiles, glob(APPROOT.'extensions/{*,*/*}/license.*.xml', GLOB_BRACE));
|
||||
$aLicenceFiles = array_merge($aLicenceFiles, glob(APPROOT.'data/*-modules/{*,*/*}/license.*.xml', GLOB_BRACE));
|
||||
$aLicenceFiles = array_merge($aLicenceFiles, glob(utils::GetDataPath().'*-modules/{*,*/*}/license.*.xml', GLOB_BRACE));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2067,11 +2067,11 @@ JS
|
||||
if (!is_dir(APPROOT.'data')) {
|
||||
mkdir(APPROOT.'data');
|
||||
}
|
||||
if (!is_dir(APPROOT.'data/setup')) {
|
||||
mkdir(APPROOT.'data/setup');
|
||||
if (!is_dir(utils::GetDataPath().'setup')) {
|
||||
mkdir(utils::GetDataPath().'setup');
|
||||
}
|
||||
$sUID = hash('sha256', rand());
|
||||
file_put_contents(APPROOT.'data/setup/authent', $sUID);
|
||||
file_put_contents(utils::GetDataPath().'setup/authent', $sUID);
|
||||
Session::Set('setup_token', $sUID);
|
||||
return $sUID;
|
||||
}
|
||||
@@ -2087,7 +2087,7 @@ JS
|
||||
final public static function CheckSetupToken($bRemoveToken = false)
|
||||
{
|
||||
$sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
|
||||
$sTokenFile = APPROOT.'data/setup/authent';
|
||||
$sTokenFile = utils::GetDataPath().'setup/authent';
|
||||
if (!file_exists($sTokenFile) || $sAuthent !== file_get_contents($sTokenFile)) {
|
||||
throw new SecurityException('Setup operations are not allowed outside of the setup');
|
||||
}
|
||||
@@ -2106,7 +2106,7 @@ JS
|
||||
{
|
||||
if (Session::IsSet('setup_token')) {
|
||||
$sAuth = Session::Get('setup_token');
|
||||
$sTokenFile = APPROOT.'data/setup/authent';
|
||||
$sTokenFile = utils::GetDataPath().'setup/authent';
|
||||
if (file_exists($sTokenFile) && $sAuth === file_get_contents($sTokenFile)) {
|
||||
return true;
|
||||
}
|
||||
@@ -2120,7 +2120,7 @@ JS
|
||||
*/
|
||||
public static function EraseSetupToken()
|
||||
{
|
||||
$sTokenFile = APPROOT.'data/setup/authent';
|
||||
$sTokenFile = utils::GetDataPath().'setup/authent';
|
||||
if (is_file($sTokenFile)) {
|
||||
unlink($sTokenFile);
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ HTML;
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add_linked_script('../setup/setup.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'setup/setup.js');
|
||||
$oPage->add_script("function CanMoveForward()\n{\n".$oStep->JSCanMoveForward()."\n}\n");
|
||||
$oPage->add_script("function CanMoveBackward()\n{\n".$oStep->JSCanMoveBackward()."\n}\n");
|
||||
$oPage->add('<form id="wiz_form" class="ibo-setup--wizard" method="post">');
|
||||
|
||||
@@ -240,7 +240,7 @@ class WizStepInstallOrUpgrade extends WizardStep
|
||||
$sPreviousVersionDir = '';
|
||||
if ($sInstallMode == '')
|
||||
{
|
||||
$sDBBackupPath = APPROOT.'data/backups/manual/setup-'.date('Y-m-d_H_i');
|
||||
$sDBBackupPath = utils::GetDataPath().'backups/manual/setup-'.date('Y-m-d_H_i');
|
||||
$bDBBackup = true;
|
||||
$aPreviousInstance = SetupUtils::GetPreviousInstance(APPROOT);
|
||||
if ($aPreviousInstance['found']) {
|
||||
@@ -2307,7 +2307,7 @@ class WizStepSummary extends WizardStep
|
||||
|
||||
$oPage->add('<fieldset id="installation_progress"><legend>Progress of the installation</legend>');
|
||||
$oPage->add('<div id="progress_content">');
|
||||
$oPage->add_linked_script('../setup/jquery.progression.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'setup/jquery.progression.js');
|
||||
$oPage->add('<p class="center"><span id="setup_msg">Ready to start...</span></p><div style="display:block;margin-left: auto; margin-right:auto;" id="progress">0%</div>');
|
||||
$oPage->add('</div>'); // progress_content
|
||||
$oPage->add('</fieldset>');
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
define ('KEYS_CACHE_FILE', APPROOT.'data/keyscache.tmp');
|
||||
define ('KEYS_CACHE_FILE', utils::GetDataPath().'keyscache.tmp');
|
||||
/**
|
||||
* Class to load sets of objects from XML files into the database
|
||||
* XML files can be produced by the 'export' web service or by any other means
|
||||
|
||||
@@ -55,7 +55,6 @@ class FormHelper
|
||||
*/
|
||||
public static function DisableAttributeBlobInputs(string $sClassName, array &$aExtraParams): void
|
||||
{
|
||||
|
||||
// Initialize extra params array
|
||||
if (!array_key_exists('fieldsFlags', $aExtraParams)) {
|
||||
$aExtraParams['fieldsFlags'] = [];
|
||||
@@ -64,13 +63,13 @@ class FormHelper
|
||||
$aExtraParams['fieldsComments'] = [];
|
||||
}
|
||||
|
||||
// Iterate throw class attributes...
|
||||
// Iterate through class attributes...
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
foreach (MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef) {
|
||||
|
||||
// Set attribute blobs in read only
|
||||
if ($oAttDef instanceof AttributeBlob) {
|
||||
$aExtraParams['fieldsFlags'][$sAttCode] = OPT_ATT_READONLY;
|
||||
$aExtraParams['fieldsComments'][$sAttCode] = ' <img src="../images/transp-lock.png" style="vertical-align:middle" title="'.utils::EscapeHtml(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
|
||||
$aExtraParams['fieldsComments'][$sAttCode] = ' <img src="' . $sAppRootUrl . 'images/transp-lock.png" style="vertical-align:middle" title="'.utils::EscapeHtml(Dict::S('UI:UploadNotSupportedInThisMode')).'"/>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\Popov
|
||||
use Combodo\iTop\Application\UI\Base\tUIContentAreas;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
use DBObject;
|
||||
use Dict;
|
||||
use MetaModel;
|
||||
@@ -100,12 +99,11 @@ class ObjectSummary extends ObjectDetails
|
||||
*/
|
||||
private function ComputeActions()
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$oDetailsButton = null;
|
||||
// We can pass a DBObject to the UIBlock, so we check for the DisplayModifyForm method
|
||||
if(method_exists($this->oObject, 'DisplayModifyForm') && UserRights::IsActionAllowed($this->sClassName, UR_ACTION_MODIFY)) {
|
||||
$oPopoverMenu = new PopoverMenu();
|
||||
|
||||
|
||||
$oDetailsAction = new URLPopupMenuItem(
|
||||
'UI:Menu:View',
|
||||
Dict::S('UI:Menu:View'),
|
||||
@@ -113,12 +111,13 @@ class ObjectSummary extends ObjectDetails
|
||||
'_blank'
|
||||
);
|
||||
$oModifyButton = ButtonUIBlockFactory::MakeLinkNeutral(
|
||||
$oRouter->GenerateUrl('object.modify', ['class' => $this->sClassName, 'id' => $this->sObjectId]),
|
||||
// Can't use URL Generator (`$this->oUrlGenerator->generate("b_object_summary", [$sObjClass, $sObjKey])`) yet as we have to find how to inject it here
|
||||
"{$sRootUrl}app.php/object/modify/{$this->sClassName}/{$this->sObjectId}",
|
||||
Dict::S('UI:Menu:Modify'),
|
||||
'fas fa-external-link-alt',
|
||||
'_blank',
|
||||
);
|
||||
|
||||
|
||||
$oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oDetailsAction))->SetContainer(PopoverMenu::ENUM_CONTAINER_PARENT);
|
||||
|
||||
$oDetailsButton = ButtonGroupUIBlockFactory::MakeButtonWithOptionsMenu($oModifyButton, $oPopoverMenu);
|
||||
|
||||
@@ -26,8 +26,8 @@ class ErrorPage extends NiceWebPage
|
||||
{
|
||||
$oKpi = new ExecutionKPI();
|
||||
parent::__construct($sTitle);
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../setup/setup.js");
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "js/jquery.blockUI.js");
|
||||
$this->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "setup/setup.js");
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-combodo/font-combodo.css');
|
||||
$this->add_saas("css/setup.scss");
|
||||
@@ -58,7 +58,7 @@ class ErrorPage extends NiceWebPage
|
||||
if(utils::IsEasterEggAllowed())
|
||||
{
|
||||
$this->add('<div class="message message-valid">'.Dict::S('UI:ErrorPage:UnstableVersion').'</div>');
|
||||
$this->add('<img src="../images/alpha-fatal-error.gif">');
|
||||
$this->add('<img src="' . utils::GetAbsoluteUrlAppRoot() . 'images/alpha-fatal-error.gif">');
|
||||
$this->add('<div class="message message-valid">'.nl2br(Dict::S('UI:ErrorPage:KittyDisclaimer')).'</div>');
|
||||
}
|
||||
$this->log_error($sText);
|
||||
|
||||
@@ -26,6 +26,7 @@ use Dict;
|
||||
use ExecutionKPI;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
@@ -734,15 +735,28 @@ class WebPage implements Page
|
||||
* Add a script (as an include, i.e. link) to the header of the page.<br>
|
||||
* Handles duplicates : calling twice with the same script will add the script only once
|
||||
*
|
||||
* @uses WebPage::$a_linked_scripts
|
||||
* @param string $s_linked_script
|
||||
* @param string $sLinkedScriptAbsUrl
|
||||
*
|
||||
* @return void
|
||||
* @uses WebPage::$a_linked_scripts
|
||||
* @since 3.2.0 N°6935 $sLinkedScriptAbsUrl MUST be an absolute URL
|
||||
*/
|
||||
public function add_linked_script($s_linked_script)
|
||||
public function add_linked_script($sLinkedScriptAbsUrl)
|
||||
{
|
||||
if (!empty(trim($s_linked_script))) {
|
||||
$this->a_linked_scripts[$s_linked_script] = $s_linked_script;
|
||||
// Ensure there is actually an URI
|
||||
if (utils::IsNullOrEmptyString(trim($sLinkedScriptAbsUrl))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if URI is absolute ("://" do allow any protocol), otherwise warn that it's a deprecated behavior
|
||||
if (false === stripos($sLinkedScriptAbsUrl, "://")) {
|
||||
IssueLog::Warning("Linked script added to page with a non absolute URL, which may lead to it not being loaded and causing javascript errors.", null, [
|
||||
"linked_script_url" => $sLinkedScriptAbsUrl,
|
||||
"request_uri" => $_SERVER['REQUEST_URI'],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->a_linked_scripts[$sLinkedScriptAbsUrl] = $sLinkedScriptAbsUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1331,12 +1345,65 @@ JS;
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$oKpi = new ExecutionKPI();
|
||||
// Send headers
|
||||
foreach ($this->a_headers as $sHeader) {
|
||||
header($sHeader);
|
||||
}
|
||||
|
||||
// Render HTML content
|
||||
$sHtml = $this->RenderContent();
|
||||
|
||||
// Echo global HTML
|
||||
$oKpi = new ExecutionKPI();
|
||||
echo $sHtml;
|
||||
$oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' KB)');
|
||||
|
||||
if (class_exists('DBSearch')) {
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Symfony\Component\HttpFoundation\Response Generate the Symfony Response object (content + code + headers) for the current page, this is equivalent (and new way) of \WebPage::output() for Symfony controllers
|
||||
* @since 3.2.0 N°6935
|
||||
*/
|
||||
public function GenerateResponse(): Response
|
||||
{
|
||||
// Render HTML content
|
||||
$sHtml = $this->RenderContent();
|
||||
|
||||
// Prepare Symfony Response
|
||||
$oKpi = new ExecutionKPI();
|
||||
|
||||
// Format headers as a key => value array to match Symfony Response format
|
||||
$aHeadersAsAssocArray = [];
|
||||
foreach ($this->a_headers as $sHeader) {
|
||||
// Limit explode to only split at the first occurrence
|
||||
list($sHeaderName, $sHeaderValue) = explode(': ', $sHeader, 2);
|
||||
$aHeadersAsAssocArray[$sHeaderName] = $sHeaderValue;
|
||||
}
|
||||
|
||||
$oResponse = new Response($sHtml, Response::HTTP_OK, $aHeadersAsAssocArray);
|
||||
$oKpi->ComputeAndReport('Preparing response ('.round(strlen($sHtml) / 1024).' KB)');
|
||||
|
||||
if (class_exists('DBSearch')) {
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
ExecutionKPI::ReportStats();
|
||||
|
||||
return $oResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Complete HTML content of the \WebPage
|
||||
* @throws \CoreTemplateException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @since 3.2.0 N°6935
|
||||
*/
|
||||
protected function RenderContent(): string
|
||||
{
|
||||
$oKpi = new ExecutionKPI();
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
|
||||
$aData = [];
|
||||
@@ -1390,16 +1457,10 @@ JS;
|
||||
$oTwigEnv = TwigHelper::GetTwigEnvironment(BlockRenderer::TWIG_BASE_PATH, BlockRenderer::TWIG_ADDITIONAL_PATHS);
|
||||
// Render final TWIG into global HTML
|
||||
$sHtml = TwigHelper::RenderTemplate($oTwigEnv, $aData, $this->GetTemplateRelPath());
|
||||
$oKpi->ComputeAndReport(get_class($this).'output');
|
||||
|
||||
// Echo global HTML
|
||||
echo $sHtml;
|
||||
$oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)');
|
||||
$oKpi->ComputeAndReport("Rendering content (".static::class.")");
|
||||
|
||||
if (class_exists('DBSearch')) {
|
||||
DBSearch::RecordQueryTrace();
|
||||
}
|
||||
ExecutionKPI::ReportStats();
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -829,6 +829,31 @@ HTML;
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
// Send headers
|
||||
if ($this->GetOutputFormat() === 'html') {
|
||||
foreach ($this->a_headers as $sHeader) {
|
||||
header($sHeader);
|
||||
}
|
||||
}
|
||||
|
||||
// Render HTKL content
|
||||
$sHtml = $this->RenderContent();
|
||||
|
||||
// Echo global HTML
|
||||
$oKpi = new ExecutionKPI();
|
||||
echo $sHtml;
|
||||
$oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)');
|
||||
|
||||
DBSearch::RecordQueryTrace();
|
||||
ExecutionKPI::ReportStats();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0 N°6935
|
||||
*/
|
||||
protected function RenderContent(): string
|
||||
{
|
||||
$oKpi = new ExecutionKPI();
|
||||
|
||||
@@ -933,16 +958,16 @@ HTML;
|
||||
$aData['aDeferredBlocks']['oPageContent'] = $this->GetDeferredBlocks($this->GetContentLayout());
|
||||
// - Prepare generic templates
|
||||
$aData['aTemplates'] = array();
|
||||
|
||||
|
||||
// TODO 3.1 Replace hardcoded 'Please wait' with dict entries
|
||||
|
||||
|
||||
// - Modal template with loader
|
||||
$oModalTemplateContentBlock = new UIContentBlock();
|
||||
$oModalTemplateContentBlock->AddCSSClass('ibo-modal')
|
||||
->AddDataAttribute('role', 'ibo-modal')
|
||||
->AddSubBlock(SpinnerUIBlockFactory::MakeMedium(null, 'Please wait'));
|
||||
$aData['aTemplates'][] = TemplateUIBlockFactory::MakeForBlock('ibo-modal-template', $oModalTemplateContentBlock);
|
||||
|
||||
|
||||
// - Small loader template
|
||||
$oSmallLoaderTemplateContentBlock = new UIContentBlock();
|
||||
$oSmallLoaderTemplateContentBlock->AddSubBlock(SpinnerUIBlockFactory::MakeSmall(null , 'Please wait'));
|
||||
@@ -997,66 +1022,14 @@ HTML;
|
||||
|
||||
$oTwigEnv = TwigHelper::GetTwigEnvironment(BlockRenderer::TWIG_BASE_PATH, BlockRenderer::TWIG_ADDITIONAL_PATHS);
|
||||
|
||||
// Send headers
|
||||
if ($this->GetOutputFormat() === 'html') {
|
||||
foreach ($this->a_headers as $sHeader) {
|
||||
header($sHeader);
|
||||
}
|
||||
}
|
||||
|
||||
// Render final TWIG into global HTML
|
||||
$sHtml = TwigHelper::RenderTemplate($oTwigEnv, $aData, $this->GetTemplateRelPath());
|
||||
|
||||
$oKpi->ComputeAndReport(get_class($this).' output');
|
||||
|
||||
// Echo global HTML
|
||||
echo $sHtml;
|
||||
$oKpi->ComputeAndReport('Echoing ('.round(strlen($sHtml) / 1024).' Kb)');
|
||||
|
||||
DBSearch::RecordQueryTrace();
|
||||
ExecutionKPI::ReportStats();
|
||||
|
||||
return;
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
////////////////// ☢ DANGER ZONE ☢ /////////////////////
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
// Render the tabs in the page (if any)
|
||||
// $this->s_content = $this->m_oTabs->RenderIntoContent($this->s_content, $this);
|
||||
|
||||
// Put here the 'ready scripts' that must be executed after all others
|
||||
$aMultiselectOptions = array(
|
||||
'header' => true,
|
||||
'checkAllText' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheckAllText' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'noneSelectedText' => Dict::S('UI:SearchValue:Any'),
|
||||
'selectedText' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'selectedList' => 1,
|
||||
);
|
||||
$sJSMultiselectOptions = json_encode($aMultiselectOptions);
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
$(window).trigger( 'hashchange' );
|
||||
|
||||
// Some table are sort-able, some are not, let's fix this
|
||||
$('table.listResults').each( function() { FixTableSorter($(this)); } );
|
||||
|
||||
$('.multiselect').multiselect($sJSMultiselectOptions);
|
||||
EOF
|
||||
);
|
||||
|
||||
$this->outputCollapsibleSectionInit();
|
||||
|
||||
// TODO 3.0.0: Is this for the "Debug" popup? We should do a helper to display a popup in various cases (welcome message for example)
|
||||
$s_captured_output = $this->ob_get_clean_safe();
|
||||
|
||||
$oKpi->ComputeAndReport("Rendering content (".static::class.")");
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws \Exception
|
||||
|
||||
@@ -54,7 +54,7 @@ class iTopWizardWebPage extends iTopWebPage
|
||||
$sStyle = ($iIndex == $this->m_iCurrentStep) ? 'wizActiveStep' : 'wizStep';
|
||||
$aSteps[] = "<div class=\"$sStyle\"><span>$sStepTitle</span></div>";
|
||||
}
|
||||
$sWizardHeader = "<div class=\"wizHeader\"><h1>".utils::EscapeHtml($this->s_title)."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"../images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
|
||||
$sWizardHeader = "<div class=\"wizHeader\"><h1>".utils::EscapeHtml($this->s_title)."</h1>\n".implode("<div class=\"wizSeparator\"><img align=\"bottom\" src=\"" . utils::GetAbsoluteUrlAppRoot() . "images/wizArrow.gif\"></div>", $aSteps)."<br style=\"clear:both;\"/></div>\n";
|
||||
$this->s_content = "$sWizardHeader<div class=\"wizContainer\">".$this->s_content."</div>";
|
||||
parent::output();
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2023 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Controller;
|
||||
|
||||
/**
|
||||
* Class AbstractAppController
|
||||
*
|
||||
* @package Combodo\iTop\Controller
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class AbstractAppController extends \Symfony\Bundle\FrameworkBundle\Controller\AbstractController
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
namespace Combodo\iTop\Controller;
|
||||
|
||||
use DeprecatedCallsLog;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as BaseAbstractControllerAlias;
|
||||
|
||||
/**
|
||||
* Class AbstractController
|
||||
*
|
||||
@@ -15,14 +18,17 @@ namespace Combodo\iTop\Controller;
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Controller
|
||||
* @since 3.1.0
|
||||
* @since 3.2.0 N°6935 Controller is now based on Symfony controller
|
||||
*/
|
||||
abstract class AbstractController implements iController
|
||||
abstract class AbstractController extends BaseAbstractControllerAlias implements iController
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @deprecated 3.2.0 N°6935 Use \Symfony\Component\HttpFoundation\Request::isXmlHttpRequest() instead
|
||||
*/
|
||||
public function IsHandlingXmlHttpRequest(): bool
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod("Use \Symfony\Component\HttpFoundation\Request::isXmlHttpRequest() instead");
|
||||
return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest');
|
||||
}
|
||||
}
|
||||
@@ -845,7 +845,7 @@ EOF
|
||||
);
|
||||
$sVersionString = Dict::Format('UI:iTopVersion:Short', ITOP_APPLICATION, ITOP_VERSION);
|
||||
$oPage->add('<div id="about_box"><div class="ibo-about-box--top-part">');
|
||||
$oPage->add('<div><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logos/logo-combodo-dark.svg?t='.utils::GetCacheBusterTimestamp().'"/></a></div>');
|
||||
$oPage->add('<div><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="' . utils::GetAbsoluteUrlAppRoot() . 'images/logos/logo-combodo-dark.svg?t='.utils::GetCacheBusterTimestamp().'"/></a></div>');
|
||||
$oPage->add('<div>'.$sVersionString.'</div>');
|
||||
$oPage->add("</div>");
|
||||
self::DisplayAboutLicenses($oPage);
|
||||
@@ -898,7 +898,7 @@ EOF
|
||||
if (file_exists(APPROOT.'extensions')) {
|
||||
$aSearchDirs[] = APPROOT.'extensions';
|
||||
}
|
||||
$sExtraDir = APPROOT.'data/'.$sCurrEnv.'-modules/';
|
||||
$sExtraDir = utils::GetDataPath().$sCurrEnv.'-modules/';
|
||||
if (file_exists($sExtraDir)) {
|
||||
$aSearchDirs[] = $sExtraDir;
|
||||
}
|
||||
@@ -927,7 +927,7 @@ EOF
|
||||
// Display
|
||||
//
|
||||
$oPage->add('<div id="about_box"><div class="ibo-about-box--top-part">');
|
||||
$oPage->add('<div><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logos/logo-combodo-dark.svg?t='.utils::GetCacheBusterTimestamp().'"/></a></div>');
|
||||
$oPage->add('<div><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="' . utils::GetAbsoluteUrlAppRoot() . 'images/logos/logo-combodo-dark.svg?t='.utils::GetCacheBusterTimestamp().'"/></a></div>');
|
||||
$oPage->add('<div>'.$sVersionString.'<br/>'.'MySQL: '.$sMySQLVersion.'<br/>'.'PHP: '.$sPHPVersion.'<br/></div>');
|
||||
$oPage->add("</div>");
|
||||
|
||||
|
||||
@@ -30,7 +30,12 @@ use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\JsonPage;
|
||||
use MetaModel;
|
||||
use SecurityException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Combodo\iTop\Service\SummaryCard\SummaryCardService;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
@@ -42,30 +47,47 @@ use utils;
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Controller\Base\Layout
|
||||
*/
|
||||
#[Route("/object", name: "b_object_")]
|
||||
class ObjectController extends AbstractController
|
||||
{
|
||||
public const ROUTE_NAMESPACE = 'object';
|
||||
/** @deprecated 3.2.0 N°6935 Replaced by Symfony route name prefix on the controller */
|
||||
//public const ROUTE_NAMESPACE = 'object';
|
||||
|
||||
/**
|
||||
* @throws \CoreException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \MySQLException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \ConfigException
|
||||
* @throws \ApplicationException
|
||||
* @throws \MissingQueryArgument
|
||||
* @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $oUrlGenerator
|
||||
* @since 3.2.0 N°6935
|
||||
*/
|
||||
public function OperationNew()
|
||||
public function __construct(
|
||||
protected UrlGeneratorInterface $oUrlGenerator
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
* @param string $sClass Class of the datamodel object to create
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
|
||||
* @throws ApplicationException
|
||||
*/
|
||||
#[Route('/new/{sClass}', name: 'new')]
|
||||
public function OperationNew(Request $oRequest, string $sClass): Response
|
||||
{
|
||||
// Retrieve parameters
|
||||
$bPrintable = utils::ReadParam('printable', '0') === '1';
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sStateCode = utils::ReadParam('state', '');
|
||||
$bCheckSubClass = utils::ReadParam('checkSubclass', true);
|
||||
|
||||
// Check parameters
|
||||
if (false === MetaModel::IsValidClass($sClass)) {
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
$oAppContext = new ApplicationContext();
|
||||
$oRouter = Router::GetInstance();
|
||||
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oPage = new AjaxPage('');
|
||||
} else {
|
||||
$oPage = new iTopWebPage('', $bPrintable);
|
||||
@@ -73,7 +95,6 @@ class ObjectController extends AbstractController
|
||||
$this->AddRequiredForModificationJsFilesToPage($oPage);
|
||||
}
|
||||
|
||||
|
||||
if (empty($sClass))
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:1ParametersMissing', 'class'));
|
||||
@@ -133,7 +154,7 @@ class ObjectController extends AbstractController
|
||||
// - Update flags with parameters set in URL
|
||||
FormHelper::UpdateFlagsFromContext($oObjToClone, $aFormExtraParams);
|
||||
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aFormExtraParams['js_handlers'] = [];
|
||||
$aFormExtraParams['noRelations'] = true;
|
||||
$aFormExtraParams['hide_transitions'] = true;
|
||||
@@ -187,9 +208,9 @@ JS;
|
||||
|
||||
cmdbAbstractObject::DisplayCreationForm($oPage, $sRealClass, $oObjToClone, array(), $aFormExtraParams);
|
||||
} else {
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oClassForm = cmdbAbstractObject::DisplayFormBlockSelectClassToCreate($sClass, MetaModel::GetName($sClass), $oAppContext, $aPossibleClasses, ['state' => $sStateCode]);
|
||||
$sCurrentUrl = $oRouter->GenerateUrl('object.new');
|
||||
$sCurrentUrl = $this->oUrlGenerator->generate('b_object_new');
|
||||
$oClassForm->SetOnSubmitJsCode(
|
||||
<<<JS
|
||||
let me = this;
|
||||
@@ -208,25 +229,35 @@ JS
|
||||
cmdbAbstractObject::DisplaySelectClassToCreate($sClass, $oPage, $oAppContext, $aPossibleClasses,['state' => $sStateCode]);
|
||||
}
|
||||
}
|
||||
return $oPage;
|
||||
|
||||
return $oPage->GenerateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iTopWebPage|AjaxPage Object edit form in its webpage
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
* @param string $sClass Class of the datamodel object to modify
|
||||
* @param string $sId ID of the object to modify
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \SecurityException
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function OperationModify()
|
||||
#[Route('/modify/{sClass}/{sId}', name: 'modify')]
|
||||
public function OperationModify(Request $oRequest, string $sClass, string $sId): Response
|
||||
{
|
||||
// Retrieve and check parameters
|
||||
$bPrintable = utils::ReadParam('printable', '0') === '1';
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sId = utils::ReadParam('id', '');
|
||||
$sFormTitle = utils::ReadPostedParam('form_title', null, utils::ENUM_SANITIZATION_FILTER_STRING);
|
||||
|
||||
// Check parameters
|
||||
if (false === MetaModel::IsValidClass($sClass)) {
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
if (utils::IsNullOrEmptyString($sClass) || utils::IsNullOrEmptyString($sId))
|
||||
{
|
||||
throw new ApplicationException(Dict::Format('UI:Error:2ParametersMissing', 'class', 'id'));
|
||||
@@ -254,7 +285,7 @@ JS
|
||||
$aFormExtraParams['form_title'] = $sFormTitle;
|
||||
}
|
||||
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oPage = new AjaxPage('');
|
||||
$aFormExtraParams['js_handlers'] = [];
|
||||
$aFormExtraParams['noRelations'] = true;
|
||||
@@ -321,21 +352,25 @@ JS;
|
||||
// Note: Code duplicated to the case 'apply_modify' in UI.php when a data integrity issue has been found
|
||||
$oObj->DisplayModifyForm($oPage, $aFormExtraParams); // wizard_container: Display the title above the form
|
||||
|
||||
return $oPage;
|
||||
return $oPage->GenerateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iTopWebPage|JsonPage Object edit form in its webpage
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \SecurityException
|
||||
*/
|
||||
public function OperationApplyNew()
|
||||
#[Route('/apply_new', name: 'apply_new')]
|
||||
public function OperationApplyNew(Request $oRequest): Response
|
||||
{
|
||||
$bPrintable = utils::ReadParam('printable', '0') === '1';
|
||||
$aResult = [];
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
$aResult['success'] = false;
|
||||
@@ -367,7 +402,7 @@ JS;
|
||||
$sUser = UserRights::GetUser();
|
||||
IssueLog::Error(__CLASS__.'::'.__METHOD__." : invalid transaction_id ! data: user='$sUser', class='$sClass'");
|
||||
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => Dict::S('UI:Error:ObjectAlreadyCreated')];
|
||||
} else {
|
||||
$oErrorAlert = AlertUIBlockFactory::MakeForFailure(Dict::S('UI:Error:ObjectAlreadyCreated'));
|
||||
@@ -464,7 +499,7 @@ JS;
|
||||
}
|
||||
} else {
|
||||
// Nothing more to do
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['success'] = true;
|
||||
$aResult['data'] = ['object' => ObjectRepository::ConvertObjectToArray($oObj, $sClass)];
|
||||
} else {
|
||||
@@ -476,7 +511,7 @@ JS;
|
||||
// Found issues, explain and give the user a second chance
|
||||
//
|
||||
$aIssues = $e->getIssues();
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => $e->getHtmlMessage()];
|
||||
} else {
|
||||
$sClassLabel = MetaModel::GetName($sClass);
|
||||
@@ -494,15 +529,18 @@ JS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oPage->SetData($aResult);
|
||||
}
|
||||
|
||||
return $oPage;
|
||||
return $oPage->GenerateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return iTopWebPage|JsonPage
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
@@ -511,10 +549,12 @@ JS;
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MySQLException
|
||||
*/
|
||||
public function OperationApplyModify(){
|
||||
public function OperationApplyModify(Request $oRequest): Response
|
||||
{
|
||||
$bPrintable = utils::ReadParam('printable', '0') === '1';
|
||||
$aResult = [];
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oPage = new JsonPage();
|
||||
$oPage->SetOutputDataOnly(true);
|
||||
$aResult['success'] = false;
|
||||
@@ -546,7 +586,7 @@ JS;
|
||||
{
|
||||
$bDisplayDetails = false;
|
||||
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => Dict::S('UI:ObjectDoesNotExist')];
|
||||
} else {
|
||||
$oPage->set_title(Dict::S('UI:ErrorPageTitle'));
|
||||
@@ -572,7 +612,7 @@ JS;
|
||||
$sUser = UserRights::GetUser();
|
||||
IssueLog::Error(__CLASS__.'::'.__METHOD__." : invalid transaction_id ! data: user='$sUser', class='$sClass'");
|
||||
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => Dict::S('UI:Error:ObjectAlreadyUpdated')];
|
||||
} else {
|
||||
$oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
|
||||
@@ -598,7 +638,7 @@ JS;
|
||||
|
||||
if (!$oObj->IsModified() && empty($aErrors))
|
||||
{
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())];
|
||||
} else {
|
||||
$oPage->set_title(Dict::Format('UI:ModificationPageTitle_Object_Class', $oObj->GetRawName(), $sClassLabel)); // Set title will take care of the encoding
|
||||
@@ -646,7 +686,7 @@ JS;
|
||||
|
||||
$sMessage = Dict::Format('UI:Class_Object_Updated', MetaModel::GetName(get_class($oObj)), $oObj->GetName());
|
||||
$sSeverity = 'ok';
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['success'] = true;
|
||||
}
|
||||
}
|
||||
@@ -656,7 +696,7 @@ JS;
|
||||
//
|
||||
$bDisplayDetails = false;
|
||||
$aIssues = $e->getIssues();
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => $e->getHtmlMessage()];
|
||||
} else {
|
||||
$oPage->AddHeaderMessage($e->getHtmlMessage(), 'message_error');
|
||||
@@ -667,7 +707,7 @@ JS;
|
||||
}
|
||||
catch (DeleteException $e)
|
||||
{
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$aResult['data'] = ['error_message' => Dict::Format('UI:Class_Object_NotUpdated', MetaModel::GetName(get_class($oObj)), $oObj->GetName())];
|
||||
} else {
|
||||
// Say two things:
|
||||
@@ -706,7 +746,7 @@ JS;
|
||||
// Nothing more to do
|
||||
$sMessage = isset($sMessage) ? $sMessage : '';
|
||||
$sSeverity = isset($sSeverity) ? $sSeverity : null;
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
;
|
||||
} else {
|
||||
ReloadAndDisplay($oPage, $oObj, 'update', $sMessage, $sSeverity);
|
||||
@@ -724,27 +764,38 @@ JS;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->IsHandlingXmlHttpRequest()) {
|
||||
if ($oRequest->isXmlHttpRequest()) {
|
||||
$oPage->SetData($aResult);
|
||||
}
|
||||
return $oPage;
|
||||
return $oPage->GenerateResponse();
|
||||
}
|
||||
|
||||
public function OperationSummary() {
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
* @param string $sClass Class of the datamodel object to view
|
||||
* @param string $sId ID of the datamodel object to view (note that friendlyname can also be used but is less efficient)
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
#[Route('/summary/{sClass}/{sId}', name: 'summary')]
|
||||
public function OperationSummary(Request $oRequest, string $sClass, string $sId): Response
|
||||
{
|
||||
$oPage = new AjaxPage('');
|
||||
|
||||
$sClass = utils::ReadParam('obj_class', '', false, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$sObjectKey = utils::ReadParam('obj_key', 0, false);
|
||||
// Check parameters
|
||||
if (false === MetaModel::IsValidClass($sClass)) {
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
// - Check if we are allowed to see/make summary for this class
|
||||
if(SummaryCardService::IsAllowedForClass($sClass)){
|
||||
if (is_numeric($sObjectKey))
|
||||
if (is_numeric($sId))
|
||||
{
|
||||
$oObj = MetaModel::GetObject($sClass, $sObjectKey, false /* MustBeFound */);
|
||||
$oObj = MetaModel::GetObject($sClass, $sId, false /* MustBeFound */);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oObj = MetaModel::GetObjectByName($sClass, $sObjectKey, false /* MustBeFound */);
|
||||
$oObj = MetaModel::GetObjectByName($sClass, $sId, false /* MustBeFound */);
|
||||
}
|
||||
|
||||
if($oObj !== null) {
|
||||
@@ -758,7 +809,7 @@ JS;
|
||||
->SetIsClosable(false)
|
||||
);
|
||||
}
|
||||
return $oPage;
|
||||
return $oPage->GenerateResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -771,7 +822,7 @@ JS;
|
||||
protected function AddRequiredForModificationJsFilesToPage(iTopWebPage &$oPage): void
|
||||
{
|
||||
foreach (static::EnumRequiredForModificationJsFilesRelPaths() as $sJsFileRelPath) {
|
||||
$oPage->add_linked_script("../$sJsFileRelPath");
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . "$sJsFileRelPath");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,10 +6,13 @@
|
||||
|
||||
namespace Combodo\iTop\Controller;
|
||||
|
||||
|
||||
/**
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @since 3.1.0
|
||||
* @package Combodo\iTop\Controller
|
||||
*
|
||||
* @deprecated 3.2.0 N°6935 As we now use Symfony controller and routing components, extend \Combodo\iTop\Controller\AbstractController instead
|
||||
*/
|
||||
interface iController
|
||||
{
|
||||
|
||||
@@ -6,17 +6,42 @@
|
||||
|
||||
namespace Combodo\iTop\Service\Router\Exception;
|
||||
|
||||
use DeprecatedCallsLog;
|
||||
|
||||
|
||||
/**
|
||||
* Class RouteNotFoundException
|
||||
*
|
||||
* Means that a said route (eg. "object.modify") could not be found
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @deprecated 3.2.0 N°6935 As we now use Symfony routing component, use the corresponding exceptions instead
|
||||
*
|
||||
* Note that we can't call \DeprecatedCallsLog::NotifyDeprecatedFile() at the beginning at the file instead.
|
||||
* Because
|
||||
* - As the class is part of the autoloader it will be read when something calls \utils::GetClassesForInterface() which will pop the deprecation message (and break redirection)
|
||||
* - Not all controllers using Combodo\iTop\Service\Router\Router service can be migrated yet for backward compatibility with extensions reasons
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Service\Router\Exception
|
||||
* @since 3.1.0
|
||||
* @internal
|
||||
*/
|
||||
class RouteNotFoundException extends RouterException
|
||||
{
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
/**
|
||||
* @deprecated 3.2.0 N°6935
|
||||
*
|
||||
* Note that we can't call \DeprecatedCallsLog::NotifyDeprecatedFile() at the beginning at the file instead.
|
||||
* Because
|
||||
* - As the class is part of the autoloader it will be read when something calls \utils::GetClassesForInterface() which will pop the deprecation message (and break redirection)
|
||||
* - Not all controllers using Combodo\iTop\Service\Router\Router service can be migrated yet for backward compatibility with extensions reasons
|
||||
*/
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile("As we now use Symfony routing component, use the corresponding exceptions instead");
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,19 +6,42 @@
|
||||
|
||||
namespace Combodo\iTop\Service\Router\Exception;
|
||||
|
||||
use DeprecatedCallsLog;
|
||||
use Exception;
|
||||
|
||||
|
||||
/**
|
||||
* Class RouterException
|
||||
*
|
||||
* Base router exception class in case we need to catch all kind of router exceptions (see derived exceptions)
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @deprecated 3.2.0 N°6935 As we now use Symfony routing component, use the corresponding exceptions instead
|
||||
*
|
||||
* Note that we can't call \DeprecatedCallsLog::NotifyDeprecatedFile() at the beginning at the file instead.
|
||||
* Because
|
||||
* - As the class is part of the autoloader it will be read when something calls \utils::GetClassesForInterface() which will pop the deprecation message (and break redirection)
|
||||
* - Not all controllers using Combodo\iTop\Service\Router\Router service can be migrated yet for backward compatibility with extensions reasons
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Service\Router\Exception
|
||||
* @since 3.1.0
|
||||
* @internal
|
||||
*/
|
||||
class RouterException extends Exception
|
||||
{
|
||||
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
|
||||
{
|
||||
/**
|
||||
* @deprecated 3.2.0 N°6935
|
||||
*
|
||||
* Note that we can't call \DeprecatedCallsLog::NotifyDeprecatedFile() at the beginning at the file instead.
|
||||
* Because
|
||||
* - As the class is part of the autoloader it will be read when something calls \utils::GetClassesForInterface() which will pop the deprecation message (and break redirection)
|
||||
* - Not all controllers using Combodo\iTop\Service\Router\Router service can be migrated yet for backward compatibility with extensions reasons
|
||||
*/
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile("As we now use Symfony routing component, use the corresponding exceptions instead");
|
||||
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
}
|
||||
@@ -7,20 +7,29 @@
|
||||
namespace Combodo\iTop\Service\Router;
|
||||
|
||||
use Combodo\iTop\Service\Router\Exception\RouteNotFoundException;
|
||||
use DeprecatedCallsLog;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use utils;
|
||||
use SetupUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Class Router
|
||||
*
|
||||
* Service to find the corresponding controller / method for a given "route" parameter.
|
||||
*
|
||||
* @deprecated 3.2.0 N°6935 As we now use Symfony routing component, use the corresponding service instead
|
||||
*
|
||||
* Note that we can't call \DeprecatedCallsLog::NotifyDeprecatedFile() at the beginning at the file instead.
|
||||
* Because
|
||||
* - As the class is part of the autoloader it will be read when something calls \utils::GetClassesForInterface() which will pop the deprecation message (and break redirection)
|
||||
* - Not all controllers using Combodo\iTop\Service\Router\Router service can be migrated yet for backward compatibility with extensions reasons
|
||||
*
|
||||
* @author Guillaume Lajarige <guillaume.lajarige@combodo.com>
|
||||
* @package Combodo\iTop\Service\Router
|
||||
* @since 3.1.0
|
||||
* @api
|
||||
*
|
||||
* @package Combodo\iTop\Service\Router
|
||||
*/
|
||||
class Router
|
||||
{
|
||||
@@ -123,6 +132,9 @@ class Router
|
||||
*/
|
||||
public function DispatchRoute(string $sRoute)
|
||||
{
|
||||
/** @deprecated 3.2.0 N°6935 */
|
||||
DeprecatedCallsLog::NotifyDeprecatedFile("As we now use Symfony routing component, use the corresponding service instead");
|
||||
|
||||
$aMethodSpecs = $this->GetDispatchSpecsForRoute($sRoute);
|
||||
$mResponse = call_user_func_array([new $aMethodSpecs[0](), $aMethodSpecs[1]], []);
|
||||
|
||||
@@ -175,8 +187,15 @@ class Router
|
||||
// If no cache, force to re-scan for routes
|
||||
if (count($aRoutes) === 0) {
|
||||
foreach (utils::GetClassesForInterface('Combodo\iTop\Controller\iController', '', ['[\\\\/]lib[\\\\/]', '[\\\\/]node_modules[\\\\/]', '[\\\\/]test[\\\\/]']) as $sControllerFQCN) {
|
||||
$sRouteNamespace = $sControllerFQCN::ROUTE_NAMESPACE;
|
||||
// Ignore controller with no namespace
|
||||
// - No ROUTE_NAMESPACE constant
|
||||
// This case could be for controller extending Combodo\iTop\Controller\AbstractController which is still implementing Combodo\iTop\Controller\iController for compatibility reasons
|
||||
// but have already been migrated to Symfony router (when migrated, constant must be removed from the controller so it doesn't use the compatibility router)
|
||||
if (false === defined("$sControllerFQCN::ROUTE_NAMESPACE")) {
|
||||
continue;
|
||||
}
|
||||
$sRouteNamespace = $sControllerFQCN::ROUTE_NAMESPACE;
|
||||
// - Namespace is empty
|
||||
if (is_null($sRouteNamespace)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ namespace Combodo\iTop\Service\SummaryCard;
|
||||
|
||||
use appUserPreferences;
|
||||
use Combodo\iTop\Core\MetaModel\FriendlyNameType;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
use MetaModel;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
* Class SummaryCardService
|
||||
@@ -19,10 +20,22 @@ use UserRights;
|
||||
*
|
||||
* @since 3.1.0
|
||||
*/
|
||||
class SummaryCardService {
|
||||
class SummaryCardService
|
||||
{
|
||||
/**
|
||||
* @param \Symfony\Component\Routing\Generator\UrlGeneratorInterface $oUrlGenerator
|
||||
*
|
||||
* @since 3.2.0 Add constructor and dependency injection of $oUrlGenerator
|
||||
*/
|
||||
public function __construct(
|
||||
protected UrlGeneratorInterface $oUrlGenerator
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $sObjClass
|
||||
* @param string $sObjClass
|
||||
* @param $sObjKey
|
||||
*
|
||||
* @return string
|
||||
@@ -30,9 +43,9 @@ class SummaryCardService {
|
||||
*/
|
||||
public static function GetHyperlinkMarkup(string $sObjClass, $sObjKey): string
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sRoute = $oRouter->GenerateUrl("object.summary", ["obj_class" => $sObjClass, "obj_key" => $sObjKey]);
|
||||
return
|
||||
// Can't use URL Generator (`$this->oUrlGenerator->generate("b_object_summary", [$sObjClass, $sObjKey])`) yet as we have to find how to inject it here
|
||||
$sRoute = utils::GetAbsoluteUrlAppRoot() . "app.php/object/summary/$sObjClass/$sObjKey";
|
||||
return
|
||||
<<<HTML
|
||||
data-tooltip-content="$sRoute"
|
||||
data-tooltip-interaction-enabled="true"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{% apply spaceless %}
|
||||
<div style="height:250px;width:100%" class="dashboard_chart" id="my_chart_{{ oUIBlock.sChartId }}{{ oUIBlock.iChartCounter }}">
|
||||
<div style="height:200px;line-height:200px;vertical-align:center;text-align:center;width:100%">
|
||||
<img src="../images/indicator.gif">
|
||||
<img src="{{ get_absolute_url_app_root() }}images/indicator.gif">
|
||||
</div>
|
||||
</div>
|
||||
{% endapply %}
|
||||
@@ -22,7 +22,7 @@ use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
function LogResult($sString)
|
||||
{
|
||||
file_put_contents(APPROOT.'data/queries.results.log', "\n".$sString, FILE_APPEND);
|
||||
file_put_contents(utils::GetDataPath().'queries.results.log', "\n".$sString, FILE_APPEND);
|
||||
}
|
||||
|
||||
function LogBenchmarkCSV()
|
||||
@@ -40,7 +40,7 @@ function LogBenchmarkCSV()
|
||||
}
|
||||
}
|
||||
$sLine = implode(';', $aValues); // the preferred for MS Excel
|
||||
file_put_contents(APPROOT.'data/queries.benchmark.csv', "\n".$sLine, FILE_APPEND);
|
||||
file_put_contents(utils::GetDataPath().'queries.benchmark.csv', "\n".$sLine, FILE_APPEND);
|
||||
}
|
||||
|
||||
class QueryLogEntry
|
||||
@@ -311,8 +311,8 @@ case 'check':
|
||||
case 'benchmark':
|
||||
$oP->add("<h2>Create data/queries.xxx reports</h2>\n");
|
||||
// Reset the log contents
|
||||
file_put_contents(APPROOT.'data/queries.results.log', date('Y-m-d H:i:s')."\n");
|
||||
file_put_contents(APPROOT.'data/queries.benchmark.csv', '');
|
||||
file_put_contents(utils::GetDataPath().'queries.results.log', date('Y-m-d H:i:s')."\n");
|
||||
file_put_contents(utils::GetDataPath().'queries.benchmark.csv', '');
|
||||
LogBenchmarkCSV('type', 'properties', 'make duration', 'class', 'tables', 'query length', 'exec duration', 'rows', 'oql');
|
||||
|
||||
$iErrors = 0;
|
||||
|
||||
@@ -36,7 +36,7 @@ class TestsRunStartHook implements BeforeFirstTestHook, AfterLastTestHook
|
||||
{
|
||||
// Note: This can't be put in the cache-<ENV> folder as we have multiple <ENV> running across the test cases
|
||||
// We also don't want to put it in the unit tests folder as it is not supposed to be writable
|
||||
return APPROOT.'data/.php-unit-tests-run-started';
|
||||
return utils::GetDataPath().'.php-unit-tests-run-started';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user