1
0
mirror of https://github.com/owncloudarchive/contacts.git synced 2024-12-10 21:24:33 +01:00

Implement HTTP Middleware

Intercept exceptions thrown and return suitable HTTP responses.
This commit is contained in:
Thomas Tanghus 2013-05-18 04:56:59 +02:00
parent f67d18b894
commit cab617f0e0
7 changed files with 134 additions and 27 deletions

View File

@ -149,10 +149,7 @@ OC.notify = function(params) {
OC.Contacts = OC.Contacts || { OC.Contacts = OC.Contacts || {
init:function() { init:function() {
if(oc_debug === true) { if(oc_debug === true) {
$.error = console.error; $.error = console.error;
$(document).ajaxError(function(e, xhr, settings, exception) {
console.error('Error in: ', settings.url, ' : ', xhr.responseText, exception);
});
} }
var self = this; var self = this;

View File

@ -2221,10 +2221,9 @@ OC.Contacts = OC.Contacts || {};
defer.reject(response); defer.reject(response);
} }
}) })
.fail(function(jqxhr, textStatus, error) { .fail(function(response) {
var err = textStatus + ', ' + error; console.warn('Request Failed:', response.message);
console.warn( "Request Failed: " + err); this.reject({error: true, message: response.message});
this.reject({error: true, message: err});
}); });
}; };

View File

@ -24,6 +24,15 @@ OC.Contacts = OC.Contacts || {};
} }
} }
$(document).ajaxError(function(e, xhr, settings, exception) {
console.error('Error in: ', settings.url, ' : ', xhr.responseText, exception);
var response = $.parseJSON(xhr.responseText);
console.log('response', response);
$(document).trigger('status.contact.error', {
message: response ? new JSONResponse(response, xhr).message : xhr.responseText
});
});
/** /**
* An object for saving contact data to backends * An object for saving contact data to backends
* *

View File

@ -25,8 +25,16 @@ namespace OCA\Contacts;
/** /**
* This class manages our addressbooks. * This class manages our addressbooks.
*/ */
class Addressbook extends AbstractPIMCollection { class Addressbook extends AbstractPIMCollection {
/**
* @brief language object
*
* @var OC_L10N
*/
public static $l10n;
protected $_count; protected $_count;
/** /**
* @var Backend\AbstractBackend * @var Backend\AbstractBackend
@ -52,12 +60,13 @@ class Addressbook extends AbstractPIMCollection {
* @param array $addressBookInfo * @param array $addressBookInfo
*/ */
public function __construct(Backend\AbstractBackend $backend, array $addressBookInfo) { public function __construct(Backend\AbstractBackend $backend, array $addressBookInfo) {
self::$l10n = \OC_L10N::get('contacts');
$this->backend = $backend; $this->backend = $backend;
$this->addressBookInfo = $addressBookInfo; $this->addressBookInfo = $addressBookInfo;
if(is_null($this->getId())) { if(is_null($this->getId())) {
$id = $this->backend->createAddressBook($addressBookInfo); $id = $this->backend->createAddressBook($addressBookInfo);
if($id === false) { if($id === false) {
throw new \Exception('Error creating address book.'); throw new \Exception('Error creating address book.', 500);
} }
$this->addressBookInfo = $this->backend->getAddressBook($id); $this->addressBookInfo = $this->backend->getAddressBook($id);
//print(__METHOD__. ' '. __LINE__ . ' addressBookInfo: ' . print_r($this->backend->getAddressBook($id), true)); //print(__METHOD__. ' '. __LINE__ . ' addressBookInfo: ' . print_r($this->backend->getAddressBook($id), true));
@ -127,7 +136,7 @@ class Addressbook extends AbstractPIMCollection {
function getChild($id) { function getChild($id) {
//\OCP\Util::writeLog('contacts', __METHOD__.' id: '.$id, \OCP\Util::DEBUG); //\OCP\Util::writeLog('contacts', __METHOD__.' id: '.$id, \OCP\Util::DEBUG);
if(!$this->hasPermission(\OCP\PERMISSION_READ)) { if(!$this->hasPermission(\OCP\PERMISSION_READ)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to see this contacts'), 403);
} }
if(!isset($this->objects[$id])) { if(!isset($this->objects[$id])) {
$contact = $this->backend->getContact($this->getId(), $id); $contact = $this->backend->getContact($this->getId(), $id);
@ -159,7 +168,7 @@ class Addressbook extends AbstractPIMCollection {
*/ */
function getChildren($limit = null, $offset = null, $omitdata = false) { function getChildren($limit = null, $offset = null, $omitdata = false) {
if(!$this->hasPermission(\OCP\PERMISSION_READ)) { if(!$this->hasPermission(\OCP\PERMISSION_READ)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to see these contacts'), 403);
} }
//\OCP\Util::writeLog('contacts', __METHOD__.' backend: ' . print_r($this->backend, true), \OCP\Util::DEBUG); //\OCP\Util::writeLog('contacts', __METHOD__.' backend: ' . print_r($this->backend, true), \OCP\Util::DEBUG);
$contacts = array(); $contacts = array();
@ -185,10 +194,10 @@ class Addressbook extends AbstractPIMCollection {
*/ */
public function addChild($data = null) { public function addChild($data = null) {
if(!$this->hasPermission(\OCP\PERMISSION_CREATE)) { if(!$this->hasPermission(\OCP\PERMISSION_CREATE)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions add contacts to the address book'), 403);
} }
if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_CREATE)) { if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_CREATE)) {
throw new \Exception('Not implemented'); throw new \Exception(self::$l10n('The backend for this address book does not support adding contacts'), 501);
} }
$contact = new Contact($this, $this->backend, $data); $contact = new Contact($this, $this->backend, $data);
if($contact->save() === false) { if($contact->save() === false) {
@ -210,10 +219,10 @@ class Addressbook extends AbstractPIMCollection {
*/ */
public function deleteChild($id) { public function deleteChild($id) {
if(!$this->hasPermission(\OCP\PERMISSION_DELETE)) { if(!$this->hasPermission(\OCP\PERMISSION_DELETE)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to delete this contact'), 403);
} }
if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_DELETE)) { if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_DELETE)) {
throw new \Exception('Not implemented'); throw new \Exception(self::$l10n('The backend for this address book does not support deleting contacts'), 501);
} }
if($this->backend->deleteContact($this->getId(), $id)) { if($this->backend->deleteContact($this->getId(), $id)) {
if(isset($this->objects[$id])) { if(isset($this->objects[$id])) {
@ -273,7 +282,7 @@ class Addressbook extends AbstractPIMCollection {
*/ */
public function save() { public function save() {
if(!$this->hasPermission(OCP\PERMISSION_UPDATE)) { if(!$this->hasPermission(OCP\PERMISSION_UPDATE)) {
throw new Exception('You don\'t have permissions to update the address book.'); throw new Exception(self::$l10n('You don\'t have permissions to update the address book.'), 403);
} }
} }
@ -284,7 +293,7 @@ class Addressbook extends AbstractPIMCollection {
*/ */
public function delete() { public function delete() {
if(!$this->hasPermission(OCP\PERMISSION_DELETE)) { if(!$this->hasPermission(OCP\PERMISSION_DELETE)) {
throw new Exception('You don\'t have permissions to delete the address book.'); throw new Exception(self::$l10n('You don\'t have permissions to delete the address book.'), 403);
} }
return $this->backend->deleteAddressBook($this->getId()); return $this->backend->deleteAddressBook($this->getId());
} }

View File

@ -42,6 +42,13 @@ class Contact extends VObject\VCard implements IPIMObject {
*/ */
public $name = 'VCARD'; public $name = 'VCARD';
/**
* @brief language object
*
* @var OC_L10N
*/
public static $l10n;
protected $props = array(); protected $props = array();
/** /**
@ -52,6 +59,7 @@ class Contact extends VObject\VCard implements IPIMObject {
* @param mixed $data * @param mixed $data
*/ */
public function __construct($parent, $backend, $data = null) { public function __construct($parent, $backend, $data = null) {
self::$l10n = $parent::$l10n;
//\OCP\Util::writeLog('contacts', __METHOD__ . ' parent: ' . print_r($parent, true) . ', backend: ' . print_r($backend, true) . ', data: ' . print_r($data, true), \OCP\Util::DEBUG); //\OCP\Util::writeLog('contacts', __METHOD__ . ' parent: ' . print_r($parent, true) . ', backend: ' . print_r($backend, true) . ', data: ' . print_r($data, true), \OCP\Util::DEBUG);
//\OCP\Util::writeLog('contacts', __METHOD__, \OCP\Util::DEBUG); //\OCP\Util::writeLog('contacts', __METHOD__, \OCP\Util::DEBUG);
$this->props['parent'] = $parent; $this->props['parent'] = $parent;
@ -101,7 +109,7 @@ class Contact extends VObject\VCard implements IPIMObject {
*/ */
public function getMetaData() { public function getMetaData() {
if(!$this->hasPermission(\OCP\PERMISSION_READ)) { if(!$this->hasPermission(\OCP\PERMISSION_READ)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to see this contacts'), 403);
} }
if(!isset($this->props['displayname'])) { if(!isset($this->props['displayname'])) {
if(!$this->retrieve()) { if(!$this->retrieve()) {
@ -148,7 +156,7 @@ class Contact extends VObject\VCard implements IPIMObject {
*/ */
function getDisplayName() { function getDisplayName() {
if(!$this->hasPermission(\OCP\PERMISSION_READ)) { if(!$this->hasPermission(\OCP\PERMISSION_READ)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to see this contacts'), 403);
} }
return isset($this->props['displayname']) ? $this->props['displayname'] : null; return isset($this->props['displayname']) ? $this->props['displayname'] : null;
} }
@ -231,7 +239,7 @@ class Contact extends VObject\VCard implements IPIMObject {
*/ */
public function delete() { public function delete() {
if(!$this->hasPermission(\OCP\PERMISSION_DELETE)) { if(!$this->hasPermission(\OCP\PERMISSION_DELETE)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to delete this contact'), 403);
} }
return $this->props['backend']->deleteContact( return $this->props['backend']->deleteContact(
$this->getParent()->getId(), $this->getParent()->getId(),
@ -246,7 +254,7 @@ class Contact extends VObject\VCard implements IPIMObject {
*/ */
public function save($force = false) { public function save($force = false) {
if(!$this->hasPermission(\OCP\PERMISSION_UPDATE)) { if(!$this->hasPermission(\OCP\PERMISSION_UPDATE)) {
throw new \Exception('Access denied'); throw new \Exception(self::$l10n('You do not have permissions to update this contact'), 403);
} }
if($this->isSaved() && !$force) { if($this->isSaved() && !$force) {
\OCP\Util::writeLog('contacts', __METHOD__.' Already saved: ' . print_r($this->props, true), \OCP\Util::DEBUG); \OCP\Util::writeLog('contacts', __METHOD__.' Already saved: ' . print_r($this->props, true), \OCP\Util::DEBUG);
@ -257,7 +265,7 @@ class Contact extends VObject\VCard implements IPIMObject {
} }
if($this->getId()) { if($this->getId()) {
if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_UPDATE)) { if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_UPDATE)) {
throw new \Exception('Not implemented'); throw new \Exception(self::$l10n('The backend for this contact does not support updating it'), 501);
} }
if($this->getBackend() if($this->getBackend()
->updateContact( ->updateContact(
@ -275,7 +283,7 @@ class Contact extends VObject\VCard implements IPIMObject {
} else { } else {
//print(__METHOD__.' ' . print_r($this->getParent(), true)); //print(__METHOD__.' ' . print_r($this->getParent(), true));
if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_CREATE)) { if(!$this->getBackend()->hasContactMethodFor(\OCP\PERMISSION_CREATE)) {
throw new \Exception('Not implemented'); throw new \Exception(self::$l10n('This not support adding contacts'), 501);
} }
$this->props['id'] = $this->getBackend()->createContact( $this->props['id'] = $this->getBackend()->createContact(
$this->getParent()->getId(), $this $this->getParent()->getId(), $this
@ -384,7 +392,7 @@ class Contact extends VObject\VCard implements IPIMObject {
} }
$idx += 1; $idx += 1;
} }
throw new Exception('Property not found', 404); throw new Exception(self::$l10n('Property not found'), 404);
} }
/** /**
@ -401,7 +409,7 @@ class Contact extends VObject\VCard implements IPIMObject {
return $property; return $property;
} }
} }
throw new \Exception('Property not found', 404); throw new \Exception(self::$l10n('Property not found'), 404);
} }
/** /**
@ -449,7 +457,7 @@ class Contact extends VObject\VCard implements IPIMObject {
break; break;
case 'IMPP': case 'IMPP':
if(is_null($parameters) || !isset($parameters['X-SERVICE-TYPE'])) { if(is_null($parameters) || !isset($parameters['X-SERVICE-TYPE'])) {
throw new \InvalidArgumentException(__METHOD__.' Missing IM parameter for: '.$name. ' ' . $value); throw new \InvalidArgumentException(self::$l10n(' Missing IM parameter for: ') . $name. ' ' . $value, 412);
} }
$serviceType = $parameters['X-SERVICE-TYPE']; $serviceType = $parameters['X-SERVICE-TYPE'];
if(is_array($serviceType)) { if(is_array($serviceType)) {
@ -457,7 +465,7 @@ class Contact extends VObject\VCard implements IPIMObject {
} }
$impp = Utils\Properties::getIMOptions($serviceType); $impp = Utils\Properties::getIMOptions($serviceType);
if(is_null($impp)) { if(is_null($impp)) {
throw new \UnexpectedValueException(__METHOD__.' Unknown IM: ' . $serviceType); throw new \UnexpectedValueException(self::$l10n('Unknown IM: ') . $serviceType, 415);
} }
$value = $impp['protocol'] . ':' . $value; $value = $impp['protocol'] . ':' . $value;
$property->setValue($value); $property->setValue($value);

View File

@ -8,7 +8,11 @@
*/ */
namespace OCA\Contacts; namespace OCA\Contacts;
use OCA\AppFramework\DependencyInjection\DIContainer as BaseContainer; use OCA\AppFramework\DependencyInjection\DIContainer as BaseContainer;
use OCA\AppFramework\Middleware\MiddlewareDispatcher;
use OCA\AppFramework\Middleware\Security\SecurityMiddleware;
use OCA\Contacts\Middleware\Http as HttpMiddleware;
use OCA\Contacts\Controller\AddressBookController; use OCA\Contacts\Controller\AddressBookController;
use OCA\Contacts\Controller\GroupController; use OCA\Contacts\Controller\GroupController;
use OCA\Contacts\Controller\ContactController; use OCA\Contacts\Controller\ContactController;
@ -25,6 +29,18 @@ class DIContainer extends BaseContainer {
// tell parent container about the app name // tell parent container about the app name
parent::__construct('contacts'); parent::__construct('contacts');
$this['HttpMiddleware'] = $this->share(function($c){
return new HttpMiddleware($c['API']);
});
$this['MiddlewareDispatcher'] = $this->share(function($c){
$dispatcher = new MiddlewareDispatcher();
$dispatcher->registerMiddleware($c['HttpMiddleware']);
$dispatcher->registerMiddleware($c['SecurityMiddleware']);
return $dispatcher;
});
/** /**
* CONTROLLERS * CONTROLLERS
*/ */

69
lib/middleware/http.php Normal file
View File

@ -0,0 +1,69 @@
<?php
/**
* ownCloud - HTTP Middleware
*
* @author Thomas Tanghus
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library 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 this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Contacts\Middleware;
use OCA\AppFramework\Controller\Controller;
use OCA\AppFramework\Middleware\Middleware;
use OCA\AppFramework\Core\API;
use OCA\Contacts\JSONResponse;
/**
* Used to intercept exceptions thrown in controllers and backends
* and transform them into valid HTTP responses.
*/
class HTTP extends Middleware {
private $api;
/**
* @param API $api an instance of the api
*/
public function __construct(API $api){
$this->api = $api;
}
/**
* If an Exception is being caught, return a JSON error response with
* a suitable status code
* @param Controller $controller the controller that is being called
* @param string $methodName the name of the method that will be called on
* the controller
* @param \Exception $exception the thrown exception
* @return Response a Response object
*/
public function afterException($controller, $methodName, \Exception $exception){
// If there's no proper status code associated, set it to 500.
$response = new JSONResponse();
if($exception->getCode() < 100) {
$response->setStatus(500);
} else {
$response->setStatus($exception->getCode());
}
$response->setErrorMessage($exception->getMessage());
$this->api->log(get_class($controller) . '->' . $methodName . ': ' . $exception->getMessage());
return $response;
}
}