mirror of
https://github.com/Combodo/iTop.git
synced 2026-06-20 14:56:36 +02:00
Compare commits
5 Commits
feature/un
...
feature/lo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3244658686 | ||
|
|
67792155dd | ||
|
|
806a5b92df | ||
|
|
7d0005acf3 | ||
|
|
9c782c41df |
@@ -5,7 +5,9 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class CoreException extends Exception
|
||||
use Combodo\iTop\Exception\ItopException;
|
||||
|
||||
class CoreException extends ItopException
|
||||
{
|
||||
protected $m_sIssue;
|
||||
protected $m_sImpact;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\Helper\ExceptionHandlerHelper;
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Service\Startup\StartupService;
|
||||
|
||||
@@ -64,6 +65,9 @@ register_shutdown_function(function () {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
set_exception_handler([ExceptionHandlerHelper::class, 'HandleException']);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
Session::Start();
|
||||
$oKPI->ComputeAndReport("Session Start");
|
||||
|
||||
@@ -614,6 +614,12 @@ class LogChannels
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public const SECURITY = 'Security';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public const EXCEPTION = 'Exception';
|
||||
}
|
||||
|
||||
abstract class LogAPI
|
||||
@@ -708,8 +714,14 @@ abstract class LogAPI
|
||||
|
||||
private static function PrepareErrorLog(string $sMessage, throwable $oException, array $aContext, bool $isPrevious = false): array
|
||||
{
|
||||
$aContext['Error Message'] = $oException->getMessage();
|
||||
$aContext['Stack Trace'] = $oException->getTraceAsString();
|
||||
$aContext['exception'] = get_class($oException);
|
||||
$aContext['message'] = $oException->getMessage();
|
||||
$aContext['stack'] = $oException->getTraceAsString();
|
||||
|
||||
if(method_exists($oException, 'GetContext')) {
|
||||
$aContext = array_merge($aContext, $oException->GetContext());
|
||||
}
|
||||
|
||||
return ['message' => ($isPrevious ? "Previous " : '')."Exception: $sMessage", 'context' => $aContext];
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,11 @@ use Combodo\iTop\CoreUpdate\Service\CoreUpdater;
|
||||
use Combodo\iTop\DBTools\Service\DBToolsUtils;
|
||||
use Combodo\iTop\FilesInformation\Service\FileNotExistException;
|
||||
use Combodo\iTop\FilesInformation\Service\FilesInformation;
|
||||
use Config;
|
||||
use ContextTag;
|
||||
use Dict;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use RunTimeEnvironment;
|
||||
use SecurityException;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
@@ -232,29 +230,6 @@ class AjaxController extends Controller
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
public function OperationRebuildToolkitEnvironment()
|
||||
{
|
||||
$sTransactionId = utils::GetNewTransactionId();
|
||||
$aParams = [];
|
||||
$aParams['sTransactionId'] = $sTransactionId;
|
||||
$aParams['bStatus'] = true;
|
||||
|
||||
$iResponseCode = 200;
|
||||
try {
|
||||
$aParams['sAjaxURL'] = utils::GetAbsoluteUrlAppRoot().'/pages/UI.php';
|
||||
$oConfig = new Config(APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE);
|
||||
$oEnvironment = new RunTimeEnvironment(ITOP_DEFAULT_ENV);
|
||||
$oEnvironment->WriteConfigFileSafe($oConfig);
|
||||
$oEnvironment->CompileFrom(ITOP_DEFAULT_ENV);
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Error('RebuildToolkitEnvironment: '.$e->getMessage());
|
||||
$aParams['sError'] = $e->getMessage();
|
||||
$iResponseCode = 500;
|
||||
$aParams['bStatus'] = false;
|
||||
}
|
||||
$this->DisplayJSONPage($aParams, $iResponseCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \SecurityException if CSRF token invalid
|
||||
*
|
||||
|
||||
@@ -90,13 +90,6 @@
|
||||
{% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl} %}
|
||||
{% UIButton ForDestructiveAction {'sLabel':'iTopUpdate:UI:SetupLaunch'|dict_s, 'sName':'launch-setup', 'sValue':'launch-setup', 'bIsSubmit':true, 'sId':'launch-setup'} %}
|
||||
{% EndUIForm %}
|
||||
{% UIAlert ForInformation {sId:'fast-setup-alert', AddCSSClass:'ibo-is-hidden'} %}
|
||||
{% UIContentBlock Standard {sId:'fast-setup-content', aContainerClasses:['ibo-fast-setup-content']} %}
|
||||
{{ 'iTopUpdate:UI:SetupMessage:Compile'|dict_s }}
|
||||
{% EndUIContentBlock %}
|
||||
{% EndUIAlert %}
|
||||
{% UIButton ForDestructiveAction {sLabel:'iTopUpdate:UI:FastSetupLaunch'|dict_s, sName:'launch-fast-setup', sValue:'launch-fast-setup', sId:'launch-fast-setup'} %}
|
||||
{% UISpinner Standard {sId:'fast-setup-wait', IsHidden:true} %}
|
||||
{% EndUIFieldSet %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -116,51 +116,4 @@ $("#launch-setup-form").on("submit", function () {
|
||||
return window.confirm("{{ 'iTopUpdate:UI:SetupLaunchConfirm'|dict_s }}");
|
||||
});
|
||||
|
||||
$("#launch-fast-setup").on("click", function(e) {
|
||||
var oMessage = $("#fast-setup-alert");
|
||||
var oContent = $("#fast-setup-content");
|
||||
oMessage.removeClass("ibo-is-hidden");
|
||||
oMessage.removeClass("ibo-is-failure");
|
||||
oMessage.removeClass("ibo-is-success");
|
||||
oMessage.addClass("ibo-is-information");
|
||||
oContent.html("{{ 'iTopUpdate:UI:SetupMessage:Compile'|dict_s }}");
|
||||
|
||||
let fast_setup_wait = $("#fast-setup-wait");
|
||||
fast_setup_wait.removeClass("ibo-is-hidden");
|
||||
$(this).prop("disabled", true);
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: "{{ sAjaxURL|raw }}",
|
||||
data: {
|
||||
route: "core_update_ajax.rebuild_toolkit_environment"
|
||||
},
|
||||
dataType: "json",
|
||||
complete: function(jqXHR, textStatus) {
|
||||
$("#fast-setup-wait").addClass("ibo-is-hidden");
|
||||
$("#launch-fast-setup").prop("disabled", false);
|
||||
fast_setup_wait.addClass("ibo-is-hidden");
|
||||
},
|
||||
success: function (data) {
|
||||
oMessage.removeClass("ibo-is-information");
|
||||
|
||||
if (data.bStatus) {
|
||||
oMessage.removeClass("ibo-is-failure");
|
||||
oMessage.addClass("ibo-is-success");
|
||||
oContent.html("{{ 'iTopUpdate:UI:SetupMessage:UpdateDone'|dict_s }}");
|
||||
} else {
|
||||
oMessage.removeClass("ibo-is-success");
|
||||
oMessage.addClass("ibo-is-failure");
|
||||
oContent.html(data.sError);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown) {
|
||||
oMessage.removeClass("ibo-is-information");
|
||||
oMessage.removeClass("ibo-is-success");
|
||||
oMessage.addClass("ibo-is-failure");
|
||||
oContent.html(textStatus + ' ' + errorThrown);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -133,6 +133,7 @@ return array(
|
||||
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => $baseDir . '/sources/Application/EventRegister/ApplicationEvents.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\BulkHelper' => $baseDir . '/sources/Application/Helper/BulkHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => $baseDir . '/sources/Application/Helper/CKEditorHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ExceptionHandlerHelper' => $baseDir . '/sources/Application/Helper/ExceptionHandlerHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => $baseDir . '/sources/Application/Helper/ExportHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\FormHelper' => $baseDir . '/sources/Application/Helper/FormHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ImportHelper' => $baseDir . '/sources/Application/Helper/ImportHelper.php',
|
||||
@@ -446,6 +447,7 @@ return array(
|
||||
'Combodo\\iTop\\Dependencies\\NPM\\iTopNPM' => $baseDir . '/sources/Dependencies/NPM/iTopNPM.php',
|
||||
'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php',
|
||||
'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php',
|
||||
'Combodo\\iTop\\Exception\\ItopException' => $baseDir . '/sources/Exception/ItopException.php',
|
||||
'Combodo\\iTop\\Form\\Field\\AbstractSimpleField' => $baseDir . '/sources/Form/Field/AbstractSimpleField.php',
|
||||
'Combodo\\iTop\\Form\\Field\\BlobField' => $baseDir . '/sources/Form/Field/BlobField.php',
|
||||
'Combodo\\iTop\\Form\\Field\\CaseLogField' => $baseDir . '/sources/Form/Field/CaseLogField.php',
|
||||
|
||||
@@ -534,6 +534,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
|
||||
'Combodo\\iTop\\Application\\EventRegister\\ApplicationEvents' => __DIR__ . '/../..' . '/sources/Application/EventRegister/ApplicationEvents.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\BulkHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/BulkHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\CKEditorHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/CKEditorHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ExceptionHandlerHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ExceptionHandlerHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ExportHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ExportHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\FormHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/FormHelper.php',
|
||||
'Combodo\\iTop\\Application\\Helper\\ImportHelper' => __DIR__ . '/../..' . '/sources/Application/Helper/ImportHelper.php',
|
||||
@@ -847,6 +848,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685
|
||||
'Combodo\\iTop\\Dependencies\\NPM\\iTopNPM' => __DIR__ . '/../..' . '/sources/Dependencies/NPM/iTopNPM.php',
|
||||
'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
|
||||
'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
|
||||
'Combodo\\iTop\\Exception\\ItopException' => __DIR__ . '/../..' . '/sources/Exception/ItopException.php',
|
||||
'Combodo\\iTop\\Form\\Field\\AbstractSimpleField' => __DIR__ . '/../..' . '/sources/Form/Field/AbstractSimpleField.php',
|
||||
'Combodo\\iTop\\Form\\Field\\BlobField' => __DIR__ . '/../..' . '/sources/Form/Field/BlobField.php',
|
||||
'Combodo\\iTop\\Form\\Field\\CaseLogField' => __DIR__ . '/../..' . '/sources/Form/Field/CaseLogField.php',
|
||||
|
||||
38
pages/UI.php
38
pages/UI.php
@@ -20,12 +20,12 @@ use Combodo\iTop\Application\UI\Base\Component\Toolbar\ToolbarUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Application\WelcomePopup\WelcomePopupService;
|
||||
use Combodo\iTop\Controller\Base\Layout\ObjectController;
|
||||
use Combodo\iTop\Controller\WelcomePopupController;
|
||||
use Combodo\iTop\Exception\ItopException;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
|
||||
/**
|
||||
@@ -1321,37 +1321,7 @@ try {
|
||||
$oKPI->ComputeAndReport('Compute page');
|
||||
$oP->output();
|
||||
} catch (Exception $e) {
|
||||
$oErrorPage = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
if ($e instanceof SecurityException) {
|
||||
$oErrorPage->add("<h1>".Dict::S('UI:SystemIntrusion')."</h1>\n");
|
||||
} else {
|
||||
$oErrorPage->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
|
||||
}
|
||||
$sErrorDetails = ($e instanceof CoreException) ? $e->getHtmlDesc() : $e->getMessage();
|
||||
$oErrorPage->error(Dict::Format('UI:Error_Details', utils::EscapeHtml($sErrorDetails)), $e);
|
||||
$oErrorPage->output();
|
||||
|
||||
$sErrorStackTrace = ($e instanceof CoreException) ? $e->getFullStackTraceAsString() : $e->getTraceAsString();
|
||||
if (MetaModel::IsLogEnabledIssue()) {
|
||||
if (MetaModel::IsValidClass('EventIssue')) {
|
||||
try {
|
||||
$oLog = new EventIssue();
|
||||
|
||||
$oLog->Set('message', $e->getMessage());
|
||||
$oLog->Set('userinfo', '');
|
||||
$sIssue = ($e instanceof CoreException) ? $e->GetIssue() : 'PHP Exception';
|
||||
$oLog->Set('issue', $sIssue);
|
||||
$oLog->Set('impact', 'Page could not be displayed');
|
||||
$oLog->Set('callstack', $sErrorStackTrace);
|
||||
$aData = ($e instanceof CoreException) ? $e->getContextData() : [];
|
||||
$oLog->Set('data', $aData);
|
||||
$oLog->DBInsertNoReload();
|
||||
} catch (Exception $e) {
|
||||
IssueLog::Exception("Failed to log issue into the DB", $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sOperationToLog = $operation ?? 'N/A';
|
||||
IssueLog::Debug('UI.php operation='.$sOperationToLog.', error='.$e->getMessage()."\n".$sErrorStackTrace, LogChannels::CONSOLE);
|
||||
throw new ItopException("Unable to handle UI operation", previous: $e, aContext: [
|
||||
'operation' => ($operation ?? 'N/A'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -124,6 +124,7 @@ require_once('./xmldataloader.class.inc.php');
|
||||
// Never cache this page
|
||||
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
|
||||
header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
|
||||
$oCtx = new ContextTag(ContextTag::TAG_SETUP);
|
||||
|
||||
/**
|
||||
* Main program
|
||||
|
||||
@@ -61,6 +61,7 @@ if (!function_exists('json_decode')) {
|
||||
//N°3671 setup context: force $bForceTrustProxy to be persisted in next calls
|
||||
utils::GetAbsoluteUrlAppRoot(true);
|
||||
$oWizard = new WizardController('WizStepWelcome');
|
||||
$oCtx = new ContextTag(ContextTag::TAG_SETUP);
|
||||
//N°3952
|
||||
if (SetupUtils::IsSessionSetupTokenValid()) {
|
||||
// Normal operation
|
||||
|
||||
@@ -196,6 +196,8 @@ class WizardController
|
||||
SetupLog::Info("=== Setup screen: ".$oStep->GetTitle().' ('.get_class($oStep).')');
|
||||
$oPage = new SetupPage($oStep->GetTitle());
|
||||
$oPage->LinkScriptFromAppRoot('setup/setup.js');
|
||||
$oStep->PreFormDisplay($oPage);
|
||||
|
||||
$oPage->add('<form id="wiz_form" class="ibo-setup--wizard" method="post">');
|
||||
$oPage->add('<div class="ibo-setup--wizard--content">');
|
||||
$oStep->Display($oPage);
|
||||
@@ -263,8 +265,8 @@ EOF
|
||||
$oPage->output();
|
||||
}
|
||||
/**
|
||||
* Make the wizard run: Start, Next or Back depending WizardUpdateButtons();
|
||||
on the page's parameters
|
||||
* Make the wizard run: 'Start', 'Next' or 'Back' depending WizardUpdateButtons();
|
||||
* on the page's parameters
|
||||
*/
|
||||
public function Run()
|
||||
{
|
||||
|
||||
@@ -52,6 +52,17 @@ class WizStepLandingBeforeAudit extends WizStepModulesChoice
|
||||
*/
|
||||
public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState
|
||||
{
|
||||
if ($this->oWizard->GetParameter('skip_wizard', false)) {
|
||||
$oRuntimeEnv = new RunTimeEnvironment();
|
||||
$sBuildConfigFile = APPCONF.$oRuntimeEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE;
|
||||
$oConfig = new Config($sBuildConfigFile);
|
||||
$oExtensionMap = iTopExtensionsMap::GetExtensionsMap($oRuntimeEnv->GetBuildEnv());
|
||||
$aExtensionsFromDatabase = $oExtensionMap->GetChoicesFromDatabase($oConfig);
|
||||
$this->oWizard->SetParameter('selected_extensions', json_encode($aExtensionsFromDatabase));
|
||||
$adModulesFromDatabase = ModuleInstallationRepository::GetInstance()->ReadComputeInstalledModules($oConfig);
|
||||
$this->oWizard->SetParameter('selected_modules', json_encode(array_keys($adModulesFromDatabase)));
|
||||
}
|
||||
|
||||
$aWizardSteps = $this->GetWizardSteps();
|
||||
$this->oWizard->SetWizardSteps($aWizardSteps);
|
||||
$this->sCurrentState = count($aWizardSteps) - 1;
|
||||
|
||||
@@ -24,6 +24,15 @@
|
||||
class WizStepWelcome extends WizardStep
|
||||
{
|
||||
protected $bCanMoveForward;
|
||||
private array $aInfo;
|
||||
private array $aWarnings;
|
||||
private array $aErrors;
|
||||
|
||||
public function __construct(WizardController $oWizard, $sCurrentState)
|
||||
{
|
||||
parent::__construct($oWizard, $sCurrentState);
|
||||
$this->CheckInstallation();
|
||||
}
|
||||
|
||||
public function GetTitle()
|
||||
{
|
||||
@@ -66,39 +75,14 @@ class WizStepWelcome extends WizardStep
|
||||
EOF
|
||||
);
|
||||
$oPage->add('<h1>'.ITOP_APPLICATION.' Installation Wizard</h1>');
|
||||
$aResults = SetupUtils::CheckPhpAndExtensions();
|
||||
$this->bCanMoveForward = true;
|
||||
$aInfo = [];
|
||||
$aWarnings = [];
|
||||
$aErrors = [];
|
||||
foreach ($aResults as $oCheckResult) {
|
||||
switch ($oCheckResult->iSeverity) {
|
||||
case CheckResult::ERROR:
|
||||
$aErrors[] = $oCheckResult->sLabel;
|
||||
$this->bCanMoveForward = false;
|
||||
break;
|
||||
|
||||
case CheckResult::WARNING:
|
||||
$aWarnings[] = $oCheckResult->sLabel;
|
||||
break;
|
||||
|
||||
case CheckResult::INFO:
|
||||
$aInfo[] = $oCheckResult->sLabel;
|
||||
break;
|
||||
|
||||
case CheckResult::TRACE:
|
||||
SetupLog::Ok($oCheckResult->sLabel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$sStyle = 'style="display:none;overflow:auto;"';
|
||||
$sToggleButtons = '<button type="button" id="show_details" class="ibo-button ibo-is-alternative ibo-is-neutral" onclick="$(\'#details\').toggle(); $(this).toggle(); $(\'#hide_details\').toggle();"><span class="ibo-button--icon fa fa-caret-down"></span><span class="ibo-button--label">Show details</span></button><button type="button" id="hide_details" class="ibo-button ibo-is-alternative ibo-is-neutral" style="display:none;" onclick="$(\'#details\').toggle(); $(this).toggle(); $(\'#show_details\').toggle();"><span class="ibo-button--icon fa fa-caret-up"></span><span class="ibo-button--label">Hide details</span></button>';
|
||||
if (count($aErrors) > 0) {
|
||||
if (count($this->aErrors) > 0) {
|
||||
$sStyle = 'style="overflow:auto;"';
|
||||
$sTitle = count($aErrors).' Error(s), '.count($aWarnings).' Warning(s).';
|
||||
$sTitle = count($this->aErrors).' Error(s), '.count($this->aWarnings).' Warning(s).';
|
||||
$sH2Class = 'text-error';
|
||||
} elseif (count($aWarnings) > 0) {
|
||||
$sTitle = count($aWarnings).' Warning(s) '.$sToggleButtons;
|
||||
} elseif (count($this->aWarnings) > 0) {
|
||||
$sTitle = count($this->aWarnings).' Warning(s) '.$sToggleButtons;
|
||||
$sH2Class = 'text-warning';
|
||||
} else {
|
||||
$sTitle = 'Ok. '.$sToggleButtons;
|
||||
@@ -110,13 +94,13 @@ EOF
|
||||
<div id="details" $sStyle>
|
||||
HTML
|
||||
);
|
||||
foreach ($aErrors as $sText) {
|
||||
foreach ($this->aErrors as $sText) {
|
||||
$oPage->error($sText);
|
||||
}
|
||||
foreach ($aWarnings as $sText) {
|
||||
foreach ($this->aWarnings as $sText) {
|
||||
$oPage->warning($sText);
|
||||
}
|
||||
foreach ($aInfo as $sText) {
|
||||
foreach ($this->aInfo as $sText) {
|
||||
$oPage->ok($sText);
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
@@ -127,8 +111,68 @@ HTML
|
||||
$oPage->add_ready_script('CheckDirectoryConfFilesPermissions("'.utils::GetItopVersionWikiSyntax().'")');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add post display stuff to the setup screen
|
||||
* @param \SetupPage $oPage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function PostFormDisplay(SetupPage $oPage)
|
||||
{
|
||||
if ($this->bCanMoveForward) {
|
||||
$sBuildConfigFile = APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE;
|
||||
if (file_exists($sBuildConfigFile)) {
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<form method="post">
|
||||
<input type="hidden" name="_class" value="WizStepLandingBeforeAudit"/>
|
||||
<input type="hidden" name="operation" value="next"/>
|
||||
<input type="hidden" name="_params[skip_wizard]" value="1"/>
|
||||
<table style="width:100%;" class="ibo-setup--wizard--buttons-container">
|
||||
<tr>
|
||||
<td style="text-align: right"><button type="submit" class="ibo-button ibo-is-regular ibo-is-secondary">Keep current choices</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function CanMoveForward()
|
||||
{
|
||||
return $this->bCanMoveForward;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public function CheckInstallation(): void
|
||||
{
|
||||
$aResults = SetupUtils::CheckPhpAndExtensions();
|
||||
$this->bCanMoveForward = true;
|
||||
$this->aInfo = [];
|
||||
$this->aWarnings = [];
|
||||
$this->aErrors = [];
|
||||
foreach ($aResults as $oCheckResult) {
|
||||
switch ($oCheckResult->iSeverity) {
|
||||
case CheckResult::ERROR:
|
||||
$this->aErrors[] = $oCheckResult->sLabel;
|
||||
$this->bCanMoveForward = false;
|
||||
break;
|
||||
|
||||
case CheckResult::WARNING:
|
||||
$this->aWarnings[] = $oCheckResult->sLabel;
|
||||
break;
|
||||
|
||||
case CheckResult::INFO:
|
||||
$this->aInfo[] = $oCheckResult->sLabel;
|
||||
break;
|
||||
|
||||
case CheckResult::TRACE:
|
||||
SetupLog::Ok($oCheckResult->sLabel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ abstract class WizardStep
|
||||
{
|
||||
}
|
||||
|
||||
public function PreFormDisplay(SetupPage $oPage)
|
||||
{
|
||||
}
|
||||
|
||||
protected function CheckDependencies()
|
||||
{
|
||||
if (is_null($this->bDependencyCheck)) {
|
||||
|
||||
119
sources/Application/Helper/ExceptionHandlerHelper.php
Normal file
119
sources/Application/Helper/ExceptionHandlerHelper.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Application\Helper;
|
||||
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use IssueLog;
|
||||
use SimpleXMLElement;
|
||||
use Throwable;
|
||||
|
||||
class ExceptionHandlerHelper
|
||||
{
|
||||
public static array $aSupportedMimeTypes = [
|
||||
'application/json' => 'json',
|
||||
'application/xml' => 'xml',
|
||||
'text/html' => 'html',
|
||||
'text/plain' => 'text',
|
||||
];
|
||||
|
||||
public static function HandleException(Throwable $oException)
|
||||
{
|
||||
$aStatus = ob_get_status();
|
||||
if (count($aStatus) !== 0) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
// Log the exception
|
||||
IssueLog::Exception('Fatal error', $oException);
|
||||
|
||||
$mime = self::NegotiateMimeType();
|
||||
|
||||
if ($mime === null) {
|
||||
http_response_code(406);
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Vary: Accept');
|
||||
echo json_encode(['error' => 'Not Acceptable'], JSON_UNESCAPED_UNICODE);
|
||||
return;
|
||||
}
|
||||
|
||||
http_response_code(500);
|
||||
header("Content-Type: {$mime}; charset=utf-8");
|
||||
header('Vary: Accept');
|
||||
|
||||
$aData = [
|
||||
'error' => 'Fatal error',
|
||||
'message' => 'We are sorry, an unexpected error has occurred. Please try again later.',
|
||||
|
||||
];
|
||||
|
||||
switch (self::$aSupportedMimeTypes[$mime]) {
|
||||
case 'json':
|
||||
echo json_encode($aData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
break;
|
||||
|
||||
case 'xml':
|
||||
$oXml = new SimpleXMLElement('<response/>');
|
||||
array_walk_recursive($aData, function ($sValue, $sKey) use ($oXml) {
|
||||
$oXml->addChild((string)$sKey, htmlspecialchars((string)$sValue, ENT_QUOTES | ENT_XML1, 'UTF-8'));
|
||||
});
|
||||
echo $oXml->asXML();
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
// Create error page
|
||||
$oErrorPage = new ErrorPage('Fatal error');
|
||||
$oErrorPage->error('We are sorry, an unexpected error has occurred. Please try again later.<br><br>', $oException);
|
||||
$oErrorPage->output();
|
||||
break;
|
||||
|
||||
case 'text':
|
||||
echo "Fatal error\n";
|
||||
echo "We are sorry, an unexpected error has occurred. Please try again later.\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function NegotiateMimeType(): ?string
|
||||
{
|
||||
$supportedMimes = array_keys(self::$aSupportedMimeTypes);
|
||||
$acceptHeader = $_SERVER['HTTP_ACCEPT'] ?? '*/*';
|
||||
|
||||
if (trim($acceptHeader) === '' || $acceptHeader === '*/*') {
|
||||
return in_array('application/json', $supportedMimes, true) ? 'application/json' : $supportedMimes[0];
|
||||
}
|
||||
|
||||
$accepted = [];
|
||||
foreach (explode(',', $acceptHeader) as $part) {
|
||||
$part = trim($part);
|
||||
$q = 1.0;
|
||||
if (str_contains($part, ';')) {
|
||||
[$type, $params] = array_map('trim', explode(';', $part, 2));
|
||||
if (preg_match('/q=([0-9.]+)/', $params, $m)) {
|
||||
$q = (float)$m[1];
|
||||
}
|
||||
} else {
|
||||
$type = $part;
|
||||
}
|
||||
$accepted[] = ['type' => $type, 'q' => $q];
|
||||
}
|
||||
|
||||
usort($accepted, fn ($a, $b) => $b['q'] <=> $a['q']);
|
||||
|
||||
foreach ($accepted as $a) {
|
||||
foreach ($supportedMimes as $mime) {
|
||||
if ($a['type'] === $mime || $a['type'] === '*/*') {
|
||||
return $mime;
|
||||
}
|
||||
// Ex: application/* match application/json
|
||||
if (str_ends_with($a['type'], '/*')) {
|
||||
$prefix = explode('/', $a['type'])[0].'/';
|
||||
if (str_starts_with($mime, $prefix)) {
|
||||
return $mime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,6 @@ require_once APPROOT.'setup/setuppage.class.inc.php';
|
||||
use ApplicationMenu;
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\WebPage\AjaxPage;
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\iTopWebPage;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Controller\AbstractController;
|
||||
@@ -263,29 +262,29 @@ abstract class Controller extends AbstractController
|
||||
*/
|
||||
public function HandleOperation(): void
|
||||
{
|
||||
try {
|
||||
$this->CheckAccess();
|
||||
$this->m_sOperation = utils::ReadParam('operation', $this->sDefaultOperation);
|
||||
// try {
|
||||
$this->CheckAccess();
|
||||
$this->m_sOperation = utils::ReadParam('operation', $this->sDefaultOperation);
|
||||
|
||||
if ($this->CallOperation(utils::ToCamelCase($this->m_sOperation))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to unchanged names for compatibility
|
||||
if ($this->CallOperation($this->m_sOperation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->DisplayBadRequest();
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
|
||||
$oP->add(get_class($e).' : '.utils::EscapeHtml($e->GetMessage()));
|
||||
$oP->output();
|
||||
|
||||
IssueLog::Exception('HandleOperation failed for '.json_encode($this->m_sOperation), $e);
|
||||
if ($this->CallOperation(utils::ToCamelCase($this->m_sOperation))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to unchanged names for compatibility
|
||||
if ($this->CallOperation($this->m_sOperation)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->DisplayBadRequest();
|
||||
// } catch (Exception $e) {
|
||||
// http_response_code(500);
|
||||
// $oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
// $oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
|
||||
// $oP->add(get_class($e).' : '.utils::EscapeHtml($e->GetMessage()));
|
||||
// $oP->output();
|
||||
//
|
||||
// IssueLog::Exception('HandleOperation failed for '.json_encode($this->m_sOperation), $e);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
28
sources/Exception/ItopException.php
Normal file
28
sources/Exception/ItopException.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Combodo\iTop\Exception;
|
||||
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use LogChannels;
|
||||
use Throwable;
|
||||
|
||||
class ItopException extends Exception
|
||||
{
|
||||
private array $aContext;
|
||||
|
||||
public function __construct(string $message = '', int $code = 0, ?Throwable $previous = null, array $aContext = [])
|
||||
{
|
||||
$aContext['code'] = $code;
|
||||
IssueLog::Debug($message, LogChannels::EXCEPTION, $aContext);
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->aContext = $aContext;
|
||||
}
|
||||
|
||||
public function getContext(): array
|
||||
{
|
||||
return $this->aContext;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user