tao-test/app/tao/actions/class.RestResource.php

362 lines
12 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2017-2018 (original work) Open Assessment Technologies SA;
*
*/
use oat\generis\model\OntologyAwareTrait;
use oat\tao\model\resources\ResourceService;
use oat\oatbox\log\LoggerAwareTrait;
/**
* Class tao_actions_RestResourceController
*
* The rest controller to manage resource APIs
*/
class tao_actions_RestResource extends tao_actions_CommonModule
{
use OntologyAwareTrait;
use LoggerAwareTrait;
const CLASS_PARAMETER = 'classUri';
const RESOURCE_PARAMETER = 'uri';
/**
* Create a resource for class found into http request parameters
*
* If http method is GET, return the form data
* If http method is POST, process form
*
* The POST request has to follow this structure:
* array (
* 'propertyUri' => 'value',
* 'propertyUri1' => 'value1',
* 'propertyUri2' => 'value2',
* 'propertyUri3' => array(
* 'value', 'value2',
* )
* )
*
* @requiresRight classUri WRITE
*/
public function create()
{
if ($this->isRequestGet()) {
try {
$this->returnSuccess($this->getForm($this->getClassParameter())->getData());
} catch (common_Exception $e) {
$this->returnFailure($e);
}
} elseif ($this->isRequestPost()) {
try {
$this->processForm($this->getClassParameter());
} catch (common_Exception $e) {
$this->returnFailure($e);
}
} else {
$this->returnFailure(new common_exception_MethodNotAllowed(__METHOD__ . ' only accepts GET or POST method'));
}
}
/**
* Edit a resource found into http request parameters
*
* If http method is GET, return the form data
* If http method is PUT, process form
*
* The PUT request has to follow this structure:
* array (
* 'propertyUri' => 'value',
* 'propertyUri1' => 'value1',
* 'propertyUri2' => 'value2',
* 'propertyUri3' => array(
* 'value', 'value2',
* )
* )
*
* @requiresRight uri WRITE
*/
public function edit()
{
if ($this->isRequestGet()) {
try {
$this->returnSuccess($this->getForm($this->getResourceParameter())->getData());
} catch (common_Exception $e) {
$this->returnFailure($e);
}
}
if ($this->isRequestPost()) {
try {
$this->processForm($this->getResourceParameter());
} catch (common_Exception $e) {
$this->returnFailure($e);
}
}
$this->returnFailure(new common_exception_MethodNotAllowed(__METHOD__ . ' only accepts GET or PUT method'));
}
/**
* Get all resources belonging to a given class.
* The result is paginated and structured based on the given format.
* The result can be filtered, or target a given selection.
*
* @requiresRight classUri READ
*/
public function getAll()
{
if ($this->isRequestGet()) {
try {
$format = $this->getRequestParameter('format');
$search = $this->hasRequestParameter('search') ? $this->getRawParameter('search') : '';
$limit = $this->hasRequestParameter('limit') ? $this->getRequestParameter('limit') : 30;
$offset = $this->hasRequestParameter('offset') ? $this->getRequestParameter('offset') : 0;
$selectedUris = [];
if (! empty($search)) {
$decodedSearch = json_decode($search, true);
if (is_array($decodedSearch) && count($decodedSearch) > 0) {
$search = $decodedSearch;
}
}
if ($this->hasRequestParameter('selectedUri')) {
$selectedUri = $this->getRequestParameter('selectedUri');
if (!empty($selectedUri)) {
$selectedUris = [$selectedUri];
}
}
$class = $this->getClassParameter();
if ($this->hasRequestParameter('classOnly')) {
$resources = $this->getResourceService()->getClasses($class, $format, $selectedUris, $search, $offset, $limit);
} else {
$resources = $this->getResourceService()->getResources($class, $format, $selectedUris, $search, $offset, $limit);
}
$user = \common_Session_SessionManager::getSession()->getUser();
if (isset($resources['nodes'])) {
$permissions = $this->getResourceService()->getResourcesPermissions($user, $resources['nodes']);
} else {
$permissions = $this->getResourceService()->getResourcesPermissions($user, $resources);
}
$this->returnSuccess([
'resources' => $resources,
'permissions' => $permissions
]);
} catch (common_Exception $e) {
$this->returnFailure($e);
}
}
}
/**
* Get the request parameters
* If http method is POST read stream from php://input
* Otherwise call parent method
*
* @return array
*/
public function getRequestParameters()
{
$parameters = [];
if ($this->isRequestPost()) {
$input = file_get_contents("php://input");
$arguments = explode('&', $input);
foreach ($arguments as $argument) {
$argumentSplited = explode('=', $argument);
$key = urldecode($argumentSplited[0]);
$value = urldecode($argumentSplited[1]);
// for multiple values
if (strpos($value, ',')) {
$value = explode(',', $value);
}
if (substr($key, -2) == '[]') {
$key = substr($key, 0, strlen($key) - 2);
if (!isset($parameters[$key])) {
$parameters[$key] = [];
}
$parameters[$key][] = $value;
} else {
$parameters[$key] = $value;
}
}
} else {
$parameters = parent::getRequestParameters();
}
return $parameters;
}
/**
* Process the form submission
* Bind the http data to form, validate, and save
*
* @param $instance
*/
protected function processForm($instance)
{
$parameters = $this->getRequestParameters();
$form = $this->getForm($instance)->bind($parameters);
$report = $form->validate();
if ($report->containsError()) {
$this->returnValidationFailure($report);
} else {
$resource = $form->save();
$this->returnSuccess(['uri' => $resource->getUri()]);
}
}
/**
* Get the form object to manage
* The $instance should be a class for creation or resource in case of edit
*
* @param $instance
* @return tao_actions_form_RestForm
*/
protected function getForm($instance)
{
return new \tao_actions_form_RestForm($instance);
}
/**
* Extract the resource from http request
* The parameter 'uri' must exists and be a valid uri
*
* @return core_kernel_classes_Resource
* @throws common_exception_MissingParameter
*/
protected function getResourceParameter()
{
if (! $this->hasRequestParameter(self::RESOURCE_PARAMETER)) {
throw new \common_exception_MissingParameter(self::RESOURCE_PARAMETER, __CLASS__);
}
$uri = $this->getRequestParameter(self::RESOURCE_PARAMETER);
if (empty($uri) || !common_Utils::isUri($uri)) {
throw new \common_exception_MissingParameter(self::RESOURCE_PARAMETER, __CLASS__);
}
return $this->getResource($uri);
}
/**
* Extract the class from http request
* The parameter 'classUri' must exists and be a valid uri
*
* @return core_kernel_classes_Class
* @throws common_exception_MissingParameter
*/
protected function getClassParameter()
{
if (! $this->hasRequestParameter(self::CLASS_PARAMETER)) {
throw new \common_exception_MissingParameter(self::CLASS_PARAMETER, __CLASS__);
}
$uri = $this->getRequestParameter(self::CLASS_PARAMETER);
if (empty($uri) || !common_Utils::isUri($uri)) {
throw new \common_exception_MissingParameter(self::CLASS_PARAMETER, __CLASS__);
}
return $this->getClass($uri);
}
/**
* Transform a report to http response with 422 code and report error messages
*
* @param common_report_Report $report
* @param bool $withMessage
*/
protected function returnValidationFailure(common_report_Report $report, $withMessage = true)
{
$data = ['data' => []];
/** @var common_report_Report $error */
foreach ($report->getErrors() as $error) {
$data['data'][$error->getData()] = $error->getMessage();
}
if ($withMessage) {
$data['success'] = false;
$data['errorCode'] = 400;
$data['errorMsg'] = 'Some fields are invalid';
$data['version'] = TAO_VERSION;
}
$this->returnJson($data, 400);
exit(0);
}
/**
* Return an error reponse following the given exception
* An exception handler manages http code, avoid to use returnJson to add unneeded header
*
* @param Exception $exception
* @param bool $withMessage
*/
protected function returnFailure(Exception $exception, $withMessage = true)
{
$data = [];
if ($withMessage) {
$data['success'] = false;
$data['errorCode'] = 500;
$data['version'] = TAO_VERSION;
if ($exception instanceof common_exception_UserReadableException) {
$data['errorMsg'] = $exception->getUserMessage();
} else {
$this->logWarning(__CLASS__ . ' : ' . $exception->getMessage());
$data['errorMsg'] = __('Unexpected error. Please contact administrator');
}
}
$this->returnJson($data, 500);
exit(0);
}
/**
* Return a successful http response
*
* @param array $rawData
* @param bool $withMessage
*/
protected function returnSuccess($rawData = [], $withMessage = true)
{
$data = [];
if ($withMessage) {
$data['success'] = true;
$data['data'] = $rawData;
$data['version'] = TAO_VERSION;
} else {
$data = $rawData;
}
$this->returnJson($data);
// exit(0);
}
/**
* Get the resource service
* @return ResourceService
*/
protected function getResourceService()
{
return $this->getServiceLocator()->get(ResourceService::SERVICE_ID);
}
}