mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Replace Response objects with PSR-7 response messages; improves #53
While the test suite passes, this commit yields a broken server: replacing ad hoc request objectss with PSR-7 ones is still required, as is emission of PSR-7 responses. Both will come in subsequent commits, with tests Diactoros was chosen specifically because it includes facilities for emitting responses, something which is awkward to test. The end of this refactoring should see both the Response and Request classes disappear, and the general REST class fully covered (as well as any speculative additions to AbstractHanlder).
This commit is contained in:
parent
27caf147df
commit
9eadd602bd
16 changed files with 458 additions and 297 deletions
|
@ -25,7 +25,8 @@
|
||||||
"fguillot/picofeed": ">=0.1.31",
|
"fguillot/picofeed": ">=0.1.31",
|
||||||
"hosteurope/password-generator": "^1.0",
|
"hosteurope/password-generator": "^1.0",
|
||||||
"docopt/docopt": "^1.0",
|
"docopt/docopt": "^1.0",
|
||||||
"jkingweb/druuid": "^3.0"
|
"jkingweb/druuid": "^3.0",
|
||||||
|
"zendframework/zend-diactoros": "^1.6"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "*"
|
"bamarni/composer-bin-plugin": "*"
|
||||||
|
|
104
composer.lock
generated
104
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "8a3c7ff23f125a5fa3dac2e6a7244a90",
|
"content-hash": "7d381fa958169b7079c1d3c5b911f3bd",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "docopt/docopt",
|
"name": "docopt/docopt",
|
||||||
|
@ -190,6 +190,108 @@
|
||||||
],
|
],
|
||||||
"time": "2017-02-09T14:17:01+00:00"
|
"time": "2017-02-09T14:17:01+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/http-message",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/http-message.git",
|
||||||
|
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||||
|
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.3.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Http\\Message\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "http://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common interface for HTTP messages",
|
||||||
|
"homepage": "https://github.com/php-fig/http-message",
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"http-message",
|
||||||
|
"psr",
|
||||||
|
"psr-7",
|
||||||
|
"request",
|
||||||
|
"response"
|
||||||
|
],
|
||||||
|
"time": "2016-08-06T14:39:51+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "zendframework/zend-diactoros",
|
||||||
|
"version": "1.6.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/zendframework/zend-diactoros.git",
|
||||||
|
"reference": "c8664b92a6d5bc229e48b0923486c097e45a7877"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/zendframework/zend-diactoros/zipball/c8664b92a6d5bc229e48b0923486c097e45a7877",
|
||||||
|
"reference": "c8664b92a6d5bc229e48b0923486c097e45a7877",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^5.6 || ^7.0",
|
||||||
|
"psr/http-message": "^1.0"
|
||||||
|
},
|
||||||
|
"provide": {
|
||||||
|
"psr/http-message-implementation": "1.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-libxml": "*",
|
||||||
|
"phpunit/phpunit": "^5.7.16 || ^6.0.8",
|
||||||
|
"zendframework/zend-coding-standard": "~1.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.6-dev",
|
||||||
|
"dev-develop": "1.7-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Zend\\Diactoros\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"BSD-2-Clause"
|
||||||
|
],
|
||||||
|
"description": "PSR HTTP Message implementations",
|
||||||
|
"homepage": "https://github.com/zendframework/zend-diactoros",
|
||||||
|
"keywords": [
|
||||||
|
"http",
|
||||||
|
"psr",
|
||||||
|
"psr-7"
|
||||||
|
],
|
||||||
|
"time": "2017-10-12T15:24:51+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "zendframework/zendxml",
|
"name": "zendframework/zendxml",
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
|
|
|
@ -48,7 +48,7 @@ class REST {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(REST\Request $req = null): REST\Response {
|
public function dispatch(REST\Request $req = null): \Psr\Http\Message\ResponseInterface {
|
||||||
if ($req===null) {
|
if ($req===null) {
|
||||||
$req = new REST\Request();
|
$req = new REST\Request();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use JKingWeb\Arsse\Misc\ValueInfo;
|
||||||
|
|
||||||
abstract class AbstractHandler implements Handler {
|
abstract class AbstractHandler implements Handler {
|
||||||
abstract public function __construct();
|
abstract public function __construct();
|
||||||
abstract public function dispatch(Request $req): Response;
|
abstract public function dispatch(Request $req): \Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
protected function fieldMapNames(array $data, array $map): array {
|
protected function fieldMapNames(array $data, array $map): array {
|
||||||
$out = [];
|
$out = [];
|
||||||
|
|
|
@ -8,5 +8,5 @@ namespace JKingWeb\Arsse\REST;
|
||||||
|
|
||||||
interface Handler {
|
interface Handler {
|
||||||
public function __construct();
|
public function __construct();
|
||||||
public function dispatch(Request $req): Response;
|
public function dispatch(Request $req): \Psr\Http\Message\ResponseInterface;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,9 @@ use JKingWeb\Arsse\Misc\ValueInfo;
|
||||||
use JKingWeb\Arsse\AbstractException;
|
use JKingWeb\Arsse\AbstractException;
|
||||||
use JKingWeb\Arsse\Db\ExceptionInput;
|
use JKingWeb\Arsse\Db\ExceptionInput;
|
||||||
use JKingWeb\Arsse\Feed\Exception as FeedException;
|
use JKingWeb\Arsse\Feed\Exception as FeedException;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use \Psr\Http\Message\ResponseInterface;
|
||||||
|
use Zend\Diactoros\Response\JsonResponse as Response;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
const REALM = "NextCloud News API v1-2";
|
const REALM = "NextCloud News API v1-2";
|
||||||
|
@ -72,10 +74,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
|
public function dispatch(\JKingWeb\Arsse\REST\Request $req): ResponseInterface {
|
||||||
// try to authenticate
|
// try to authenticate
|
||||||
if (!Arsse::$user->authHTTP()) {
|
if (!Arsse::$user->authHTTP()) {
|
||||||
return new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.self::REALM.'"']);
|
return new EmptyResponse(401, ['WWW-Authenticate' => 'Basic realm="'.self::REALM.'"']);
|
||||||
}
|
}
|
||||||
// handle HTTP OPTIONS requests
|
// handle HTTP OPTIONS requests
|
||||||
if ($req->method=="OPTIONS") {
|
if ($req->method=="OPTIONS") {
|
||||||
|
@ -85,12 +87,12 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
if ($req->body) {
|
if ($req->body) {
|
||||||
// if the entity body is not JSON according to content type, return "415 Unsupported Media Type"
|
// if the entity body is not JSON according to content type, return "415 Unsupported Media Type"
|
||||||
if (!preg_match("<^application/json\b|^$>", $req->type)) {
|
if (!preg_match("<^application/json\b|^$>", $req->type)) {
|
||||||
return new Response(415, "", "", ['Accept: application/json']);
|
return new EmptyResponse(415, ['Accept' => "application/json"]);
|
||||||
}
|
}
|
||||||
$data = @json_decode($req->body, true);
|
$data = @json_decode($req->body, true);
|
||||||
if (json_last_error() != \JSON_ERROR_NONE) {
|
if (json_last_error() != \JSON_ERROR_NONE) {
|
||||||
// if the body could not be parsed as JSON, return "400 Bad Request"
|
// if the body could not be parsed as JSON, return "400 Bad Request"
|
||||||
return new Response(400);
|
return new EmptyResponse(400);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$data = [];
|
$data = [];
|
||||||
|
@ -101,12 +103,12 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
try {
|
try {
|
||||||
$func = $this->chooseCall($req->paths, $req->method);
|
$func = $this->chooseCall($req->paths, $req->method);
|
||||||
} catch (Exception404 $e) {
|
} catch (Exception404 $e) {
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
} catch (Exception405 $e) {
|
} catch (Exception405 $e) {
|
||||||
return new Response(405, "", "", ["Allow: ".$e->getMessage()]);
|
return new EmptyResponse(405, ['Allow' => $e->getMessage()]);
|
||||||
}
|
}
|
||||||
if (!method_exists($this, $func)) {
|
if (!method_exists($this, $func)) {
|
||||||
return new Response(501); // @codeCoverageIgnore
|
return new EmptyResponse(501); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
// dispatch
|
// dispatch
|
||||||
try {
|
try {
|
||||||
|
@ -114,10 +116,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// @codeCoverageIgnoreStart
|
// @codeCoverageIgnoreStart
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// if there was a REST exception return 400
|
// if there was a REST exception return 400
|
||||||
return new Response(400);
|
return new EmptyResponse(400);
|
||||||
} catch (AbstractException $e) {
|
} catch (AbstractException $e) {
|
||||||
// if there was any other Arsse exception return 500
|
// if there was any other Arsse exception return 500
|
||||||
return new Response(500);
|
return new EmptyResponse(500);
|
||||||
}
|
}
|
||||||
// @codeCoverageIgnoreEnd
|
// @codeCoverageIgnoreEnd
|
||||||
}
|
}
|
||||||
|
@ -242,7 +244,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
return $article;
|
return $article;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleHTTPOptions(array $url): Response {
|
protected function handleHTTPOptions(array $url): ResponseInterface {
|
||||||
// normalize the URL path
|
// normalize the URL path
|
||||||
$url = $this->normalizePath($url);
|
$url = $this->normalizePath($url);
|
||||||
if (isset($this->paths[$url])) {
|
if (isset($this->paths[$url])) {
|
||||||
|
@ -252,81 +254,81 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
if (in_array("GET", $allowed)) {
|
if (in_array("GET", $allowed)) {
|
||||||
array_unshift($allowed, "HEAD");
|
array_unshift($allowed, "HEAD");
|
||||||
}
|
}
|
||||||
return new Response(204, "", "", [
|
return new EmptyResponse(204, [
|
||||||
"Allow: ".implode(",", $allowed),
|
'Allow' => implode(",", $allowed),
|
||||||
"Accept: application/json",
|
'Accept' => "application/json",
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// if the path is not supported, return 404
|
// if the path is not supported, return 404
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// list folders
|
// list folders
|
||||||
protected function folderList(array $url, array $data): Response {
|
protected function folderList(array $url, array $data): ResponseInterface {
|
||||||
$folders = [];
|
$folders = [];
|
||||||
foreach (Arsse::$db->folderList(Arsse::$user->id, null, false) as $folder) {
|
foreach (Arsse::$db->folderList(Arsse::$user->id, null, false) as $folder) {
|
||||||
$folders[] = $this->folderTranslate($folder);
|
$folders[] = $this->folderTranslate($folder);
|
||||||
}
|
}
|
||||||
return new Response(200, ['folders' => $folders]);
|
return new Response(['folders' => $folders]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create a folder
|
// create a folder
|
||||||
protected function folderAdd(array $url, array $data): Response {
|
protected function folderAdd(array $url, array $data): ResponseInterface {
|
||||||
try {
|
try {
|
||||||
$folder = Arsse::$db->folderAdd(Arsse::$user->id, ['name' => $data['name']]);
|
$folder = Arsse::$db->folderAdd(Arsse::$user->id, ['name' => $data['name']]);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
switch ($e->getCode()) {
|
switch ($e->getCode()) {
|
||||||
// folder already exists
|
// folder already exists
|
||||||
case 10236: return new Response(409);
|
case 10236: return new EmptyResponse(409);
|
||||||
// folder name not acceptable
|
// folder name not acceptable
|
||||||
case 10231:
|
case 10231:
|
||||||
case 10232: return new Response(422);
|
case 10232: return new EmptyResponse(422);
|
||||||
// other errors related to input
|
// other errors related to input
|
||||||
default: return new Response(400); // @codeCoverageIgnore
|
default: return new EmptyResponse(400); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$folder = $this->folderTranslate(Arsse::$db->folderPropertiesGet(Arsse::$user->id, $folder));
|
$folder = $this->folderTranslate(Arsse::$db->folderPropertiesGet(Arsse::$user->id, $folder));
|
||||||
return new Response(200, ['folders' => [$folder]]);
|
return new Response(['folders' => [$folder]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete a folder
|
// delete a folder
|
||||||
protected function folderRemove(array $url, array $data): Response {
|
protected function folderRemove(array $url, array $data): ResponseInterface {
|
||||||
// perform the deletion
|
// perform the deletion
|
||||||
try {
|
try {
|
||||||
Arsse::$db->folderRemove(Arsse::$user->id, (int) $url[1]);
|
Arsse::$db->folderRemove(Arsse::$user->id, (int) $url[1]);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// folder does not exist
|
// folder does not exist
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rename a folder (also supports moving nesting folders, but this is not a feature of the API)
|
// rename a folder (also supports moving nesting folders, but this is not a feature of the API)
|
||||||
protected function folderRename(array $url, array $data): Response {
|
protected function folderRename(array $url, array $data): ResponseInterface {
|
||||||
try {
|
try {
|
||||||
Arsse::$db->folderPropertiesSet(Arsse::$user->id, (int) $url[1], ['name' => $data['name']]);
|
Arsse::$db->folderPropertiesSet(Arsse::$user->id, (int) $url[1], ['name' => $data['name']]);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
switch ($e->getCode()) {
|
switch ($e->getCode()) {
|
||||||
// folder does not exist
|
// folder does not exist
|
||||||
case 10239: return new Response(404);
|
case 10239: return new EmptyResponse(404);
|
||||||
// folder already exists
|
// folder already exists
|
||||||
case 10236: return new Response(409);
|
case 10236: return new EmptyResponse(409);
|
||||||
// folder name not acceptable
|
// folder name not acceptable
|
||||||
case 10231:
|
case 10231:
|
||||||
case 10232: return new Response(422);
|
case 10232: return new EmptyResponse(422);
|
||||||
// other errors related to input
|
// other errors related to input
|
||||||
default: return new Response(400); // @codeCoverageIgnore
|
default: return new EmptyResponse(400); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark all articles associated with a folder as read
|
// mark all articles associated with a folder as read
|
||||||
protected function folderMarkRead(array $url, array $data): Response {
|
protected function folderMarkRead(array $url, array $data): ResponseInterface {
|
||||||
if (!ValueInfo::id($data['newestItemId'])) {
|
if (!ValueInfo::id($data['newestItemId'])) {
|
||||||
// if the item ID is invalid (i.e. not a positive integer), this is an error
|
// if the item ID is invalid (i.e. not a positive integer), this is an error
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
}
|
}
|
||||||
// build the context
|
// build the context
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
|
@ -337,16 +339,16 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// folder does not exist
|
// folder does not exist
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return list of feeds which should be refreshed
|
// return list of feeds which should be refreshed
|
||||||
protected function feedListStale(array $url, array $data): Response {
|
protected function feedListStale(array $url, array $data): ResponseInterface {
|
||||||
// function requires admin rights per spec
|
// function requires admin rights per spec
|
||||||
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
||||||
return new Response(403);
|
return new EmptyResponse(403);
|
||||||
}
|
}
|
||||||
// list stale feeds which should be checked for updates
|
// list stale feeds which should be checked for updates
|
||||||
$feeds = Arsse::$db->feedListStale();
|
$feeds = Arsse::$db->feedListStale();
|
||||||
|
@ -355,42 +357,42 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// since in our implementation feeds don't belong the users, the 'userId' field will always be an empty string
|
// since in our implementation feeds don't belong the users, the 'userId' field will always be an empty string
|
||||||
$out[] = ['id' => $feed, 'userId' => ""];
|
$out[] = ['id' => $feed, 'userId' => ""];
|
||||||
}
|
}
|
||||||
return new Response(200, ['feeds' => $out]);
|
return new Response(['feeds' => $out]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// refresh a feed
|
// refresh a feed
|
||||||
protected function feedUpdate(array $url, array $data): Response {
|
protected function feedUpdate(array $url, array $data): ResponseInterface {
|
||||||
// function requires admin rights per spec
|
// function requires admin rights per spec
|
||||||
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
||||||
return new Response(403);
|
return new EmptyResponse(403);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Arsse::$db->feedUpdate($data['feedId']);
|
Arsse::$db->feedUpdate($data['feedId']);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
switch ($e->getCode()) {
|
switch ($e->getCode()) {
|
||||||
case 10239: // feed does not exist
|
case 10239: // feed does not exist
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
case 10237: // feed ID invalid
|
case 10237: // feed ID invalid
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
default: // other errors related to input
|
default: // other errors related to input
|
||||||
return new Response(400); // @codeCoverageIgnore
|
return new EmptyResponse(400); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a new feed
|
// add a new feed
|
||||||
protected function subscriptionAdd(array $url, array $data): Response {
|
protected function subscriptionAdd(array $url, array $data): ResponseInterface {
|
||||||
// try to add the feed
|
// try to add the feed
|
||||||
$tr = Arsse::$db->begin();
|
$tr = Arsse::$db->begin();
|
||||||
try {
|
try {
|
||||||
$id = Arsse::$db->subscriptionAdd(Arsse::$user->id, (string) $data['url']);
|
$id = Arsse::$db->subscriptionAdd(Arsse::$user->id, (string) $data['url']);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// feed already exists
|
// feed already exists
|
||||||
return new Response(409);
|
return new EmptyResponse(409);
|
||||||
} catch (FeedException $e) {
|
} catch (FeedException $e) {
|
||||||
// feed could not be retrieved
|
// feed could not be retrieved
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
}
|
}
|
||||||
// if a folder was specified, move the feed to the correct folder; silently ignore errors
|
// if a folder was specified, move the feed to the correct folder; silently ignore errors
|
||||||
if ($data['folderId']) {
|
if ($data['folderId']) {
|
||||||
|
@ -408,11 +410,11 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
if ($newest) {
|
if ($newest) {
|
||||||
$out['newestItemId'] = $newest;
|
$out['newestItemId'] = $newest;
|
||||||
}
|
}
|
||||||
return new Response(200, $out);
|
return new Response($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return list of feeds for the logged-in user
|
// return list of feeds for the logged-in user
|
||||||
protected function subscriptionList(array $url, array $data): Response {
|
protected function subscriptionList(array $url, array $data): ResponseInterface {
|
||||||
$subs = Arsse::$db->subscriptionList(Arsse::$user->id);
|
$subs = Arsse::$db->subscriptionList(Arsse::$user->id);
|
||||||
$out = [];
|
$out = [];
|
||||||
foreach ($subs as $sub) {
|
foreach ($subs as $sub) {
|
||||||
|
@ -424,43 +426,43 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
if ($newest) {
|
if ($newest) {
|
||||||
$out['newestItemId'] = $newest;
|
$out['newestItemId'] = $newest;
|
||||||
}
|
}
|
||||||
return new Response(200, $out);
|
return new Response($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete a feed
|
// delete a feed
|
||||||
protected function subscriptionRemove(array $url, array $data): Response {
|
protected function subscriptionRemove(array $url, array $data): ResponseInterface {
|
||||||
try {
|
try {
|
||||||
Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $url[1]);
|
Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $url[1]);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// feed does not exist
|
// feed does not exist
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// rename a feed
|
// rename a feed
|
||||||
protected function subscriptionRename(array $url, array $data): Response {
|
protected function subscriptionRename(array $url, array $data): ResponseInterface {
|
||||||
try {
|
try {
|
||||||
Arsse::$db->subscriptionPropertiesSet(Arsse::$user->id, (int) $url[1], ['title' => (string) $data['feedTitle']]);
|
Arsse::$db->subscriptionPropertiesSet(Arsse::$user->id, (int) $url[1], ['title' => (string) $data['feedTitle']]);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
switch ($e->getCode()) {
|
switch ($e->getCode()) {
|
||||||
// subscription does not exist
|
// subscription does not exist
|
||||||
case 10239: return new Response(404);
|
case 10239: return new EmptyResponse(404);
|
||||||
// name is invalid
|
// name is invalid
|
||||||
case 10231:
|
case 10231:
|
||||||
case 10232: return new Response(422);
|
case 10232: return new EmptyResponse(422);
|
||||||
// other errors related to input
|
// other errors related to input
|
||||||
default: return new Response(400); // @codeCoverageIgnore
|
default: return new EmptyResponse(400); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// move a feed to a folder
|
// move a feed to a folder
|
||||||
protected function subscriptionMove(array $url, array $data): Response {
|
protected function subscriptionMove(array $url, array $data): ResponseInterface {
|
||||||
// if no folder is specified this is an error
|
// if no folder is specified this is an error
|
||||||
if (!isset($data['folderId'])) {
|
if (!isset($data['folderId'])) {
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
}
|
}
|
||||||
// perform the move
|
// perform the move
|
||||||
try {
|
try {
|
||||||
|
@ -468,22 +470,22 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
switch ($e->getCode()) {
|
switch ($e->getCode()) {
|
||||||
case 10239: // subscription does not exist
|
case 10239: // subscription does not exist
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
case 10235: // folder does not exist
|
case 10235: // folder does not exist
|
||||||
case 10237: // folder ID is invalid
|
case 10237: // folder ID is invalid
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
default: // other errors related to input
|
default: // other errors related to input
|
||||||
return new Response(400); // @codeCoverageIgnore
|
return new EmptyResponse(400); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark all articles associated with a subscription as read
|
// mark all articles associated with a subscription as read
|
||||||
protected function subscriptionMarkRead(array $url, array $data): Response {
|
protected function subscriptionMarkRead(array $url, array $data): ResponseInterface {
|
||||||
if (!ValueInfo::id($data['newestItemId'])) {
|
if (!ValueInfo::id($data['newestItemId'])) {
|
||||||
// if the item ID is invalid (i.e. not a positive integer), this is an error
|
// if the item ID is invalid (i.e. not a positive integer), this is an error
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
}
|
}
|
||||||
// build the context
|
// build the context
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
|
@ -494,13 +496,13 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// subscription does not exist
|
// subscription does not exist
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// list articles and their properties
|
// list articles and their properties
|
||||||
protected function articleList(array $url, array $data): Response {
|
protected function articleList(array $url, array $data): ResponseInterface {
|
||||||
// set the context options supplied by the client
|
// set the context options supplied by the client
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
// set the batch size
|
// set the batch size
|
||||||
|
@ -553,32 +555,32 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$items = Arsse::$db->articleList(Arsse::$user->id, $c, Database::LIST_TYPICAL);
|
$items = Arsse::$db->articleList(Arsse::$user->id, $c, Database::LIST_TYPICAL);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// ID of subscription or folder is not valid
|
// ID of subscription or folder is not valid
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
}
|
}
|
||||||
$out = [];
|
$out = [];
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
$out[] = $this->articleTranslate($item);
|
$out[] = $this->articleTranslate($item);
|
||||||
}
|
}
|
||||||
$out = ['items' => $out];
|
$out = ['items' => $out];
|
||||||
return new Response(200, $out);
|
return new Response($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark all articles as read
|
// mark all articles as read
|
||||||
protected function articleMarkReadAll(array $url, array $data): Response {
|
protected function articleMarkReadAll(array $url, array $data): ResponseInterface {
|
||||||
if (!ValueInfo::id($data['newestItemId'])) {
|
if (!ValueInfo::id($data['newestItemId'])) {
|
||||||
// if the item ID is invalid (i.e. not a positive integer), this is an error
|
// if the item ID is invalid (i.e. not a positive integer), this is an error
|
||||||
return new Response(422);
|
return new EmptyResponse(422);
|
||||||
}
|
}
|
||||||
// build the context
|
// build the context
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
$c->latestEdition((int) $data['newestItemId']);
|
$c->latestEdition((int) $data['newestItemId']);
|
||||||
// perform the operation
|
// perform the operation
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c);
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark a single article as read
|
// mark a single article as read
|
||||||
protected function articleMarkRead(array $url, array $data): Response {
|
protected function articleMarkRead(array $url, array $data): ResponseInterface {
|
||||||
// initialize the matching context
|
// initialize the matching context
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
$c->edition((int) $url[1]);
|
$c->edition((int) $url[1]);
|
||||||
|
@ -588,13 +590,13 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// ID is not valid
|
// ID is not valid
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark a single article as read
|
// mark a single article as read
|
||||||
protected function articleMarkStarred(array $url, array $data): Response {
|
protected function articleMarkStarred(array $url, array $data): ResponseInterface {
|
||||||
// initialize the matching context
|
// initialize the matching context
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
$c->article((int) $url[2]);
|
$c->article((int) $url[2]);
|
||||||
|
@ -604,13 +606,13 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
// ID is not valid
|
// ID is not valid
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark an array of articles as read
|
// mark an array of articles as read
|
||||||
protected function articleMarkReadMulti(array $url, array $data): Response {
|
protected function articleMarkReadMulti(array $url, array $data): ResponseInterface {
|
||||||
// determine whether to mark read or unread
|
// determine whether to mark read or unread
|
||||||
$set = ($url[1]=="read");
|
$set = ($url[1]=="read");
|
||||||
// initialize the matching context
|
// initialize the matching context
|
||||||
|
@ -620,11 +622,11 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark an array of articles as starred
|
// mark an array of articles as starred
|
||||||
protected function articleMarkStarredMulti(array $url, array $data): Response {
|
protected function articleMarkStarredMulti(array $url, array $data): ResponseInterface {
|
||||||
// determine whether to mark starred or unstarred
|
// determine whether to mark starred or unstarred
|
||||||
$set = ($url[1]=="star");
|
$set = ($url[1]=="star");
|
||||||
// initialize the matching context
|
// initialize the matching context
|
||||||
|
@ -634,10 +636,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
}
|
}
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function userStatus(array $url, array $data): Response {
|
protected function userStatus(array $url, array $data): ResponseInterface {
|
||||||
$data = Arsse::$user->propertiesGet(Arsse::$user->id, true);
|
$data = Arsse::$user->propertiesGet(Arsse::$user->id, true);
|
||||||
// construct the avatar structure, if an image is available
|
// construct the avatar structure, if an image is available
|
||||||
if (isset($data['avatar'])) {
|
if (isset($data['avatar'])) {
|
||||||
|
@ -655,37 +657,37 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
'lastLoginTimestamp' => time(),
|
'lastLoginTimestamp' => time(),
|
||||||
'avatar' => $avatar,
|
'avatar' => $avatar,
|
||||||
];
|
];
|
||||||
return new Response(200, $out);
|
return new Response($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function cleanupBefore(array $url, array $data): Response {
|
protected function cleanupBefore(array $url, array $data): ResponseInterface {
|
||||||
// function requires admin rights per spec
|
// function requires admin rights per spec
|
||||||
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
||||||
return new Response(403);
|
return new EmptyResponse(403);
|
||||||
}
|
}
|
||||||
Service::cleanupPre();
|
Service::cleanupPre();
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function cleanupAfter(array $url, array $data): Response {
|
protected function cleanupAfter(array $url, array $data): ResponseInterface {
|
||||||
// function requires admin rights per spec
|
// function requires admin rights per spec
|
||||||
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
if (Arsse::$user->rightsGet(Arsse::$user->id)==User::RIGHTS_NONE) {
|
||||||
return new Response(403);
|
return new EmptyResponse(403);
|
||||||
}
|
}
|
||||||
Service::cleanupPost();
|
Service::cleanupPost();
|
||||||
return new Response(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return the server version
|
// return the server version
|
||||||
protected function serverVersion(array $url, array $data): Response {
|
protected function serverVersion(array $url, array $data): ResponseInterface {
|
||||||
return new Response(200, [
|
return new Response([
|
||||||
'version' => self::VERSION,
|
'version' => self::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function serverStatus(array $url, array $data): Response {
|
protected function serverStatus(array $url, array $data): ResponseInterface {
|
||||||
return new Response(200, [
|
return new Response([
|
||||||
'version' => self::VERSION,
|
'version' => self::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
'warnings' => [
|
'warnings' => [
|
||||||
|
|
|
@ -6,22 +6,23 @@
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\REST\NextCloudNews;
|
namespace JKingWeb\Arsse\REST\NextCloudNews;
|
||||||
|
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use Zend\Diactoros\Response\JsonResponse as Response;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
class Versions implements \JKingWeb\Arsse\REST\Handler {
|
class Versions implements \JKingWeb\Arsse\REST\Handler {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
|
public function dispatch(\JKingWeb\Arsse\REST\Request $req): \Psr\Http\Message\ResponseInterface {
|
||||||
if (!preg_match("<^/?$>", $req->path)) {
|
if (!preg_match("<^/?$>", $req->path)) {
|
||||||
// if the request path is an empty string or just a slash, the client is probably trying a version we don't support
|
// if the request path is an empty string or just a slash, the client is probably trying a version we don't support
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
} elseif ($req->method=="OPTIONS") {
|
} elseif ($req->method=="OPTIONS") {
|
||||||
// if the request method is OPTIONS, respond accordingly
|
// if the request method is OPTIONS, respond accordingly
|
||||||
return new Response(204, "", "", ["Allow: HEAD,GET"]);
|
return new EmptyResponse(204, ['Allow' => "HEAD,GET"]);
|
||||||
} elseif ($req->method != "GET") {
|
} elseif ($req->method != "GET") {
|
||||||
// if a method other than GET was used, this is an error
|
// if a method other than GET was used, this is an error
|
||||||
return new Response(405, "", "", ["Allow: HEAD,GET"]);
|
return new EmptyResponse(405, ['Allow' => "HEAD,GET"]);
|
||||||
} else {
|
} else {
|
||||||
// otherwise return the supported versions
|
// otherwise return the supported versions
|
||||||
$out = [
|
$out = [
|
||||||
|
@ -29,7 +30,7 @@ class Versions implements \JKingWeb\Arsse\REST\Handler {
|
||||||
'v1-2',
|
'v1-2',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
return new Response(200, $out);
|
return new Response($out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ use JKingWeb\Arsse\ExceptionType;
|
||||||
use JKingWeb\Arsse\Db\ExceptionInput;
|
use JKingWeb\Arsse\Db\ExceptionInput;
|
||||||
use JKingWeb\Arsse\Db\ResultEmpty;
|
use JKingWeb\Arsse\Db\ResultEmpty;
|
||||||
use JKingWeb\Arsse\Feed\Exception as FeedException;
|
use JKingWeb\Arsse\Feed\Exception as FeedException;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use Zend\Diactoros\Response\JsonResponse as Response;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
const LEVEL = 14; // emulated API level
|
const LEVEL = 14; // emulated API level
|
||||||
|
@ -88,23 +89,23 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
|
public function dispatch(\JKingWeb\Arsse\REST\Request $req): \Psr\Http\Message\ResponseInterface {
|
||||||
if (!preg_match("<^(?:/(?:index\.php)?)?$>", $req->path)) {
|
if (!preg_match("<^(?:/(?:index\.php)?)?$>", $req->path)) {
|
||||||
// reject paths other than the index
|
// reject paths other than the index
|
||||||
return new Response(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
if ($req->method=="OPTIONS") {
|
if ($req->method=="OPTIONS") {
|
||||||
// respond to OPTIONS rquests; the response is a fib, as we technically accept any type or method
|
// respond to OPTIONS rquests; the response is a fib, as we technically accept any type or method
|
||||||
return new Response(204, "", "", [
|
return new EmptyResponse(204, [
|
||||||
"Allow: POST",
|
'Allow' => "POST",
|
||||||
"Accept: application/json, text/json",
|
'Accept' => "application/json, text/json",
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
if ($req->body) {
|
if ($req->body) {
|
||||||
// only JSON entities are allowed, but Content-Type is ignored, as is request method
|
// only JSON entities are allowed, but Content-Type is ignored, as is request method
|
||||||
$data = @json_decode($req->body, true);
|
$data = @json_decode($req->body, true);
|
||||||
if (json_last_error() != \JSON_ERROR_NONE || !is_array($data)) {
|
if (json_last_error() != \JSON_ERROR_NONE || !is_array($data)) {
|
||||||
return new Response(200, self::FATAL_ERR);
|
return new Response(self::FATAL_ERR);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// normalize input
|
// normalize input
|
||||||
|
@ -123,23 +124,23 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// TT-RSS operations are case-insensitive by dint of PHP method names being case-insensitive; this will only trigger if the method really doesn't exist
|
// TT-RSS operations are case-insensitive by dint of PHP method names being case-insensitive; this will only trigger if the method really doesn't exist
|
||||||
throw new Exception("UNKNOWN_METHOD", ['method' => $data['op']]);
|
throw new Exception("UNKNOWN_METHOD", ['method' => $data['op']]);
|
||||||
}
|
}
|
||||||
return new Response(200, [
|
return new Response([
|
||||||
'seq' => $data['seq'],
|
'seq' => $data['seq'],
|
||||||
'status' => 0,
|
'status' => 0,
|
||||||
'content' => $this->$method($data),
|
'content' => $this->$method($data),
|
||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return new Response(200, [
|
return new Response([
|
||||||
'seq' => $data['seq'],
|
'seq' => $data['seq'],
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
'content' => $e->getData(),
|
'content' => $e->getData(),
|
||||||
]);
|
]);
|
||||||
} catch (AbstractException $e) {
|
} catch (AbstractException $e) {
|
||||||
return new Response(500);
|
return new EmptyResponse(500);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// absence of a request body indicates an error
|
// absence of a request body indicates an error
|
||||||
return new Response(200, self::FATAL_ERR);
|
return new Response(self::FATAL_ERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,16 @@ declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\REST\TinyTinyRSS;
|
namespace JKingWeb\Arsse\REST\TinyTinyRSS;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Arsse;
|
use JKingWeb\Arsse\Arsse;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use Zend\Diactoros\Response\EmptyResponse as Response;
|
||||||
|
|
||||||
class Icon extends \JKingWeb\Arsse\REST\AbstractHandler {
|
class Icon extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
|
public function dispatch(\JKingWeb\Arsse\REST\Request $req): \Psr\Http\Message\ResponseInterface {
|
||||||
if ($req->method != "GET") {
|
if ($req->method != "GET") {
|
||||||
// only GET requests are allowed
|
// only GET requests are allowed
|
||||||
return new Response(405, "", "", ["Allow: GET"]);
|
return new Response(405, ['Allow' => "GET"]);
|
||||||
} elseif (!preg_match("<^(\d+)\.ico$>", $req->url, $match) || !((int) $match[1])) {
|
} elseif (!preg_match("<^(\d+)\.ico$>", $req->url, $match) || !((int) $match[1])) {
|
||||||
return new Response(404);
|
return new Response(404);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ class Icon extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
if (($pos = strpos($url, "\r")) !== false || ($pos = strpos($url, "\n")) !== false) {
|
if (($pos = strpos($url, "\r")) !== false || ($pos = strpos($url, "\n")) !== false) {
|
||||||
$url = substr($url, 0, $pos);
|
$url = substr($url, 0, $pos);
|
||||||
}
|
}
|
||||||
return new Response(301, "", "", ["Location: $url"]);
|
return new Response(301, ['Location' => $url]);
|
||||||
} else {
|
} else {
|
||||||
return new Response(404);
|
return new Response(404);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,14 @@ use JKingWeb\Arsse\User;
|
||||||
use JKingWeb\Arsse\Database;
|
use JKingWeb\Arsse\Database;
|
||||||
use JKingWeb\Arsse\Service;
|
use JKingWeb\Arsse\Service;
|
||||||
use JKingWeb\Arsse\REST\Request;
|
use JKingWeb\Arsse\REST\Request;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
|
||||||
use JKingWeb\Arsse\Test\Result;
|
use JKingWeb\Arsse\Test\Result;
|
||||||
use JKingWeb\Arsse\Misc\Date;
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
use JKingWeb\Arsse\Misc\Context;
|
use JKingWeb\Arsse\Misc\Context;
|
||||||
use JKingWeb\Arsse\Db\ExceptionInput;
|
use JKingWeb\Arsse\Db\ExceptionInput;
|
||||||
use JKingWeb\Arsse\Db\Transaction;
|
use JKingWeb\Arsse\Db\Transaction;
|
||||||
use JKingWeb\Arsse\REST\NextCloudNews\V1_2;
|
use JKingWeb\Arsse\REST\NextCloudNews\V1_2;
|
||||||
|
use Zend\Diactoros\Response\JsonResponse as Response;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
use Phake;
|
use Phake;
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\REST\NextCloudNews\V1_2<extended> */
|
/** @covers \JKingWeb\Arsse\REST\NextCloudNews\V1_2<extended> */
|
||||||
|
@ -317,14 +318,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->clearData();
|
$this->clearData();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertResponse(Response $exp, Response $act, string $text = null) {
|
|
||||||
$this->assertEquals($exp, $act, $text);
|
|
||||||
$this->assertSame($exp->payload, $act->payload, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSendAuthenticationChallenge() {
|
public function testSendAuthenticationChallenge() {
|
||||||
Phake::when(Arsse::$user)->authHTTP->thenReturn(false);
|
Phake::when(Arsse::$user)->authHTTP->thenReturn(false);
|
||||||
$exp = new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.V1_2::REALM.'"']);
|
$exp = new EmptyResponse(401, ['WWW-Authenticate' => 'Basic realm="'.V1_2::REALM.'"']);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,12 +357,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
foreach ($errs[404] as $req) {
|
foreach ($errs[404] as $req) {
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
list($method, $path) = $req;
|
list($method, $path) = $req;
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 404.");
|
$this->assertResponse($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 404.");
|
||||||
}
|
}
|
||||||
foreach ($errs[405] as $allow => $cases) {
|
foreach ($errs[405] as $allow => $cases) {
|
||||||
$exp = new Response(405, "", "", ['Allow: '.$allow]);
|
$exp = new EmptyResponse(405, ['Allow' => $allow]);
|
||||||
foreach ($cases as $req) {
|
foreach ($cases as $req) {
|
||||||
list($method, $path) = $req;
|
list($method, $path) = $req;
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 405.");
|
$this->assertResponse($exp, $this->h->dispatch(new Request($method, $path)), "$method call to $path did not return 405.");
|
||||||
|
@ -375,29 +371,29 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRespondToInvalidInputTypes() {
|
public function testRespondToInvalidInputTypes() {
|
||||||
$exp = new Response(415, "", "", ['Accept: application/json']);
|
$exp = new EmptyResponse(415, ['Accept' => "application/json"]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '<data/>', 'application/xml')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '<data/>', 'application/xml')));
|
||||||
$exp = new Response(400);
|
$exp = new EmptyResponse(400);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '<data/>', 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '<data/>', 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRespondToOptionsRequests() {
|
public function testRespondToOptionsRequests() {
|
||||||
$exp = new Response(204, "", "", [
|
$exp = new EmptyResponse(204, [
|
||||||
"Allow: HEAD,GET,POST",
|
'Allow' => "HEAD,GET,POST",
|
||||||
"Accept: application/json",
|
'Accept' => "application/json",
|
||||||
]);
|
]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds")));
|
||||||
$exp = new Response(204, "", "", [
|
$exp = new EmptyResponse(204, [
|
||||||
"Allow: DELETE",
|
'Allow' => "DELETE",
|
||||||
"Accept: application/json",
|
'Accept' => "application/json",
|
||||||
]);
|
]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds/2112")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds/2112")));
|
||||||
$exp = new Response(204, "", "", [
|
$exp = new EmptyResponse(204, [
|
||||||
"Allow: HEAD,GET",
|
'Allow' => "HEAD,GET",
|
||||||
"Accept: application/json",
|
'Accept' => "application/json",
|
||||||
]);
|
]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/user")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/user")));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/invalid/path")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "/invalid/path")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,9 +407,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
['id' => 12, 'name' => "Hardware"],
|
['id' => 12, 'name' => "Hardware"],
|
||||||
];
|
];
|
||||||
Phake::when(Arsse::$db)->folderList(Arsse::$user->id, null, false)->thenReturn(new Result([]))->thenReturn(new Result($list));
|
Phake::when(Arsse::$db)->folderList(Arsse::$user->id, null, false)->thenReturn(new Result([]))->thenReturn(new Result($list));
|
||||||
$exp = new Response(200, ['folders' => []]);
|
$exp = new Response(['folders' => []]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/folders")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/folders")));
|
||||||
$exp = new Response(200, ['folders' => $out]);
|
$exp = new Response(['folders' => $out]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/folders")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/folders")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,33 +437,33 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => ""])->thenThrow(new ExceptionInput("missing"));
|
Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => ""])->thenThrow(new ExceptionInput("missing"));
|
||||||
Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => " "])->thenThrow(new ExceptionInput("whitespace"));
|
Phake::when(Arsse::$db)->folderAdd(Arsse::$user->id, ['name' => " "])->thenThrow(new ExceptionInput("whitespace"));
|
||||||
// correctly add two folders, using different means
|
// correctly add two folders, using different means
|
||||||
$exp = new Response(200, ['folders' => [$out[0]]]);
|
$exp = new Response(['folders' => [$out[0]]]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[0]), 'application/json')));
|
||||||
$exp = new Response(200, ['folders' => [$out[1]]]);
|
$exp = new Response(['folders' => [$out[1]]]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders?name=Hardware")));
|
||||||
Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[0]);
|
Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[0]);
|
||||||
Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[1]);
|
Phake::verify(Arsse::$db)->folderAdd(Arsse::$user->id, $in[1]);
|
||||||
Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 1);
|
Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 1);
|
||||||
Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 2);
|
Phake::verify(Arsse::$db)->folderPropertiesGet(Arsse::$user->id, 2);
|
||||||
// test bad folder names
|
// test bad folder names
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":""}', 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":""}', 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":" "}', 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":" "}', 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":{}}', 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", '{"name":{}}', 'application/json')));
|
||||||
// try adding the same two folders again
|
// try adding the same two folders again
|
||||||
$exp = new Response(409);
|
$exp = new EmptyResponse(409);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders?name=Software")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders?name=Software")));
|
||||||
$exp = new Response(409);
|
$exp = new EmptyResponse(409);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/folders", json_encode($in[1]), 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAFolder() {
|
public function testRemoveAFolder() {
|
||||||
Phake::when(Arsse::$db)->folderRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
|
Phake::when(Arsse::$db)->folderRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/folders/1")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/folders/1")));
|
||||||
// fail on the second invocation because it no longer exists
|
// fail on the second invocation because it no longer exists
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/folders/1")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/folders/1")));
|
||||||
Phake::verify(Arsse::$db, Phake::times(2))->folderRemove(Arsse::$user->id, 1);
|
Phake::verify(Arsse::$db, Phake::times(2))->folderRemove(Arsse::$user->id, 1);
|
||||||
}
|
}
|
||||||
|
@ -486,22 +482,22 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[3])->thenThrow(new ExceptionInput("whitespace"));
|
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[3])->thenThrow(new ExceptionInput("whitespace"));
|
||||||
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database
|
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 1, $in[4])->thenReturn(true); // this should be stopped by the handler before the request gets to the database
|
||||||
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 3, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // folder ID 3 does not exist
|
Phake::when(Arsse::$db)->folderPropertiesSet(Arsse::$user->id, 3, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // folder ID 3 does not exist
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[0]), 'application/json')));
|
||||||
$exp = new Response(409);
|
$exp = new EmptyResponse(409);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/2", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/2", json_encode($in[1]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[2]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[2]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[3]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[3]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[4]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1", json_encode($in[4]), 'application/json')));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/3", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/3", json_encode($in[0]), 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRetrieveServerVersion() {
|
public function testRetrieveServerVersion() {
|
||||||
$exp = new Response(200, [
|
$exp = new Response([
|
||||||
'version' => V1_2::VERSION,
|
'version' => V1_2::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
]);
|
]);
|
||||||
|
@ -521,9 +517,9 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->subscriptionList(Arsse::$user->id)->thenReturn(new Result([]))->thenReturn(new Result($this->feeds['db']));
|
Phake::when(Arsse::$db)->subscriptionList(Arsse::$user->id)->thenReturn(new Result([]))->thenReturn(new Result($this->feeds['db']));
|
||||||
Phake::when(Arsse::$db)->articleStarred(Arsse::$user->id)->thenReturn(['total' => 0])->thenReturn(['total' => 5]);
|
Phake::when(Arsse::$db)->articleStarred(Arsse::$user->id)->thenReturn(['total' => 0])->thenReturn(['total' => 5]);
|
||||||
Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id)->thenReturn(0)->thenReturn(4758915);
|
Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id)->thenReturn(0)->thenReturn(4758915);
|
||||||
$exp = new Response(200, $exp1);
|
$exp = new Response($exp1);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds")));
|
||||||
$exp = new Response(200, $exp2);
|
$exp = new Response($exp2);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -556,31 +552,31 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
// set up a mock for a bad feed which succeeds the second time
|
// set up a mock for a bad feed which succeeds the second time
|
||||||
Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException()))->thenReturn(47);
|
Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException()))->thenReturn(47);
|
||||||
// add the subscriptions
|
// add the subscriptions
|
||||||
$exp = new Response(200, $out[0]);
|
$exp = new Response($out[0]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[0]), 'application/json')));
|
||||||
$exp = new Response(200, $out[1]);
|
$exp = new Response($out[1]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[1]), 'application/json')));
|
||||||
// try to add them a second time
|
// try to add them a second time
|
||||||
$exp = new Response(409);
|
$exp = new EmptyResponse(409);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[0]), 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[1]), 'application/json')));
|
||||||
// try to add a bad feed
|
// try to add a bad feed
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[2]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[2]), 'application/json')));
|
||||||
// try again (this will succeed), with an invalid folder ID
|
// try again (this will succeed), with an invalid folder ID
|
||||||
$exp = new Response(200, $out[2]);
|
$exp = new Response($out[2]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[3]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[3]), 'application/json')));
|
||||||
// try to add no feed
|
// try to add no feed
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[4]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/feeds", json_encode($in[4]), 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveASubscription() {
|
public function testRemoveASubscription() {
|
||||||
Phake::when(Arsse::$db)->subscriptionRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
|
Phake::when(Arsse::$db)->subscriptionRemove(Arsse::$user->id, 1)->thenReturn(true)->thenThrow(new ExceptionInput("subjectMissing"));
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1")));
|
||||||
// fail on the second invocation because it no longer exists
|
// fail on the second invocation because it no longer exists
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("DELETE", "/feeds/1")));
|
||||||
Phake::verify(Arsse::$db, Phake::times(2))->subscriptionRemove(Arsse::$user->id, 1);
|
Phake::verify(Arsse::$db, Phake::times(2))->subscriptionRemove(Arsse::$user->id, 1);
|
||||||
}
|
}
|
||||||
|
@ -599,17 +595,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => 2112])->thenThrow(new ExceptionInput("idMissing")); // folder does not exist
|
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => 2112])->thenThrow(new ExceptionInput("idMissing")); // folder does not exist
|
||||||
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => -1])->thenThrow(new ExceptionInput("typeViolation")); // folder is invalid
|
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => -1])->thenThrow(new ExceptionInput("typeViolation")); // folder is invalid
|
||||||
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // subscription does not exist
|
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing")); // subscription does not exist
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[0]), 'application/json')));
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[1]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[2]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[2]), 'application/json')));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/move", json_encode($in[3]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/move", json_encode($in[3]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[4]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[4]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[5]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/move", json_encode($in[5]), 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,17 +625,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => ""]))->thenThrow(new ExceptionInput("missing"));
|
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => ""]))->thenThrow(new ExceptionInput("missing"));
|
||||||
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => false]))->thenThrow(new ExceptionInput("missing"));
|
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, $this->identicalTo(['title' => false]))->thenThrow(new ExceptionInput("missing"));
|
||||||
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing"));
|
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, $this->anything())->thenThrow(new ExceptionInput("subjectMissing"));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[0]), 'application/json')));
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[1]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[2]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[2]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[3]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[3]), 'application/json')));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/rename", json_encode($in[4]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/rename", json_encode($in[4]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[6]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/rename", json_encode($in[6]), 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,11 +651,11 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
Phake::when(Arsse::$db)->feedListStale->thenReturn(array_column($out, "id"));
|
Phake::when(Arsse::$db)->feedListStale->thenReturn(array_column($out, "id"));
|
||||||
$exp = new Response(200, ['feeds' => $out]);
|
$exp = new Response(['feeds' => $out]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/all")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/all")));
|
||||||
// retrieving the list when not an admin fails
|
// retrieving the list when not an admin fails
|
||||||
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
||||||
$exp = new Response(403);
|
$exp = new EmptyResponse(403);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/all")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/all")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -674,17 +670,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->feedUpdate(42)->thenReturn(true);
|
Phake::when(Arsse::$db)->feedUpdate(42)->thenReturn(true);
|
||||||
Phake::when(Arsse::$db)->feedUpdate(2112)->thenThrow(new ExceptionInput("subjectMissing"));
|
Phake::when(Arsse::$db)->feedUpdate(2112)->thenThrow(new ExceptionInput("subjectMissing"));
|
||||||
Phake::when(Arsse::$db)->feedUpdate($this->lessThan(1))->thenThrow(new ExceptionInput("typeViolation"));
|
Phake::when(Arsse::$db)->feedUpdate($this->lessThan(1))->thenThrow(new ExceptionInput("typeViolation"));
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json')));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[1]), 'application/json')));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[2]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[2]), 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[3]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[3]), 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[4]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[4]), 'application/json')));
|
||||||
// updating a feed when not an admin fails
|
// updating a feed when not an admin fails
|
||||||
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
||||||
$exp = new Response(403);
|
$exp = new EmptyResponse(403);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/feeds/update", json_encode($in[0]), 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,12 +706,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(2112), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("idMissing"));
|
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(2112), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("idMissing"));
|
||||||
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->subscription(-1), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("typeViolation"));
|
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->subscription(-1), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("typeViolation"));
|
||||||
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(-1), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("typeViolation"));
|
Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->reverse(true)->folder(-1), Database::LIST_TYPICAL)->thenThrow(new ExceptionInput("typeViolation"));
|
||||||
$exp = new Response(200, ['items' => $this->articles['rest']]);
|
$exp = new Response(['items' => $this->articles['rest']]);
|
||||||
// check the contents of the response
|
// check the contents of the response
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items"))); // first instance of base context
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items"))); // first instance of base context
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items/updated"))); // second instance of base context
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items/updated"))); // second instance of base context
|
||||||
// check error conditions
|
// check error conditions
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items", json_encode($in[0]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items", json_encode($in[0]), 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items", json_encode($in[1]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items", json_encode($in[1]), 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items", json_encode($in[2]), 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/items", json_encode($in[2]), 'application/json')));
|
||||||
|
@ -748,13 +744,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$in = json_encode(['newestItemId' => 2112]);
|
$in = json_encode(['newestItemId' => 2112]);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(1)->latestEdition(2112))->thenReturn(42);
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(1)->latestEdition(2112))->thenReturn(42);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // folder doesn't exist
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->folder(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // folder doesn't exist
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read", $in, 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read", $in, 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read?newestItemId=2112")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read?newestItemId=2112")));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read?newestItemId=ook")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/1/read?newestItemId=ook")));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/42/read", $in, 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/folders/42/read", $in, 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,13 +759,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$in = json_encode(['newestItemId' => 2112]);
|
$in = json_encode(['newestItemId' => 2112]);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(1)->latestEdition(2112))->thenReturn(42);
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(1)->latestEdition(2112))->thenReturn(42);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // subscription doesn't exist
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->subscription(42)->latestEdition(2112))->thenThrow(new ExceptionInput("idMissing")); // subscription doesn't exist
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read", $in, 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read", $in, 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read?newestItemId=2112")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read?newestItemId=2112")));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read?newestItemId=ook")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/1/read?newestItemId=ook")));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/read", $in, 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/feeds/42/read", $in, 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -777,10 +773,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$read = ['read' => true];
|
$read = ['read' => true];
|
||||||
$in = json_encode(['newestItemId' => 2112]);
|
$in = json_encode(['newestItemId' => 2112]);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->latestEdition(2112))->thenReturn(42);
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $read, (new Context)->latestEdition(2112))->thenReturn(42);
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read", $in, 'application/json')));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read", $in, 'application/json')));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read?newestItemId=2112")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read?newestItemId=2112")));
|
||||||
$exp = new Response(422);
|
$exp = new EmptyResponse(422);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read?newestItemId=ook")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read?newestItemId=ook")));
|
||||||
}
|
}
|
||||||
|
@ -798,12 +794,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->article(2112))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $star, (new Context)->article(2112))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(4))->thenReturn(42);
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(4))->thenReturn(42);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(1337))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $unstar, (new Context)->article(1337))->thenThrow(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/read")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/read")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/2/unread")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/2/unread")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/3/star")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/3/star")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/4400/4/unstar")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/4400/4/unstar")));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/42/read")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/42/read")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/47/unread")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/47/unread")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/2112/star")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/1/2112/star")));
|
||||||
|
@ -829,7 +825,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), $this->anything())->thenReturn(42);
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), $this->anything())->thenReturn(42);
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->editions([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->editions([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
|
||||||
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->articles([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
|
Phake::when(Arsse::$db)->articleMark(Arsse::$user->id, $this->anything(), (new Context)->articles([]))->thenThrow(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read/multiple")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/read/multiple")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/unread/multiple")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/unread/multiple")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/star/multiple")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "/items/star/multiple")));
|
||||||
|
@ -882,29 +878,29 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
];
|
];
|
||||||
$arr2['warnings']['improperlyConfiguredCron'] = true;
|
$arr2['warnings']['improperlyConfiguredCron'] = true;
|
||||||
$arr2['warnings']['incorrectDbCharset'] = true;
|
$arr2['warnings']['incorrectDbCharset'] = true;
|
||||||
$exp = new Response(200, $arr1);
|
$exp = new Response($arr1);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/status")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/status")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCleanUpBeforeUpdate() {
|
public function testCleanUpBeforeUpdate() {
|
||||||
Phake::when(Arsse::$db)->feedCleanup()->thenReturn(true);
|
Phake::when(Arsse::$db)->feedCleanup()->thenReturn(true);
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/before-update")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/before-update")));
|
||||||
Phake::verify(Arsse::$db)->feedCleanup();
|
Phake::verify(Arsse::$db)->feedCleanup();
|
||||||
// performing a cleanup when not an admin fails
|
// performing a cleanup when not an admin fails
|
||||||
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
||||||
$exp = new Response(403);
|
$exp = new EmptyResponse(403);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/before-update")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/before-update")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCleanUpAfterUpdate() {
|
public function testCleanUpAfterUpdate() {
|
||||||
Phake::when(Arsse::$db)->articleCleanup()->thenReturn(true);
|
Phake::when(Arsse::$db)->articleCleanup()->thenReturn(true);
|
||||||
$exp = new Response(204);
|
$exp = new EmptyResponse(204);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/after-update")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/after-update")));
|
||||||
Phake::verify(Arsse::$db)->articleCleanup();
|
Phake::verify(Arsse::$db)->articleCleanup();
|
||||||
// performing a cleanup when not an admin fails
|
// performing a cleanup when not an admin fails
|
||||||
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
Phake::when(Arsse::$user)->rightsGet->thenReturn(0);
|
||||||
$exp = new Response(403);
|
$exp = new EmptyResponse(403);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/after-update")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "/cleanup/after-update")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ namespace JKingWeb\Arsse\TestCase\REST\NextCloudNews;
|
||||||
|
|
||||||
use JKingWeb\Arsse\REST\NextCloudNews\Versions;
|
use JKingWeb\Arsse\REST\NextCloudNews\Versions;
|
||||||
use JKingWeb\Arsse\REST\Request;
|
use JKingWeb\Arsse\REST\Request;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use Zend\Diactoros\Response\JsonResponse as Response;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\REST\NextCloudNews\Versions */
|
/** @covers \JKingWeb\Arsse\REST\NextCloudNews\Versions */
|
||||||
class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest {
|
class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
@ -17,43 +18,43 @@ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testFetchVersionList() {
|
public function testFetchVersionList() {
|
||||||
$exp = new Response(200, ['apiLevels' => ['v1-2']]);
|
$exp = new Response(['apiLevels' => ['v1-2']]);
|
||||||
$h = new Versions;
|
$h = new Versions;
|
||||||
$req = new Request("GET", "/");
|
$req = new Request("GET", "/");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
$req = new Request("GET", "");
|
$req = new Request("GET", "");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
$req = new Request("GET", "/?id=1827");
|
$req = new Request("GET", "/?id=1827");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRespondToOptionsRequest() {
|
public function testRespondToOptionsRequest() {
|
||||||
$exp = new Response(204, "", "", ["Allow: HEAD,GET"]);
|
$exp = new EmptyResponse(204, ['Allow' => "HEAD,GET"]);
|
||||||
$h = new Versions;
|
$h = new Versions;
|
||||||
$req = new Request("OPTIONS", "/");
|
$req = new Request("OPTIONS", "/");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUseIncorrectMethod() {
|
public function testUseIncorrectMethod() {
|
||||||
$exp = new Response(405, "", "", ["Allow: HEAD,GET"]);
|
$exp = new EmptyResponse(405, ['Allow' => "HEAD,GET"]);
|
||||||
$h = new Versions;
|
$h = new Versions;
|
||||||
$req = new Request("POST", "/");
|
$req = new Request("POST", "/");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUseIncorrectPath() {
|
public function testUseIncorrectPath() {
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$h = new Versions;
|
$h = new Versions;
|
||||||
$req = new Request("GET", "/ook");
|
$req = new Request("GET", "/ook");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
$req = new Request("OPTIONS", "/ook");
|
$req = new Request("OPTIONS", "/ook");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertResponse($exp, $res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,15 @@ use JKingWeb\Arsse\User;
|
||||||
use JKingWeb\Arsse\Database;
|
use JKingWeb\Arsse\Database;
|
||||||
use JKingWeb\Arsse\Service;
|
use JKingWeb\Arsse\Service;
|
||||||
use JKingWeb\Arsse\REST\Request;
|
use JKingWeb\Arsse\REST\Request;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
|
||||||
use JKingWeb\Arsse\Test\Result;
|
use JKingWeb\Arsse\Test\Result;
|
||||||
use JKingWeb\Arsse\Misc\Date;
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
use JKingWeb\Arsse\Misc\Context;
|
use JKingWeb\Arsse\Misc\Context;
|
||||||
use JKingWeb\Arsse\Db\ExceptionInput;
|
use JKingWeb\Arsse\Db\ExceptionInput;
|
||||||
use JKingWeb\Arsse\Db\Transaction;
|
use JKingWeb\Arsse\Db\Transaction;
|
||||||
use JKingWeb\Arsse\REST\TinyTinyRSS\API;
|
use JKingWeb\Arsse\REST\TinyTinyRSS\API;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Zend\Diactoros\Response\JsonResponse as Response;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
use Phake;
|
use Phake;
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\API<extended>
|
/** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\API<extended>
|
||||||
|
@ -122,12 +124,12 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
</section>
|
</section>
|
||||||
LONG_STRING;
|
LONG_STRING;
|
||||||
|
|
||||||
protected function req($data) : Response {
|
protected function req($data): ResponseInterface {
|
||||||
return $this->h->dispatch(new Request("POST", "", json_encode($data)));
|
return $this->h->dispatch(new Request("POST", "", json_encode($data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function respGood($content = null, $seq = 0): Response {
|
protected function respGood($content = null, $seq = 0): Response {
|
||||||
return new Response(200, [
|
return new Response([
|
||||||
'seq' => $seq,
|
'seq' => $seq,
|
||||||
'status' => 0,
|
'status' => 0,
|
||||||
'content' => $content,
|
'content' => $content,
|
||||||
|
@ -136,18 +138,13 @@ LONG_STRING;
|
||||||
|
|
||||||
protected function respErr(string $msg, $content = [], $seq = 0): Response {
|
protected function respErr(string $msg, $content = [], $seq = 0): Response {
|
||||||
$err = ['error' => $msg];
|
$err = ['error' => $msg];
|
||||||
return new Response(200, [
|
return new Response([
|
||||||
'seq' => $seq,
|
'seq' => $seq,
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
'content' => array_merge($err, $content, $err),
|
'content' => array_merge($err, $content, $err),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function assertResponse(Response $exp, Response $act, string $text = null) {
|
|
||||||
$this->assertEquals($exp, $act, $text);
|
|
||||||
$this->assertSame($exp->payload, $act->payload, $text);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$this->clearData();
|
$this->clearData();
|
||||||
Arsse::$conf = new Conf();
|
Arsse::$conf = new Conf();
|
||||||
|
@ -178,14 +175,14 @@ LONG_STRING;
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "", "")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "", "")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/", "")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/", "")));
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/index.php", "")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/index.php", "")));
|
||||||
$exp = new Response(404);
|
$exp = new EmptyResponse(404);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/bad/path", "")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("POST", "/bad/path", "")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testHandleOptionsRequest() {
|
public function testHandleOptionsRequest() {
|
||||||
$exp = new Response(204, "", "", [
|
$exp = new EmptyResponse(204, [
|
||||||
"Allow: POST",
|
'Allow' => "POST",
|
||||||
"Accept: application/json, text/json",
|
'Accept' => "application/json, text/json",
|
||||||
]);
|
]);
|
||||||
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("OPTIONS", "")));
|
||||||
}
|
}
|
||||||
|
@ -226,7 +223,7 @@ LONG_STRING;
|
||||||
'user' => Arsse::$user->id,
|
'user' => Arsse::$user->id,
|
||||||
'password' => "secret",
|
'password' => "secret",
|
||||||
];
|
];
|
||||||
$exp = new Response(500);
|
$exp = new EmptyResponse(500);
|
||||||
$this->assertResponse($exp, $this->req($data));
|
$this->assertResponse($exp, $this->req($data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1630,10 +1627,10 @@ LONG_STRING;
|
||||||
$this->assertResponse($this->outputHeadlines(1), $test);
|
$this->assertResponse($this->outputHeadlines(1), $test);
|
||||||
// test 'show_content'
|
// test 'show_content'
|
||||||
$test = $this->req($in[1]);
|
$test = $this->req($in[1]);
|
||||||
$this->assertArrayHasKey("content", $test->payload['content'][0]);
|
$this->assertArrayHasKey("content", $test->getPayload()['content'][0]);
|
||||||
$this->assertArrayHasKey("content", $test->payload['content'][1]);
|
$this->assertArrayHasKey("content", $test->getPayload()['content'][1]);
|
||||||
foreach ($this->generateHeadlines(1) as $key => $row) {
|
foreach ($this->generateHeadlines(1) as $key => $row) {
|
||||||
$this->assertSame($row['content'], $test->payload['content'][$key]['content']);
|
$this->assertSame($row['content'], $test->getPayload()['content'][$key]['content']);
|
||||||
}
|
}
|
||||||
// test 'include_attachments'
|
// test 'include_attachments'
|
||||||
$test = $this->req($in[2]);
|
$test = $this->req($in[2]);
|
||||||
|
@ -1649,25 +1646,23 @@ LONG_STRING;
|
||||||
'post_id' => "2112",
|
'post_id' => "2112",
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$this->assertArrayHasKey("attachments", $test->payload['content'][0]);
|
$this->assertArrayHasKey("attachments", $test->getPayload()['content'][0]);
|
||||||
$this->assertArrayHasKey("attachments", $test->payload['content'][1]);
|
$this->assertArrayHasKey("attachments", $test->getPayload()['content'][1]);
|
||||||
$this->assertSame([], $test->payload['content'][0]['attachments']);
|
$this->assertSame([], $test->getPayload()['content'][0]['attachments']);
|
||||||
$this->assertSame($exp, $test->payload['content'][1]['attachments']);
|
$this->assertSame($exp, $test->getPayload()['content'][1]['attachments']);
|
||||||
// test 'include_header'
|
// test 'include_header'
|
||||||
$test = $this->req($in[3]);
|
$test = $this->req($in[3]);
|
||||||
$exp = $this->outputHeadlines(1);
|
$exp = $this->respGood([
|
||||||
$exp->payload['content'] = [
|
|
||||||
['id' => -4, 'is_cat' => false, 'first_id' => 1],
|
['id' => -4, 'is_cat' => false, 'first_id' => 1],
|
||||||
$exp->payload['content'],
|
$this->outputHeadlines(1)->getPayload()['content'],
|
||||||
];
|
]);
|
||||||
$this->assertResponse($exp, $test);
|
$this->assertResponse($exp, $test);
|
||||||
// test 'include_header' with a category
|
// test 'include_header' with a category
|
||||||
$test = $this->req($in[4]);
|
$test = $this->req($in[4]);
|
||||||
$exp = $this->outputHeadlines(1);
|
$exp = $this->respGood([
|
||||||
$exp->payload['content'] = [
|
|
||||||
['id' => -3, 'is_cat' => true, 'first_id' => 1],
|
['id' => -3, 'is_cat' => true, 'first_id' => 1],
|
||||||
$exp->payload['content'],
|
$this->outputHeadlines(1)->getPayload()['content'],
|
||||||
];
|
]);
|
||||||
$this->assertResponse($exp, $test);
|
$this->assertResponse($exp, $test);
|
||||||
// test 'include_header' with an empty result
|
// test 'include_header' with an empty result
|
||||||
$test = $this->req($in[5]);
|
$test = $this->req($in[5]);
|
||||||
|
@ -1686,37 +1681,34 @@ LONG_STRING;
|
||||||
$this->assertResponse($exp, $test);
|
$this->assertResponse($exp, $test);
|
||||||
// test 'include_header' with ascending order
|
// test 'include_header' with ascending order
|
||||||
$test = $this->req($in[7]);
|
$test = $this->req($in[7]);
|
||||||
$exp = $this->outputHeadlines(1);
|
$exp = $this->respGood([
|
||||||
$exp->payload['content'] = [
|
|
||||||
['id' => -4, 'is_cat' => false, 'first_id' => 0],
|
['id' => -4, 'is_cat' => false, 'first_id' => 0],
|
||||||
$exp->payload['content'],
|
$this->outputHeadlines(1)->getPayload()['content'],
|
||||||
];
|
]);
|
||||||
$this->assertResponse($exp, $test);
|
$this->assertResponse($exp, $test);
|
||||||
// test 'include_header' with skip
|
// test 'include_header' with skip
|
||||||
Phake::when(Arsse::$db)->articleList($this->anything(), (new Context)->reverse(true)->limit(1)->subscription(42), Database::LIST_MINIMAL)->thenReturn($this->generateHeadlines(1867));
|
Phake::when(Arsse::$db)->articleList($this->anything(), (new Context)->reverse(true)->limit(1)->subscription(42), Database::LIST_MINIMAL)->thenReturn($this->generateHeadlines(1867));
|
||||||
$test = $this->req($in[8]);
|
$test = $this->req($in[8]);
|
||||||
$exp = $this->outputHeadlines(1);
|
$exp = $this->respGood([
|
||||||
$exp->payload['content'] = [
|
|
||||||
['id' => 42, 'is_cat' => false, 'first_id' => 1867],
|
['id' => 42, 'is_cat' => false, 'first_id' => 1867],
|
||||||
$exp->payload['content'],
|
$this->outputHeadlines(1)->getPayload()['content'],
|
||||||
];
|
]);
|
||||||
$this->assertResponse($exp, $test);
|
$this->assertResponse($exp, $test);
|
||||||
// test 'include_header' with skip and ascending order
|
// test 'include_header' with skip and ascending order
|
||||||
$test = $this->req($in[9]);
|
$test = $this->req($in[9]);
|
||||||
$exp = $this->outputHeadlines(1);
|
$exp = $this->respGood([
|
||||||
$exp->payload['content'] = [
|
|
||||||
['id' => 42, 'is_cat' => false, 'first_id' => 0],
|
['id' => 42, 'is_cat' => false, 'first_id' => 0],
|
||||||
$exp->payload['content'],
|
$this->outputHeadlines(1)->getPayload()['content'],
|
||||||
];
|
]);
|
||||||
$this->assertResponse($exp, $test);
|
$this->assertResponse($exp, $test);
|
||||||
// test 'show_excerpt'
|
// test 'show_excerpt'
|
||||||
$exp1 = "“This & that, you know‽”";
|
$exp1 = "“This & that, you know‽”";
|
||||||
$exp2 = "Pour vous faire mieux connaitre d’ou\u{300} vient l’erreur de ceux qui bla\u{302}ment la volupte\u{301}, et qui louent en…";
|
$exp2 = "Pour vous faire mieux connaitre d’ou\u{300} vient l’erreur de ceux qui bla\u{302}ment la volupte\u{301}, et qui louent en…";
|
||||||
$test = $this->req($in[10]);
|
$test = $this->req($in[10]);
|
||||||
$this->assertArrayHasKey("excerpt", $test->payload['content'][0]);
|
$this->assertArrayHasKey("excerpt", $test->getPayload()['content'][0]);
|
||||||
$this->assertArrayHasKey("excerpt", $test->payload['content'][1]);
|
$this->assertArrayHasKey("excerpt", $test->getPayload()['content'][1]);
|
||||||
$this->assertSame($exp1, $test->payload['content'][0]['excerpt']);
|
$this->assertSame($exp1, $test->getPayload()['content'][0]['excerpt']);
|
||||||
$this->assertSame($exp2, $test->payload['content'][1]['excerpt']);
|
$this->assertSame($exp2, $test->getPayload()['content'][1]['excerpt']);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function generateHeadlines(int $id): Result {
|
protected function generateHeadlines(int $id): Result {
|
||||||
|
|
|
@ -12,7 +12,7 @@ use JKingWeb\Arsse\User;
|
||||||
use JKingWeb\Arsse\Database;
|
use JKingWeb\Arsse\Database;
|
||||||
use JKingWeb\Arsse\REST\TinyTinyRSS\Icon;
|
use JKingWeb\Arsse\REST\TinyTinyRSS\Icon;
|
||||||
use JKingWeb\Arsse\REST\Request;
|
use JKingWeb\Arsse\REST\Request;
|
||||||
use JKingWeb\Arsse\REST\Response;
|
use Zend\Diactoros\Response\EmptyResponse as Response;
|
||||||
use Phake;
|
use Phake;
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Icon<extended> */
|
/** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Icon<extended> */
|
||||||
|
@ -38,20 +38,20 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
Phake::when(Arsse::$db)->subscriptionFavicon(2112)->thenReturn("http://example.net/logo.png");
|
Phake::when(Arsse::$db)->subscriptionFavicon(2112)->thenReturn("http://example.net/logo.png");
|
||||||
Phake::when(Arsse::$db)->subscriptionFavicon(1337)->thenReturn("http://example.org/icon.gif\r\nLocation: http://bad.example.com/");
|
Phake::when(Arsse::$db)->subscriptionFavicon(1337)->thenReturn("http://example.org/icon.gif\r\nLocation: http://bad.example.com/");
|
||||||
// these requests should succeed
|
// these requests should succeed
|
||||||
$exp = new Response(301, "", "", ["Location: http://example.com/favicon.ico"]);
|
$exp = new Response(301, ['Location' => "http://example.com/favicon.ico"]);
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "42.ico")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "42.ico")));
|
||||||
$exp = new Response(301, "", "", ["Location: http://example.net/logo.png"]);
|
$exp = new Response(301, ['Location' => "http://example.net/logo.png"]);
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "2112.ico")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "2112.ico")));
|
||||||
$exp = new Response(301, "", "", ["Location: http://example.org/icon.gif"]);
|
$exp = new Response(301, ['Location' => "http://example.org/icon.gif"]);
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "1337.ico")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "1337.ico")));
|
||||||
// these requests should fail
|
// these requests should fail
|
||||||
$exp = new Response(404);
|
$exp = new Response(404);
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "ook.ico")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "ook.ico")));
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "ook")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "ook")));
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "47.ico")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "47.ico")));
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "2112.png")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("GET", "2112.png")));
|
||||||
// only GET is allowed
|
// only GET is allowed
|
||||||
$exp = new Response(405, "", "", ["Allow: GET"]);
|
$exp = new Response(405, ['Allow' => "GET"]);
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "2112.ico")));
|
$this->assertResponse($exp, $this->h->dispatch(new Request("PUT", "2112.ico")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,9 @@ namespace JKingWeb\Arsse\Test;
|
||||||
use JKingWeb\Arsse\Exception;
|
use JKingWeb\Arsse\Exception;
|
||||||
use JKingWeb\Arsse\Arsse;
|
use JKingWeb\Arsse\Arsse;
|
||||||
use JKingWeb\Arsse\Misc\Date;
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Zend\Diactoros\Response\JsonResponse;
|
||||||
|
use Zend\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
/** @coversNothing */
|
/** @coversNothing */
|
||||||
abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
|
@ -29,6 +32,16 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function assertResponse(ResponseInterface $exp, ResponseInterface $act, string $text = null) {
|
||||||
|
$this->assertEquals($exp->getHeaders(), $act->getHeaders(), $text);
|
||||||
|
$this->assertEquals($exp->getStatusCode(), $act->getStatusCode(), $text);
|
||||||
|
$this->assertInstanceOf(get_class($exp), $act);
|
||||||
|
if ($exp instanceof JsonResponse) {
|
||||||
|
$this->assertEquals($exp->getPayload(), $act->getPayload(), $text);
|
||||||
|
$this->assertSame($exp->getPayload(), $act->getPayload(), $text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function approximateTime($exp, $act) {
|
public function approximateTime($exp, $act) {
|
||||||
if (is_null($act)) {
|
if (is_null($act)) {
|
||||||
return null;
|
return null;
|
||||||
|
|
20
vendor-bin/phpunit/composer.lock
generated
20
vendor-bin/phpunit/composer.lock
generated
|
@ -777,16 +777,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit",
|
"name": "phpunit/phpunit",
|
||||||
"version": "6.5.4",
|
"version": "6.5.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||||
"reference": "1b2f933d5775f9237369deaa2d2bfbf9d652be4c"
|
"reference": "83d27937a310f2984fd575686138597147bdc7df"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1b2f933d5775f9237369deaa2d2bfbf9d652be4c",
|
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/83d27937a310f2984fd575686138597147bdc7df",
|
||||||
"reference": "1b2f933d5775f9237369deaa2d2bfbf9d652be4c",
|
"reference": "83d27937a310f2984fd575686138597147bdc7df",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -857,7 +857,7 @@
|
||||||
"testing",
|
"testing",
|
||||||
"xunit"
|
"xunit"
|
||||||
],
|
],
|
||||||
"time": "2017-12-10T08:06:19+00:00"
|
"time": "2017-12-17T06:31:19+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "phpunit/phpunit-mock-objects",
|
"name": "phpunit/phpunit-mock-objects",
|
||||||
|
@ -965,16 +965,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/comparator",
|
"name": "sebastian/comparator",
|
||||||
"version": "2.1.0",
|
"version": "2.1.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/sebastianbergmann/comparator.git",
|
"url": "https://github.com/sebastianbergmann/comparator.git",
|
||||||
"reference": "1174d9018191e93cb9d719edec01257fc05f8158"
|
"reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1174d9018191e93cb9d719edec01257fc05f8158",
|
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b11c729f95109b56a0fe9650c6a63a0fcd8c439f",
|
||||||
"reference": "1174d9018191e93cb9d719edec01257fc05f8158",
|
"reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -1025,7 +1025,7 @@
|
||||||
"compare",
|
"compare",
|
||||||
"equality"
|
"equality"
|
||||||
],
|
],
|
||||||
"time": "2017-11-03T07:16:52+00:00"
|
"time": "2017-12-22T14:50:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "sebastian/diff",
|
"name": "sebastian/diff",
|
||||||
|
|
76
vendor-bin/robo/composer.lock
generated
76
vendor-bin/robo/composer.lock
generated
|
@ -59,28 +59,33 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "consolidation/config",
|
"name": "consolidation/config",
|
||||||
"version": "1.0.7",
|
"version": "1.0.9",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/consolidation/config.git",
|
"url": "https://github.com/consolidation/config.git",
|
||||||
"reference": "b59a3b9ea750c21397f26a68fd2e04d9580af42e"
|
"reference": "34ca8d7c1ee60a7b591b10617114cf1210a2e92c"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/consolidation/config/zipball/b59a3b9ea750c21397f26a68fd2e04d9580af42e",
|
"url": "https://api.github.com/repos/consolidation/config/zipball/34ca8d7c1ee60a7b591b10617114cf1210a2e92c",
|
||||||
"reference": "b59a3b9ea750c21397f26a68fd2e04d9580af42e",
|
"reference": "34ca8d7c1ee60a7b591b10617114cf1210a2e92c",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"dflydev/dot-access-data": "^1.1.0",
|
"dflydev/dot-access-data": "^1.1.0",
|
||||||
"grasmash/yaml-expander": "^1.1",
|
"grasmash/expander": "^1",
|
||||||
"php": ">=5.4.0"
|
"php": ">=5.4.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"greg-1-anderson/composer-test-scenarios": "^1",
|
||||||
"phpunit/phpunit": "^4",
|
"phpunit/phpunit": "^4",
|
||||||
"satooshi/php-coveralls": "^1.0",
|
"satooshi/php-coveralls": "^1.0",
|
||||||
"squizlabs/php_codesniffer": "2.*",
|
"squizlabs/php_codesniffer": "2.*",
|
||||||
"symfony/console": "^2.5|^3"
|
"symfony/console": "^2.5|^3|^4",
|
||||||
|
"symfony/yaml": "^2.8.11|^3|^4"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/yaml": "Required to use Consolidation\\Config\\Loader\\YamlConfigLoader"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
|
@ -104,7 +109,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Provide configuration services for a commandline tool.",
|
"description": "Provide configuration services for a commandline tool.",
|
||||||
"time": "2017-10-25T05:50:10+00:00"
|
"time": "2017-12-22T17:28:19+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "consolidation/log",
|
"name": "consolidation/log",
|
||||||
|
@ -205,16 +210,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "consolidation/robo",
|
"name": "consolidation/robo",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/consolidation/Robo.git",
|
"url": "https://github.com/consolidation/Robo.git",
|
||||||
"reference": "c46c13de3eca55e6b3635f363688ce85e845adf0"
|
"reference": "b6296f1cf1088f1a11b0b819f9e42ef6f00b79a9"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/consolidation/Robo/zipball/c46c13de3eca55e6b3635f363688ce85e845adf0",
|
"url": "https://api.github.com/repos/consolidation/Robo/zipball/b6296f1cf1088f1a11b0b819f9e42ef6f00b79a9",
|
||||||
"reference": "c46c13de3eca55e6b3635f363688ce85e845adf0",
|
"reference": "b6296f1cf1088f1a11b0b819f9e42ef6f00b79a9",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -278,7 +283,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Modern task runner",
|
"description": "Modern task runner",
|
||||||
"time": "2017-12-13T02:10:49+00:00"
|
"time": "2017-12-29T06:48:35+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "container-interop/container-interop",
|
"name": "container-interop/container-interop",
|
||||||
|
@ -370,6 +375,53 @@
|
||||||
],
|
],
|
||||||
"time": "2017-01-20T21:14:22+00:00"
|
"time": "2017-01-20T21:14:22+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "grasmash/expander",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/grasmash/expander.git",
|
||||||
|
"reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/grasmash/expander/zipball/95d6037344a4be1dd5f8e0b0b2571a28c397578f",
|
||||||
|
"reference": "95d6037344a4be1dd5f8e0b0b2571a28c397578f",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"dflydev/dot-access-data": "^1.1.0",
|
||||||
|
"php": ">=5.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"greg-1-anderson/composer-test-scenarios": "^1",
|
||||||
|
"phpunit/phpunit": "^4|^5.5.4",
|
||||||
|
"satooshi/php-coveralls": "^1.0.2|dev-master",
|
||||||
|
"squizlabs/php_codesniffer": "^2.7"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Grasmash\\Expander\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Matthew Grasmick"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Expands internal property references in PHP arrays file.",
|
||||||
|
"time": "2017-12-21T22:14:55+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "grasmash/yaml-expander",
|
"name": "grasmash/yaml-expander",
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
|
|
Loading…
Reference in a new issue