Merge branch '1.0'

This commit is contained in:
Robbie Averill 2017-11-17 14:59:38 +13:00
commit e5a757d589
4 changed files with 190 additions and 157 deletions

View File

@ -4,22 +4,16 @@ sudo: false
language: php language: php
php:
- 5.3
- 5.4
- 5.5
env:
- DB=MYSQL CORE_RELEASE=3.5
matrix: matrix:
include: include:
- php: 5.4
env: DB=MYSQL CORE_RELEASE=3.3
- php: 5.5
env: DB=MYSQL CORE_RELEASE=3.4
- php: 5.6 - php: 5.6
env: DB=PGSQL CORE_RELEASE=3.5
- php: 7.0
env: DB=MYSQL CORE_RELEASE=3 env: DB=MYSQL CORE_RELEASE=3
- php: 5.6
env: DB=MYSQL CORE_RELEASE=3.1
- php: 5.6
env: DB=PGSQL CORE_RELEASE=3.2
- php: 7.1 - php: 7.1
env: DB=MYSQL CORE_RELEASE=3.6 env: DB=MYSQL CORE_RELEASE=3.6

View File

@ -204,7 +204,7 @@ class RestfulServer extends Controller
if (!$obj) { if (!$obj) {
return $this->notFound(); return $this->notFound();
} }
if (!$obj->canView()) { if (!$obj->canView($this->getMember())) {
return $this->permissionFailure(); return $this->permissionFailure();
} }
@ -229,20 +229,22 @@ class RestfulServer extends Controller
$fields = $rawFields ? explode(',', $rawFields) : null; $fields = $rawFields ? explode(',', $rawFields) : null;
if ($obj instanceof SS_List) { if ($obj instanceof SS_List) {
$responseFormatter->setTotalSize($obj->dataQuery()->query()->unlimitedRowCount()); $objs = ArrayList::create($obj->toArray());
$objs = new ArrayList($obj->toArray());
foreach ($objs as $obj) { foreach ($objs as $obj) {
if (!$obj->canView()) { if (!$obj->canView($this->getMember())) {
$objs->remove($obj); $objs->remove($obj);
} }
} }
$responseFormatter->setTotalSize($objs->count());
return $responseFormatter->convertDataObjectSet($objs, $fields); return $responseFormatter->convertDataObjectSet($objs, $fields);
} elseif (!$obj) { }
if (!$obj) {
$responseFormatter->setTotalSize(0); $responseFormatter->setTotalSize(0);
return $responseFormatter->convertDataObjectSet(new ArrayList(), $fields); return $responseFormatter->convertDataObjectSet(new ArrayList(), $fields);
} else {
return $responseFormatter->convertDataObject($obj, $fields);
} }
return $responseFormatter->convertDataObject($obj, $fields);
} }
/** /**
@ -372,7 +374,7 @@ class RestfulServer extends Controller
if (!$obj) { if (!$obj) {
return $this->notFound(); return $this->notFound();
} }
if (!$obj->canDelete()) { if (!$obj->canDelete($this->getMember())) {
return $this->permissionFailure(); return $this->permissionFailure();
} }
@ -391,7 +393,7 @@ class RestfulServer extends Controller
if (!$obj) { if (!$obj) {
return $this->notFound(); return $this->notFound();
} }
if (!$obj->canEdit()) { if (!$obj->canEdit($this->getMember())) {
return $this->permissionFailure(); return $this->permissionFailure();
} }
@ -405,7 +407,11 @@ class RestfulServer extends Controller
return $this->unsupportedMediaType(); return $this->unsupportedMediaType();
} }
/** @var DataObject|string */
$obj = $this->updateDataObject($obj, $reqFormatter); $obj = $this->updateDataObject($obj, $reqFormatter);
if (is_string($obj)) {
return $obj;
}
$this->getResponse()->setStatusCode(200); // Success $this->getResponse()->setStatusCode(200); // Success
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType()); $this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
@ -456,37 +462,41 @@ class RestfulServer extends Controller
$this->getResponse()->setStatusCode(204); // No Content $this->getResponse()->setStatusCode(204); // No Content
return true; return true;
} else {
if (!singleton($className)->canCreate()) {
return $this->permissionFailure();
}
$obj = new $className();
$reqFormatter = $this->getRequestDataFormatter($className);
if (!$reqFormatter) {
return $this->unsupportedMediaType();
}
$responseFormatter = $this->getResponseDataFormatter($className);
$obj = $this->updateDataObject($obj, $reqFormatter);
$this->getResponse()->setStatusCode(201); // Created
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
// Append the default extension for the output format to the Location header
// or else we'll use the default (XML)
$types = $responseFormatter->supportedExtensions();
$type = '';
if (count($types)) {
$type = ".{$types[0]}";
}
$objHref = Director::absoluteURL(self::$api_base . "$obj->class/$obj->ID" . $type);
$this->getResponse()->addHeader('Location', $objHref);
return $responseFormatter->convertDataObject($obj);
} }
if (!singleton($className)->canCreate($this->getMember())) {
return $this->permissionFailure();
}
$obj = new $className();
$reqFormatter = $this->getRequestDataFormatter($className);
if (!$reqFormatter) {
return $this->unsupportedMediaType();
}
$responseFormatter = $this->getResponseDataFormatter($className);
/** @var DataObject|string $obj */
$obj = $this->updateDataObject($obj, $reqFormatter);
if (is_string($obj)) {
return $obj;
}
$this->getResponse()->setStatusCode(201); // Created
$this->getResponse()->addHeader('Content-Type', $responseFormatter->getOutputContentType());
// Append the default extension for the output format to the Location header
// or else we'll use the default (XML)
$types = $responseFormatter->supportedExtensions();
$type = '';
if (count($types)) {
$type = ".{$types[0]}";
}
$objHref = Director::absoluteURL(self::$api_base . "$obj->class/$obj->ID" . $type);
$this->getResponse()->addHeader('Location', $objHref);
return $responseFormatter->convertDataObject($obj);
} }
/** /**
@ -498,7 +508,7 @@ class RestfulServer extends Controller
* *
* @param DataObject $obj * @param DataObject $obj
* @param DataFormatter $formatter * @param DataFormatter $formatter
* @return DataObject The passed object * @return DataObject|string The passed object, or "No Content" if incomplete input data is provided
*/ */
protected function updateDataObject($obj, $formatter) protected function updateDataObject($obj, $formatter)
{ {
@ -649,6 +659,16 @@ class RestfulServer extends Controller
} }
return $allowedRelations; return $allowedRelations;
} }
/**
* Get the current Member, if available
*
* @return Member|null
*/
protected function getMember()
{
return Member::currentUser();
}
} }
/** /**

View File

@ -1,28 +1,29 @@
{ {
"name": "silverstripe/restfulserver", "name": "silverstripe/restfulserver",
"description": "Add a RESTful API to your SilverStripe application", "description": "Add a RESTful API to your SilverStripe application",
"type": "silverstripe-module", "type": "silverstripe-module",
"keywords": ["silverstripe", "rest", "api"], "keywords": [
"authors": [ "silverstripe",
{ "rest",
"name": "Hamish Friedlander", "api"
"email": "hamish@silverstripe.com" ],
}, "authors": [
{ {
"name": "Sam Minnee", "name": "Hamish Friedlander",
"email": "sam@silverstripe.com" "email": "hamish@silverstripe.com"
} },
], {
"require": "name": "Sam Minnee",
{ "email": "sam@silverstripe.com"
"silverstripe/framework": "3.*" }
}, ],
"extra": "require": {
{ "silverstripe/framework": "3.*"
"branch-alias": },
{ "extra": {
"dev-master": "1.0.x-dev" "branch-alias": {
} "dev-master": "1.1.x-dev"
}, }
"license": "BSD-3-Clause" },
"license": "BSD-3-Clause"
} }

View File

@ -193,6 +193,19 @@ class RestfulServerTest extends SapphireTest
unset($_SERVER['PHP_AUTH_PW']); unset($_SERVER['PHP_AUTH_PW']);
} }
public function testPostWithoutBodyReturnsNoContent()
{
$_SERVER['PHP_AUTH_USER'] = 'editor@test.com';
$_SERVER['PHP_AUTH_PW'] = 'editor';
$url = '/api/v1/RestfulServerTest_Comment';
$response = Director::test($url, null, null, 'POST');
$this->assertEquals('No Content', $response->getBody());
unset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']);
}
public function testPUTwithJSON() public function testPUTwithJSON()
{ {
$comment1 = $this->objFromFixture('RestfulServerTest_Comment', 'comment1'); $comment1 = $this->objFromFixture('RestfulServerTest_Comment', 'comment1');
@ -463,6 +476,8 @@ class RestfulServerTest extends SapphireTest
$response = Director::test($url, null, null, 'GET'); $response = Director::test($url, null, null, 'GET');
$this->assertEquals($response->getStatusCode(), 200); $this->assertEquals($response->getStatusCode(), 200);
$this->assertNotContains('Unspeakable', $response->getBody()); $this->assertNotContains('Unspeakable', $response->getBody());
$responseArray = Convert::json2array($response->getBody());
$this->assertSame(0, $responseArray['totalSize']);
// With authentication // With authentication
$_SERVER['PHP_AUTH_USER'] = 'editor@test.com'; $_SERVER['PHP_AUTH_USER'] = 'editor@test.com';
@ -471,6 +486,9 @@ class RestfulServerTest extends SapphireTest
$response = Director::test($url, null, null, 'GET'); $response = Director::test($url, null, null, 'GET');
$this->assertEquals($response->getStatusCode(), 200); $this->assertEquals($response->getStatusCode(), 200);
$this->assertContains('Unspeakable', $response->getBody()); $this->assertContains('Unspeakable', $response->getBody());
// Assumption: default formatter is XML
$responseArray = Convert::xml2array($response->getBody());
$this->assertEquals(1, $responseArray['@attributes']['totalSize']);
unset($_SERVER['PHP_AUTH_USER']); unset($_SERVER['PHP_AUTH_USER']);
unset($_SERVER['PHP_AUTH_PW']); unset($_SERVER['PHP_AUTH_PW']);
} }