diff options
Diffstat (limited to 'lib/public/AppFramework')
30 files changed, 3583 insertions, 0 deletions
diff --git a/lib/public/AppFramework/ApiController.php b/lib/public/AppFramework/ApiController.php new file mode 100644 index 00000000000..07b72d9a46c --- /dev/null +++ b/lib/public/AppFramework/ApiController.php @@ -0,0 +1,96 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\Controller class + */ + +namespace OCP\AppFramework; + +use OCP\AppFramework\Http\Response; +use OCP\IRequest; + + +/** + * Base class to inherit your controllers from that are used for RESTful APIs + * @since 7.0.0 + */ +abstract class ApiController extends Controller { + + private $corsMethods; + private $corsAllowedHeaders; + private $corsMaxAge; + + /** + * constructor of the controller + * @param string $appName the name of the app + * @param IRequest $request an instance of the request + * @param string $corsMethods comma separated string of HTTP verbs which + * should be allowed for websites or webapps when calling your API, defaults to + * 'PUT, POST, GET, DELETE, PATCH' + * @param string $corsAllowedHeaders comma separated string of HTTP headers + * which should be allowed for websites or webapps when calling your API, + * defaults to 'Authorization, Content-Type, Accept' + * @param int $corsMaxAge number in seconds how long a preflighted OPTIONS + * request should be cached, defaults to 1728000 seconds + * @since 7.0.0 + */ + public function __construct($appName, + IRequest $request, + $corsMethods='PUT, POST, GET, DELETE, PATCH', + $corsAllowedHeaders='Authorization, Content-Type, Accept', + $corsMaxAge=1728000){ + parent::__construct($appName, $request); + $this->corsMethods = $corsMethods; + $this->corsAllowedHeaders = $corsAllowedHeaders; + $this->corsMaxAge = $corsMaxAge; + } + + + /** + * This method implements a preflighted cors response for you that you can + * link to for the options request + * + * @NoAdminRequired + * @NoCSRFRequired + * @PublicPage + * @since 7.0.0 + */ + public function preflightedCors() { + if(isset($this->request->server['HTTP_ORIGIN'])) { + $origin = $this->request->server['HTTP_ORIGIN']; + } else { + $origin = '*'; + } + + $response = new Response(); + $response->addHeader('Access-Control-Allow-Origin', $origin); + $response->addHeader('Access-Control-Allow-Methods', $this->corsMethods); + $response->addHeader('Access-Control-Max-Age', $this->corsMaxAge); + $response->addHeader('Access-Control-Allow-Headers', $this->corsAllowedHeaders); + $response->addHeader('Access-Control-Allow-Credentials', 'false'); + return $response; + } + + +} diff --git a/lib/public/AppFramework/App.php b/lib/public/AppFramework/App.php new file mode 100644 index 00000000000..e5069150765 --- /dev/null +++ b/lib/public/AppFramework/App.php @@ -0,0 +1,136 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Robin Appelman <icewind@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework/App class + */ + +namespace OCP\AppFramework; +use OC\AppFramework\Routing\RouteConfig; + + +/** + * Class App + * @package OCP\AppFramework + * + * Any application must inherit this call - all controller instances to be used are + * to be registered using IContainer::registerService + * @since 6.0.0 + */ +class App { + + + /** + * Turns an app id into a namespace by convetion. The id is split at the + * underscores, all parts are camelcased and reassembled. e.g.: + * some_app_id -> OCA\SomeAppId + * @param string $appId the app id + * @param string $topNamespace the namespace which should be prepended to + * the transformed app id, defaults to OCA\ + * @return string the starting namespace for the app + * @since 8.0.0 + */ + public static function buildAppNamespace($appId, $topNamespace='OCA\\') { + return \OC\AppFramework\App::buildAppNamespace($appId, $topNamespace); + } + + + /** + * @param array $urlParams an array with variables extracted from the routes + * @since 6.0.0 + */ + public function __construct($appName, $urlParams = array()) { + $this->container = new \OC\AppFramework\DependencyInjection\DIContainer($appName, $urlParams); + } + + private $container; + + /** + * @return IAppContainer + * @since 6.0.0 + */ + public function getContainer() { + return $this->container; + } + + /** + * This function is to be called to create single routes and restful routes based on the given $routes array. + * + * Example code in routes.php of tasks app (it will register two restful resources): + * $routes = array( + * 'resources' => array( + * 'lists' => array('url' => '/tasklists'), + * 'tasks' => array('url' => '/tasklists/{listId}/tasks') + * ) + * ); + * + * $a = new TasksApp(); + * $a->registerRoutes($this, $routes); + * + * @param \OCP\Route\IRouter $router + * @param array $routes + * @since 6.0.0 + */ + public function registerRoutes($router, $routes) { + $routeConfig = new RouteConfig($this->container, $router, $routes); + $routeConfig->register(); + } + + /** + * This function is called by the routing component to fire up the frameworks dispatch mechanism. + * + * Example code in routes.php of the task app: + * $this->create('tasks_index', '/')->get()->action( + * function($params){ + * $app = new TaskApp($params); + * $app->dispatch('PageController', 'index'); + * } + * ); + * + * + * Example for for TaskApp implementation: + * class TaskApp extends \OCP\AppFramework\App { + * + * public function __construct($params){ + * parent::__construct('tasks', $params); + * + * $this->getContainer()->registerService('PageController', function(IAppContainer $c){ + * $a = $c->query('API'); + * $r = $c->query('Request'); + * return new PageController($a, $r); + * }); + * } + * } + * + * @param string $controllerName the name of the controller under which it is + * stored in the DI container + * @param string $methodName the method that you want to call + * @since 6.0.0 + */ + public function dispatch($controllerName, $methodName) { + \OC\AppFramework\App::main($controllerName, $methodName, $this->container); + } +} diff --git a/lib/public/AppFramework/Controller.php b/lib/public/AppFramework/Controller.php new file mode 100644 index 00000000000..bd87197a7f1 --- /dev/null +++ b/lib/public/AppFramework/Controller.php @@ -0,0 +1,263 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * @author Vincent Petry <pvince81@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\Controller class + */ + +namespace OCP\AppFramework; + +use OCP\AppFramework\Http\TemplateResponse; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\Response; +use OCP\IRequest; + + +/** + * Base class to inherit your controllers from + * @since 6.0.0 + */ +abstract class Controller { + + /** + * app name + * @var string + * @since 7.0.0 + */ + protected $appName; + + /** + * current request + * @var \OCP\IRequest + * @since 6.0.0 + */ + protected $request; + + /** + * @var array + * @since 7.0.0 + */ + private $responders; + + /** + * constructor of the controller + * @param string $appName the name of the app + * @param IRequest $request an instance of the request + * @since 6.0.0 - parameter $appName was added in 7.0.0 - parameter $app was removed in 7.0.0 + */ + public function __construct($appName, + IRequest $request) { + $this->appName = $appName; + $this->request = $request; + + // default responders + $this->responders = array( + 'json' => function ($data) { + if ($data instanceof DataResponse) { + $response = new JSONResponse( + $data->getData(), + $data->getStatus() + ); + $dataHeaders = $data->getHeaders(); + $headers = $response->getHeaders(); + // do not overwrite Content-Type if it already exists + if (isset($dataHeaders['Content-Type'])) { + unset($headers['Content-Type']); + } + $response->setHeaders(array_merge($dataHeaders, $headers)); + return $response; + } else { + return new JSONResponse($data); + } + } + ); + } + + + /** + * Parses an HTTP accept header and returns the supported responder type + * @param string $acceptHeader + * @return string the responder type + * @since 7.0.0 + */ + public function getResponderByHTTPHeader($acceptHeader) { + $headers = explode(',', $acceptHeader); + + // return the first matching responder + foreach ($headers as $header) { + $header = strtolower(trim($header)); + + $responder = str_replace('application/', '', $header); + + if (array_key_exists($responder, $this->responders)) { + return $responder; + } + } + + // no matching header defaults to json + return 'json'; + } + + + /** + * Registers a formatter for a type + * @param string $format + * @param \Closure $responder + * @since 7.0.0 + */ + 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 + * @since 7.0.0 + */ + public function buildResponse($response, $format='json') { + if(array_key_exists($format, $this->responders)) { + + $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 + * @deprecated 7.0.0 write your parameters as method arguments instead + * @param string $key the key which you want to access in the URL Parameter + * placeholder, $_POST or $_GET array. + * The priority how they're returned is the following: + * 1. URL parameters + * 2. POST parameters + * 3. GET parameters + * @param string $default If the key is not found, this value will be returned + * @return mixed the content of the array + * @since 6.0.0 + */ + public function params($key, $default=null){ + return $this->request->getParam($key, $default); + } + + + /** + * Returns all params that were received, be it from the request + * (as GET or POST) or through the URL by the route + * @deprecated 7.0.0 use $this->request instead + * @return array the array with all parameters + * @since 6.0.0 + */ + public function getParams() { + return $this->request->getParams(); + } + + + /** + * Returns the method of the request + * @deprecated 7.0.0 use $this->request instead + * @return string the method of the request (POST, GET, etc) + * @since 6.0.0 + */ + public function method() { + return $this->request->getMethod(); + } + + + /** + * Shortcut for accessing an uploaded file through the $_FILES array + * @deprecated 7.0.0 use $this->request instead + * @param string $key the key that will be taken from the $_FILES array + * @return array the file in the $_FILES element + * @since 6.0.0 + */ + public function getUploadedFile($key) { + return $this->request->getUploadedFile($key); + } + + + /** + * Shortcut for getting env variables + * @deprecated 7.0.0 use $this->request instead + * @param string $key the key that will be taken from the $_ENV array + * @return array the value in the $_ENV element + * @since 6.0.0 + */ + public function env($key) { + return $this->request->getEnv($key); + } + + + /** + * Shortcut for getting cookie variables + * @deprecated 7.0.0 use $this->request instead + * @param string $key the key that will be taken from the $_COOKIE array + * @return array the value in the $_COOKIE element + * @since 6.0.0 + */ + public function cookie($key) { + return $this->request->getCookie($key); + } + + + /** + * Shortcut for rendering a template + * @deprecated 7.0.0 return a template response instead + * @param string $templateName the name of the template + * @param array $params the template parameters in key => value structure + * @param string $renderAs user renders a full page, blank only your template + * admin an entry in the admin settings + * @param string[] $headers set additional headers in name/value pairs + * @return \OCP\AppFramework\Http\TemplateResponse containing the page + * @since 6.0.0 + */ + public function render($templateName, array $params=array(), + $renderAs='user', array $headers=array()){ + $response = new TemplateResponse($this->appName, $templateName); + $response->setParams($params); + $response->renderAs($renderAs); + + foreach($headers as $name => $value){ + $response->addHeader($name, $value); + } + + return $response; + } + + +} diff --git a/lib/public/AppFramework/Db/DoesNotExistException.php b/lib/public/AppFramework/Db/DoesNotExistException.php new file mode 100644 index 00000000000..9682a08d3cf --- /dev/null +++ b/lib/public/AppFramework/Db/DoesNotExistException.php @@ -0,0 +1,43 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OCP\AppFramework\Db; + + +/** + * This is returned or should be returned when a find request does not find an + * entry in the database + * @since 7.0.0 + */ +class DoesNotExistException extends \Exception { + + /** + * Constructor + * @param string $msg the error message + * @since 7.0.0 + */ + public function __construct($msg){ + parent::__construct($msg); + } + +} diff --git a/lib/public/AppFramework/Db/Entity.php b/lib/public/AppFramework/Db/Entity.php new file mode 100644 index 00000000000..d7db4d3c5a7 --- /dev/null +++ b/lib/public/AppFramework/Db/Entity.php @@ -0,0 +1,253 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Db; + + +/** + * @method integer getId() + * @method void setId(integer $id) + * @since 7.0.0 + */ +abstract class Entity { + + public $id; + + private $_updatedFields = array(); + private $_fieldTypes = array('id' => 'integer'); + + + /** + * Simple alternative constructor for building entities from a request + * @param array $params the array which was obtained via $this->params('key') + * in the controller + * @return Entity + * @since 7.0.0 + */ + public static function fromParams(array $params) { + $instance = new static(); + + foreach($params as $key => $value) { + $method = 'set' . ucfirst($key); + $instance->$method($value); + } + + return $instance; + } + + + /** + * Maps the keys of the row array to the attributes + * @param array $row the row to map onto the entity + * @since 7.0.0 + */ + public static function fromRow(array $row){ + $instance = new static(); + + foreach($row as $key => $value){ + $prop = ucfirst($instance->columnToProperty($key)); + $setter = 'set' . $prop; + $instance->$setter($value); + } + + $instance->resetUpdatedFields(); + + return $instance; + } + + + /** + * @return array with attribute and type + * @since 7.0.0 + */ + public function getFieldTypes() { + return $this->_fieldTypes; + } + + + /** + * Marks the entity as clean needed for setting the id after the insertion + * @since 7.0.0 + */ + public function resetUpdatedFields(){ + $this->_updatedFields = array(); + } + + /** + * Generic setter for properties + * @since 7.0.0 + */ + protected function setter($name, $args) { + // setters should only work for existing attributes + if(property_exists($this, $name)){ + if($this->$name === $args[0]) { + return; + } + $this->markFieldUpdated($name); + + // if type definition exists, cast to correct type + if($args[0] !== null && array_key_exists($name, $this->_fieldTypes)) { + settype($args[0], $this->_fieldTypes[$name]); + } + $this->$name = $args[0]; + + } else { + throw new \BadFunctionCallException($name . + ' is not a valid attribute'); + } + } + + /** + * Generic getter for properties + * @since 7.0.0 + */ + protected function getter($name) { + // getters should only work for existing attributes + if(property_exists($this, $name)){ + return $this->$name; + } else { + throw new \BadFunctionCallException($name . + ' is not a valid attribute'); + } + } + + + /** + * Each time a setter is called, push the part after set + * into an array: for instance setId will save Id in the + * updated fields array so it can be easily used to create the + * getter method + * @since 7.0.0 + */ + public function __call($methodName, $args){ + $attr = lcfirst( substr($methodName, 3) ); + + if(strpos($methodName, 'set') === 0){ + $this->setter($attr, $args); + } elseif(strpos($methodName, 'get') === 0) { + return $this->getter($attr); + } else { + throw new \BadFunctionCallException($methodName . + ' does not exist'); + } + + } + + + /** + * Mark am attribute as updated + * @param string $attribute the name of the attribute + * @since 7.0.0 + */ + protected function markFieldUpdated($attribute){ + $this->_updatedFields[$attribute] = true; + } + + + /** + * Transform a database columnname to a property + * @param string $columnName the name of the column + * @return string the property name + * @since 7.0.0 + */ + public function columnToProperty($columnName){ + $parts = explode('_', $columnName); + $property = null; + + foreach($parts as $part){ + if($property === null){ + $property = $part; + } else { + $property .= ucfirst($part); + } + } + + return $property; + } + + + /** + * Transform a property to a database column name + * @param string $property the name of the property + * @return string the column name + * @since 7.0.0 + */ + public function propertyToColumn($property){ + $parts = preg_split('/(?=[A-Z])/', $property); + $column = null; + + foreach($parts as $part){ + if($column === null){ + $column = $part; + } else { + $column .= '_' . lcfirst($part); + } + } + + return $column; + } + + + /** + * @return array array of updated fields for update query + * @since 7.0.0 + */ + public function getUpdatedFields(){ + return $this->_updatedFields; + } + + + /** + * Adds type information for a field so that its automatically casted to + * that value once its being returned from the database + * @param string $fieldName the name of the attribute + * @param string $type the type which will be used to call settype() + * @since 7.0.0 + */ + protected function addType($fieldName, $type){ + $this->_fieldTypes[$fieldName] = $type; + } + + + /** + * Slugify the value of a given attribute + * Warning: This doesn't result in a unique value + * @param string $attributeName the name of the attribute, which value should be slugified + * @return string slugified value + * @since 7.0.0 + */ + public function slugify($attributeName){ + // toSlug should only work for existing attributes + if(property_exists($this, $attributeName)){ + $value = $this->$attributeName; + // replace everything except alphanumeric with a single '-' + $value = preg_replace('/[^A-Za-z0-9]+/', '-', $value); + $value = strtolower($value); + // trim '-' + return trim($value, '-'); + } else { + throw new \BadFunctionCallException($attributeName . + ' is not a valid attribute'); + } + } + +} diff --git a/lib/public/AppFramework/Db/Mapper.php b/lib/public/AppFramework/Db/Mapper.php new file mode 100644 index 00000000000..2e97b06802a --- /dev/null +++ b/lib/public/AppFramework/Db/Mapper.php @@ -0,0 +1,376 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OCP\AppFramework\Db; + +use OCP\IDBConnection; +use OCP\IDb; + + +/** + * Simple parent class for inheriting your data access layer from. This class + * may be subject to change in the future + * @since 7.0.0 + */ +abstract class Mapper { + + protected $tableName; + protected $entityClass; + protected $db; + + /** + * @param IDBConnection $db Instance of the Db abstraction layer + * @param string $tableName the name of the table. set this to allow entity + * @param string $entityClass the name of the entity that the sql should be + * mapped to queries without using sql + * @since 7.0.0 + */ + public function __construct(IDBConnection $db, $tableName, $entityClass=null){ + $this->db = $db; + $this->tableName = '*PREFIX*' . $tableName; + + // if not given set the entity name to the class without the mapper part + // cache it here for later use since reflection is slow + if($entityClass === null) { + $this->entityClass = str_replace('Mapper', '', get_class($this)); + } else { + $this->entityClass = $entityClass; + } + } + + + /** + * @return string the table name + * @since 7.0.0 + */ + public function getTableName(){ + return $this->tableName; + } + + + /** + * Deletes an entity from the table + * @param Entity $entity the entity that should be deleted + * @return Entity the deleted entity + * @since 7.0.0 - return value added in 8.1.0 + */ + public function delete(Entity $entity){ + $sql = 'DELETE FROM `' . $this->tableName . '` WHERE `id` = ?'; + $stmt = $this->execute($sql, [$entity->getId()]); + $stmt->closeCursor(); + return $entity; + } + + + /** + * Creates a new entry in the db from an entity + * @param Entity $entity the entity that should be created + * @return Entity the saved entity with the set id + * @since 7.0.0 + */ + public function insert(Entity $entity){ + // get updated fields to save, fields have to be set using a setter to + // be saved + $properties = $entity->getUpdatedFields(); + $values = ''; + $columns = ''; + $params = []; + + // build the fields + $i = 0; + foreach($properties as $property => $updated) { + $column = $entity->propertyToColumn($property); + $getter = 'get' . ucfirst($property); + + $columns .= '`' . $column . '`'; + $values .= '?'; + + // only append colon if there are more entries + if($i < count($properties)-1){ + $columns .= ','; + $values .= ','; + } + + $params[] = $entity->$getter(); + $i++; + + } + + $sql = 'INSERT INTO `' . $this->tableName . '`(' . + $columns . ') VALUES(' . $values . ')'; + + $stmt = $this->execute($sql, $params); + + $entity->setId((int) $this->db->lastInsertId($this->tableName)); + + $stmt->closeCursor(); + + return $entity; + } + + + + /** + * Updates an entry in the db from an entity + * @throws \InvalidArgumentException if entity has no id + * @param Entity $entity the entity that should be created + * @return Entity the saved entity with the set id + * @since 7.0.0 - return value was added in 8.0.0 + */ + public function update(Entity $entity){ + // if entity wasn't changed it makes no sense to run a db query + $properties = $entity->getUpdatedFields(); + if(count($properties) === 0) { + return $entity; + } + + // entity needs an id + $id = $entity->getId(); + if($id === null){ + throw new \InvalidArgumentException( + 'Entity which should be updated has no id'); + } + + // get updated fields to save, fields have to be set using a setter to + // be saved + // do not update the id field + unset($properties['id']); + + $columns = ''; + $params = []; + + // build the fields + $i = 0; + foreach($properties as $property => $updated) { + + $column = $entity->propertyToColumn($property); + $getter = 'get' . ucfirst($property); + + $columns .= '`' . $column . '` = ?'; + + // only append colon if there are more entries + if($i < count($properties)-1){ + $columns .= ','; + } + + $params[] = $entity->$getter(); + $i++; + } + + $sql = 'UPDATE `' . $this->tableName . '` SET ' . + $columns . ' WHERE `id` = ?'; + $params[] = $id; + + $stmt = $this->execute($sql, $params); + $stmt->closeCursor(); + + return $entity; + } + + /** + * Checks if an array is associative + * @param array $array + * @return bool true if associative + * @since 8.1.0 + */ + private function isAssocArray(array $array) { + return array_values($array) !== $array; + } + + /** + * Returns the correct PDO constant based on the value type + * @param $value + * @return int PDO constant + * @since 8.1.0 + */ + private function getPDOType($value) { + switch (gettype($value)) { + case 'integer': + return \PDO::PARAM_INT; + case 'boolean': + return \PDO::PARAM_BOOL; + default: + return \PDO::PARAM_STR; + } + } + + + /** + * Runs an sql query + * @param string $sql the prepare string + * @param array $params the params which should replace the ? in the sql query + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return \PDOStatement the database query result + * @since 7.0.0 + */ + protected function execute($sql, array $params=[], $limit=null, $offset=null){ + if ($this->db instanceof IDb) { + $query = $this->db->prepareQuery($sql, $limit, $offset); + } else { + $query = $this->db->prepare($sql, $limit, $offset); + } + + if ($this->isAssocArray($params)) { + foreach ($params as $key => $param) { + $pdoConstant = $this->getPDOType($param); + $query->bindValue($key, $param, $pdoConstant); + } + } else { + $index = 1; // bindParam is 1 indexed + foreach ($params as $param) { + $pdoConstant = $this->getPDOType($param); + $query->bindValue($index, $param, $pdoConstant); + $index++; + } + } + + $result = $query->execute(); + + // this is only for backwards compatibility reasons and can be removed + // in owncloud 10. IDb returns a StatementWrapper from execute, PDO, + // Doctrine and IDbConnection don't so this needs to be done in order + // to stay backwards compatible for the things that rely on the + // StatementWrapper being returned + if ($result instanceof \OC_DB_StatementWrapper) { + return $result; + } + + return $query; + } + + + /** + * Returns an db result and throws exceptions when there are more or less + * results + * @see findEntity + * @param string $sql the sql query + * @param array $params the parameters of the sql query + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @throws DoesNotExistException if the item does not exist + * @throws MultipleObjectsReturnedException if more than one item exist + * @return array the result as row + * @since 7.0.0 + */ + protected function findOneQuery($sql, array $params=[], $limit=null, $offset=null){ + $stmt = $this->execute($sql, $params, $limit, $offset); + $row = $stmt->fetch(); + + if($row === false || $row === null){ + $stmt->closeCursor(); + $msg = $this->buildDebugMessage( + 'Did expect one result but found none when executing', $sql, $params, $limit, $offset + ); + throw new DoesNotExistException($msg); + } + $row2 = $stmt->fetch(); + $stmt->closeCursor(); + //MDB2 returns null, PDO and doctrine false when no row is available + if( ! ($row2 === false || $row2 === null )) { + $msg = $this->buildDebugMessage( + 'Did not expect more than one result when executing', $sql, $params, $limit, $offset + ); + throw new MultipleObjectsReturnedException($msg); + } else { + return $row; + } + } + + /** + * Builds an error message by prepending the $msg to an error message which + * has the parameters + * @see findEntity + * @param string $sql the sql query + * @param array $params the parameters of the sql query + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return string formatted error message string + * @since 9.1.0 + */ + private function buildDebugMessage($msg, $sql, array $params=[], $limit=null, $offset=null) { + return $msg . + ': query "' . $sql . '"; ' . + 'parameters ' . print_r($params, true) . '; ' . + 'limit "' . $limit . '"; '. + 'offset "' . $offset . '"'; + } + + + /** + * Creates an entity from a row. Automatically determines the entity class + * from the current mapper name (MyEntityMapper -> MyEntity) + * @param array $row the row which should be converted to an entity + * @return Entity the entity + * @since 7.0.0 + */ + protected function mapRowToEntity($row) { + return call_user_func($this->entityClass .'::fromRow', $row); + } + + + /** + * Runs a sql query and returns an array of entities + * @param string $sql the prepare string + * @param array $params the params which should replace the ? in the sql query + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @return array all fetched entities + * @since 7.0.0 + */ + protected function findEntities($sql, array $params=[], $limit=null, $offset=null) { + $stmt = $this->execute($sql, $params, $limit, $offset); + + $entities = []; + + while($row = $stmt->fetch()){ + $entities[] = $this->mapRowToEntity($row); + } + + $stmt->closeCursor(); + + return $entities; + } + + + /** + * Returns an db result and throws exceptions when there are more or less + * results + * @param string $sql the sql query + * @param array $params the parameters of the sql query + * @param int $limit the maximum number of rows + * @param int $offset from which row we want to start + * @throws DoesNotExistException if the item does not exist + * @throws MultipleObjectsReturnedException if more than one item exist + * @return Entity the entity + * @since 7.0.0 + */ + protected function findEntity($sql, array $params=[], $limit=null, $offset=null){ + return $this->mapRowToEntity($this->findOneQuery($sql, $params, $limit, $offset)); + } + + +} diff --git a/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php b/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php new file mode 100644 index 00000000000..b9207051826 --- /dev/null +++ b/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php @@ -0,0 +1,43 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OCP\AppFramework\Db; + + +/** + * This is returned or should be returned when a find request finds more than one + * row + * @since 7.0.0 + */ +class MultipleObjectsReturnedException extends \Exception { + + /** + * Constructor + * @param string $msg the error message + * @since 7.0.0 + */ + public function __construct($msg){ + parent::__construct($msg); + } + +} diff --git a/lib/public/AppFramework/Http.php b/lib/public/AppFramework/Http.php new file mode 100644 index 00000000000..e0108146db7 --- /dev/null +++ b/lib/public/AppFramework/Http.php @@ -0,0 +1,96 @@ +<?php +/** + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP class + */ + +namespace OCP\AppFramework; + +/** + * Base class which contains constants for HTTP status codes + * @since 6.0.0 + */ +class Http { + + const STATUS_CONTINUE = 100; + const STATUS_SWITCHING_PROTOCOLS = 101; + const STATUS_PROCESSING = 102; + const STATUS_OK = 200; + const STATUS_CREATED = 201; + const STATUS_ACCEPTED = 202; + const STATUS_NON_AUTHORATIVE_INFORMATION = 203; + const STATUS_NO_CONTENT = 204; + const STATUS_RESET_CONTENT = 205; + const STATUS_PARTIAL_CONTENT = 206; + const STATUS_MULTI_STATUS = 207; + const STATUS_ALREADY_REPORTED = 208; + const STATUS_IM_USED = 226; + const STATUS_MULTIPLE_CHOICES = 300; + const STATUS_MOVED_PERMANENTLY = 301; + const STATUS_FOUND = 302; + const STATUS_SEE_OTHER = 303; + const STATUS_NOT_MODIFIED = 304; + const STATUS_USE_PROXY = 305; + const STATUS_RESERVED = 306; + const STATUS_TEMPORARY_REDIRECT = 307; + const STATUS_BAD_REQUEST = 400; + const STATUS_UNAUTHORIZED = 401; + const STATUS_PAYMENT_REQUIRED = 402; + const STATUS_FORBIDDEN = 403; + const STATUS_NOT_FOUND = 404; + const STATUS_METHOD_NOT_ALLOWED = 405; + const STATUS_NOT_ACCEPTABLE = 406; + const STATUS_PROXY_AUTHENTICATION_REQUIRED = 407; + const STATUS_REQUEST_TIMEOUT = 408; + const STATUS_CONFLICT = 409; + const STATUS_GONE = 410; + const STATUS_LENGTH_REQUIRED = 411; + const STATUS_PRECONDITION_FAILED = 412; + const STATUS_REQUEST_ENTITY_TOO_LARGE = 413; + const STATUS_REQUEST_URI_TOO_LONG = 414; + const STATUS_UNSUPPORTED_MEDIA_TYPE = 415; + const STATUS_REQUEST_RANGE_NOT_SATISFIABLE = 416; + const STATUS_EXPECTATION_FAILED = 417; + const STATUS_IM_A_TEAPOT = 418; + const STATUS_UNPROCESSABLE_ENTITY = 422; + const STATUS_LOCKED = 423; + const STATUS_FAILED_DEPENDENCY = 424; + const STATUS_UPGRADE_REQUIRED = 426; + const STATUS_PRECONDITION_REQUIRED = 428; + const STATUS_TOO_MANY_REQUESTS = 429; + const STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; + const STATUS_INTERNAL_SERVER_ERROR = 500; + const STATUS_NOT_IMPLEMENTED = 501; + const STATUS_BAD_GATEWAY = 502; + const STATUS_SERVICE_UNAVAILABLE = 503; + const STATUS_GATEWAY_TIMEOUT = 504; + const STATUS_HTTP_VERSION_NOT_SUPPORTED = 505; + const STATUS_VARIANT_ALSO_NEGOTIATES = 506; + const STATUS_INSUFFICIENT_STORAGE = 507; + const STATUS_LOOP_DETECTED = 508; + const STATUS_BANDWIDTH_LIMIT_EXCEEDED = 509; + const STATUS_NOT_EXTENDED = 510; + const STATUS_NETWORK_AUTHENTICATION_REQUIRED = 511; +} diff --git a/lib/public/AppFramework/Http/ContentSecurityPolicy.php b/lib/public/AppFramework/Http/ContentSecurityPolicy.php new file mode 100644 index 00000000000..7762ca809a2 --- /dev/null +++ b/lib/public/AppFramework/Http/ContentSecurityPolicy.php @@ -0,0 +1,88 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author sualko <klaus@jsxc.org> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * Class ContentSecurityPolicy is a simple helper which allows applications to + * modify the Content-Security-Policy sent by ownCloud. Per default only JavaScript, + * stylesheets, images, fonts, media and connections from the same domain + * ('self') are allowed. + * + * Even if a value gets modified above defaults will still get appended. Please + * notice that ownCloud ships already with sensible defaults and those policies + * should require no modification at all for most use-cases. + * + * @package OCP\AppFramework\Http + * @since 8.1.0 + */ +class ContentSecurityPolicy extends EmptyContentSecurityPolicy { + /** @var bool Whether inline JS snippets are allowed */ + protected $inlineScriptAllowed = false; + /** + * @var bool Whether eval in JS scripts is allowed + * TODO: Disallow per default + * @link https://github.com/owncloud/core/issues/11925 + */ + protected $evalScriptAllowed = true; + /** @var array Domains from which scripts can get loaded */ + protected $allowedScriptDomains = [ + '\'self\'', + ]; + /** + * @var bool Whether inline CSS is allowed + * TODO: Disallow per default + * @link https://github.com/owncloud/core/issues/13458 + */ + protected $inlineStyleAllowed = true; + /** @var array Domains from which CSS can get loaded */ + protected $allowedStyleDomains = [ + '\'self\'', + ]; + /** @var array Domains from which images can get loaded */ + protected $allowedImageDomains = [ + '\'self\'', + 'data:', + 'blob:', + ]; + /** @var array Domains to which connections can be done */ + protected $allowedConnectDomains = [ + '\'self\'', + ]; + /** @var array Domains from which media elements can be loaded */ + protected $allowedMediaDomains = [ + '\'self\'', + ]; + /** @var array Domains from which object elements can be loaded */ + protected $allowedObjectDomains = []; + /** @var array Domains from which iframes can be loaded */ + protected $allowedFrameDomains = []; + /** @var array Domains from which fonts can be loaded */ + protected $allowedFontDomains = [ + '\'self\'', + ]; + /** @var array Domains from which web-workers and nested browsing content can load elements */ + protected $allowedChildSrcDomains = []; +} diff --git a/lib/public/AppFramework/Http/DataDisplayResponse.php b/lib/public/AppFramework/Http/DataDisplayResponse.php new file mode 100644 index 00000000000..4209c86a059 --- /dev/null +++ b/lib/public/AppFramework/Http/DataDisplayResponse.php @@ -0,0 +1,88 @@ +<?php +/** + * @author Morris Jobke <hey@morrisjobke.de> + * @author Roeland Jago Douma <rullzer@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * Class DataDisplayResponse + * + * @package OCP\AppFramework\Http + * @since 8.1.0 + */ +class DataDisplayResponse extends Response { + + /** + * response data + * @var string; + */ + protected $data; + + + /** + * @param string $data the data to display + * @param int $statusCode the Http status code, defaults to 200 + * @param array $headers additional key value based headers + * @since 8.1.0 + */ + public function __construct($data="", $statusCode=Http::STATUS_OK, + $headers=[]) { + $this->data = $data; + $this->setStatus($statusCode); + $this->setHeaders(array_merge($this->getHeaders(), $headers)); + $this->addHeader('Content-Disposition', 'inline; filename=""'); + } + + /** + * Outputs data. No processing is done. + * @return string + * @since 8.1.0 + */ + public function render() { + return $this->data; + } + + + /** + * Sets values in the data + * @param string $data the data to display + * @return DataDisplayResponse Reference to this object + * @since 8.1.0 + */ + public function setData($data){ + $this->data = $data; + + return $this; + } + + + /** + * Used to get the set parameters + * @return string the data + * @since 8.1.0 + */ + public function getData(){ + return $this->data; + } + +} diff --git a/lib/public/AppFramework/Http/DataDownloadResponse.php b/lib/public/AppFramework/Http/DataDownloadResponse.php new file mode 100644 index 00000000000..55ef4e6c82c --- /dev/null +++ b/lib/public/AppFramework/Http/DataDownloadResponse.php @@ -0,0 +1,63 @@ +<?php +/** + * @author Georg Ehrke <georg@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ +namespace OCP\AppFramework\Http; + +/** + * Class DataDownloadResponse + * + * @package OCP\AppFramework\Http + * @since 8.0.0 + */ +class DataDownloadResponse extends DownloadResponse { + /** + * @var string + */ + private $data; + + /** + * Creates a response that prompts the user to download the text + * @param string $data text to be downloaded + * @param string $filename the name that the downloaded file should have + * @param string $contentType the mimetype that the downloaded file should have + * @since 8.0.0 + */ + public function __construct($data, $filename, $contentType) { + $this->data = $data; + parent::__construct($filename, $contentType); + } + + /** + * @param string $data + * @since 8.0.0 + */ + public function setData($data) { + $this->data = $data; + } + + /** + * @return string + * @since 8.0.0 + */ + public function render() { + return $this->data; + } +} diff --git a/lib/public/AppFramework/Http/DataResponse.php b/lib/public/AppFramework/Http/DataResponse.php new file mode 100644 index 00000000000..3ec4e2bdc32 --- /dev/null +++ b/lib/public/AppFramework/Http/DataResponse.php @@ -0,0 +1,83 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\DataResponse class + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * A generic DataResponse class that is used to return generic data responses + * for responders to transform + * @since 8.0.0 + */ +class DataResponse extends Response { + + /** + * response data + * @var array|object + */ + protected $data; + + + /** + * @param array|object $data the object or array that should be transformed + * @param int $statusCode the Http status code, defaults to 200 + * @param array $headers additional key value based headers + * @since 8.0.0 + */ + public function __construct($data=array(), $statusCode=Http::STATUS_OK, + array $headers=array()) { + $this->data = $data; + $this->setStatus($statusCode); + $this->setHeaders(array_merge($this->getHeaders(), $headers)); + } + + + /** + * Sets values in the data json array + * @param array|object $data an array or object which will be transformed + * @return DataResponse Reference to this object + * @since 8.0.0 + */ + public function setData($data){ + $this->data = $data; + + return $this; + } + + + /** + * Used to get the set parameters + * @return array the data + * @since 8.0.0 + */ + public function getData(){ + return $this->data; + } + + +} diff --git a/lib/public/AppFramework/Http/DownloadResponse.php b/lib/public/AppFramework/Http/DownloadResponse.php new file mode 100644 index 00000000000..af0d76951ca --- /dev/null +++ b/lib/public/AppFramework/Http/DownloadResponse.php @@ -0,0 +1,52 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OCP\AppFramework\Http; + + +/** + * Prompts the user to download the a file + * @since 7.0.0 + */ +class DownloadResponse extends \OCP\AppFramework\Http\Response { + + private $filename; + private $contentType; + + /** + * Creates a response that prompts the user to download the file + * @param string $filename the name that the downloaded file should have + * @param string $contentType the mimetype that the downloaded file should have + * @since 7.0.0 + */ + public function __construct($filename, $contentType) { + $this->filename = $filename; + $this->contentType = $contentType; + + $this->addHeader('Content-Disposition', 'attachment; filename="' . $filename . '"'); + $this->addHeader('Content-Type', $contentType); + } + + +} diff --git a/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php new file mode 100644 index 00000000000..61718ff7c0e --- /dev/null +++ b/lib/public/AppFramework/Http/EmptyContentSecurityPolicy.php @@ -0,0 +1,385 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * Class EmptyContentSecurityPolicy is a simple helper which allows applications + * to modify the Content-Security-Policy sent by ownCloud. Per default the policy + * is forbidding everything. + * + * As alternative with sane exemptions look at ContentSecurityPolicy + * + * @see \OCP\AppFramework\Http\ContentSecurityPolicy + * @package OCP\AppFramework\Http + * @since 9.0.0 + */ +class EmptyContentSecurityPolicy { + /** @var bool Whether inline JS snippets are allowed */ + protected $inlineScriptAllowed = null; + /** + * @var bool Whether eval in JS scripts is allowed + * TODO: Disallow per default + * @link https://github.com/owncloud/core/issues/11925 + */ + protected $evalScriptAllowed = null; + /** @var array Domains from which scripts can get loaded */ + protected $allowedScriptDomains = null; + /** + * @var bool Whether inline CSS is allowed + * TODO: Disallow per default + * @link https://github.com/owncloud/core/issues/13458 + */ + protected $inlineStyleAllowed = null; + /** @var array Domains from which CSS can get loaded */ + protected $allowedStyleDomains = null; + /** @var array Domains from which images can get loaded */ + protected $allowedImageDomains = null; + /** @var array Domains to which connections can be done */ + protected $allowedConnectDomains = null; + /** @var array Domains from which media elements can be loaded */ + protected $allowedMediaDomains = null; + /** @var array Domains from which object elements can be loaded */ + protected $allowedObjectDomains = null; + /** @var array Domains from which iframes can be loaded */ + protected $allowedFrameDomains = null; + /** @var array Domains from which fonts can be loaded */ + protected $allowedFontDomains = null; + /** @var array Domains from which web-workers and nested browsing content can load elements */ + protected $allowedChildSrcDomains = null; + + /** + * Whether inline JavaScript snippets are allowed or forbidden + * @param bool $state + * @return $this + * @since 8.1.0 + */ + public function allowInlineScript($state = false) { + $this->inlineScriptAllowed = $state; + return $this; + } + + /** + * Whether eval in JavaScript is allowed or forbidden + * @param bool $state + * @return $this + * @since 8.1.0 + */ + public function allowEvalScript($state = true) { + $this->evalScriptAllowed = $state; + return $this; + } + + /** + * Allows to execute JavaScript files from a specific domain. Use * to + * allow JavaScript from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedScriptDomain($domain) { + $this->allowedScriptDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed script domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowScriptDomain($domain) { + $this->allowedScriptDomains = array_diff($this->allowedScriptDomains, [$domain]); + return $this; + } + + /** + * Whether inline CSS snippets are allowed or forbidden + * @param bool $state + * @return $this + * @since 8.1.0 + */ + public function allowInlineStyle($state = true) { + $this->inlineStyleAllowed = $state; + return $this; + } + + /** + * Allows to execute CSS files from a specific domain. Use * to allow + * CSS from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedStyleDomain($domain) { + $this->allowedStyleDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed style domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowStyleDomain($domain) { + $this->allowedStyleDomains = array_diff($this->allowedStyleDomains, [$domain]); + return $this; + } + + /** + * Allows using fonts from a specific domain. Use * to allow + * fonts from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedFontDomain($domain) { + $this->allowedFontDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed font domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowFontDomain($domain) { + $this->allowedFontDomains = array_diff($this->allowedFontDomains, [$domain]); + return $this; + } + + /** + * Allows embedding images from a specific domain. Use * to allow + * images from all domains. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedImageDomain($domain) { + $this->allowedImageDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed image domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowImageDomain($domain) { + $this->allowedImageDomains = array_diff($this->allowedImageDomains, [$domain]); + return $this; + } + + /** + * To which remote domains the JS connect to. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedConnectDomain($domain) { + $this->allowedConnectDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed connect domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowConnectDomain($domain) { + $this->allowedConnectDomains = array_diff($this->allowedConnectDomains, [$domain]); + return $this; + } + + /** + * From which domains media elements can be embedded. + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedMediaDomain($domain) { + $this->allowedMediaDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed media domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowMediaDomain($domain) { + $this->allowedMediaDomains = array_diff($this->allowedMediaDomains, [$domain]); + return $this; + } + + /** + * From which domains objects such as <object>, <embed> or <applet> are executed + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedObjectDomain($domain) { + $this->allowedObjectDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed object domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowObjectDomain($domain) { + $this->allowedObjectDomains = array_diff($this->allowedObjectDomains, [$domain]); + return $this; + } + + /** + * Which domains can be embedded in an iframe + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedFrameDomain($domain) { + $this->allowedFrameDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed frame domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowFrameDomain($domain) { + $this->allowedFrameDomains = array_diff($this->allowedFrameDomains, [$domain]); + return $this; + } + + /** + * Domains from which web-workers and nested browsing content can load elements + * @param string $domain Domain to whitelist. Any passed value needs to be properly sanitized. + * @return $this + * @since 8.1.0 + */ + public function addAllowedChildSrcDomain($domain) { + $this->allowedChildSrcDomains[] = $domain; + return $this; + } + + /** + * Remove the specified allowed child src domain from the allowed domains. + * + * @param string $domain + * @return $this + * @since 8.1.0 + */ + public function disallowChildSrcDomain($domain) { + $this->allowedChildSrcDomains = array_diff($this->allowedChildSrcDomains, [$domain]); + return $this; + } + + /** + * Get the generated Content-Security-Policy as a string + * @return string + * @since 8.1.0 + */ + public function buildPolicy() { + $policy = "default-src 'none';"; + + if(!empty($this->allowedScriptDomains) || $this->inlineScriptAllowed || $this->evalScriptAllowed) { + $policy .= 'script-src '; + if(is_array($this->allowedScriptDomains)) { + $policy .= implode(' ', $this->allowedScriptDomains); + } + if($this->inlineScriptAllowed) { + $policy .= ' \'unsafe-inline\''; + } + if($this->evalScriptAllowed) { + $policy .= ' \'unsafe-eval\''; + } + $policy .= ';'; + } + + if(!empty($this->allowedStyleDomains) || $this->inlineStyleAllowed) { + $policy .= 'style-src '; + if(is_array($this->allowedStyleDomains)) { + $policy .= implode(' ', $this->allowedStyleDomains); + } + if($this->inlineStyleAllowed) { + $policy .= ' \'unsafe-inline\''; + } + $policy .= ';'; + } + + if(!empty($this->allowedImageDomains)) { + $policy .= 'img-src ' . implode(' ', $this->allowedImageDomains); + $policy .= ';'; + } + + if(!empty($this->allowedFontDomains)) { + $policy .= 'font-src ' . implode(' ', $this->allowedFontDomains); + $policy .= ';'; + } + + if(!empty($this->allowedConnectDomains)) { + $policy .= 'connect-src ' . implode(' ', $this->allowedConnectDomains); + $policy .= ';'; + } + + if(!empty($this->allowedMediaDomains)) { + $policy .= 'media-src ' . implode(' ', $this->allowedMediaDomains); + $policy .= ';'; + } + + if(!empty($this->allowedObjectDomains)) { + $policy .= 'object-src ' . implode(' ', $this->allowedObjectDomains); + $policy .= ';'; + } + + if(!empty($this->allowedFrameDomains)) { + $policy .= 'frame-src ' . implode(' ', $this->allowedFrameDomains); + $policy .= ';'; + } + + if(!empty($this->allowedChildSrcDomains)) { + $policy .= 'child-src ' . implode(' ', $this->allowedChildSrcDomains); + $policy .= ';'; + } + + return rtrim($policy, ';'); + } +} diff --git a/lib/public/AppFramework/Http/ICallbackResponse.php b/lib/public/AppFramework/Http/ICallbackResponse.php new file mode 100644 index 00000000000..97de484e917 --- /dev/null +++ b/lib/public/AppFramework/Http/ICallbackResponse.php @@ -0,0 +1,43 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + + +/** + * Interface ICallbackResponse + * + * @package OCP\AppFramework\Http + * @since 8.1.0 + */ +interface ICallbackResponse { + + /** + * Outputs the content that should be printed + * + * @param IOutput $output a small wrapper that handles output + * @since 8.1.0 + */ + function callback(IOutput $output); + +} diff --git a/lib/public/AppFramework/Http/IOutput.php b/lib/public/AppFramework/Http/IOutput.php new file mode 100644 index 00000000000..6c404c0b026 --- /dev/null +++ b/lib/public/AppFramework/Http/IOutput.php @@ -0,0 +1,77 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + + +/** + * Very thin wrapper class to make output testable + * @since 8.1.0 + */ +interface IOutput { + + /** + * @param string $out + * @since 8.1.0 + */ + public function setOutput($out); + + /** + * @param string $path + * + * @return bool false if an error occurred + * @since 8.1.0 + */ + public function setReadfile($path); + + /** + * @param string $header + * @since 8.1.0 + */ + public function setHeader($header); + + /** + * @return int returns the current http response code + * @since 8.1.0 + */ + public function getHttpResponseCode(); + + /** + * @param int $code sets the http status code + * @since 8.1.0 + */ + public function setHttpResponseCode($code); + + /** + * @param string $name + * @param string $value + * @param int $expire + * @param string $path + * @param string $domain + * @param bool $secure + * @param bool $httpOnly + * @since 8.1.0 + */ + public function setCookie($name, $value, $expire, $path, $domain, $secure, $httpOnly); + +} diff --git a/lib/public/AppFramework/Http/JSONResponse.php b/lib/public/AppFramework/Http/JSONResponse.php new file mode 100644 index 00000000000..89433fd23e5 --- /dev/null +++ b/lib/public/AppFramework/Http/JSONResponse.php @@ -0,0 +1,100 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\JSONResponse class + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * A renderer for JSON calls + * @since 6.0.0 + */ +class JSONResponse extends Response { + + /** + * response data + * @var array|object + */ + protected $data; + + + /** + * constructor of JSONResponse + * @param array|object $data the object or array that should be transformed + * @param int $statusCode the Http status code, defaults to 200 + * @since 6.0.0 + */ + public function __construct($data=array(), $statusCode=Http::STATUS_OK) { + $this->data = $data; + $this->setStatus($statusCode); + $this->addHeader('Content-Type', 'application/json; charset=utf-8'); + } + + + /** + * Returns the rendered json + * @return string the rendered json + * @since 6.0.0 + * @throws \Exception If data could not get encoded + */ + public function render() { + $response = json_encode($this->data, JSON_HEX_TAG); + if($response === false) { + throw new \Exception(sprintf('Could not json_encode due to invalid ' . + 'non UTF-8 characters in the array: %s', var_export($this->data, true))); + } + + return $response; + } + + /** + * Sets values in the data json array + * @param array|object $data an array or object which will be transformed + * to JSON + * @return JSONResponse Reference to this object + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function setData($data){ + $this->data = $data; + + return $this; + } + + + /** + * Used to get the set parameters + * @return array the data + * @since 6.0.0 + */ + public function getData(){ + return $this->data; + } + +} diff --git a/lib/public/AppFramework/Http/NotFoundResponse.php b/lib/public/AppFramework/Http/NotFoundResponse.php new file mode 100644 index 00000000000..8dcebd7cceb --- /dev/null +++ b/lib/public/AppFramework/Http/NotFoundResponse.php @@ -0,0 +1,49 @@ +<?php +/** + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; +use OCP\Template; + +/** + * A generic 404 response showing an 404 error page as well to the end-user + * @since 8.1.0 + */ +class NotFoundResponse extends Response { + + /** + * @since 8.1.0 + */ + public function __construct() { + $this->setStatus(404); + } + + /** + * @return string + * @since 8.1.0 + */ + public function render() { + $template = new Template('core', '404', 'guest'); + return $template->fetchPage(); + } +} diff --git a/lib/public/AppFramework/Http/OCSResponse.php b/lib/public/AppFramework/Http/OCSResponse.php new file mode 100644 index 00000000000..da9de712c0a --- /dev/null +++ b/lib/public/AppFramework/Http/OCSResponse.php @@ -0,0 +1,91 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\JSONResponse class + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * A renderer for OCS responses + * @since 8.1.0 + */ +class OCSResponse extends Response { + + private $data; + private $format; + private $statuscode; + private $message; + private $itemscount; + private $itemsperpage; + + /** + * generates the xml or json response for the API call from an multidimenional data array. + * @param string $format + * @param int $statuscode + * @param string $message + * @param array $data + * @param int|string $itemscount + * @param int|string $itemsperpage + * @since 8.1.0 + */ + public function __construct($format, $statuscode, $message, + $data=[], $itemscount='', + $itemsperpage='') { + $this->format = $format; + $this->statuscode = $statuscode; + $this->message = $message; + $this->data = $data; + $this->itemscount = $itemscount; + $this->itemsperpage = $itemsperpage; + + // set the correct header based on the format parameter + if ($format === 'json') { + $this->addHeader( + 'Content-Type', 'application/json; charset=utf-8' + ); + } else { + $this->addHeader( + 'Content-Type', 'application/xml; charset=utf-8' + ); + } + } + + /** + * @return string + * @since 8.1.0 + */ + public function render() { + $r = new \OC_OCS_Result($this->data, $this->statuscode, $this->message); + $r->setTotalItems($this->itemscount); + $r->setItemsPerPage($this->itemsperpage); + + return \OC_API::renderResult($this->format, $r->getMeta(), $r->getData()); + } + + +} diff --git a/lib/public/AppFramework/Http/RedirectResponse.php b/lib/public/AppFramework/Http/RedirectResponse.php new file mode 100644 index 00000000000..97140c9955f --- /dev/null +++ b/lib/public/AppFramework/Http/RedirectResponse.php @@ -0,0 +1,61 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author v1r0x <vinzenz.rosenkranz@gmail.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http\Response; +use OCP\AppFramework\Http; + + +/** + * Redirects to a different URL + * @since 7.0.0 + */ +class RedirectResponse extends Response { + + private $redirectURL; + + /** + * Creates a response that redirects to a url + * @param string $redirectURL the url to redirect to + * @since 7.0.0 + */ + public function __construct($redirectURL) { + $this->redirectURL = $redirectURL; + $this->setStatus(Http::STATUS_SEE_OTHER); + $this->addHeader('Location', $redirectURL); + } + + + /** + * @return string the url to redirect + * @since 7.0.0 + */ + public function getRedirectURL() { + return $this->redirectURL; + } + + +} diff --git a/lib/public/AppFramework/Http/Response.php b/lib/public/AppFramework/Http/Response.php new file mode 100644 index 00000000000..253d58b86ff --- /dev/null +++ b/lib/public/AppFramework/Http/Response.php @@ -0,0 +1,326 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\Response class + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * Base class for responses. Also used to just send headers. + * + * It handles headers, HTTP status code, last modified and ETag. + * @since 6.0.0 + */ +class Response { + + /** + * Headers - defaults to ['Cache-Control' => 'no-cache, must-revalidate'] + * @var array + */ + private $headers = array( + 'Cache-Control' => 'no-cache, must-revalidate' + ); + + + /** + * Cookies that will be need to be constructed as header + * @var array + */ + private $cookies = array(); + + + /** + * HTTP status code - defaults to STATUS OK + * @var int + */ + private $status = Http::STATUS_OK; + + + /** + * Last modified date + * @var \DateTime + */ + private $lastModified; + + + /** + * ETag + * @var string + */ + private $ETag; + + /** @var ContentSecurityPolicy|null Used Content-Security-Policy */ + private $contentSecurityPolicy = null; + + + /** + * Caches the response + * @param int $cacheSeconds the amount of seconds that should be cached + * if 0 then caching will be disabled + * @return $this + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function cacheFor($cacheSeconds) { + + if($cacheSeconds > 0) { + $this->addHeader('Cache-Control', 'max-age=' . $cacheSeconds . + ', must-revalidate'); + } else { + $this->addHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); + } + + return $this; + } + + /** + * Adds a new cookie to the response + * @param string $name The name of the cookie + * @param string $value The value of the cookie + * @param \DateTime|null $expireDate Date on that the cookie should expire, if set + * to null cookie will be considered as session + * cookie. + * @return $this + * @since 8.0.0 + */ + public function addCookie($name, $value, \DateTime $expireDate = null) { + $this->cookies[$name] = array('value' => $value, 'expireDate' => $expireDate); + return $this; + } + + + /** + * Set the specified cookies + * @param array $cookies array('foo' => array('value' => 'bar', 'expire' => null)) + * @return $this + * @since 8.0.0 + */ + public function setCookies(array $cookies) { + $this->cookies = $cookies; + return $this; + } + + + /** + * Invalidates the specified cookie + * @param string $name + * @return $this + * @since 8.0.0 + */ + public function invalidateCookie($name) { + $this->addCookie($name, 'expired', new \DateTime('1971-01-01 00:00')); + return $this; + } + + /** + * Invalidates the specified cookies + * @param array $cookieNames array('foo', 'bar') + * @return $this + * @since 8.0.0 + */ + public function invalidateCookies(array $cookieNames) { + foreach($cookieNames as $cookieName) { + $this->invalidateCookie($cookieName); + } + return $this; + } + + /** + * Returns the cookies + * @return array + * @since 8.0.0 + */ + public function getCookies() { + return $this->cookies; + } + + /** + * Adds a new header to the response that will be called before the render + * function + * @param string $name The name of the HTTP header + * @param string $value The value, null will delete it + * @return $this + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function addHeader($name, $value) { + $name = trim($name); // always remove leading and trailing whitespace + // to be able to reliably check for security + // headers + + if(is_null($value)) { + unset($this->headers[$name]); + } else { + $this->headers[$name] = $value; + } + + return $this; + } + + + /** + * Set the headers + * @param array $headers value header pairs + * @return $this + * @since 8.0.0 + */ + public function setHeaders(array $headers) { + $this->headers = $headers; + + return $this; + } + + + /** + * Returns the set headers + * @return array the headers + * @since 6.0.0 + */ + public function getHeaders() { + $mergeWith = []; + + if($this->lastModified) { + $mergeWith['Last-Modified'] = + $this->lastModified->format(\DateTime::RFC2822); + } + + // Build Content-Security-Policy and use default if none has been specified + if(is_null($this->contentSecurityPolicy)) { + $this->setContentSecurityPolicy(new ContentSecurityPolicy()); + } + $this->headers['Content-Security-Policy'] = $this->contentSecurityPolicy->buildPolicy(); + + if($this->ETag) { + $mergeWith['ETag'] = '"' . $this->ETag . '"'; + } + + return array_merge($mergeWith, $this->headers); + } + + + /** + * By default renders no output + * @return null + * @since 6.0.0 + */ + public function render() { + return null; + } + + + /** + * Set response status + * @param int $status a HTTP status code, see also the STATUS constants + * @return Response Reference to this object + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function setStatus($status) { + $this->status = $status; + + return $this; + } + + /** + * Set a Content-Security-Policy + * @param ContentSecurityPolicy $csp Policy to set for the response object + * @return $this + * @since 8.1.0 + */ + public function setContentSecurityPolicy(ContentSecurityPolicy $csp) { + $this->contentSecurityPolicy = $csp; + return $this; + } + + /** + * Get the currently used Content-Security-Policy + * @return ContentSecurityPolicy|null Used Content-Security-Policy or null if + * none specified. + * @since 8.1.0 + */ + public function getContentSecurityPolicy() { + return $this->contentSecurityPolicy; + } + + + /** + * Get response status + * @since 6.0.0 + */ + public function getStatus() { + return $this->status; + } + + + /** + * Get the ETag + * @return string the etag + * @since 6.0.0 + */ + public function getETag() { + return $this->ETag; + } + + + /** + * Get "last modified" date + * @return \DateTime RFC2822 formatted last modified date + * @since 6.0.0 + */ + public function getLastModified() { + return $this->lastModified; + } + + + /** + * Set the ETag + * @param string $ETag + * @return Response Reference to this object + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function setETag($ETag) { + $this->ETag = $ETag; + + return $this; + } + + + /** + * Set "last modified" date + * @param \DateTime $lastModified + * @return Response Reference to this object + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function setLastModified($lastModified) { + $this->lastModified = $lastModified; + + return $this; + } + + +} diff --git a/lib/public/AppFramework/Http/StreamResponse.php b/lib/public/AppFramework/Http/StreamResponse.php new file mode 100644 index 00000000000..e9157f9ddb2 --- /dev/null +++ b/lib/public/AppFramework/Http/StreamResponse.php @@ -0,0 +1,64 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Lukas Reschke <lukas@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Http; + +use OCP\AppFramework\Http; + +/** + * Class StreamResponse + * + * @package OCP\AppFramework\Http + * @since 8.1.0 + */ +class StreamResponse extends Response implements ICallbackResponse { + /** @var string */ + private $filePath; + + /** + * @param string $filePath the path to the file which should be streamed + * @since 8.1.0 + */ + public function __construct ($filePath) { + $this->filePath = $filePath; + } + + + /** + * Streams the file using readfile + * + * @param IOutput $output a small wrapper that handles output + * @since 8.1.0 + */ + public function callback (IOutput $output) { + // handle caching + if ($output->getHttpResponseCode() !== Http::STATUS_NOT_MODIFIED) { + if (!file_exists($this->filePath)) { + $output->setHttpResponseCode(Http::STATUS_NOT_FOUND); + } elseif ($output->setReadfile($this->filePath) === false) { + $output->setHttpResponseCode(Http::STATUS_BAD_REQUEST); + } + } + } + +} diff --git a/lib/public/AppFramework/Http/TemplateResponse.php b/lib/public/AppFramework/Http/TemplateResponse.php new file mode 100644 index 00000000000..7774d881e4d --- /dev/null +++ b/lib/public/AppFramework/Http/TemplateResponse.php @@ -0,0 +1,159 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\HTTP\TemplateResponse class + */ + +namespace OCP\AppFramework\Http; + + +/** + * Response for a normal template + * @since 6.0.0 + */ +class TemplateResponse extends Response { + + /** + * name of the template + * @var string + */ + protected $templateName; + + /** + * parameters + * @var array + */ + protected $params; + + /** + * rendering type (admin, user, blank) + * @var string + */ + protected $renderAs; + + /** + * app name + * @var string + */ + protected $appName; + + /** + * constructor of TemplateResponse + * @param string $appName the name of the app to load the template from + * @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 + * @since 6.0.0 - parameters $params and $renderAs were added in 7.0.0 + */ + public function __construct($appName, $templateName, array $params=array(), + $renderAs='user') { + $this->templateName = $templateName; + $this->appName = $appName; + $this->params = $params; + $this->renderAs = $renderAs; + } + + + /** + * Sets template parameters + * @param array $params an array with key => value structure which sets template + * variables + * @return TemplateResponse Reference to this object + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function setParams(array $params){ + $this->params = $params; + + return $this; + } + + + /** + * Used for accessing the set parameters + * @return array the params + * @since 6.0.0 + */ + public function getParams(){ + return $this->params; + } + + + /** + * Used for accessing the name of the set template + * @return string the name of the used template + * @since 6.0.0 + */ + public function getTemplateName(){ + return $this->templateName; + } + + + /** + * Sets the template page + * @param string $renderAs admin, user or blank. Admin also prints the admin + * settings header and footer, user renders the normal + * normal page including footer and header and blank + * just renders the plain template + * @return TemplateResponse Reference to this object + * @since 6.0.0 - return value was added in 7.0.0 + */ + public function renderAs($renderAs){ + $this->renderAs = $renderAs; + + return $this; + } + + + /** + * Returns the set renderAs + * @return string the renderAs value + * @since 6.0.0 + */ + public function getRenderAs(){ + return $this->renderAs; + } + + + /** + * Returns the rendered html + * @return string the rendered html + * @since 6.0.0 + */ + public function render(){ + // \OCP\Template needs an empty string instead of 'blank' for an unwrapped response + $renderAs = $this->renderAs === 'blank' ? '' : $this->renderAs; + + $template = new \OCP\Template($this->appName, $this->templateName, $renderAs); + + foreach($this->params as $key => $value){ + $template->assign($key, $value); + } + + return $template->fetchPage(); + } + +} diff --git a/lib/public/AppFramework/IApi.php b/lib/public/AppFramework/IApi.php new file mode 100644 index 00000000000..66614328873 --- /dev/null +++ b/lib/public/AppFramework/IApi.php @@ -0,0 +1,97 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework/IApi interface + */ + +namespace OCP\AppFramework; + + +/** + * A few very basic and frequently used API functions are combined in here + * @deprecated 8.0.0 + */ +interface IApi { + + + /** + * Gets the userid of the current user + * @return string the user id of the current user + * @deprecated 8.0.0 Use \OC::$server->getUserSession()->getUser()->getUID() + */ + function getUserId(); + + + /** + * Adds a new javascript file + * @deprecated 8.0.0 include javascript and css in template files + * @param string $scriptName the name of the javascript in js/ without the suffix + * @param string $appName the name of the app, defaults to the current one + * @return void + */ + function addScript($scriptName, $appName = null); + + + /** + * Adds a new css file + * @deprecated 8.0.0 include javascript and css in template files + * @param string $styleName the name of the css file in css/without the suffix + * @param string $appName the name of the app, defaults to the current one + * @return void + */ + function addStyle($styleName, $appName = null); + + + /** + * @deprecated 8.0.0 include javascript and css in template files + * shorthand for addScript for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + * @return void + */ + function add3rdPartyScript($name); + + + /** + * @deprecated 8.0.0 include javascript and css in template files + * shorthand for addStyle for files in the 3rdparty directory + * @param string $name the name of the file without the suffix + * @return void + */ + function add3rdPartyStyle($name); + + + /** + * Checks if an app is enabled + * @deprecated 8.0.0 communication between apps should happen over built in + * callbacks or interfaces (check the contacts and calendar managers) + * Checks if an app is enabled + * also use \OC::$server->getAppManager()->isEnabledForUser($appName) + * @param string $appName the name of an app + * @return bool true if app is enabled + */ + public function isAppEnabled($appName); + +} diff --git a/lib/public/AppFramework/IAppContainer.php b/lib/public/AppFramework/IAppContainer.php new file mode 100644 index 00000000000..905539e735e --- /dev/null +++ b/lib/public/AppFramework/IAppContainer.php @@ -0,0 +1,97 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Jörn Friedrich Dreyer <jfd@butonic.de> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Roeland Jago Douma <rullzer@owncloud.com> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework; + +use OCP\AppFramework\IApi; +use OCP\IContainer; + +/** + * Class IAppContainer + * @package OCP\AppFramework + * + * This container interface provides short cuts for app developers to access predefined app service. + * @since 6.0.0 + */ +interface IAppContainer extends IContainer { + + /** + * used to return the appname of the set application + * @return string the name of your application + * @since 6.0.0 + */ + function getAppName(); + + /** + * @deprecated 8.0.0 implements only deprecated methods + * @return IApi + * @since 6.0.0 + */ + function getCoreApi(); + + /** + * @return \OCP\IServerContainer + * @since 6.0.0 + */ + function getServer(); + + /** + * @param string $middleWare + * @return boolean + * @since 6.0.0 + */ + function registerMiddleWare($middleWare); + + /** + * @deprecated 8.0.0 use IUserSession->isLoggedIn() + * @return boolean + * @since 6.0.0 + */ + function isLoggedIn(); + + /** + * @deprecated 8.0.0 use IGroupManager->isAdmin($userId) + * @return boolean + * @since 6.0.0 + */ + function isAdminUser(); + + /** + * @deprecated 8.0.0 use the ILogger instead + * @param string $message + * @param string $level + * @return mixed + * @since 6.0.0 + */ + function log($message, $level); + + /** + * Register a capability + * + * @param string $serviceName e.g. 'OCA\Files\Capabilities' + * @since 8.2.0 + */ + public function registerCapability($serviceName); +} diff --git a/lib/public/AppFramework/Middleware.php b/lib/public/AppFramework/Middleware.php new file mode 100644 index 00000000000..12ec5f7d573 --- /dev/null +++ b/lib/public/AppFramework/Middleware.php @@ -0,0 +1,110 @@ +<?php +/** + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * @author Thomas Tanghus <thomas@tanghus.net> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\Middleware class + */ + +namespace OCP\AppFramework; + +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Response; + + +/** + * Middleware is used to provide hooks before or after controller methods and + * deal with possible exceptions raised in the controller methods. + * They're modeled after Django's middleware system: + * https://docs.djangoproject.com/en/dev/topics/http/middleware/ + * @since 6.0.0 + */ +abstract class Middleware { + + + /** + * This is being run in normal order before the controller is being + * called which allows several modifications and checks + * + * @param Controller $controller the controller that is being called + * @param string $methodName the name of the method that will be called on + * the controller + * @since 6.0.0 + */ + public function beforeController($controller, $methodName){ + + } + + + /** + * This is being run when either the beforeController method or the + * controller method itself is throwing an exception. The middleware is + * asked in reverse order to handle the exception and to return a response. + * If the response is null, it is assumed that the exception could not be + * handled and the error will be thrown again + * + * @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 + * @throws \Exception the passed in exception if it can't handle it + * @return Response a Response object in case that the exception was handled + * @since 6.0.0 + */ + public function afterException($controller, $methodName, \Exception $exception){ + throw $exception; + } + + + /** + * This is being run after a successful controllermethod call and allows + * the manipulation of a Response object. The middleware is run in reverse order + * + * @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 Response $response the generated response from the controller + * @return Response a Response object + * @since 6.0.0 + */ + public function afterController($controller, $methodName, Response $response){ + return $response; + } + + + /** + * This is being run after the response object has been rendered and + * allows the manipulation of the output. The middleware is run in reverse order + * + * @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 string $output the generated output from a response + * @return string the output that should be printed + * @since 6.0.0 + */ + public function beforeOutput($controller, $methodName, $output){ + return $output; + } + +} diff --git a/lib/public/AppFramework/OCSController.php b/lib/public/AppFramework/OCSController.php new file mode 100644 index 00000000000..4736e94326e --- /dev/null +++ b/lib/public/AppFramework/OCSController.php @@ -0,0 +1,102 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Thomas Müller <thomas.mueller@tmit.eu> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +/** + * Public interface of ownCloud for apps to use. + * AppFramework\Controller class + */ + +namespace OCP\AppFramework; + +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\Http\OCSResponse; +use OCP\IRequest; + + +/** + * Base class to inherit your controllers from that are used for RESTful APIs + * @since 8.1.0 + */ +abstract class OCSController extends ApiController { + + /** + * constructor of the controller + * @param string $appName the name of the app + * @param IRequest $request an instance of the request + * @param string $corsMethods comma separated string of HTTP verbs which + * should be allowed for websites or webapps when calling your API, defaults to + * 'PUT, POST, GET, DELETE, PATCH' + * @param string $corsAllowedHeaders comma separated string of HTTP headers + * which should be allowed for websites or webapps when calling your API, + * defaults to 'Authorization, Content-Type, Accept' + * @param int $corsMaxAge number in seconds how long a preflighted OPTIONS + * request should be cached, defaults to 1728000 seconds + * @since 8.1.0 + */ + public function __construct($appName, + IRequest $request, + $corsMethods='PUT, POST, GET, DELETE, PATCH', + $corsAllowedHeaders='Authorization, Content-Type, Accept', + $corsMaxAge=1728000){ + parent::__construct($appName, $request, $corsMethods, + $corsAllowedHeaders, $corsMaxAge); + $this->registerResponder('json', function ($data) { + return $this->buildOCSResponse('json', $data); + }); + $this->registerResponder('xml', function ($data) { + return $this->buildOCSResponse('xml', $data); + }); + } + + + /** + * Unwrap data and build ocs response + * @param string $format json or xml + * @param array|DataResponse $data the data which should be transformed + * @since 8.1.0 + */ + private function buildOCSResponse($format, $data) { + if ($data instanceof DataResponse) { + $data = $data->getData(); + } + + $params = [ + 'statuscode' => 100, + 'message' => 'OK', + 'data' => [], + 'itemscount' => '', + 'itemsperpage' => '' + ]; + + foreach ($data as $key => $value) { + $params[$key] = $value; + } + + return new OCSResponse( + $format, $params['statuscode'], + $params['message'], $params['data'], + $params['itemscount'], $params['itemsperpage'] + ); + } + +} diff --git a/lib/public/AppFramework/QueryException.php b/lib/public/AppFramework/QueryException.php new file mode 100644 index 00000000000..62ab77dd839 --- /dev/null +++ b/lib/public/AppFramework/QueryException.php @@ -0,0 +1,33 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework; + +use Exception; + +/** + * Class QueryException + * + * @package OCP\AppFramework + * @since 8.1.0 + */ +class QueryException extends Exception {} diff --git a/lib/public/AppFramework/Utility/IControllerMethodReflector.php b/lib/public/AppFramework/Utility/IControllerMethodReflector.php new file mode 100644 index 00000000000..e2939ff8896 --- /dev/null +++ b/lib/public/AppFramework/Utility/IControllerMethodReflector.php @@ -0,0 +1,70 @@ +<?php +/** + * @author Joas Schilling <nickvergessen@owncloud.com> + * @author Morris Jobke <hey@morrisjobke.de> + * @author Olivier Paroz <github@oparoz.com> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +namespace OCP\AppFramework\Utility; + +/** + * Interface ControllerMethodReflector + * + * Reads and parses annotations from doc comments + * + * @package OCP\AppFramework\Utility + * @since 8.0.0 + */ +interface IControllerMethodReflector { + + /** + * @param object $object an object or classname + * @param string $method the method which we want to inspect + * @return void + * @since 8.0.0 + */ + public function reflect($object, $method); + + /** + * 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 + * @since 8.0.0 + */ + public function getType($parameter); + + /** + * @return array the arguments of the method with key => default value + * @since 8.0.0 + */ + public function getParameters(); + + /** + * Check if a method contains an annotation + * + * @param string $name the name of the annotation + * @return bool true if the annotation is found + * @since 8.0.0 + */ + public function hasAnnotation($name); + +} diff --git a/lib/public/AppFramework/Utility/ITimeFactory.php b/lib/public/AppFramework/Utility/ITimeFactory.php new file mode 100644 index 00000000000..a3333dd1949 --- /dev/null +++ b/lib/public/AppFramework/Utility/ITimeFactory.php @@ -0,0 +1,39 @@ +<?php +/** + * @author Bernhard Posselt <dev@bernhard-posselt.com> + * @author Morris Jobke <hey@morrisjobke.de> + * + * @copyright Copyright (c) 2016, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program 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, version 3, + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + + +namespace OCP\AppFramework\Utility; + + +/** + * Needed to mock calls to time() + * @since 8.0.0 + */ +interface ITimeFactory { + + /** + * @return int the result of a call to time() + * @since 8.0.0 + */ + public function getTime(); + +} |