Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2 API (Folders) #1003

Merged
merged 25 commits into from
Apr 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e93c5f6
add serialization methods for v2 API
powerpaul17 Dec 25, 2020
87295b5
add api version 2 & folder api routes
powerpaul17 Dec 26, 2020
c28c74b
add api v2 response trait
powerpaul17 Dec 26, 2020
aeb75e0
add folder api v2
powerpaul17 Dec 26, 2020
392275b
lint & add missing copyright/author information
powerpaul17 Dec 27, 2020
13b5209
add possibility to serialize a reduced version of an entity
powerpaul17 Dec 27, 2020
f3ea05b
update API to not return existing folders when error in request occurs
powerpaul17 Jan 9, 2021
91c2517
do not return existing folders when an API request error occurs
powerpaul17 Jan 9, 2021
387661d
remove unused 'findByName' method of folder mapper/service
powerpaul17 Jan 9, 2021
1d3ad27
separate serialization functions
powerpaul17 Jan 9, 2021
e8d2f18
fix wrong parentheses
powerpaul17 Jan 9, 2021
e2abbe5
linting
powerpaul17 Jan 9, 2021
9387744
change method names to follow nextcloud convention
powerpaul17 Jan 9, 2021
5dcb7e8
move v2 api responses into existing php traits
powerpaul17 Jan 9, 2021
f79cc89
fix wrong function definition & remove leftover copyright headers
powerpaul17 Jan 10, 2021
4d0f821
remove unused service exceptions & allow equally named folders
powerpaul17 Feb 8, 2021
466eb5c
add json error response without an exception
powerpaul17 Mar 24, 2021
5b1a994
return error if no folder name is provided
powerpaul17 Mar 24, 2021
b5aae29
add folder part of v2 API to changelog
powerpaul17 Jan 9, 2021
8b1f72b
use last modified timestamp data instead of removed 'updatedAt' field
powerpaul17 Mar 24, 2021
59827ac
fix typo in api documentation
powerpaul17 Mar 25, 2021
4e1ae2d
return error if new folder name is missing on update
powerpaul17 Mar 25, 2021
6980639
add tests for 'toAPI2' method
powerpaul17 Mar 28, 2021
81b0da7
add missing type hints
powerpaul17 Mar 28, 2021
cdf18fa
fix invalid 'empty' checks
powerpaul17 Mar 29, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ The format is almost based on [Keep a Changelog](https://keepachangelog.com/en/1

## [Unreleased]

- v2 API implementation (folder part)

### Changed
- Add BATS as integration tests
- Update FeedFetcher to import categories from feeds (#1248)
Expand Down
7 changes: 7 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
*
* @author Alessandro Cosentino <[email protected]>
* @author Bernhard Posselt <[email protected]>
* @author Paul Tirk <[email protected]>
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
* @copyright 2020 Paul Tirk
*/

return ['routes' => [
Expand Down Expand Up @@ -58,6 +60,11 @@
// general API
['name' => 'api#index', 'url' => '/api', 'verb' => 'GET'],

// API 2
['name' => 'folder_api_v2#create', 'url' => '/api/v2/folders', 'verb' => 'POST'],
['name' => 'folder_api_v2#update', 'url' => '/api/v2/folders/{folderId}', 'verb' => 'PATCH'],
['name' => 'folder_api_v2#delete', 'url' => '/api/v2/folders/{folderId}', 'verb' => 'DELETE'],

// API 1.2
['name' => 'user_api#index', 'url' => '/api/v1-2/user', 'verb' => 'GET'],
['name' => 'user_api#avatar', 'url' => '/api/v1-2/user/avatar', 'verb' => 'GET'],
Expand Down
14 changes: 6 additions & 8 deletions docs/externalapi/External-Api.md
Original file line number Diff line number Diff line change
Expand Up @@ -356,9 +356,8 @@ Status codes:
* **200**: Folder was created successfully
* **400**: Folder creation error, check the error object:
* **code**: 1: folder name is empty
* **409**: Folder with given name exists already

In case of an HTTP 200 or 409, the created or already existing folder is returned in full in the response, e.g.:
In case of an HTTP 200, the created or already existing folder is returned in full in the response, e.g.:

```js
{
Expand Down Expand Up @@ -389,13 +388,12 @@ with the following request body:
The following response is being returned:

Status codes:
* **200**: Folder was created successfully
* **400**: Folder creation error, check the error object:
* **200**: Folder was updated successfully
* **400**: Folder update error, check the error object:
* **code**: 1: folder name is empty
* **409**: Folder with given name exists already
* Other ownCloud errors, see [Response Format](#response-format)

In case of an HTTP 200 or 409, the changed or already existing folder is returned in full in the response, e.g.:
In case of an HTTP 200, the changed or already existing folder is returned in full in the response, e.g.:

```js
{
Expand Down Expand Up @@ -604,7 +602,7 @@ The attributes mean the following:
* **title**: Abitrary long text, item's title
* **author**: Abitrary long text, name of the author/authors
* **publishedAt**: String representing an ISO 8601 DateTime object, when the item was published
* **updatedAt**: String representing an ISO 8601 DateTime object, when the item was updated
* **lastModifiedAt**: String representing an ISO 8601 DateTime object, when the item was last modified
* **enclosure**: An enclosure object or null if none is present
* **mimeType**: Abitrary long text, the enclosures mime type
* **url**: Abitrary long text, location of the enclosure
Expand All @@ -626,7 +624,7 @@ A full item contains the full content:
"title": "Plasma-nm after the solid sprint",
"author": "Jan Grulich (grulja)",
"publishedAt": "2005-08-15T15:52:01+0000",
"updatedAt": "2005-08-15T15:52:01+0000",
"lastModifiedAt": "2005-08-15T15:52:01+0000",
"enclosure": {
"mimeType": "video/webm",
"url": "http://video.webmfiles.org/elephants-dream.webm"
Expand Down
4 changes: 3 additions & 1 deletion lib/Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@
* @author Alessandro Cosentino <[email protected]>
* @author Bernhard Posselt <[email protected]>
* @author David Guillot <[email protected]>
* @author Paul Tirk <[email protected]>
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
* @copyright 2018 David Guillot
* @copyright 2020 Paul Tirk
*/

namespace OCA\News\Controller;
Expand Down Expand Up @@ -80,7 +82,7 @@ protected function getUserId()
public function index(): array
{
return [
'apiLevels' => ['v1-2']
'apiLevels' => ['v1-2', 'v2']
];
}
}
37 changes: 36 additions & 1 deletion lib/Controller/ApiPayloadTrait.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<?php


namespace OCA\News\Controller;

use \OCP\AppFramework\Http;
use \OCP\AppFramework\Http\JSONResponse;

use OCA\News\Db\IAPI;

trait ApiPayloadTrait
Expand Down Expand Up @@ -33,4 +35,37 @@ public function serialize($data): array
}
return $return;
}

/**
* Serialize an entity
*
* @param IAPI $data
*
* @return array
*/
public function serializeEntityV2($data, bool $reduced = false): array
{
return $data->toAPI2($reduced);
}

/**
* Serialize array of entities
*
* @param array $data
*
* @return array
*/
public function serializeEntitiesV2($data, bool $reduced = false): array
{
$return = [];
foreach ($data as $entity) {
$return[] = $entity->toAPI2($reduced);
}
return $return;
}

public function responseV2($data, $code = Http::STATUS_OK)
{
return new JSONResponse($data, $code);
}
}
120 changes: 120 additions & 0 deletions lib/Controller/FolderApiV2Controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?php
/**
* Nextcloud - News
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Paul Tirk <[email protected]>
* @copyright 2020 Paul Tirk
*/

namespace OCA\News\Controller;

use \OCP\IRequest;
use \OCP\IUserSession;
use \OCP\AppFramework\Http;

use \OCA\News\Service\FolderServiceV2;
use \OCA\News\Service\ItemServiceV2;
use \OCA\News\Service\Exceptions\ServiceNotFoundException;

class FolderApiV2Controller extends ApiController
{
use ApiPayloadTrait;
use JSONHttpErrorTrait;

/**
* @var FolderServiceV2
*/
private $folderService;

/**
* @var ItemServiceV2
*/
private $itemService;

public function __construct(
IRequest $request,
IUserSession $userSession,
FolderServiceV2 $folderService,
ItemServiceV2 $itemService
) {
parent::__construct($request, $userSession);

$this->folderService = $folderService;
$this->itemService = $itemService;
}

/**
* @NoAdminRequired
* @NoCSRFRequired
* @CORS
*
* @param string $name
* @return array|mixed|\OCP\AppFramework\Http\JSONResponse
*/
public function create(string $name)
{
if (trim($name) === '') {
return $this->errorResponseV2('folder name is empty', 1, Http::STATUS_BAD_REQUEST);
}

$this->folderService->purgeDeleted($this->getUserId(), false);
$responseData = $this->serializeEntityV2(
$this->folderService->create($this->getUserId(), $name)
);
return $this->responseV2([
'folder' => $responseData
]);
}

/**
* @NoAdminRequired
* @NoCSRFRequired
* @CORS
* @param int $folderId
* @param string $name
* @return array|\OCP\AppFramework\Http\JSONResponse
*/
public function update(int $folderId, string $name)
{
if (trim($name) === '') {
return $this->errorResponseV2('folder name is empty', 1, Http::STATUS_BAD_REQUEST);
}

$response = null;
try {
$response = $this->folderService->rename($this->getUserId(), $folderId, $name);
} catch (ServiceNotFoundException $ex) {
return $this->errorResponseWithExceptionV2($ex, Http::STATUS_NOT_FOUND);
}

return $this->responseV2([
'folder' => $response
]);
}


/**
* @NoAdminRequired
* @NoCSRFRequired
* @CORS
*
* @param int $folderId
* @return array|\OCP\AppFramework\Http\JSONResponse
*/
public function delete(int $folderId)
{
try {
$responseData = $this->serializeEntityV2(
$this->folderService->delete($this->getUserId(), $folderId)
);
return $this->responseV2([
'folder' => $responseData
]);
} catch (ServiceNotFoundException $ex) {
return $this->errorResponseWithExceptionV2($ex, Http::STATUS_NOT_FOUND);
}
}
}
30 changes: 30 additions & 0 deletions lib/Controller/JSONHttpErrorTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,34 @@ public function error(\Exception $exception, int $code)
{
return new JSONResponse(['message' => $exception->getMessage()], $code);
}

/**
* @param \Exception $exception
* @param int $code
* @return \OCP\AppFramework\Http\JSONResponse
*/
public function errorResponseWithExceptionV2(\Exception $exception, int $code): JSONResponse
{
return $this->errorResponseV2(
$exception->getMessage(),
$exception->getCode(),
$code
);
}

/**
* @param string $message
* @param int $code
* @param int $httpStatusCode
* @return \OCP\AppFramework\Http\JSONResponse
*/
public function errorResponseV2(string $message, int $code, int $httpStatusCode): JSONResponse
{
return new JSONResponse([
'error' => [
'code' => $code,
'message' => $message,
]
], $httpStatusCode);
}
}
25 changes: 25 additions & 0 deletions lib/Db/Feed.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
*
* @author Alessandro Cosentino <[email protected]>
* @author Bernhard Posselt <[email protected]>
* @author Paul Tirk <[email protected]>
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
* @copyright 2020 Paul Tirk
*/

namespace OCA\News\Db;
Expand Down Expand Up @@ -660,4 +662,27 @@ public function toAPI(): array
]
);
}

public function toAPI2(bool $reduced = false): array
{
$result = [
'id' => $this->getId(),
'name' => $this->getTitle(),
'faviconLink' => $this->getFaviconLink(),
'folderId' => $this->getFolderId(),
'ordering' => $this->getOrdering(),
'fullTextEnabled' => $this->getFullTextEnabled(),
'updateMode' => $this->getUpdateMode(),
'isPinned' => $this->getPinned()
];

if (!is_null($this->getLastUpdateError()) || trim($this->getLastUpdateError()) !== '') {
$result['error'] = [
'code' => 1,
'message' => $this->getLastUpdateError()
];
}

return $result;
}
}
7 changes: 7 additions & 0 deletions lib/Db/Folder.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
*
* @author Alessandro Cosentino <[email protected]>
* @author Bernhard Posselt <[email protected]>
* @author Paul Tirk <[email protected]>
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
* @copyright 2020 Paul Tirk
*/

namespace OCA\News\Db;
Expand Down Expand Up @@ -172,4 +174,9 @@ public function toAPI(): array
]
);
}

public function toAPI2(bool $reduced = false): array
{
return $this->toAPI();
}
}
3 changes: 3 additions & 0 deletions lib/Db/IAPI.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@
*
* @author Alessandro Cosentino <[email protected]>
* @author Bernhard Posselt <[email protected]>
* @author Paul Tirk <[email protected]>
* @copyright 2012 Alessandro Cosentino
* @copyright 2012-2014 Bernhard Posselt
* @copyright 2020 Paul Tirk
*/

namespace OCA\News\Db;

interface IAPI
{
public function toAPI();
public function toAPI2(bool $reduced = false): array;
}
Loading