API: Remove api response structure from OC_OCS_Result, handle multiple registered methods for api calls
This commit is contained in:
parent
1dac2ba496
commit
934735043b
155
lib/api.php
155
lib/api.php
|
@ -33,6 +33,13 @@ class OC_API {
|
||||||
const USER_AUTH = 1;
|
const USER_AUTH = 1;
|
||||||
const SUBADMIN_AUTH = 2;
|
const SUBADMIN_AUTH = 2;
|
||||||
const ADMIN_AUTH = 3;
|
const ADMIN_AUTH = 3;
|
||||||
|
/**
|
||||||
|
* API Response Codes
|
||||||
|
*/
|
||||||
|
const RESPOND_UNAUTHORISED = 997;
|
||||||
|
const RESPOND_SERVER_ERROR = 996;
|
||||||
|
const RESPOND_NOT_FOUND = 998;
|
||||||
|
const RESPOND_UNKNOWN_ERROR = 999;
|
||||||
|
|
||||||
private static $server;
|
private static $server;
|
||||||
|
|
||||||
|
@ -42,12 +49,12 @@ class OC_API {
|
||||||
private static function init() {
|
private static function init() {
|
||||||
self::$server = new OC_OAuth_Server(new OC_OAuth_Store());
|
self::$server = new OC_OAuth_Server(new OC_OAuth_Store());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* api actions
|
* api actions
|
||||||
*/
|
*/
|
||||||
protected static $actions = array();
|
protected static $actions = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* registers an api call
|
* registers an api call
|
||||||
* @param string $method the http method
|
* @param string $method the http method
|
||||||
|
@ -58,7 +65,7 @@ class OC_API {
|
||||||
* @param array $defaults
|
* @param array $defaults
|
||||||
* @param array $requirements
|
* @param array $requirements
|
||||||
*/
|
*/
|
||||||
public static function register($method, $url, $action, $app,
|
public static function register($method, $url, $action, $app,
|
||||||
$authLevel = OC_API::USER_AUTH,
|
$authLevel = OC_API::USER_AUTH,
|
||||||
$defaults = array(),
|
$defaults = array(),
|
||||||
$requirements = array()) {
|
$requirements = array()) {
|
||||||
|
@ -71,9 +78,9 @@ class OC_API {
|
||||||
->action('OC_API', 'call');
|
->action('OC_API', 'call');
|
||||||
self::$actions[$name] = array();
|
self::$actions[$name] = array();
|
||||||
}
|
}
|
||||||
self::$actions[$name] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel);
|
self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handles an api call
|
* handles an api call
|
||||||
* @param array $parameters
|
* @param array $parameters
|
||||||
|
@ -86,29 +93,99 @@ class OC_API {
|
||||||
parse_str(file_get_contents("php://input"), $parameters['_delete']);
|
parse_str(file_get_contents("php://input"), $parameters['_delete']);
|
||||||
}
|
}
|
||||||
$name = $parameters['_route'];
|
$name = $parameters['_route'];
|
||||||
// Check authentication and availability
|
// Foreach registered action
|
||||||
if(self::isAuthorised(self::$actions[$name])) {
|
$responses = array();
|
||||||
if(is_callable(self::$actions[$name]['action'])) {
|
foreach(self::$actions[$name] as $action) {
|
||||||
$response = call_user_func(self::$actions[$name]['action'], $parameters);
|
// Check authentication and availability
|
||||||
if(!($response instanceof OC_OCS_Result)) {
|
if(!self::isAuthorised(self::$actions[$name])) {
|
||||||
$response = new OC_OCS_Result(null, 996, 'Internal Server Error');
|
$responses[] = array(
|
||||||
}
|
'app' => $action['app'],
|
||||||
} else {
|
'response' => new OC_OCS_Result(null, OC_API::RESPOND_UNAUTHORISED, 'Unauthorised'),
|
||||||
$response = new OC_OCS_Result(null, 998, 'Api method not found');
|
);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
if(!is_callable($action['action'])) {
|
||||||
header('WWW-Authenticate: Basic realm="Authorization Required"');
|
$responses[] = array(
|
||||||
header('HTTP/1.0 401 Unauthorized');
|
'app' => $action['app'],
|
||||||
$response = new OC_OCS_Result(null, 997, 'Unauthorised');
|
'response' => new OC_OCS_Result(null, OC_API::RESPOND_NOT_FOUND, 'Api method not found'),
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Run the action
|
||||||
|
$responses[] = array(
|
||||||
|
'app' => $action['app'],
|
||||||
|
'response' => call_user_func($action['action'], $parameters),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Send the response
|
|
||||||
|
|
||||||
|
$response = self::mergeResponses($responses);
|
||||||
$formats = array('json', 'xml');
|
$formats = array('json', 'xml');
|
||||||
$format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml';
|
$format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml';
|
||||||
self::respond($response, $format);
|
self::respond($response);
|
||||||
// logout the user to be stateless
|
|
||||||
OC_User::logout();
|
OC_User::logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* merge the returned result objects into one response
|
||||||
|
* @param array $responses
|
||||||
|
*/
|
||||||
|
private static function mergeResponses($responses) {
|
||||||
|
$response = array();
|
||||||
|
// Sort into shipped and thirdparty
|
||||||
|
$shipped = array(
|
||||||
|
'succeded' => array(),
|
||||||
|
'failed' => array(),
|
||||||
|
);
|
||||||
|
$thirdparty = array(
|
||||||
|
'succeeded' => array(),
|
||||||
|
'failed' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($responses as $response) {
|
||||||
|
if(OC_App::isShipped($response['app'])) {
|
||||||
|
if($response['response']->succeeded()) {
|
||||||
|
$shipped['succeeded'][$response['app']] = $response['response'];
|
||||||
|
} else {
|
||||||
|
$shipped['failed'][$response['app']] = $response['response'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if($response['response']->succeeded()) {
|
||||||
|
$thirdparty['succeeded'][$response['app']] = $response['response'];
|
||||||
|
} else {
|
||||||
|
$thirdparty['failed'][$response['app']] = $response['response'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Remove any error responses if there is one shipped response that succeeded
|
||||||
|
if(!empty($shipped['succeeded'])){
|
||||||
|
$responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']);
|
||||||
|
} else if(!empty($shipped['failed'])){
|
||||||
|
// Which shipped response do we use if they all failed?
|
||||||
|
// They may have failed for different reasons (different status codes)
|
||||||
|
// Which reponse code should we return?
|
||||||
|
// Maybe any that are not OC_API::RESPOND_SERVER_ERROR
|
||||||
|
$response = $shipped['failed'][0];
|
||||||
|
return $response;
|
||||||
|
} else {
|
||||||
|
// Return the third party failure result
|
||||||
|
$response = $thirdparty['failed'][0];
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
// Merge the successful responses
|
||||||
|
$meta = array();
|
||||||
|
$data = array();
|
||||||
|
foreach($responses as $app => $response) {
|
||||||
|
if(OC_App::isShipped($app)) {
|
||||||
|
$data = array_merge_recursive($response->getData(), $data);
|
||||||
|
} else {
|
||||||
|
$data = array_merge_recursive($data, $response->getData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = new OC_OCS_Result($data, 100);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* authenticate the api call
|
* authenticate the api call
|
||||||
* @param array $action the action details as supplied to OC_API::register()
|
* @param array $action the action details as supplied to OC_API::register()
|
||||||
|
@ -132,7 +209,8 @@ class OC_API {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
$subAdmin = OC_SubAdmin::isSubAdmin($user);
|
$subAdmin = OC_SubAdmin::isSubAdmin($user);
|
||||||
if($subAdmin) {
|
$admin = OC_Group::inGroup($user, 'admin');
|
||||||
|
if($subAdmin || $admin) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -145,7 +223,7 @@ class OC_API {
|
||||||
if(!$user) {
|
if(!$user) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return OC_User::isAdminUser($user);
|
return OC_Group::inGroup($user, 'admin');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -153,25 +231,35 @@ class OC_API {
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* http basic auth
|
* http basic auth
|
||||||
* @return string|false (username, or false on failure)
|
* @return string|false (username, or false on failure)
|
||||||
*/
|
*/
|
||||||
private static function loginUser(){
|
private static function loginUser(){
|
||||||
$authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
|
$authUser = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
|
||||||
$authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
|
$authPw = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
|
||||||
return OC_User::login($authUser, $authPw) ? $authUser : false;
|
return OC_User::login($authUser, $authPw) ? $authUser : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* respond to a call
|
* respond to a call
|
||||||
* @param int|array $result the result from the api method
|
* @param OC_OCS_Result $result
|
||||||
* @param string $format the format xml|json
|
* @param string $format the format xml|json
|
||||||
*/
|
*/
|
||||||
private static function respond($result, $format='xml') {
|
private static function respond($result, $format='xml') {
|
||||||
$response = array('ocs' => $result->getResult());
|
// Send 401 headers if unauthorised
|
||||||
|
if($result->getStatusCode() === self::RESPOND_UNAUTHORISED) {
|
||||||
|
header('WWW-Authenticate: Basic realm="Authorisation Required"');
|
||||||
|
header('HTTP/1.0 401 Unauthorized');
|
||||||
|
}
|
||||||
|
$response = array(
|
||||||
|
'ocs' => array(
|
||||||
|
'meta' => $result->getMeta(),
|
||||||
|
'data' => $result->getData(),
|
||||||
|
),
|
||||||
|
);
|
||||||
if ($format == 'json') {
|
if ($format == 'json') {
|
||||||
OC_JSON::encodedPrint($response);
|
OC_JSON::encodedPrint($response);
|
||||||
} else if ($format == 'xml') {
|
} else if ($format == 'xml') {
|
||||||
|
@ -188,10 +276,13 @@ class OC_API {
|
||||||
|
|
||||||
private static function toXML($array, $writer) {
|
private static function toXML($array, $writer) {
|
||||||
foreach($array as $k => $v) {
|
foreach($array as $k => $v) {
|
||||||
if (is_numeric($k)) {
|
if ($k[0] === '@') {
|
||||||
|
$writer->writeAttribute(substr($k, 1), $v);
|
||||||
|
continue;
|
||||||
|
} else if (is_numeric($k)) {
|
||||||
$k = 'element';
|
$k = 'element';
|
||||||
}
|
}
|
||||||
if (is_array($v)) {
|
if(is_array($v)) {
|
||||||
$writer->startElement($k);
|
$writer->startElement($k);
|
||||||
self::toXML($v, $writer);
|
self::toXML($v, $writer);
|
||||||
$writer->endElement();
|
$writer->endElement();
|
||||||
|
@ -200,5 +291,5 @@ class OC_API {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,26 +49,48 @@ class OC_OCS_Result{
|
||||||
public function setItemsPerPage(int $items) {
|
public function setItemsPerPage(int $items) {
|
||||||
$this->perPage = $items;
|
$this->perPage = $items;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the data associated with the api result
|
* get the status code
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getStatusCode() {
|
||||||
|
return $this->statusCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the meta data for the result
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getResult() {
|
public function getMeta() {
|
||||||
$return = array();
|
$meta = array();
|
||||||
$return['meta'] = array();
|
$meta['status'] = ($this->statusCode === 100) ? 'ok' : 'failure';
|
||||||
$return['meta']['status'] = ($this->statusCode === 100) ? 'ok' : 'failure';
|
$meta['statuscode'] = $this->statusCode;
|
||||||
$return['meta']['statuscode'] = $this->statusCode;
|
$meta['message'] = $this->message;
|
||||||
$return['meta']['message'] = $this->message;
|
|
||||||
if(isset($this->items)) {
|
if(isset($this->items)) {
|
||||||
$return['meta']['totalitems'] = $this->items;
|
$meta['totalitems'] = $this->items;
|
||||||
}
|
}
|
||||||
if(isset($this->perPage)) {
|
if(isset($this->perPage)) {
|
||||||
$return['meta']['itemsperpage'] = $this->perPage;
|
$meta['itemsperpage'] = $this->perPage;
|
||||||
}
|
}
|
||||||
$return['data'] = $this->data;
|
return $meta;
|
||||||
// Return the result data.
|
|
||||||
return $return;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the result data
|
||||||
|
* @return array|string|int
|
||||||
|
*/
|
||||||
|
public function getData() {
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return bool if the method succedded
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function succeeded() {
|
||||||
|
return (substr($this->statusCode, 0, 1) === '1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue