From 32aa962138fa05bee64ee34a0faeccb40d58083c Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Fri, 20 Mar 2015 17:20:34 -0400 Subject: [PATCH] Fixed error logging and refactored ErrorController to get invoked correctly when using API key authentication * Along with the bugfixes, backported improved ErrorController from upstream branch, including style improvements. --- airtime_mvc/application/Bootstrap.php | 1 + .../controllers/ErrorController.php | 98 ++++++++++++++---- .../controllers/ProvisioningController.php | 6 +- .../controllers/plugins/Acl_plugin.php | 13 ++- .../views/scripts/error/error-400.phtml | 18 ++++ .../views/scripts/error/error-403.phtml | 18 ++++ .../views/scripts/error/error-500.phtml | 18 ++++ .../views/scripts/error/error.phtml | 3 +- airtime_mvc/public/css/images/maintenance.png | Bin 0 -> 14597 bytes airtime_mvc/public/css/styles.css | 39 ++++--- 10 files changed, 166 insertions(+), 48 deletions(-) create mode 100644 airtime_mvc/application/views/scripts/error/error-400.phtml create mode 100644 airtime_mvc/application/views/scripts/error/error-403.phtml create mode 100644 airtime_mvc/application/views/scripts/error/error-500.phtml create mode 100644 airtime_mvc/public/css/images/maintenance.png diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index b3ba22263..57ff42b0d 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -52,6 +52,7 @@ Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance()); $front = Zend_Controller_Front::getInstance(); $front->registerPlugin(new RabbitMqPlugin()); +$front->throwExceptions(false); //localization configuration Application_Model_Locale::configureLocalization(); diff --git a/airtime_mvc/application/controllers/ErrorController.php b/airtime_mvc/application/controllers/ErrorController.php index 70829db63..8a62d9ea6 100644 --- a/airtime_mvc/application/controllers/ErrorController.php +++ b/airtime_mvc/application/controllers/ErrorController.php @@ -1,26 +1,40 @@ view->layout()->disableLayout(); + $this->setupCSS(); + + } + + public function errorAction() { $errors = $this->_getParam('error_handler'); - switch ($errors->type) { - case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE: - case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER: - case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION: + if ($errors) { + // log error message and stack trace + Logging::error($errors->exception->getMessage()); + Logging::error($errors->exception->getTraceAsString()); - // 404 error -- controller or action not found - $this->getResponse()->setHttpResponseCode(404); - $this->view->message = _('Page not found'); - break; - default: - // application error - $this->getResponse()->setHttpResponseCode(500); - $this->view->message = _('Application error'); - break; + switch ($errors->type) { + case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE : + case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER : + $this->error404Action(); + break; + case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION : + $this->error400Action(); + break; + default : + $this->error500Action(); + break; + } + } else { + $exceptions = $this->_getAllParams(); + Logging::error($exceptions); + $this->error500Action(); + return; } // Log exception, if logger available @@ -33,11 +47,17 @@ class ErrorController extends Zend_Controller_Action $this->view->exception = $errors->exception; } - $this->view->request = $errors->request; + $this->view->request = $errors->request; } - public function getLog() + private function setupCSS() { + $CC_CONFIG = Config::getConfig(); + $staticBaseDir = Application_Common_OsPath::formatDirectoryWithDirectorySeparators($CC_CONFIG['staticBaseDir']); + $this->view->headLink()->appendStylesheet($staticBaseDir . 'css/styles.css?' . $CC_CONFIG['airtime_version']); + } + + public function getLog() { $bootstrap = $this->getInvokeArg('bootstrap'); if (!$bootstrap->hasPluginResource('Log')) { return false; @@ -47,9 +67,43 @@ class ErrorController extends Zend_Controller_Action return $log; } - public function deniedAction() - { - // action body + /** + * 404 error - route or controller + */ + public function error404Action() { + $this->_helper->viewRenderer('error-404'); + $this->getResponse()->setHttpResponseCode(404); + $this->view->message = _('Page not found.'); } + /** + * 400 error - no such action + */ + public function error400Action() { + $this->_helper->viewRenderer('error-400'); + $this->getResponse()->setHttpResponseCode(400); + $this->view->message = _('The requested action is not supported.'); + + } + + /** + * 403 error - permission denied + */ + public function error403Action() { + + $this->_helper->viewRenderer('error-403'); + $this->getResponse()->setHttpResponseCode(403); + $this->view->message = _('You do not have permission to access this resource.'); + } + + /** + * 500 error - internal server error + */ + public function error500Action() { + + $this->_helper->viewRenderer('error-500'); + + $this->getResponse()->setHttpResponseCode(500); + $this->view->message = _('An internal application error has occurred.'); + } } diff --git a/airtime_mvc/application/controllers/ProvisioningController.php b/airtime_mvc/application/controllers/ProvisioningController.php index 0ecd185d2..4aa02fa39 100644 --- a/airtime_mvc/application/controllers/ProvisioningController.php +++ b/airtime_mvc/application/controllers/ProvisioningController.php @@ -26,7 +26,7 @@ class ProvisioningController extends Zend_Controller_Action $this->view->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); - if (!RestAuth::verifyAuth(true, true, $this)) { + if (!RestAuth::verifyAuth(true, false, $this)) { return; } @@ -65,12 +65,12 @@ class ProvisioningController extends Zend_Controller_Action } $CC_CONFIG = Config::getConfig(); - + foreach ($CC_CONFIG["supportedStorageBackends"] as $storageBackend) { $proxyStorageBackend = new ProxyStorageBackend($storageBackend); $proxyStorageBackend->deleteAllCloudFileObjects(); } - + $this->getResponse() ->setHttpResponseCode(200) ->appendBody("OK"); diff --git a/airtime_mvc/application/controllers/plugins/Acl_plugin.php b/airtime_mvc/application/controllers/plugins/Acl_plugin.php index 10910fb73..7ea1336d0 100644 --- a/airtime_mvc/application/controllers/plugins/Acl_plugin.php +++ b/airtime_mvc/application/controllers/plugins/Acl_plugin.php @@ -28,7 +28,7 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract { $this->_errorPage = array('module' => 'default', 'controller' => 'error', - 'action' => 'denied'); + 'action' => 'error'); $this->_roleName = $roleName; @@ -111,7 +111,16 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract $controller = strtolower($request->getControllerName()); Application_Model_Auth::pinSessionToClient(Zend_Auth::getInstance()); - if (in_array($controller, array("api", "auth", "locale", "upgrade", 'whmcs-login', "provisioning"))) { + if (in_array($controller, array( + "api", + "auth", + "error", + "locale", + "upgrade", + 'whmcs-login', + "provisioning" + ))) + { $this->setRoleName("G"); } elseif (!Zend_Auth::getInstance()->hasIdentity()) { diff --git a/airtime_mvc/application/views/scripts/error/error-400.phtml b/airtime_mvc/application/views/scripts/error/error-400.phtml new file mode 100644 index 000000000..329b55228 --- /dev/null +++ b/airtime_mvc/application/views/scripts/error/error-400.phtml @@ -0,0 +1,18 @@ + + + + + <?php echo _("An error has occurred.") ?> + headLink(); ?> + + +
+

+

+
+ +
+
+ + diff --git a/airtime_mvc/application/views/scripts/error/error-403.phtml b/airtime_mvc/application/views/scripts/error/error-403.phtml new file mode 100644 index 000000000..0e8d781fd --- /dev/null +++ b/airtime_mvc/application/views/scripts/error/error-403.phtml @@ -0,0 +1,18 @@ + + + + + <?php echo _("An error has occurred.") ?> + headLink(); ?> + + +
+

+

+
+ +
+
+ + diff --git a/airtime_mvc/application/views/scripts/error/error-500.phtml b/airtime_mvc/application/views/scripts/error/error-500.phtml new file mode 100644 index 000000000..fe5bd9f39 --- /dev/null +++ b/airtime_mvc/application/views/scripts/error/error-500.phtml @@ -0,0 +1,18 @@ + + + + + <?php echo _("An error has occurred.") ?> + headLink(); ?> + + +
+

+

+
+ +
+
+ + diff --git a/airtime_mvc/application/views/scripts/error/error.phtml b/airtime_mvc/application/views/scripts/error/error.phtml index 4c5146296..7a17ae7c6 100644 --- a/airtime_mvc/application/views/scripts/error/error.phtml +++ b/airtime_mvc/application/views/scripts/error/error.phtml @@ -3,7 +3,8 @@ - <?php echo _("Zend Framework Default Application") ?> + <?php echo _("An error has occurred.") ?> + headLink(); ?>
diff --git a/airtime_mvc/public/css/images/maintenance.png b/airtime_mvc/public/css/images/maintenance.png new file mode 100644 index 0000000000000000000000000000000000000000..0a000c6c6a68df65086a5f99fcaa471195c197f1 GIT binary patch literal 14597 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