Merge pull request #8477 from owncloud/better-controllers
Better appframework controllers
This commit is contained in:
commit
6499995474
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -33,6 +33,7 @@ use OC\AppFramework\Middleware\Security\SecurityMiddleware;
|
||||||
use OC\AppFramework\Middleware\Security\CORSMiddleware;
|
use OC\AppFramework\Middleware\Security\CORSMiddleware;
|
||||||
use OC\AppFramework\Utility\SimpleContainer;
|
use OC\AppFramework\Utility\SimpleContainer;
|
||||||
use OC\AppFramework\Utility\TimeFactory;
|
use OC\AppFramework\Utility\TimeFactory;
|
||||||
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OCP\AppFramework\IApi;
|
use OCP\AppFramework\IApi;
|
||||||
use OCP\AppFramework\IAppContainer;
|
use OCP\AppFramework\IAppContainer;
|
||||||
use OCP\AppFramework\Middleware;
|
use OCP\AppFramework\Middleware;
|
||||||
|
@ -81,7 +82,12 @@ class DIContainer extends SimpleContainer implements IAppContainer{
|
||||||
});
|
});
|
||||||
|
|
||||||
$this['Dispatcher'] = $this->share(function($c) {
|
$this['Dispatcher'] = $this->share(function($c) {
|
||||||
return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']);
|
return new Dispatcher(
|
||||||
|
$c['Protocol'],
|
||||||
|
$c['MiddlewareDispatcher'],
|
||||||
|
$c['ControllerMethodReflector'],
|
||||||
|
$c['Request']
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,11 +96,18 @@ class DIContainer extends SimpleContainer implements IAppContainer{
|
||||||
*/
|
*/
|
||||||
$app = $this;
|
$app = $this;
|
||||||
$this['SecurityMiddleware'] = $this->share(function($c) use ($app){
|
$this['SecurityMiddleware'] = $this->share(function($c) use ($app){
|
||||||
return new SecurityMiddleware($app, $c['Request']);
|
return new SecurityMiddleware(
|
||||||
|
$app,
|
||||||
|
$c['Request'],
|
||||||
|
$c['ControllerMethodReflector']
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$this['CORSMiddleware'] = $this->share(function($c) {
|
$this['CORSMiddleware'] = $this->share(function($c) {
|
||||||
return new CORSMiddleware($c['Request']);
|
return new CORSMiddleware(
|
||||||
|
$c['Request'],
|
||||||
|
$c['ControllerMethodReflector']
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$middleWares = &$this->middleWares;
|
$middleWares = &$this->middleWares;
|
||||||
|
@ -118,6 +131,9 @@ class DIContainer extends SimpleContainer implements IAppContainer{
|
||||||
return new TimeFactory();
|
return new TimeFactory();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$this['ControllerMethodReflector'] = $this->share(function($c) {
|
||||||
|
return new ControllerMethodReflector();
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -26,7 +26,11 @@ namespace OC\AppFramework\Http;
|
||||||
|
|
||||||
use \OC\AppFramework\Middleware\MiddlewareDispatcher;
|
use \OC\AppFramework\Middleware\MiddlewareDispatcher;
|
||||||
use \OC\AppFramework\Http;
|
use \OC\AppFramework\Http;
|
||||||
|
use \OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
|
|
||||||
use OCP\AppFramework\Controller;
|
use OCP\AppFramework\Controller;
|
||||||
|
use OCP\AppFramework\Http\Response;
|
||||||
|
use OCP\IRequest;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,17 +40,25 @@ class Dispatcher {
|
||||||
|
|
||||||
private $middlewareDispatcher;
|
private $middlewareDispatcher;
|
||||||
private $protocol;
|
private $protocol;
|
||||||
|
private $reflector;
|
||||||
|
private $request;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Http $protocol the http protocol with contains all status headers
|
* @param Http $protocol the http protocol with contains all status headers
|
||||||
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
|
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
|
||||||
* runs the middleware
|
* runs the middleware
|
||||||
|
* @param ControllerMethodReflector the reflector that is used to inject
|
||||||
|
* the arguments for the controller
|
||||||
|
* @param IRequest $request the incoming request
|
||||||
*/
|
*/
|
||||||
public function __construct(Http $protocol,
|
public function __construct(Http $protocol,
|
||||||
MiddlewareDispatcher $middlewareDispatcher) {
|
MiddlewareDispatcher $middlewareDispatcher,
|
||||||
|
ControllerMethodReflector $reflector,
|
||||||
|
IRequest $request) {
|
||||||
$this->protocol = $protocol;
|
$this->protocol = $protocol;
|
||||||
$this->middlewareDispatcher = $middlewareDispatcher;
|
$this->middlewareDispatcher = $middlewareDispatcher;
|
||||||
|
$this->reflector = $reflector;
|
||||||
|
$this->request = $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -63,10 +75,13 @@ class Dispatcher {
|
||||||
$out = array(null, array(), null);
|
$out = array(null, array(), null);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// prefill reflector with everything thats needed for the
|
||||||
|
// middlewares
|
||||||
|
$this->reflector->reflect($controller, $methodName);
|
||||||
|
|
||||||
$this->middlewareDispatcher->beforeController($controller,
|
$this->middlewareDispatcher->beforeController($controller,
|
||||||
$methodName);
|
$methodName);
|
||||||
$response = $controller->$methodName();
|
$response = $this->executeController($controller, $methodName);
|
||||||
|
|
||||||
// if an exception appears, the middleware checks if it can handle the
|
// if an exception appears, the middleware checks if it can handle the
|
||||||
// exception and creates a response. If no response is created, it is
|
// exception and creates a response. If no response is created, it is
|
||||||
|
@ -98,4 +113,70 @@ class Dispatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the reflected parameters, types and request parameters to execute
|
||||||
|
* the controller
|
||||||
|
* @param Controller $controller the controller to be executed
|
||||||
|
* @param string $methodName the method on the controller that should be executed
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
private function executeController($controller, $methodName) {
|
||||||
|
$arguments = array();
|
||||||
|
|
||||||
|
// valid types that will be casted
|
||||||
|
$types = array('int', 'integer', 'bool', 'boolean', 'float');
|
||||||
|
|
||||||
|
foreach($this->reflector->getParameters() as $param) {
|
||||||
|
|
||||||
|
// try to get the parameter from the request object and cast
|
||||||
|
// it to the type annotated in the @param annotation
|
||||||
|
$value = $this->request->getParam($param);
|
||||||
|
$type = $this->reflector->getType($param);
|
||||||
|
|
||||||
|
// if this is submitted using GET or a POST form, 'false' should be
|
||||||
|
// converted to false
|
||||||
|
if(($type === 'bool' || $type === 'boolean') &&
|
||||||
|
$value === 'false' &&
|
||||||
|
(
|
||||||
|
$this->request->method === 'GET' ||
|
||||||
|
strpos($this->request->getHeader('Content-Type'),
|
||||||
|
'application/x-www-form-urlencoded') !== false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$value = false;
|
||||||
|
|
||||||
|
} elseif(in_array($type, $types)) {
|
||||||
|
settype($value, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
$arguments[] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = call_user_func_array(array($controller, $methodName), $arguments);
|
||||||
|
|
||||||
|
// format response if not of type response
|
||||||
|
if(!($response instanceof Response)) {
|
||||||
|
|
||||||
|
// get format from the url format or request format parameter
|
||||||
|
$format = $this->request->getParam('format');
|
||||||
|
|
||||||
|
// if none is given try the first Accept header
|
||||||
|
if($format === null) {
|
||||||
|
$header = $this->request->getHeader('Accept');
|
||||||
|
$formats = explode(',', $header);
|
||||||
|
|
||||||
|
if($header !== null && count($formats) > 0) {
|
||||||
|
$accept = strtolower(trim($formats[0]));
|
||||||
|
$format = str_replace('application/', '', $accept);
|
||||||
|
} else {
|
||||||
|
$format = 'json';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $controller->buildResponse($response, $format);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
* ownCloud - Request
|
* ownCloud - Request
|
||||||
*
|
*
|
||||||
* @author Thomas Tanghus
|
* @author Thomas Tanghus
|
||||||
|
* @author Bernhard Posselt
|
||||||
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
* @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
|
||||||
|
* @copyright 2014 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
namespace OC\AppFramework\Middleware\Security;
|
namespace OC\AppFramework\Middleware\Security;
|
||||||
|
|
||||||
use OC\AppFramework\Utility\MethodAnnotationReader;
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
use OCP\AppFramework\Http\Response;
|
use OCP\AppFramework\Http\Response;
|
||||||
use OCP\AppFramework\Middleware;
|
use OCP\AppFramework\Middleware;
|
||||||
|
@ -25,12 +25,16 @@ use OCP\AppFramework\Middleware;
|
||||||
class CORSMiddleware extends Middleware {
|
class CORSMiddleware extends Middleware {
|
||||||
|
|
||||||
private $request;
|
private $request;
|
||||||
|
private $reflector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
|
* @param ControllerMethodReflector $reflector
|
||||||
*/
|
*/
|
||||||
public function __construct(IRequest $request) {
|
public function __construct(IRequest $request,
|
||||||
|
ControllerMethodReflector $reflector) {
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
|
$this->reflector = $reflector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,10 +50,9 @@ class CORSMiddleware extends Middleware {
|
||||||
*/
|
*/
|
||||||
public function afterController($controller, $methodName, Response $response){
|
public function afterController($controller, $methodName, Response $response){
|
||||||
// only react if its a CORS request and if the request sends origin and
|
// only react if its a CORS request and if the request sends origin and
|
||||||
$reflector = new MethodAnnotationReader($controller, $methodName);
|
|
||||||
|
|
||||||
if(isset($this->request->server['HTTP_ORIGIN']) &&
|
if(isset($this->request->server['HTTP_ORIGIN']) &&
|
||||||
$reflector->hasAnnotation('CORS')) {
|
$this->reflector->hasAnnotation('CORS')) {
|
||||||
|
|
||||||
// allow credentials headers must not be true or CSRF is possible
|
// allow credentials headers must not be true or CSRF is possible
|
||||||
// otherwise
|
// otherwise
|
||||||
|
@ -57,7 +60,7 @@ class CORSMiddleware extends Middleware {
|
||||||
if(strtolower($header) === 'access-control-allow-credentials' &&
|
if(strtolower($header) === 'access-control-allow-credentials' &&
|
||||||
strtolower(trim($value)) === 'true') {
|
strtolower(trim($value)) === 'true') {
|
||||||
$msg = 'Access-Control-Allow-Credentials must not be '.
|
$msg = 'Access-Control-Allow-Credentials must not be '.
|
||||||
'set to true in order to prevent CSRF';
|
'set to true in order to prevent CSRF';
|
||||||
throw new SecurityException($msg);
|
throw new SecurityException($msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
namespace OC\AppFramework\Middleware\Security;
|
namespace OC\AppFramework\Middleware\Security;
|
||||||
|
|
||||||
use OC\AppFramework\Http;
|
use OC\AppFramework\Http;
|
||||||
use OC\AppFramework\Utility\MethodAnnotationReader;
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OCP\AppFramework\Http\RedirectResponse;
|
use OCP\AppFramework\Http\RedirectResponse;
|
||||||
use OCP\AppFramework\Middleware;
|
use OCP\AppFramework\Middleware;
|
||||||
use OCP\AppFramework\Http\Response;
|
use OCP\AppFramework\Http\Response;
|
||||||
|
@ -52,13 +52,21 @@ class SecurityMiddleware extends Middleware {
|
||||||
*/
|
*/
|
||||||
private $request;
|
private $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var OC\AppFramework\Utility\ControllerMethodReflector
|
||||||
|
*/
|
||||||
|
private $reflector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param IAppContainer $app
|
* @param IAppContainer $app
|
||||||
* @param IRequest $request
|
* @param IRequest $request
|
||||||
|
* @param ControllerMethodReflector $reflector
|
||||||
*/
|
*/
|
||||||
public function __construct(IAppContainer $app, IRequest $request){
|
public function __construct(IAppContainer $app, IRequest $request,
|
||||||
|
ControllerMethodReflector $reflector){
|
||||||
$this->app = $app;
|
$this->app = $app;
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
|
$this->reflector = $reflector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,28 +80,25 @@ class SecurityMiddleware extends Middleware {
|
||||||
*/
|
*/
|
||||||
public function beforeController($controller, $methodName){
|
public function beforeController($controller, $methodName){
|
||||||
|
|
||||||
// get annotations from comments
|
|
||||||
$annotationReader = new MethodAnnotationReader($controller, $methodName);
|
|
||||||
|
|
||||||
// this will set the current navigation entry of the app, use this only
|
// this will set the current navigation entry of the app, use this only
|
||||||
// for normal HTML requests and not for AJAX requests
|
// for normal HTML requests and not for AJAX requests
|
||||||
$this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName());
|
$this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName());
|
||||||
|
|
||||||
// security checks
|
// security checks
|
||||||
$isPublicPage = $annotationReader->hasAnnotation('PublicPage');
|
$isPublicPage = $this->reflector->hasAnnotation('PublicPage');
|
||||||
if(!$isPublicPage) {
|
if(!$isPublicPage) {
|
||||||
if(!$this->app->isLoggedIn()) {
|
if(!$this->app->isLoggedIn()) {
|
||||||
throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED);
|
throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$annotationReader->hasAnnotation('NoAdminRequired')) {
|
if(!$this->reflector->hasAnnotation('NoAdminRequired')) {
|
||||||
if(!$this->app->isAdminUser()) {
|
if(!$this->app->isAdminUser()) {
|
||||||
throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN);
|
throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$annotationReader->hasAnnotation('NoCSRFRequired')) {
|
if(!$this->reflector->hasAnnotation('NoCSRFRequired')) {
|
||||||
if(!$this->request->passesCSRFCheck()) {
|
if(!$this->request->passesCSRFCheck()) {
|
||||||
throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED);
|
throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2014 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -28,23 +28,63 @@ namespace OC\AppFramework\Utility;
|
||||||
/**
|
/**
|
||||||
* Reads and parses annotations from doc comments
|
* Reads and parses annotations from doc comments
|
||||||
*/
|
*/
|
||||||
class MethodAnnotationReader {
|
class ControllerMethodReflector {
|
||||||
|
|
||||||
private $annotations;
|
private $annotations;
|
||||||
|
private $types;
|
||||||
|
private $parameters;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->types = array();
|
||||||
|
$this->parameters = array();
|
||||||
|
$this->annotations = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param object $object an object or classname
|
* @param object $object an object or classname
|
||||||
* @param string $method the method which we want to inspect for annotations
|
* @param string $method the method which we want to inspect
|
||||||
*/
|
*/
|
||||||
public function __construct($object, $method){
|
public function reflect($object, $method){
|
||||||
$this->annotations = array();
|
|
||||||
|
|
||||||
$reflection = new \ReflectionMethod($object, $method);
|
$reflection = new \ReflectionMethod($object, $method);
|
||||||
$docs = $reflection->getDocComment();
|
$docs = $reflection->getDocComment();
|
||||||
|
|
||||||
// extract everything prefixed by @ and first letter uppercase
|
// extract everything prefixed by @ and first letter uppercase
|
||||||
preg_match_all('/@([A-Z]\w+)/', $docs, $matches);
|
preg_match_all('/@([A-Z]\w+)/', $docs, $matches);
|
||||||
$this->annotations = $matches[1];
|
$this->annotations = $matches[1];
|
||||||
|
|
||||||
|
// extract type parameter information
|
||||||
|
preg_match_all('/@param (?<type>\w+) \$(?<var>\w+)/', $docs, $matches);
|
||||||
|
$this->types = array_combine($matches['var'], $matches['type']);
|
||||||
|
|
||||||
|
// get method parameters
|
||||||
|
foreach ($reflection->getParameters() as $param) {
|
||||||
|
$this->parameters[] = $param->name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inspects the PHPDoc parameters for types
|
||||||
|
* @param string $parameter the parameter whose type comments should be
|
||||||
|
* parsed
|
||||||
|
* @return string|null type in the type parameters (@param int $something)
|
||||||
|
* would return int or null if not existing
|
||||||
|
*/
|
||||||
|
public function getType($parameter) {
|
||||||
|
if(array_key_exists($parameter, $this->types)) {
|
||||||
|
return $this->types[$parameter];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array the arguments of the method
|
||||||
|
*/
|
||||||
|
public function getParameters() {
|
||||||
|
return $this->parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012, 2014 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -28,6 +28,8 @@
|
||||||
namespace OCP\AppFramework;
|
namespace OCP\AppFramework;
|
||||||
|
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
use OCP\AppFramework\Http\IResponseSerializer;
|
||||||
use OCP\IRequest;
|
use OCP\IRequest;
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,6 +50,8 @@ abstract class Controller {
|
||||||
*/
|
*/
|
||||||
protected $request;
|
protected $request;
|
||||||
|
|
||||||
|
private $serializer;
|
||||||
|
private $responders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* constructor of the controller
|
* constructor of the controller
|
||||||
|
@ -66,11 +70,66 @@ abstract class Controller {
|
||||||
IRequest $request){
|
IRequest $request){
|
||||||
$this->appName = $appName;
|
$this->appName = $appName;
|
||||||
$this->request = $request;
|
$this->request = $request;
|
||||||
|
|
||||||
|
// default responders
|
||||||
|
$this->responders = array(
|
||||||
|
'json' => function ($response) {
|
||||||
|
return new JSONResponse($response);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a serializer that is executed before a formatter is being
|
||||||
|
* called, useful for turning any data into PHP arrays that can be used
|
||||||
|
* by a JSONResponse for instance
|
||||||
|
* @param IResponseSerializer $serializer
|
||||||
|
*/
|
||||||
|
protected function registerSerializer(IResponseSerializer $serializer) {
|
||||||
|
$this->serializer = $serializer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a formatter for a type
|
||||||
|
* @param string $format
|
||||||
|
* @param \Closure $responder
|
||||||
|
*/
|
||||||
|
protected function registerResponder($format, \Closure $responder) {
|
||||||
|
$this->responders[$format] = $responder;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes and formats a response
|
||||||
|
* @param mixed $response the value that was returned from a controller and
|
||||||
|
* is not a Response instance
|
||||||
|
* @param string $format the format for which a formatter has been registered
|
||||||
|
* @throws \DomainException if format does not match a registered formatter
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function buildResponse($response, $format='json') {
|
||||||
|
if(array_key_exists($format, $this->responders)) {
|
||||||
|
|
||||||
|
if ($this->serializer) {
|
||||||
|
$response = $this->serializer->serialize($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
$responder = $this->responders[$format];
|
||||||
|
|
||||||
|
return $responder($response);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new \DomainException('No responder registered for format ' .
|
||||||
|
$format . '!');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lets you access post and get parameters by the index
|
* Lets you access post and get parameters by the index
|
||||||
|
* @deprecated write your parameters as method arguments instead
|
||||||
* @param string $key the key which you want to access in the URL Parameter
|
* @param string $key the key which you want to access in the URL Parameter
|
||||||
* placeholder, $_POST or $_GET array.
|
* placeholder, $_POST or $_GET array.
|
||||||
* The priority how they're returned is the following:
|
* The priority how they're returned is the following:
|
||||||
|
@ -88,6 +147,7 @@ abstract class Controller {
|
||||||
/**
|
/**
|
||||||
* Returns all params that were received, be it from the request
|
* Returns all params that were received, be it from the request
|
||||||
* (as GET or POST) or throuh the URL by the route
|
* (as GET or POST) or throuh the URL by the route
|
||||||
|
* @deprecated use $this->request instead
|
||||||
* @return array the array with all parameters
|
* @return array the array with all parameters
|
||||||
*/
|
*/
|
||||||
public function getParams() {
|
public function getParams() {
|
||||||
|
@ -97,6 +157,7 @@ abstract class Controller {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the method of the request
|
* Returns the method of the request
|
||||||
|
* @deprecated use $this->request instead
|
||||||
* @return string the method of the request (POST, GET, etc)
|
* @return string the method of the request (POST, GET, etc)
|
||||||
*/
|
*/
|
||||||
public function method() {
|
public function method() {
|
||||||
|
@ -106,6 +167,7 @@ abstract class Controller {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for accessing an uploaded file through the $_FILES array
|
* Shortcut for accessing an uploaded file through the $_FILES array
|
||||||
|
* @deprecated use $this->request instead
|
||||||
* @param string $key the key that will be taken from the $_FILES array
|
* @param string $key the key that will be taken from the $_FILES array
|
||||||
* @return array the file in the $_FILES element
|
* @return array the file in the $_FILES element
|
||||||
*/
|
*/
|
||||||
|
@ -116,6 +178,7 @@ abstract class Controller {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for getting env variables
|
* Shortcut for getting env variables
|
||||||
|
* @deprecated use $this->request instead
|
||||||
* @param string $key the key that will be taken from the $_ENV array
|
* @param string $key the key that will be taken from the $_ENV array
|
||||||
* @return array the value in the $_ENV element
|
* @return array the value in the $_ENV element
|
||||||
*/
|
*/
|
||||||
|
@ -126,6 +189,7 @@ abstract class Controller {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for getting cookie variables
|
* Shortcut for getting cookie variables
|
||||||
|
* @deprecated use $this->request instead
|
||||||
* @param string $key the key that will be taken from the $_COOKIE array
|
* @param string $key the key that will be taken from the $_COOKIE array
|
||||||
* @return array the value in the $_COOKIE element
|
* @return array the value in the $_COOKIE element
|
||||||
*/
|
*/
|
||||||
|
@ -136,6 +200,7 @@ abstract class Controller {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shortcut for rendering a template
|
* Shortcut for rendering a template
|
||||||
|
* @deprecated return a template response instead
|
||||||
* @param string $templateName the name of the template
|
* @param string $templateName the name of the template
|
||||||
* @param array $params the template parameters in key => value structure
|
* @param array $params the template parameters in key => value structure
|
||||||
* @param string $renderAs user renders a full page, blank only your template
|
* @param string $renderAs user renders a full page, blank only your template
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* ownCloud - App Framework
|
||||||
|
*
|
||||||
|
* @author Bernhard Posselt
|
||||||
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
|
*
|
||||||
|
* 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 OCP\AppFramework\Http;
|
||||||
|
|
||||||
|
interface IResponseSerializer {
|
||||||
|
function serialize($response);
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
* @author Bernhard Posselt, Thomas Tanghus, Bart Visscher
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -61,12 +61,16 @@ class TemplateResponse extends Response {
|
||||||
* constructor of TemplateResponse
|
* constructor of TemplateResponse
|
||||||
* @param string $appName the name of the app to load the template from
|
* @param string $appName the name of the app to load the template from
|
||||||
* @param string $templateName the name of the template
|
* @param string $templateName the name of the template
|
||||||
|
* @param array $params an array of parameters which should be passed to the
|
||||||
|
* template
|
||||||
|
* @param string $renderAs how the page should be rendered, defaults to user
|
||||||
*/
|
*/
|
||||||
public function __construct($appName, $templateName) {
|
public function __construct($appName, $templateName, array $params=array(),
|
||||||
|
$renderAs='user') {
|
||||||
$this->templateName = $templateName;
|
$this->templateName = $templateName;
|
||||||
$this->appName = $appName;
|
$this->appName = $appName;
|
||||||
$this->params = array();
|
$this->params = $params;
|
||||||
$this->renderAs = 'user';
|
$this->renderAs = $renderAs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2012 Bernhard Posselt <nukeawhale@gmail.com>
|
* Copyright (c) 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
* This file is licensed under the Affero General Public License version 3 or
|
* This file is licensed under the Affero General Public License version 3 or
|
||||||
* later.
|
* later.
|
||||||
* See the COPYING-README file.
|
* See the COPYING-README file.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -26,9 +26,31 @@ namespace OCP\AppFramework;
|
||||||
|
|
||||||
use OC\AppFramework\Http\Request;
|
use OC\AppFramework\Http\Request;
|
||||||
use OCP\AppFramework\Http\TemplateResponse;
|
use OCP\AppFramework\Http\TemplateResponse;
|
||||||
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
use OCP\AppFramework\Http\IResponseSerializer;
|
||||||
|
|
||||||
|
|
||||||
class ChildController extends Controller {};
|
class ToUpperCaseSerializer implements IResponseSerializer {
|
||||||
|
public function serialize($response) {
|
||||||
|
return array(strtoupper($response));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChildController extends Controller {
|
||||||
|
public function custom($in) {
|
||||||
|
$this->registerResponder('json', function ($response) {
|
||||||
|
return new JSONResponse(array(strlen($response)));
|
||||||
|
});
|
||||||
|
|
||||||
|
return $in;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function serializer($in) {
|
||||||
|
$this->registerSerializer(new ToUpperCaseSerializer());
|
||||||
|
|
||||||
|
return $in;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class ControllerTest extends \PHPUnit_Framework_TestCase {
|
class ControllerTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
@ -129,4 +151,35 @@ class ControllerTest extends \PHPUnit_Framework_TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \DomainException
|
||||||
|
*/
|
||||||
|
public function testFormatResonseInvalidFormat() {
|
||||||
|
$this->controller->buildResponse(null, 'test');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testFormat() {
|
||||||
|
$response = $this->controller->buildResponse(array('hi'), 'json');
|
||||||
|
|
||||||
|
$this->assertEquals(array('hi'), $response->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testCustomFormatter() {
|
||||||
|
$response = $this->controller->custom('hi');
|
||||||
|
$response = $this->controller->buildResponse($response, 'json');
|
||||||
|
|
||||||
|
$this->assertEquals(array(2), $response->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testCustomSerializer() {
|
||||||
|
$response = $this->controller->serializer('hi');
|
||||||
|
$response = $this->controller->buildResponse($response, 'json');
|
||||||
|
|
||||||
|
$this->assertEquals(array('HI'), $response->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @author Morris Jobke
|
* @author Morris Jobke
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
* @copyright 2013 Morris Jobke morris.jobke@gmail.com
|
* @copyright 2013 Morris Jobke <morris.jobke@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -25,8 +25,28 @@
|
||||||
namespace OC\AppFramework\Http;
|
namespace OC\AppFramework\Http;
|
||||||
|
|
||||||
use OC\AppFramework\Middleware\MiddlewareDispatcher;
|
use OC\AppFramework\Middleware\MiddlewareDispatcher;
|
||||||
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OCP\AppFramework\Http;
|
use OCP\AppFramework\Http;
|
||||||
//require_once(__DIR__ . "/../classloader.php");
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
use OCP\AppFramework\Controller;
|
||||||
|
|
||||||
|
|
||||||
|
class TestController extends Controller {
|
||||||
|
public function __construct($appName, $request) {
|
||||||
|
parent::__construct($appName, $request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $int
|
||||||
|
* @param bool $bool
|
||||||
|
*/
|
||||||
|
public function exec($int, $bool) {
|
||||||
|
$this->registerResponder('text', function($in) {
|
||||||
|
return new JSONResponse(array('text' => $in));
|
||||||
|
});
|
||||||
|
return array($int, $bool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
@ -39,6 +59,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
private $lastModified;
|
private $lastModified;
|
||||||
private $etag;
|
private $etag;
|
||||||
private $http;
|
private $http;
|
||||||
|
private $reflector;
|
||||||
|
|
||||||
protected function setUp() {
|
protected function setUp() {
|
||||||
$this->controllerMethod = 'test';
|
$this->controllerMethod = 'test';
|
||||||
|
@ -64,8 +85,17 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
'\OCP\AppFramework\Controller',
|
'\OCP\AppFramework\Controller',
|
||||||
array($this->controllerMethod), array($app, $request));
|
array($this->controllerMethod), array($app, $request));
|
||||||
|
|
||||||
|
$this->request = $this->getMockBuilder(
|
||||||
|
'\OC\AppFramework\Http\Request')
|
||||||
|
->disableOriginalConstructor()
|
||||||
|
->getMock();
|
||||||
|
|
||||||
|
$this->reflector = new ControllerMethodReflector();
|
||||||
|
|
||||||
$this->dispatcher = new Dispatcher(
|
$this->dispatcher = new Dispatcher(
|
||||||
$this->http, $this->middlewareDispatcher);
|
$this->http, $this->middlewareDispatcher, $this->reflector,
|
||||||
|
$this->request
|
||||||
|
);
|
||||||
|
|
||||||
$this->response = $this->getMockBuilder(
|
$this->response = $this->getMockBuilder(
|
||||||
'\OCP\AppFramework\Http\Response')
|
'\OCP\AppFramework\Http\Response')
|
||||||
|
@ -81,7 +111,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
* @param string $out
|
* @param string $out
|
||||||
* @param string $httpHeaders
|
* @param string $httpHeaders
|
||||||
*/
|
*/
|
||||||
private function setMiddlewareExpections($out=null,
|
private function setMiddlewareExpectations($out=null,
|
||||||
$httpHeaders=null, $responseHeaders=array(),
|
$httpHeaders=null, $responseHeaders=array(),
|
||||||
$ex=false, $catchEx=true) {
|
$ex=false, $catchEx=true) {
|
||||||
|
|
||||||
|
@ -159,14 +189,12 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
->with($this->equalTo($this->controller),
|
->with($this->equalTo($this->controller),
|
||||||
$this->equalTo($this->controllerMethod),
|
$this->equalTo($this->controllerMethod),
|
||||||
$this->equalTo($out))
|
$this->equalTo($out))
|
||||||
->will($this->returnValue($out));
|
->will($this->returnValue($out));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testDispatcherReturnsArrayWith2Entries() {
|
public function testDispatcherReturnsArrayWith2Entries() {
|
||||||
$this->setMiddlewareExpections();
|
$this->setMiddlewareExpectations();
|
||||||
|
|
||||||
$response = $this->dispatcher->dispatch($this->controller,
|
$response = $this->dispatcher->dispatch($this->controller,
|
||||||
$this->controllerMethod);
|
$this->controllerMethod);
|
||||||
|
@ -180,7 +208,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
$out = 'yo';
|
$out = 'yo';
|
||||||
$httpHeaders = 'Http';
|
$httpHeaders = 'Http';
|
||||||
$responseHeaders = array('hell' => 'yeah');
|
$responseHeaders = array('hell' => 'yeah');
|
||||||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders);
|
$this->setMiddlewareExpectations($out, $httpHeaders, $responseHeaders);
|
||||||
|
|
||||||
$response = $this->dispatcher->dispatch($this->controller,
|
$response = $this->dispatcher->dispatch($this->controller,
|
||||||
$this->controllerMethod);
|
$this->controllerMethod);
|
||||||
|
@ -195,7 +223,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
$out = 'yo';
|
$out = 'yo';
|
||||||
$httpHeaders = 'Http';
|
$httpHeaders = 'Http';
|
||||||
$responseHeaders = array('hell' => 'yeah');
|
$responseHeaders = array('hell' => 'yeah');
|
||||||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true);
|
$this->setMiddlewareExpectations($out, $httpHeaders, $responseHeaders, true);
|
||||||
|
|
||||||
$response = $this->dispatcher->dispatch($this->controller,
|
$response = $this->dispatcher->dispatch($this->controller,
|
||||||
$this->controllerMethod);
|
$this->controllerMethod);
|
||||||
|
@ -210,7 +238,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
$out = 'yo';
|
$out = 'yo';
|
||||||
$httpHeaders = 'Http';
|
$httpHeaders = 'Http';
|
||||||
$responseHeaders = array('hell' => 'yeah');
|
$responseHeaders = array('hell' => 'yeah');
|
||||||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false);
|
$this->setMiddlewareExpectations($out, $httpHeaders, $responseHeaders, true, false);
|
||||||
|
|
||||||
$this->setExpectedException('\Exception');
|
$this->setExpectedException('\Exception');
|
||||||
$response = $this->dispatcher->dispatch($this->controller,
|
$response = $this->dispatcher->dispatch($this->controller,
|
||||||
|
@ -218,4 +246,120 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function dispatcherPassthrough() {
|
||||||
|
$this->middlewareDispatcher->expects($this->once())
|
||||||
|
->method('beforeController');
|
||||||
|
$this->middlewareDispatcher->expects($this->once())
|
||||||
|
->method('afterController')
|
||||||
|
->will($this->returnCallback(function($a, $b, $in) {
|
||||||
|
return $in;
|
||||||
|
}));
|
||||||
|
$this->middlewareDispatcher->expects($this->once())
|
||||||
|
->method('beforeOutput')
|
||||||
|
->will($this->returnCallback(function($a, $b, $in) {
|
||||||
|
return $in;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testControllerParametersInjected() {
|
||||||
|
$this->request = new Request(array(
|
||||||
|
'post' => array(
|
||||||
|
'int' => '3',
|
||||||
|
'bool' => 'false'
|
||||||
|
),
|
||||||
|
'method' => 'POST'
|
||||||
|
));
|
||||||
|
$this->dispatcher = new Dispatcher(
|
||||||
|
$this->http, $this->middlewareDispatcher, $this->reflector,
|
||||||
|
$this->request
|
||||||
|
);
|
||||||
|
$controller = new TestController('app', $this->request);
|
||||||
|
|
||||||
|
// reflector is supposed to be called once
|
||||||
|
$this->dispatcherPassthrough();
|
||||||
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
|
$this->assertEquals('[3,true]', $response[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testResponseTransformedByUrlFormat() {
|
||||||
|
$this->request = new Request(array(
|
||||||
|
'post' => array(
|
||||||
|
'int' => '3',
|
||||||
|
'bool' => 'false'
|
||||||
|
),
|
||||||
|
'urlParams' => array(
|
||||||
|
'format' => 'text'
|
||||||
|
),
|
||||||
|
'method' => 'GET'
|
||||||
|
));
|
||||||
|
$this->dispatcher = new Dispatcher(
|
||||||
|
$this->http, $this->middlewareDispatcher, $this->reflector,
|
||||||
|
$this->request
|
||||||
|
);
|
||||||
|
$controller = new TestController('app', $this->request);
|
||||||
|
|
||||||
|
// reflector is supposed to be called once
|
||||||
|
$this->dispatcherPassthrough();
|
||||||
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
|
$this->assertEquals('{"text":[3,false]}', $response[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testResponseTransformedByAcceptHeader() {
|
||||||
|
$this->request = new Request(array(
|
||||||
|
'post' => array(
|
||||||
|
'int' => '3',
|
||||||
|
'bool' => 'false'
|
||||||
|
),
|
||||||
|
'server' => array(
|
||||||
|
'HTTP_ACCEPT' => 'application/text, test',
|
||||||
|
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'
|
||||||
|
),
|
||||||
|
'method' => 'PUT'
|
||||||
|
));
|
||||||
|
$this->dispatcher = new Dispatcher(
|
||||||
|
$this->http, $this->middlewareDispatcher, $this->reflector,
|
||||||
|
$this->request
|
||||||
|
);
|
||||||
|
$controller = new TestController('app', $this->request);
|
||||||
|
|
||||||
|
// reflector is supposed to be called once
|
||||||
|
$this->dispatcherPassthrough();
|
||||||
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
|
$this->assertEquals('{"text":[3,false]}', $response[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testResponsePrimarilyTransformedByParameterFormat() {
|
||||||
|
$this->request = new Request(array(
|
||||||
|
'post' => array(
|
||||||
|
'int' => '3',
|
||||||
|
'bool' => 'false'
|
||||||
|
),
|
||||||
|
'get' => array(
|
||||||
|
'format' => 'text'
|
||||||
|
),
|
||||||
|
'server' => array(
|
||||||
|
'HTTP_ACCEPT' => 'application/json, test'
|
||||||
|
),
|
||||||
|
'method' => 'POST'
|
||||||
|
));
|
||||||
|
$this->dispatcher = new Dispatcher(
|
||||||
|
$this->http, $this->middlewareDispatcher, $this->reflector,
|
||||||
|
$this->request
|
||||||
|
);
|
||||||
|
$controller = new TestController('app', $this->request);
|
||||||
|
|
||||||
|
// reflector is supposed to be called once
|
||||||
|
$this->dispatcherPassthrough();
|
||||||
|
$response = $this->dispatcher->dispatch($controller, 'exec');
|
||||||
|
|
||||||
|
$this->assertEquals('{"text":[3,true]}', $response[2]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @author Morris Jobke
|
* @author Morris Jobke
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
* @copyright 2013 Morris Jobke morris.jobke@gmail.com
|
* @copyright 2013 Morris Jobke <morris.jobke@gmail.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -51,6 +51,22 @@ class TemplateResponseTest extends \PHPUnit_Framework_TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testSetParamsConstructor(){
|
||||||
|
$params = array('hi' => 'yo');
|
||||||
|
$this->tpl = new TemplateResponse($this->api, 'home', $params);
|
||||||
|
|
||||||
|
$this->assertEquals(array('hi' => 'yo'), $this->tpl->getParams());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function testSetRenderAsConstructor(){
|
||||||
|
$renderAs = 'myrender';
|
||||||
|
$this->tpl = new TemplateResponse($this->api, 'home', array(), $renderAs);
|
||||||
|
|
||||||
|
$this->assertEquals($renderAs, $this->tpl->getRenderAs());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function testSetParams(){
|
public function testSetParams(){
|
||||||
$params = array('hi' => 'yo');
|
$params = array('hi' => 'yo');
|
||||||
$this->tpl->setParams($params);
|
$this->tpl->setParams($params);
|
||||||
|
@ -63,36 +79,6 @@ class TemplateResponseTest extends \PHPUnit_Framework_TestCase {
|
||||||
$this->assertEquals('home', $this->tpl->getTemplateName());
|
$this->assertEquals('home', $this->tpl->getTemplateName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public function testRender(){
|
|
||||||
// $ocTpl = $this->getMock('Template', array('fetchPage'));
|
|
||||||
// $ocTpl->expects($this->once())
|
|
||||||
// ->method('fetchPage');
|
|
||||||
//
|
|
||||||
// $tpl = new TemplateResponse('core', 'error');
|
|
||||||
//
|
|
||||||
// $tpl->render();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// public function testRenderAssignsParams(){
|
|
||||||
// $params = array('john' => 'doe');
|
|
||||||
//
|
|
||||||
// $tpl = new TemplateResponse('app', 'home');
|
|
||||||
// $tpl->setParams($params);
|
|
||||||
//
|
|
||||||
// $tpl->render();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// public function testRenderDifferentApp(){
|
|
||||||
//
|
|
||||||
// $tpl = new TemplateResponse('app', 'home', 'app2');
|
|
||||||
//
|
|
||||||
// $tpl->render();
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
public function testGetRenderAs(){
|
public function testGetRenderAs(){
|
||||||
$render = 'myrender';
|
$render = 'myrender';
|
||||||
$this->tpl->renderAs($render);
|
$this->tpl->renderAs($render);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -13,11 +13,19 @@
|
||||||
namespace OC\AppFramework\Middleware\Security;
|
namespace OC\AppFramework\Middleware\Security;
|
||||||
|
|
||||||
use OC\AppFramework\Http\Request;
|
use OC\AppFramework\Http\Request;
|
||||||
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
|
|
||||||
use OCP\AppFramework\Http\Response;
|
use OCP\AppFramework\Http\Response;
|
||||||
|
|
||||||
|
|
||||||
class CORSMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
class CORSMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
private $reflector;
|
||||||
|
|
||||||
|
protected function setUp() {
|
||||||
|
$this->reflector = new ControllerMethodReflector();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @CORS
|
* @CORS
|
||||||
*/
|
*/
|
||||||
|
@ -25,11 +33,11 @@ class CORSMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
$request = new Request(
|
$request = new Request(
|
||||||
array('server' => array('HTTP_ORIGIN' => 'test'))
|
array('server' => array('HTTP_ORIGIN' => 'test'))
|
||||||
);
|
);
|
||||||
|
$this->reflector->reflect($this, __FUNCTION__);
|
||||||
|
$middleware = new CORSMiddleware($request, $this->reflector);
|
||||||
|
|
||||||
$middleware = new CORSMiddleware($request);
|
|
||||||
$response = $middleware->afterController($this, __FUNCTION__, new Response());
|
$response = $middleware->afterController($this, __FUNCTION__, new Response());
|
||||||
$headers = $response->getHeaders();
|
$headers = $response->getHeaders();
|
||||||
|
|
||||||
$this->assertEquals('test', $headers['Access-Control-Allow-Origin']);
|
$this->assertEquals('test', $headers['Access-Control-Allow-Origin']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +46,7 @@ class CORSMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
$request = new Request(
|
$request = new Request(
|
||||||
array('server' => array('HTTP_ORIGIN' => 'test'))
|
array('server' => array('HTTP_ORIGIN' => 'test'))
|
||||||
);
|
);
|
||||||
$middleware = new CORSMiddleware($request);
|
$middleware = new CORSMiddleware($request, $this->reflector);
|
||||||
|
|
||||||
$response = $middleware->afterController($this, __FUNCTION__, new Response());
|
$response = $middleware->afterController($this, __FUNCTION__, new Response());
|
||||||
$headers = $response->getHeaders();
|
$headers = $response->getHeaders();
|
||||||
|
@ -51,8 +59,9 @@ class CORSMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
*/
|
*/
|
||||||
public function testNoOriginHeaderNoCORSHEADER() {
|
public function testNoOriginHeaderNoCORSHEADER() {
|
||||||
$request = new Request();
|
$request = new Request();
|
||||||
|
$this->reflector->reflect($this, __FUNCTION__);
|
||||||
|
$middleware = new CORSMiddleware($request, $this->reflector);
|
||||||
|
|
||||||
$middleware = new CORSMiddleware($request);
|
|
||||||
$response = $middleware->afterController($this, __FUNCTION__, new Response());
|
$response = $middleware->afterController($this, __FUNCTION__, new Response());
|
||||||
$headers = $response->getHeaders();
|
$headers = $response->getHeaders();
|
||||||
$this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers));
|
$this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers));
|
||||||
|
@ -67,7 +76,8 @@ class CORSMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
$request = new Request(
|
$request = new Request(
|
||||||
array('server' => array('HTTP_ORIGIN' => 'test'))
|
array('server' => array('HTTP_ORIGIN' => 'test'))
|
||||||
);
|
);
|
||||||
$middleware = new CORSMiddleware($request);
|
$this->reflector->reflect($this, __FUNCTION__);
|
||||||
|
$middleware = new CORSMiddleware($request, $this->reflector);
|
||||||
|
|
||||||
$response = new Response();
|
$response = new Response();
|
||||||
$response->addHeader('AcCess-control-Allow-Credentials ', 'TRUE');
|
$response->addHeader('AcCess-control-Allow-Credentials ', 'TRUE');
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* ownCloud - App Framework
|
* ownCloud - App Framework
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
@ -26,6 +26,7 @@ namespace OC\AppFramework\Middleware\Security;
|
||||||
|
|
||||||
use OC\AppFramework\Http;
|
use OC\AppFramework\Http;
|
||||||
use OC\AppFramework\Http\Request;
|
use OC\AppFramework\Http\Request;
|
||||||
|
use OC\AppFramework\Utility\ControllerMethodReflector;
|
||||||
use OCP\AppFramework\Http\RedirectResponse;
|
use OCP\AppFramework\Http\RedirectResponse;
|
||||||
use OCP\AppFramework\Http\JSONResponse;
|
use OCP\AppFramework\Http\JSONResponse;
|
||||||
|
|
||||||
|
@ -37,14 +38,16 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
private $secException;
|
private $secException;
|
||||||
private $secAjaxException;
|
private $secAjaxException;
|
||||||
private $request;
|
private $request;
|
||||||
|
private $reader;
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$api = $this->getMock('OC\AppFramework\DependencyInjection\DIContainer', array(), array('test'));
|
$api = $this->getMock('OC\AppFramework\DependencyInjection\DIContainer', array(), array('test'));
|
||||||
$this->controller = $this->getMock('OCP\AppFramework\Controller',
|
$this->controller = $this->getMock('OCP\AppFramework\Controller',
|
||||||
array(), array($api, new Request()));
|
array(), array($api, new Request()));
|
||||||
|
$this->reader = new ControllerMethodReflector();
|
||||||
|
|
||||||
$this->request = new Request();
|
$this->request = new Request();
|
||||||
$this->middleware = new SecurityMiddleware($api, $this->request);
|
$this->middleware = new SecurityMiddleware($api, $this->request, $this->reader);
|
||||||
$this->secException = new SecurityException('hey', false);
|
$this->secException = new SecurityException('hey', false);
|
||||||
$this->secAjaxException = new SecurityException('hey', true);
|
$this->secAjaxException = new SecurityException('hey', true);
|
||||||
}
|
}
|
||||||
|
@ -68,7 +71,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
$api->expects($this->any())->method('getServer')
|
$api->expects($this->any())->method('getServer')
|
||||||
->will($this->returnValue($serverMock));
|
->will($this->returnValue($serverMock));
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $this->request);
|
$sec = new SecurityMiddleware($api, $this->request, $this->reader);
|
||||||
|
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method);
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method);
|
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,11 +103,12 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $this->request);
|
$sec = new SecurityMiddleware($api, $this->request, $this->reader);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest',
|
$controller = '\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest';
|
||||||
$method);
|
$this->reader->reflect($controller, $method);
|
||||||
|
$sec->beforeController($controller, $method);
|
||||||
} catch (SecurityException $ex){
|
} catch (SecurityException $ex){
|
||||||
$this->assertEquals($status, $ex->getCode());
|
$this->assertEquals($status, $ex->getCode());
|
||||||
}
|
}
|
||||||
|
@ -184,7 +189,9 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
->method('isLoggedIn')
|
->method('isLoggedIn')
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $this->request);
|
$sec = new SecurityMiddleware($api, $this->request, $this->reader);
|
||||||
|
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest',
|
||||||
|
'testNoChecks');
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest',
|
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest',
|
||||||
'testNoChecks');
|
'testNoChecks');
|
||||||
}
|
}
|
||||||
|
@ -207,7 +214,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $this->request);
|
$sec = new SecurityMiddleware($api, $this->request, $this->reader);
|
||||||
|
|
||||||
if($shouldFail){
|
if($shouldFail){
|
||||||
$this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException');
|
$this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException');
|
||||||
|
@ -215,6 +222,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
$this->setExpectedException(null);
|
$this->setExpectedException(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method);
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method);
|
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +238,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
->method('passesCSRFCheck')
|
->method('passesCSRFCheck')
|
||||||
->will($this->returnValue(false));
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $request);
|
$sec = new SecurityMiddleware($api, $request, $this->reader);
|
||||||
|
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testCsrfCheck');
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testCsrfCheck');
|
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testCsrfCheck');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +255,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
->method('passesCSRFCheck')
|
->method('passesCSRFCheck')
|
||||||
->will($this->returnValue(false));
|
->will($this->returnValue(false));
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $request);
|
$sec = new SecurityMiddleware($api, $request, $this->reader);
|
||||||
|
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testNoCsrfCheck');
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testNoCsrfCheck');
|
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testNoCsrfCheck');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +271,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
->method('passesCSRFCheck')
|
->method('passesCSRFCheck')
|
||||||
->will($this->returnValue(true));
|
->will($this->returnValue(true));
|
||||||
|
|
||||||
$sec = new SecurityMiddleware($api, $request);
|
$sec = new SecurityMiddleware($api, $request, $this->reader);
|
||||||
|
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testFailCsrfCheck');
|
||||||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testFailCsrfCheck');
|
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testFailCsrfCheck');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,7 +329,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
$this->request = new Request(
|
$this->request = new Request(
|
||||||
array('server' => array('HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')));
|
array('server' => array('HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8')));
|
||||||
$this->middleware = new SecurityMiddleware($api, $this->request);
|
$this->middleware = new SecurityMiddleware($api, $this->request, $this->reader);
|
||||||
$response = $this->middleware->afterException($this->controller, 'test',
|
$response = $this->middleware->afterException($this->controller, 'test',
|
||||||
$this->secException);
|
$this->secException);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ownCloud - App Framework
|
||||||
|
*
|
||||||
|
* @author Bernhard Posselt
|
||||||
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
|
*
|
||||||
|
* 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 OC\AppFramework\Utility;
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerMethodReflectorTest extends \PHPUnit_Framework_TestCase {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
*/
|
||||||
|
public function testReadAnnotation(){
|
||||||
|
$reader = new ControllerMethodReflector();
|
||||||
|
$reader->reflect(
|
||||||
|
'\OC\AppFramework\Utility\ControllerMethodReflectorTest',
|
||||||
|
'testReadAnnotation'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue($reader->hasAnnotation('Annotation'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @param test
|
||||||
|
*/
|
||||||
|
public function testReadAnnotationNoLowercase(){
|
||||||
|
$reader = new ControllerMethodReflector();
|
||||||
|
$reader->reflect(
|
||||||
|
'\OC\AppFramework\Utility\ControllerMethodReflectorTest',
|
||||||
|
'testReadAnnotationNoLowercase'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue($reader->hasAnnotation('Annotation'));
|
||||||
|
$this->assertFalse($reader->hasAnnotation('param'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @param int $test
|
||||||
|
*/
|
||||||
|
public function testReadTypeIntAnnotations(){
|
||||||
|
$reader = new ControllerMethodReflector();
|
||||||
|
$reader->reflect(
|
||||||
|
'\OC\AppFramework\Utility\ControllerMethodReflectorTest',
|
||||||
|
'testReadTypeIntAnnotations'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('int', $reader->getType('test'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Annotation
|
||||||
|
* @param double $test something special
|
||||||
|
*/
|
||||||
|
public function testReadTypeDoubleAnnotations(){
|
||||||
|
$reader = new ControllerMethodReflector();
|
||||||
|
$reader->reflect(
|
||||||
|
'\OC\AppFramework\Utility\ControllerMethodReflectorTest',
|
||||||
|
'testReadTypeDoubleAnnotations'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals('double', $reader->getType('test'));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function arguments($arg, $arg2) {}
|
||||||
|
public function testReflectParameters() {
|
||||||
|
$reader = new ControllerMethodReflector();
|
||||||
|
$reader->reflect(
|
||||||
|
'\OC\AppFramework\Utility\ControllerMethodReflectorTest',
|
||||||
|
'arguments'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(array('arg', 'arg2'), $reader->getParameters());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function arguments2($arg) {}
|
||||||
|
public function testReflectParameters2() {
|
||||||
|
$reader = new ControllerMethodReflector();
|
||||||
|
$reader->reflect(
|
||||||
|
'\OC\AppFramework\Utility\ControllerMethodReflectorTest',
|
||||||
|
'arguments2'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals(array('arg',), $reader->getParameters());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ownCloud - App Framework
|
|
||||||
*
|
|
||||||
* @author Bernhard Posselt
|
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
|
||||||
*
|
|
||||||
* 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 OC\AppFramework\Utility;
|
|
||||||
|
|
||||||
|
|
||||||
class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase {
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
*/
|
|
||||||
public function testReadAnnotation(){
|
|
||||||
$reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest',
|
|
||||||
'testReadAnnotation');
|
|
||||||
|
|
||||||
$this->assertTrue($reader->hasAnnotation('Annotation'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Annotation
|
|
||||||
* @param test
|
|
||||||
*/
|
|
||||||
public function testReadAnnotationNoLowercase(){
|
|
||||||
$reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest',
|
|
||||||
'testReadAnnotationNoLowercase');
|
|
||||||
|
|
||||||
$this->assertTrue($reader->hasAnnotation('Annotation'));
|
|
||||||
$this->assertFalse($reader->hasAnnotation('param'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -4,8 +4,8 @@
|
||||||
*
|
*
|
||||||
* @author Robin Appelman
|
* @author Robin Appelman
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Robin Appelman icewind@owncloud.com
|
* @copyright 2012 Robin Appelman <icewind@owncloud.com>
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* ownCloud
|
* ownCloud
|
||||||
*
|
*
|
||||||
* @author Bernhard Posselt
|
* @author Bernhard Posselt
|
||||||
* @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
|
* @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.com>
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||||
|
|
Loading…
Reference in New Issue