N°589 - Portal: Displaying a better error message when the portal crashes because the current contact's organization is not among the current user's allowed organizations. More over we introduced an exception handler to display a nicer web page and log the exception in the error log.

SVN:trunk[4557]
This commit is contained in:
Guillaume Lajarige
2017-02-23 10:07:12 +00:00
parent 9fa6157c37
commit 0d3203476c
3 changed files with 167 additions and 2 deletions

View File

@@ -0,0 +1,146 @@
<?php
// Copyright (C) 2010-2015 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
// along with iTop. If not, see <http://www.gnu.org/licenses/>
namespace Combodo\iTop\Portal\Handler;
use \Exception;
use \Silex\Application;
use \Symfony\Component\Debug\ExceptionHandler as BaseExceptionHandler;
use \Symfony\Component\Debug\Exception\FlattenException;
use \Symfony\Component\HttpFoundation\Request;
use \IssueLog;
use \Dict;
/**
* Extends the default ExceptionHandler to provide a better template.
*
* @author Guillaume Lajarige
*/
class ExceptionHandler extends BaseExceptionHandler
{
private $debug;
private $charset;
private $handler;
private $caughtBuffer;
private $caughtLength;
private $fileLinkFormat;
/**
* Sends a response for the given Exception.
*
* To be as fail-safe as possible, the exception is first handled
* by our simple exception handler, then by the user exception handler.
* The latter takes precedence and any output from the former is cancelled,
* if and only if nothing bad happens in this handling path.
*/
public function handle(\Exception $exception)
{
IssueLog::Error('Portal: '.$exception->getMessage());
parent::handle($exception);
}
/**
* Gets the HTML content associated with the given exception.
*
* @param FlattenException $exception A FlattenException instance
*
* @return string The content as a string
*/
public function getContent(FlattenException $exception)
{
switch ($exception->getStatusCode()) {
case 404:
$title = Dict::S('Error:HTTP:404');
break;
default:
$title = Dict::S('Error:HTTP:500');
}
$content = '';
if ($this->debug) {
try {
$count = count($exception->getAllPrevious());
$total = $count + 1;
foreach ($exception->toArray() as $position => $e) {
$ind = $count - $position + 1;
$class = $this->formatClass($e['class']);
$message = nl2br($this->escapeHtml($e['message']));
$content .= sprintf(<<<EOF
<h2 class="block_exception clear_fix">
<span class="exception_counter">%d/%d</span>
<span class="exception_title">%s%s:</span>
<span class="exception_message">%s</span>
</h2>
<div class="block">
<ol class="traces list_exception">
EOF
, $ind, $total, $class, $this->formatPath($e['trace'][0]['file'], $e['trace'][0]['line']), $message);
foreach ($e['trace'] as $trace) {
$content .= ' <li>';
if ($trace['function']) {
$content .= sprintf('at %s%s%s(%s)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
}
if (isset($trace['file']) && isset($trace['line'])) {
$content .= $this->formatPath($trace['file'], $trace['line']);
}
$content .= "</li>\n";
}
$content .= " </ol>\n</div>\n";
}
} catch (\Exception $e) {
// something nasty happened and we cannot throw an exception anymore
if ($this->debug) {
$title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $this->escapeHtml($e->getMessage()));
} else {
$title = 'Whoops, looks like something went wrong.';
}
}
}
else{
$content = $exception->getMessage();
}
return <<<EOF
<div id="sf-resetcontent" class="sf-reset">
<h1>$title</h1>
<div class="content">$content</div>
</div>
EOF;
}
/**
* Gets the stylesheet associated with the given exception.
*
* @param FlattenException $exception A FlattenException instance
*
* @return string The stylesheet as a string
*/
public function getStylesheet(FlattenException $exception)
{
$parentStylesheet = parent::getStylesheet($exception);
$stylesheet = <<<EOF
.sf-reset .content{ background-color: #FFFFFF; padding: 15px 28px; margin-bottom: 20px; -webkit-border-radius: 10px; -moz-border-radius: 10px; border-radius: 10px; border: 1px solid #ccc; font-size: 13px; }
EOF;
return $stylesheet . $parentStylesheet;
}
}

View File

@@ -22,7 +22,8 @@ namespace Combodo\iTop\Portal\Helper;
use \Exception;
use \Silex\Application;
use \Symfony\Component\Debug\ErrorHandler;
use \Symfony\Component\Debug\ExceptionHandler;
//use \Symfony\Component\Debug\ExceptionHandler;
use \Combodo\iTop\Portal\Handler\ExceptionHandler;
use \Symfony\Component\HttpFoundation\Request;
use \Twig_SimpleFilter;
use \Dict;
@@ -248,9 +249,11 @@ class ApplicationHelper
*/
static function RegisterExceptionHandler(Application $oApp)
{
// Intercepting fatal errors and exceptions
ErrorHandler::register();
ExceptionHandler::register(($oApp['debug'] === true));
// Intercepting manually aborted request
if (!$oApp['debug'])
{
$oApp->error(function(Exception $e, $code) use ($oApp)
@@ -489,7 +492,22 @@ class ApplicationHelper
// Contact
$sContactPhotoUrl = $oApp['combodo.portal.base.absolute_url'] . 'img/user-profile-default-256px.png';
$oContact = UserRights::GetContactObject();
// - Checking if we can load the contact
try{
$oContact = UserRights::GetContactObject();
}
catch(Exception $e)
{
$oAllowedOrgSet = $oUser->Get('allowed_org_list');
if($oAllowedOrgSet->Count() > 0)
{
throw new Exception('Could not load contact related to connected user. (Tip: Make sure the contact\'s organization is among the user\'s allowed organizations)');
}
else{
throw new Exception('Could not load contact related to connected user.');
}
}
// - Retrieving picture
if ($oContact)
{
if (MetaModel::IsValidAttCode(get_class($oContact), 'picture'))

View File

@@ -31,6 +31,7 @@ require_once APPROOT . '/core/moduledesign.class.inc.php';
require_once APPROOT . '/application/loginwebpage.class.inc.php';
require_once APPROOT . '/sources/autoload.php';
// Portal
require_once __DIR__ . '/../src/handlers/exceptionhandler.class.inc.php';
require_once __DIR__ . '/../src/providers/urlgeneratorserviceprovider.class.inc.php';
require_once __DIR__ . '/../src/helpers/urlgeneratorhelper.class.inc.php';
require_once __DIR__ . '/../src/providers/contextmanipulatorserviceprovider.class.inc.php';