mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 05:02:40 +00:00
Address remaining errors
Still many failures to fix
This commit is contained in:
parent
56f015bfb9
commit
459e44e041
10 changed files with 233 additions and 261 deletions
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
/** @license MIT
|
||||
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||
* See LICENSE and AUTHORS files for details */
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\Arsse\REST\Miniflux;
|
||||
|
||||
use JKingWeb\Arsse\Arsse;
|
||||
|
||||
class ErrorResponse extends \Laminas\Diactoros\Response\JsonResponse {
|
||||
public function __construct($data, int $status = 400, array $headers = [], int $encodingOptions = self::DEFAULT_JSON_FLAGS) {
|
||||
assert(isset(Arsse::$lang) && Arsse::$lang instanceof \JKingWeb\Arsse\Lang, new \Exception("Language database must be initialized before use"));
|
||||
$data = (array) $data;
|
||||
$msg = array_shift($data);
|
||||
$data = ["error_message" => Arsse::$lang->msg("API.Miniflux.Error.".$msg, $data)];
|
||||
parent::__construct($data, $status, $headers, $encodingOptions);
|
||||
}
|
||||
}
|
|
@ -212,6 +212,14 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
public static function respError($data, int $status = 400, array $headers = []): ResponseInterface {
|
||||
assert(isset(Arsse::$lang) && Arsse::$lang instanceof \JKingWeb\Arsse\Lang, new \Exception("Language database must be initialized before use"));
|
||||
$data = (array) $data;
|
||||
$msg = array_shift($data);
|
||||
$data = ["error_message" => Arsse::$lang->msg("API.Miniflux.Error.".$msg, $data)];
|
||||
return HTTP::respJson($data, $status, $headers);
|
||||
}
|
||||
|
||||
protected function authenticate(ServerRequestInterface $req): bool {
|
||||
// first check any tokens; this is what Miniflux does
|
||||
|
@ -245,7 +253,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
}
|
||||
// try to authenticate
|
||||
if (!$this->authenticate($req)) {
|
||||
return new ErrorResponse("401", 401);
|
||||
return self::respError("401", 401);
|
||||
}
|
||||
$func = $this->chooseCall($target, $method);
|
||||
if ($func instanceof ResponseInterface) {
|
||||
|
@ -254,7 +262,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
[$func, $reqAdmin, $reqPath, $reqBody, $reqQuery, $reqFields] = $func;
|
||||
}
|
||||
if ($reqAdmin && !$this->isAdmin()) {
|
||||
return new ErrorResponse("403", 403);
|
||||
return self::respError("403", 403);
|
||||
}
|
||||
$args = [];
|
||||
if ($reqPath) {
|
||||
|
@ -269,7 +277,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$data = @json_decode($data, true);
|
||||
if (json_last_error() !== \JSON_ERROR_NONE) {
|
||||
// if the body could not be parsed as JSON, return "400 Bad Request"
|
||||
return new ErrorResponse(["InvalidBodyJSON", json_last_error_msg()], 400);
|
||||
return self::respError(["InvalidBodyJSON", json_last_error_msg()], 400);
|
||||
}
|
||||
} else {
|
||||
$data = [];
|
||||
|
@ -344,20 +352,20 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
if (!isset($body[$k])) {
|
||||
$body[$k] = null;
|
||||
} elseif (gettype($body[$k]) !== $t) {
|
||||
return new ErrorResponse(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422);
|
||||
return self::respError(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422);
|
||||
} elseif (
|
||||
(in_array($k, ["keeplist_rules", "blocklist_rules"]) && !Rule::validate($body[$k]))
|
||||
|| (in_array($k, ["url", "feed_url"]) && !URL::absolute($body[$k]))
|
||||
|| ($k === "category_id" && $body[$k] < 1)
|
||||
|| ($k === "status" && !in_array($body[$k], ["read", "unread", "removed"]))
|
||||
) {
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => $k], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => $k], 422);
|
||||
} elseif ($k === "entry_ids") {
|
||||
foreach ($body[$k] as $v) {
|
||||
if (gettype($v) !== "integer") {
|
||||
return new ErrorResponse(["InvalidInputType", 'field' => $k, 'expected' => "integer", 'actual' => gettype($v)], 422);
|
||||
return self::respError(["InvalidInputType", 'field' => $k, 'expected' => "integer", 'actual' => gettype($v)], 422);
|
||||
} elseif ($v < 1) {
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => $k], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => $k], 422);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,16 +377,16 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$body[$k] = null;
|
||||
} elseif ($k === "entry_sorting_direction") {
|
||||
if (!in_array($body[$k], ["asc", "desc"])) {
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => $k], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => $k], 422);
|
||||
}
|
||||
} elseif (gettype($body[$k]) !== $t) {
|
||||
return new ErrorResponse(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422);
|
||||
return self::respError(["InvalidInputType", 'field' => $k, 'expected' => $t, 'actual' => gettype($body[$k])], 422);
|
||||
}
|
||||
}
|
||||
// check for any missing required values
|
||||
foreach ($req as $k) {
|
||||
if (!isset($body[$k]) || (is_array($body[$k]) && !$body[$k])) {
|
||||
return new ErrorResponse(["MissingInputValue", 'field' => $k], 422);
|
||||
return self::respError(["MissingInputValue", 'field' => $k], 422);
|
||||
}
|
||||
}
|
||||
return $body;
|
||||
|
@ -407,7 +415,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
if ($seen[$k] && !$a) {
|
||||
// if the key has already been seen and it's not an array field, bail
|
||||
// NOTE: Miniflux itself simply ignores duplicates entirely
|
||||
return new ErrorResponse(["DuplicateInputValue", 'field' => $k], 400);
|
||||
return self::respError(["DuplicateInputValue", 'field' => $k], 400);
|
||||
}
|
||||
$seen[$k] = true;
|
||||
if ($k === "starred") {
|
||||
|
@ -423,7 +431,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$out[$k] = V::normalize($v, $t + V::M_STRICT, "unix");
|
||||
}
|
||||
} catch (ExceptionType $e) {
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => $k], 400);
|
||||
return self::respError(["InvalidInputValue", 'field' => $k], 400);
|
||||
}
|
||||
// perform additional validation
|
||||
if (
|
||||
|
@ -433,7 +441,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
|| ($k === "order" && !in_array($v, ["id", "status", "published_at", "category_title", "category_id"]))
|
||||
|| ($k === "status" && !in_array($v, ["read", "unread", "removed"]))
|
||||
) {
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => $k], 400);
|
||||
return self::respError(["InvalidInputValue", 'field' => $k], 400);
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
|
@ -525,7 +533,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
10507 => "Fetch401",
|
||||
10521 => "Fetch404",
|
||||
][$e->getCode()] ?? "FetchOther";
|
||||
return new ErrorResponse($msg, 502);
|
||||
return self::respError($msg, 502);
|
||||
}
|
||||
$out = [];
|
||||
foreach ($list as $url) {
|
||||
|
@ -544,7 +552,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
return HTTP::respJson($this->listUsers([$path[1]], true)[0] ?? new \stdClass);
|
||||
} catch (UserException $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,7 +561,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$user = Arsse::$user->lookup((int) $path[1]);
|
||||
return HTTP::respJson($this->listUsers([$user], true)[0] ?? new \stdClass);
|
||||
} catch (UserException $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -570,13 +578,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
} catch (UserException $e) {
|
||||
switch ($e->getCode()) {
|
||||
case 10403:
|
||||
return new ErrorResponse(["DuplicateUser", 'user' => $data['username']], 409);
|
||||
return self::respError(["DuplicateUser", 'user' => $data['username']], 409);
|
||||
case 10441:
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => "timezone"], 422);
|
||||
case 10443:
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422);
|
||||
case 10444:
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => "username"], 422);
|
||||
}
|
||||
throw $e; // @codeCoverageIgnore
|
||||
}
|
||||
|
@ -589,16 +597,16 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
if (((int) $path[1]) === $user['num']) {
|
||||
if ($data['is_admin'] && !$user['admin']) {
|
||||
// non-admins should not be able to set themselves as admin
|
||||
return new ErrorResponse("InvalidElevation", 403);
|
||||
return self::respError("InvalidElevation", 403);
|
||||
}
|
||||
$user = Arsse::$user->id;
|
||||
} elseif (!$user['admin']) {
|
||||
return new ErrorResponse("403", 403);
|
||||
return self::respError("403", 403);
|
||||
} else {
|
||||
try {
|
||||
$user = Arsse::$user->lookup((int) $path[1]);
|
||||
} catch (ExceptionConflict $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
// make any requested changes
|
||||
|
@ -616,13 +624,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
} catch (UserException $e) {
|
||||
switch ($e->getCode()) {
|
||||
case 10403:
|
||||
return new ErrorResponse(["DuplicateUser", 'user' => $data['username']], 409);
|
||||
return self::respError(["DuplicateUser", 'user' => $data['username']], 409);
|
||||
case 10441:
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => "timezone"], 422);
|
||||
case 10443:
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422);
|
||||
case 10444:
|
||||
return new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422);
|
||||
return self::respError(["InvalidInputValue", 'field' => "username"], 422);
|
||||
}
|
||||
throw $e; // @codeCoverageIgnore
|
||||
}
|
||||
|
@ -633,7 +641,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
Arsse::$user->remove(Arsse::$user->lookup((int) $path[1]));
|
||||
} catch (ExceptionConflict $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respEmpty(204);
|
||||
}
|
||||
|
@ -673,9 +681,9 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$id = Arsse::$db->folderAdd(Arsse::$user->id, ['name' => (string) $data['title']]);
|
||||
} catch (ExceptionInput $e) {
|
||||
if ($e->getCode() === 10236) {
|
||||
return new ErrorResponse(["DuplicateCategory", 'title' => $data['title']], 409);
|
||||
return self::respError(["DuplicateCategory", 'title' => $data['title']], 409);
|
||||
} else {
|
||||
return new ErrorResponse(["InvalidCategory", 'title' => $data['title']], 422);
|
||||
return self::respError(["InvalidCategory", 'title' => $data['title']], 422);
|
||||
}
|
||||
}
|
||||
$meta = Arsse::$user->propertiesGet(Arsse::$user->id, false);
|
||||
|
@ -698,11 +706,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
}
|
||||
} catch (ExceptionInput $e) {
|
||||
if ($e->getCode() === 10236) {
|
||||
return new ErrorResponse(["DuplicateCategory", 'title' => $title], 409);
|
||||
return self::respError(["DuplicateCategory", 'title' => $title], 409);
|
||||
} elseif (in_array($e->getCode(), [10237, 10239])) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
} else {
|
||||
return new ErrorResponse(["InvalidCategory", 'title' => $title], 422);
|
||||
return self::respError(["InvalidCategory", 'title' => $title], 422);
|
||||
}
|
||||
}
|
||||
$meta = Arsse::$user->propertiesGet(Arsse::$user->id, false);
|
||||
|
@ -724,7 +732,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$tr->commit();
|
||||
}
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respEmpty(204);
|
||||
}
|
||||
|
@ -788,7 +796,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
}
|
||||
} catch (ExceptionInput $e) {
|
||||
// the folder does not exist
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respJson($out);
|
||||
}
|
||||
|
@ -800,7 +808,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
$sub = Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, (int) $path[1]);
|
||||
return HTTP::respJson($this->transformFeed($sub, $meta['num'], $meta['root'], $meta['tz']));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -823,13 +831,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
10521 => "Fetch404",
|
||||
10522 => "FetchFormat",
|
||||
][$e->getCode()] ?? "FetchOther";
|
||||
return new ErrorResponse($msg, 502);
|
||||
return self::respError($msg, 502);
|
||||
} catch (ExceptionInput $e) {
|
||||
switch ($e->getCode()) {
|
||||
case 10235:
|
||||
return new ErrorResponse("MissingCategory", 422);
|
||||
return self::respError("MissingCategory", 422);
|
||||
case 10236:
|
||||
return new ErrorResponse("DuplicateFeed", 409);
|
||||
return self::respError("DuplicateFeed", 409);
|
||||
}
|
||||
}
|
||||
return HTTP::respJson(['feed_id' => $id], 201);
|
||||
|
@ -851,11 +859,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
switch ($e->getCode()) {
|
||||
case 10231:
|
||||
case 10232:
|
||||
return new ErrorResponse("InvalidTitle", 422);
|
||||
return self::respError("InvalidTitle", 422);
|
||||
case 10235:
|
||||
return new ErrorResponse("MissingCategory", 422);
|
||||
return self::respError("MissingCategory", 422);
|
||||
case 10239:
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
return $this->getFeed($path)->withStatus(201);
|
||||
|
@ -866,7 +874,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $path[1]);
|
||||
return HTTP::respEmpty(204);
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -874,10 +882,10 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
$icon = Arsse::$db->subscriptionIcon(Arsse::$user->id, (int) $path[1]);
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
if (!$icon || !$icon['type'] || !$icon['data']) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respJson([
|
||||
'id' => (int) $icon['id'],
|
||||
|
@ -1038,7 +1046,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
return HTTP::respJson($this->listEntries($query, new Context));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("MissingCategory", 400);
|
||||
return self::respError("MissingCategory", 400);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1056,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
return HTTP::respJson($this->listEntries($query, $c));
|
||||
} catch (ExceptionInput $e) {
|
||||
// FIXME: this should differentiate between a missing feed and a missing category, but doesn't
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1057,7 +1065,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
return HTTP::respJson($this->listEntries($query, new Context));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1065,7 +1073,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
return HTTP::respJson($this->findEntry((int) $path[1]));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1082,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
return HTTP::respJson($this->findEntry((int) $path[3], $c));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1088,7 +1096,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
return HTTP::respJson($this->findEntry((int) $path[3], $c));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1113,7 +1121,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
// this function is restricted to the logged-in user
|
||||
$user = Arsse::$user->propertiesGet(Arsse::$user->id, false);
|
||||
if (((int) $path[1]) !== $user['num']) {
|
||||
return new ErrorResponse("403", 403);
|
||||
return self::respError("403", 403);
|
||||
}
|
||||
$this->massRead(new Context);
|
||||
return HTTP::respEmpty(204);
|
||||
|
@ -1123,7 +1131,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
$this->massRead((new Context)->subscription((int) $path[1]));
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respEmpty(204);
|
||||
}
|
||||
|
@ -1140,7 +1148,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
$this->massRead($c);
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respEmpty(204);
|
||||
}
|
||||
|
@ -1158,7 +1166,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
}
|
||||
$tr->commit();
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respEmpty(204);
|
||||
}
|
||||
|
@ -1168,7 +1176,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
try {
|
||||
Arsse::$db->subscriptionPropertiesGet(Arsse::$user->id, (int) $path[1]);
|
||||
} catch (ExceptionInput $e) {
|
||||
return new ErrorResponse("404", 404);
|
||||
return self::respError("404", 404);
|
||||
}
|
||||
return HTTP::respEmpty(204);
|
||||
}
|
||||
|
@ -1185,18 +1193,18 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
|||
} catch (ImportException $e) {
|
||||
switch ($e->getCode()) {
|
||||
case 10611:
|
||||
return new ErrorResponse("InvalidBodyXML", 400);
|
||||
return self::respError("InvalidBodyXML", 400);
|
||||
case 10612:
|
||||
return new ErrorResponse("InvalidBodyOPML", 422);
|
||||
return self::respError("InvalidBodyOPML", 422);
|
||||
case 10613:
|
||||
return new ErrorResponse("InvalidImportCategory", 422);
|
||||
return self::respError("InvalidImportCategory", 422);
|
||||
case 10614:
|
||||
return new ErrorResponse("DuplicateImportCategory", 422);
|
||||
return self::respError("DuplicateImportCategory", 422);
|
||||
case 10615:
|
||||
return new ErrorResponse("InvalidImportLabel", 422);
|
||||
return self::respError("InvalidImportLabel", 422);
|
||||
}
|
||||
} catch (FeedException $e) {
|
||||
return new ErrorResponse(["FailedImportFeed", 'url' => $e->getParams()['url'], 'code' => $e->getCode()], 502);
|
||||
return self::respError(["FailedImportFeed", 'url' => $e->getParams()['url'], 'code' => $e->getCode()], 502);
|
||||
}
|
||||
return HTTP::respJson(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")]);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ use JKingWeb\Arsse\Db\ExceptionInput;
|
|||
use JKingWeb\Arsse\Db\Transaction;
|
||||
use JKingWeb\Arsse\REST\Fever\API;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Laminas\Diactoros\Response\XmlResponse;
|
||||
|
||||
/** @covers \JKingWeb\Arsse\REST\Fever\API<extended> */
|
||||
class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||
|
@ -472,7 +471,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
'items' => $this->articles['rest'],
|
||||
'total_items' => 1024,
|
||||
]);
|
||||
$exp = new XmlResponse("<response><items><item><id>101</id><feed_id>8</feed_id><title>Article title 1</title><author></author><html><p>Article content 1</p></html><url>http://example.com/1</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>946684800</created_on_time></item><item><id>102</id><feed_id>8</feed_id><title>Article title 2</title><author></author><html><p>Article content 2</p></html><url>http://example.com/2</url><is_saved>0</is_saved><is_read>1</is_read><created_on_time>946771200</created_on_time></item><item><id>103</id><feed_id>9</feed_id><title>Article title 3</title><author></author><html><p>Article content 3</p></html><url>http://example.com/3</url><is_saved>1</is_saved><is_read>0</is_read><created_on_time>946857600</created_on_time></item><item><id>104</id><feed_id>9</feed_id><title>Article title 4</title><author></author><html><p>Article content 4</p></html><url>http://example.com/4</url><is_saved>1</is_saved><is_read>1</is_read><created_on_time>946944000</created_on_time></item><item><id>105</id><feed_id>10</feed_id><title>Article title 5</title><author></author><html><p>Article content 5</p></html><url>http://example.com/5</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>947030400</created_on_time></item></items><total_items>1024</total_items></response>");
|
||||
$exp = HTTP::respXml("<response><items><item><id>101</id><feed_id>8</feed_id><title>Article title 1</title><author></author><html><p>Article content 1</p></html><url>http://example.com/1</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>946684800</created_on_time></item><item><id>102</id><feed_id>8</feed_id><title>Article title 2</title><author></author><html><p>Article content 2</p></html><url>http://example.com/2</url><is_saved>0</is_saved><is_read>1</is_read><created_on_time>946771200</created_on_time></item><item><id>103</id><feed_id>9</feed_id><title>Article title 3</title><author></author><html><p>Article content 3</p></html><url>http://example.com/3</url><is_saved>1</is_saved><is_read>0</is_read><created_on_time>946857600</created_on_time></item><item><id>104</id><feed_id>9</feed_id><title>Article title 4</title><author></author><html><p>Article content 4</p></html><url>http://example.com/4</url><is_saved>1</is_saved><is_read>1</is_read><created_on_time>946944000</created_on_time></item><item><id>105</id><feed_id>10</feed_id><title>Article title 5</title><author></author><html><p>Article content 5</p></html><url>http://example.com/5</url><is_saved>0</is_saved><is_read>0</is_read><created_on_time>947030400</created_on_time></item></items><total_items>1024</total_items></response>");
|
||||
$this->assertMessage($exp, $this->req("api=xml"));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
/** @license MIT
|
||||
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||
* See LICENSE and AUTHORS files for details */
|
||||
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\Arsse\TestCase\REST\Miniflux;
|
||||
|
||||
use JKingWeb\Arsse\REST\Miniflux\ErrorResponse;
|
||||
|
||||
/** @covers \JKingWeb\Arsse\REST\Miniflux\ErrorResponse */
|
||||
class TestErrorResponse extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||
public function testCreateConstantResponse(): void {
|
||||
$act = new ErrorResponse("401", 401);
|
||||
$this->assertSame('{"error_message":"Access Unauthorized"}', (string) $act->getBody());
|
||||
}
|
||||
|
||||
public function testCreateVariableResponse(): void {
|
||||
$act = new ErrorResponse(["InvalidBodyJSON", "Doh!"], 401);
|
||||
$this->assertSame('{"error_message":"Invalid JSON payload: Doh!"}', (string) $act->getBody());
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ use JKingWeb\Arsse\Misc\HTTP;
|
|||
use JKingWeb\Arsse\REST\Miniflux\Status;
|
||||
use JKingWeb\Arsse\REST\Miniflux\V1;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Laminas\Diactoros\Response\TextResponse;
|
||||
|
||||
/** @covers \JKingWeb\Arsse\REST\Miniflux\Status */
|
||||
class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||
|
@ -22,10 +21,10 @@ class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function provideRequests(): iterable {
|
||||
return [
|
||||
["/version", "GET", new TextResponse(V1::VERSION)],
|
||||
["/version", "GET", HTTP::respText(V1::VERSION)],
|
||||
["/version", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])],
|
||||
["/version", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])],
|
||||
["/healthcheck", "GET", new TextResponse("OK")],
|
||||
["/healthcheck", "GET", HTTP::respText("OK")],
|
||||
["/healthcheck", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])],
|
||||
["/healthcheck", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])],
|
||||
["/version/", "GET", HTTP::respEmpty(404)],
|
||||
|
|
|
@ -26,7 +26,6 @@ use JKingWeb\Arsse\User\ExceptionConflict;
|
|||
use JKingWeb\Arsse\User\ExceptionInput as UserExceptionInput;
|
||||
use JKingWeb\Arsse\Test\Result;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Laminas\Diactoros\Response\TextResponse;
|
||||
|
||||
/** @covers \JKingWeb\Arsse\REST\Miniflux\V1<extended> */
|
||||
class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||
|
@ -101,7 +100,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
/** @dataProvider provideAuthResponses */
|
||||
public function testAuthenticateAUser($token, bool $auth, bool $success): void {
|
||||
$exp = $success ? HTTP::respEmpty(404) : new ErrorResponse("401", 401);
|
||||
$exp = $success ? HTTP::respEmpty(404) : V1::respError("401", 401);
|
||||
$user = "john.doe@example.com";
|
||||
if ($token !== null) {
|
||||
$headers = ['X-Auth-Token' => $token];
|
||||
|
@ -165,7 +164,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
}
|
||||
|
||||
public function testRejectBadlyTypedData(): void {
|
||||
$exp = new ErrorResponse(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422);
|
||||
$exp = V1::respError(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422);
|
||||
$this->assertMessage($exp, $this->req("POST", "/discover", ['url' => 2112]));
|
||||
}
|
||||
|
||||
|
@ -183,10 +182,10 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
return [
|
||||
["http://localhost:8000/Feed/Discovery/Valid", HTTP::respJson($discovered)],
|
||||
["http://localhost:8000/Feed/Discovery/Invalid", HTTP::respJson([])],
|
||||
["http://localhost:8000/Feed/Discovery/Missing", new ErrorResponse("Fetch404", 502)],
|
||||
[1, new ErrorResponse(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422)],
|
||||
["Not a URL", new ErrorResponse(["InvalidInputValue", 'field' => "url"], 422)],
|
||||
[null, new ErrorResponse(["MissingInputValue", 'field' => "url"], 422)],
|
||||
["http://localhost:8000/Feed/Discovery/Missing", V1::respError("Fetch404", 502)],
|
||||
[1, V1::respError(["InvalidInputType", 'field' => "url", 'expected' => "string", 'actual' => "integer"], 422)],
|
||||
["Not a URL", V1::respError(["InvalidInputValue", 'field' => "url"], 422)],
|
||||
[null, V1::respError(["MissingInputValue", 'field' => "url"], 422)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -231,16 +230,16 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
[true, "/users/1", HTTP::respJson(self::USERS[0])],
|
||||
[true, "/users/jane.doe@example.com", HTTP::respJson(self::USERS[1])],
|
||||
[true, "/users/2", HTTP::respJson(self::USERS[1])],
|
||||
[true, "/users/jack.doe@example.com", new ErrorResponse("404", 404)],
|
||||
[true, "/users/47", new ErrorResponse("404", 404)],
|
||||
[false, "/users", new ErrorResponse("403", 403)],
|
||||
[true, "/users/jack.doe@example.com", V1::respError("404", 404)],
|
||||
[true, "/users/47", V1::respError("404", 404)],
|
||||
[false, "/users", V1::respError("403", 403)],
|
||||
[false, "/me", HTTP::respJson(self::USERS[1])],
|
||||
[false, "/users/john.doe@example.com", new ErrorResponse("403", 403)],
|
||||
[false, "/users/1", new ErrorResponse("403", 403)],
|
||||
[false, "/users/jane.doe@example.com", new ErrorResponse("403", 403)],
|
||||
[false, "/users/2", new ErrorResponse("403", 403)],
|
||||
[false, "/users/jack.doe@example.com", new ErrorResponse("403", 403)],
|
||||
[false, "/users/47", new ErrorResponse("403", 403)],
|
||||
[false, "/users/john.doe@example.com", V1::respError("403", 403)],
|
||||
[false, "/users/1", V1::respError("403", 403)],
|
||||
[false, "/users/jane.doe@example.com", V1::respError("403", 403)],
|
||||
[false, "/users/2", V1::respError("403", 403)],
|
||||
[false, "/users/jack.doe@example.com", V1::respError("403", 403)],
|
||||
[false, "/users/47", V1::respError("403", 403)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -305,21 +304,21 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$resp1 = array_merge(self::USERS[1], ['username' => "john.doe@example.com"]);
|
||||
$resp2 = array_merge(self::USERS[1], ['id' => 1, 'is_admin' => true]);
|
||||
return [
|
||||
[false, "/users/1", ['is_admin' => 0], null, null, null, null, null, null, new ErrorResponse(["InvalidInputType", 'field' => "is_admin", 'expected' => "boolean", 'actual' => "integer"], 422)],
|
||||
[false, "/users/1", ['entry_sorting_direction' => "bad"], null, null, null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_sorting_direction"], 422)],
|
||||
[false, "/users/1", ['theme' => "stark"], null, null, null, null, null, null, new ErrorResponse("403", 403)],
|
||||
[false, "/users/2", ['is_admin' => true], null, null, null, null, null, null, new ErrorResponse("InvalidElevation", 403)],
|
||||
[false, "/users/1", ['is_admin' => 0], null, null, null, null, null, null, V1::respError(["InvalidInputType", 'field' => "is_admin", 'expected' => "boolean", 'actual' => "integer"], 422)],
|
||||
[false, "/users/1", ['entry_sorting_direction' => "bad"], null, null, null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "entry_sorting_direction"], 422)],
|
||||
[false, "/users/1", ['theme' => "stark"], null, null, null, null, null, null, V1::respError("403", 403)],
|
||||
[false, "/users/2", ['is_admin' => true], null, null, null, null, null, null, V1::respError("InvalidElevation", 403)],
|
||||
[false, "/users/2", ['language' => "fr_CA"], null, null, null, null, ['lang' => "fr_CA"], $out1, HTTP::respJson($resp1, 201)],
|
||||
[false, "/users/2", ['entry_sorting_direction' => "asc"], null, null, null, null, ['sort_asc' => true], $out1, HTTP::respJson($resp1, 201)],
|
||||
[false, "/users/2", ['entry_sorting_direction' => "desc"], null, null, null, null, ['sort_asc' => false], $out1, HTTP::respJson($resp1, 201)],
|
||||
[false, "/users/2", ['entries_per_page' => -1], null, null, null, null, ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422)],
|
||||
[false, "/users/2", ['timezone' => "Ook"], null, null, null, null, ['tz' => "Ook"], new UserExceptionInput("invalidTimezone"), new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422)],
|
||||
[false, "/users/2", ['username' => "j:k"], "j:k", new UserExceptionInput("invalidUsername"), null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422)],
|
||||
[false, "/users/2", ['username' => "ook"], "ook", new ExceptionConflict("alreadyExists"), null, null, null, null, new ErrorResponse(["DuplicateUser", 'user' => "ook"], 409)],
|
||||
[false, "/users/2", ['entries_per_page' => -1], null, null, null, null, ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), V1::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422)],
|
||||
[false, "/users/2", ['timezone' => "Ook"], null, null, null, null, ['tz' => "Ook"], new UserExceptionInput("invalidTimezone"), V1::respError(["InvalidInputValue", 'field' => "timezone"], 422)],
|
||||
[false, "/users/2", ['username' => "j:k"], "j:k", new UserExceptionInput("invalidUsername"), null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "username"], 422)],
|
||||
[false, "/users/2", ['username' => "ook"], "ook", new ExceptionConflict("alreadyExists"), null, null, null, null, V1::respError(["DuplicateUser", 'user' => "ook"], 409)],
|
||||
[false, "/users/2", ['password' => "ook"], null, null, "ook", "ook", null, null, HTTP::respJson(array_merge($resp1, ['password' => "ook"]), 201)],
|
||||
[false, "/users/2", ['username' => "ook", 'password' => "ook"], "ook", true, "ook", "ook", null, null, HTTP::respJson(array_merge($resp1, ['username' => "ook", 'password' => "ook"]), 201)],
|
||||
[true, "/users/1", ['theme' => "stark"], null, null, null, null, ['theme' => "stark"], $out2, HTTP::respJson($resp2, 201)],
|
||||
[true, "/users/3", ['theme' => "stark"], null, null, null, null, null, null, new ErrorResponse("404", 404)],
|
||||
[true, "/users/3", ['theme' => "stark"], null, null, null, null, null, null, V1::respError("404", 404)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -360,18 +359,18 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function provideUserAdditions(): iterable {
|
||||
$resp1 = array_merge(self::USERS[1], ['username' => "ook", 'password' => "eek"]);
|
||||
return [
|
||||
[[], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "username"], 422)],
|
||||
[['username' => "ook"], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "password"], 422)],
|
||||
[['username' => "ook", 'password' => "eek"], ["ook", "eek"], new ExceptionConflict("alreadyExists"), null, null, new ErrorResponse(["DuplicateUser", 'user' => "ook"], 409)],
|
||||
[['username' => "j:k", 'password' => "eek"], ["j:k", "eek"], new UserExceptionInput("invalidUsername"), null, null, new ErrorResponse(["InvalidInputValue", 'field' => "username"], 422)],
|
||||
[['username' => "ook", 'password' => "eek", 'timezone' => "ook"], ["ook", "eek"], "eek", ['tz' => "ook"], new UserExceptionInput("invalidTimezone"), new ErrorResponse(["InvalidInputValue", 'field' => "timezone"], 422)],
|
||||
[['username' => "ook", 'password' => "eek", 'entries_per_page' => -1], ["ook", "eek"], "eek", ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), new ErrorResponse(["InvalidInputValue", 'field' => "entries_per_page"], 422)],
|
||||
[[], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "username"], 422)],
|
||||
[['username' => "ook"], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "password"], 422)],
|
||||
[['username' => "ook", 'password' => "eek"], ["ook", "eek"], new ExceptionConflict("alreadyExists"), null, null, V1::respError(["DuplicateUser", 'user' => "ook"], 409)],
|
||||
[['username' => "j:k", 'password' => "eek"], ["j:k", "eek"], new UserExceptionInput("invalidUsername"), null, null, V1::respError(["InvalidInputValue", 'field' => "username"], 422)],
|
||||
[['username' => "ook", 'password' => "eek", 'timezone' => "ook"], ["ook", "eek"], "eek", ['tz' => "ook"], new UserExceptionInput("invalidTimezone"), V1::respError(["InvalidInputValue", 'field' => "timezone"], 422)],
|
||||
[['username' => "ook", 'password' => "eek", 'entries_per_page' => -1], ["ook", "eek"], "eek", ['page_size' => -1], new UserExceptionInput("invalidNonZeroInteger"), V1::respError(["InvalidInputValue", 'field' => "entries_per_page"], 422)],
|
||||
[['username' => "ook", 'password' => "eek", 'theme' => "default"], ["ook", "eek"], "eek", ['theme' => "default"], ['theme' => "default"], HTTP::respJson($resp1, 201)],
|
||||
];
|
||||
}
|
||||
|
||||
public function testAddAUserWithoutAuthority(): void {
|
||||
$this->assertMessage(new ErrorResponse("403", 403), $this->req("POST", "/users", []));
|
||||
$this->assertMessage(V1::respError("403", 403), $this->req("POST", "/users", []));
|
||||
}
|
||||
|
||||
public function testDeleteAUser(): void {
|
||||
|
@ -391,13 +390,13 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
Arsse::$user->method("remove")->willReturn(true);
|
||||
Arsse::$user->expects($this->exactly(1))->method("lookup")->with(2112);
|
||||
Arsse::$user->expects($this->exactly(0))->method("remove");
|
||||
$this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/users/2112"));
|
||||
$this->assertMessage(V1::respError("404", 404), $this->req("DELETE", "/users/2112"));
|
||||
}
|
||||
|
||||
public function testDeleteAUserWithoutAuthority(): void {
|
||||
Arsse::$user->expects($this->exactly(0))->method("lookup");
|
||||
Arsse::$user->expects($this->exactly(0))->method("remove");
|
||||
$this->assertMessage(new ErrorResponse("403", 403), $this->req("DELETE", "/users/2112"));
|
||||
$this->assertMessage(V1::respError("403", 403), $this->req("DELETE", "/users/2112"));
|
||||
}
|
||||
|
||||
public function testListCategories(): void {
|
||||
|
@ -440,11 +439,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function provideCategoryAdditions(): iterable {
|
||||
return [
|
||||
["New", HTTP::respJson(['id' => 2112, 'title' => "New", 'user_id' => 42], 201)],
|
||||
["Duplicate", new ErrorResponse(["DuplicateCategory", 'title' => "Duplicate"], 409)],
|
||||
["", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)],
|
||||
[" ", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)],
|
||||
[null, new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)],
|
||||
[false, new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)],
|
||||
["Duplicate", V1::respError(["DuplicateCategory", 'title' => "Duplicate"], 409)],
|
||||
["", V1::respError(["InvalidCategory", 'title' => ""], 422)],
|
||||
[" ", V1::respError(["InvalidCategory", 'title' => " "], 422)],
|
||||
[null, V1::respError(["MissingInputValue", 'field' => "title"], 422)],
|
||||
[false, V1::respError(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -465,19 +464,19 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function provideCategoryUpdates(): iterable {
|
||||
return [
|
||||
[3, "New", "subjectMissing", new ErrorResponse("404", 404)],
|
||||
[3, "New", "subjectMissing", V1::respError("404", 404)],
|
||||
[2, "New", true, HTTP::respJson(['id' => 2, 'title' => "New", 'user_id' => 42], 201)],
|
||||
[2, "Duplicate", "constraintViolation", new ErrorResponse(["DuplicateCategory", 'title' => "Duplicate"], 409)],
|
||||
[2, "", "missing", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)],
|
||||
[2, " ", "whitespace", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)],
|
||||
[2, null, "missing", new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)],
|
||||
[2, false, "subjectMissing", new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)],
|
||||
[2, "Duplicate", "constraintViolation", V1::respError(["DuplicateCategory", 'title' => "Duplicate"], 409)],
|
||||
[2, "", "missing", V1::respError(["InvalidCategory", 'title' => ""], 422)],
|
||||
[2, " ", "whitespace", V1::respError(["InvalidCategory", 'title' => " "], 422)],
|
||||
[2, null, "missing", V1::respError(["MissingInputValue", 'field' => "title"], 422)],
|
||||
[2, false, "subjectMissing", V1::respError(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)],
|
||||
[1, "New", true, HTTP::respJson(['id' => 1, 'title' => "New", 'user_id' => 42], 201)],
|
||||
[1, "Duplicate", "constraintViolation", HTTP::respJson(['id' => 1, 'title' => "Duplicate", 'user_id' => 42], 201)], // This is allowed because the name of the root folder is only a duplicate in circumstances where it is used
|
||||
[1, "", "missing", new ErrorResponse(["InvalidCategory", 'title' => ""], 422)],
|
||||
[1, " ", "whitespace", new ErrorResponse(["InvalidCategory", 'title' => " "], 422)],
|
||||
[1, null, "missing", new ErrorResponse(["MissingInputValue", 'field' => "title"], 422)],
|
||||
[1, false, false, new ErrorResponse(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)],
|
||||
[1, "", "missing", V1::respError(["InvalidCategory", 'title' => ""], 422)],
|
||||
[1, " ", "whitespace", V1::respError(["InvalidCategory", 'title' => " "], 422)],
|
||||
[1, null, "missing", V1::respError(["MissingInputValue", 'field' => "title"], 422)],
|
||||
[1, false, false, V1::respError(["InvalidInputType", 'field' => "title", 'actual' => "boolean", 'expected' => "string"], 422)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -485,7 +484,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$this->dbMock->folderRemove->returns(true)->throws(new ExceptionInput("subjectMissing"));
|
||||
$this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/categories/2112"));
|
||||
$this->dbMock->folderRemove->calledWith("john.doe@example.com", 2111);
|
||||
$this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/categories/47"));
|
||||
$this->assertMessage(V1::respError("404", 404), $this->req("DELETE", "/categories/47"));
|
||||
$this->dbMock->folderRemove->calledWith("john.doe@example.com", 46);
|
||||
}
|
||||
|
||||
|
@ -529,7 +528,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function testListFeedsOfAMissingCategory(): void {
|
||||
$this->dbMock->subscriptionList->throws(new ExceptionInput("idMissing"));
|
||||
$exp = new ErrorResponse("404", 404);
|
||||
$exp = V1::respError("404", 404);
|
||||
$this->assertMessage($exp, $this->req("GET", "/categories/2112/feeds"));
|
||||
$this->dbMock->subscriptionList->calledWith(Arsse::$user->id, 2111, true);
|
||||
}
|
||||
|
@ -544,7 +543,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function testGetAMissingFeed(): void {
|
||||
$this->dbMock->subscriptionPropertiesGet->throws(new ExceptionInput("subjectMissing"));
|
||||
$this->assertMessage(new ErrorResponse("404", 404), $this->req("GET", "/feeds/1"));
|
||||
$this->assertMessage(V1::respError("404", 404), $this->req("GET", "/feeds/1"));
|
||||
$this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 1);
|
||||
}
|
||||
|
||||
|
@ -610,29 +609,29 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function provideFeedCreations(): iterable {
|
||||
self::clearData();
|
||||
return [
|
||||
[['category_id' => 1], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "feed_url"], 422)],
|
||||
[['feed_url' => "http://example.com/"], null, null, null, null, new ErrorResponse(["MissingInputValue", 'field' => "category_id"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => "1"], null, null, null, null, new ErrorResponse(["InvalidInputType", 'field' => "category_id", 'expected' => "integer", 'actual' => "string"], 422)],
|
||||
[['feed_url' => "Not a URL", 'category_id' => 1], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "feed_url"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 0], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "category_id"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "["], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "keeplist_rules"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "["], null, null, null, null, new ErrorResponse(["InvalidInputValue", 'field' => "blocklist_rules"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("internalError"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidCertificate"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidUrl"), null, null, null, new ErrorResponse("Fetch404", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxRedirect"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxSize"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("timeout"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("forbidden"), null, null, null, new ErrorResponse("Fetch403", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unauthorized"), null, null, null, new ErrorResponse("Fetch401", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("transmissionError"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("connectionFailed"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("malformedXml"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("xmlEntity"), null, null, null, new ErrorResponse("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("subscriptionNotFound"), null, null, null, new ErrorResponse("Fetch404", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unsupportedFeedFormat"), null, null, null, new ErrorResponse("FetchFormat", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], 2112, new ExceptionInput("constraintViolation"), null, null, new ErrorResponse("DuplicateFeed", 409)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, new ExceptionInput("idMissing"), null, new ErrorResponse("MissingCategory", 422)],
|
||||
[['category_id' => 1], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "feed_url"], 422)],
|
||||
[['feed_url' => "http://example.com/"], null, null, null, null, V1::respError(["MissingInputValue", 'field' => "category_id"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => "1"], null, null, null, null, V1::respError(["InvalidInputType", 'field' => "category_id", 'expected' => "integer", 'actual' => "string"], 422)],
|
||||
[['feed_url' => "Not a URL", 'category_id' => 1], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "feed_url"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 0], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "category_id"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "["], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "keeplist_rules"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "["], null, null, null, null, V1::respError(["InvalidInputValue", 'field' => "blocklist_rules"], 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("internalError"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidCertificate"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("invalidUrl"), null, null, null, V1::respError("Fetch404", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxRedirect"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("maxSize"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("timeout"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("forbidden"), null, null, null, V1::respError("Fetch403", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unauthorized"), null, null, null, V1::respError("Fetch401", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("transmissionError"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("connectionFailed"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("malformedXml"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("xmlEntity"), null, null, null, V1::respError("FetchOther", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("subscriptionNotFound"), null, null, null, V1::respError("Fetch404", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], new FeedException("unsupportedFeedFormat"), null, null, null, V1::respError("FetchFormat", 502)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], 2112, new ExceptionInput("constraintViolation"), null, null, V1::respError("DuplicateFeed", 409)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, new ExceptionInput("idMissing"), null, V1::respError("MissingCategory", 422)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1], 2112, 44, true, null, HTTP::respJson(['feed_id' => 44], 201)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1, 'keeplist_rules' => "^A"], 2112, 44, true, true, HTTP::respJson(['feed_id' => 44], 201)],
|
||||
[['feed_url' => "http://example.com/", 'category_id' => 1, 'blocklist_rules' => "A"], 2112, 44, true, true, HTTP::respJson(['feed_id' => 44], 201)],
|
||||
|
@ -657,11 +656,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$success = HTTP::respJson(self::FEEDS_OUT[0], 201);
|
||||
return [
|
||||
[[], [], true, $success],
|
||||
[[], [], new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)],
|
||||
[['title' => ""], ['title' => ""], new ExceptionInput("missing"), new ErrorResponse("InvalidTitle", 422)],
|
||||
[['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), new ErrorResponse("InvalidTitle", 422)],
|
||||
[['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), new ErrorResponse("InvalidTitle", 422)],
|
||||
[['category_id' => 47], ['folder' => 46], new ExceptionInput("idMissing"), new ErrorResponse("MissingCategory", 422)],
|
||||
[[], [], new ExceptionInput("subjectMissing"), V1::respError("404", 404)],
|
||||
[['title' => ""], ['title' => ""], new ExceptionInput("missing"), V1::respError("InvalidTitle", 422)],
|
||||
[['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), V1::respError("InvalidTitle", 422)],
|
||||
[['title' => " "], ['title' => " "], new ExceptionInput("whitespace"), V1::respError("InvalidTitle", 422)],
|
||||
[['category_id' => 47], ['folder' => 46], new ExceptionInput("idMissing"), V1::respError("MissingCategory", 422)],
|
||||
[['crawler' => false], ['scrape' => false], true, $success],
|
||||
[['keeplist_rules' => ""], ['keep_rule' => ""], true, $success],
|
||||
[['blocklist_rules' => "ook"], ['block_rule' => "ook"], true, $success],
|
||||
|
@ -685,7 +684,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function testDeleteAMissingFeed(): void {
|
||||
$this->dbMock->subscriptionRemove->throws(new ExceptionInput("subjectMissing"));
|
||||
$this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/feeds/2112"));
|
||||
$this->assertMessage(V1::respError("404", 404), $this->req("DELETE", "/feeds/2112"));
|
||||
$this->dbMock->subscriptionRemove->calledWith(Arsse::$user->id, 2112);
|
||||
}
|
||||
|
||||
|
@ -703,11 +702,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function provideIcons(): iterable {
|
||||
return [
|
||||
[['id' => 44, 'type' => "image/svg+xml", 'data' => "<svg/>"], HTTP::respJson(['id' => 44, 'data' => "image/svg+xml;base64,PHN2Zy8+", 'mime_type' => "image/svg+xml"])],
|
||||
[['id' => 47, 'type' => "", 'data' => "<svg/>"], new ErrorResponse("404", 404)],
|
||||
[['id' => 47, 'type' => null, 'data' => "<svg/>"], new ErrorResponse("404", 404)],
|
||||
[['id' => 47, 'type' => null, 'data' => null], new ErrorResponse("404", 404)],
|
||||
[null, new ErrorResponse("404", 404)],
|
||||
[new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)],
|
||||
[['id' => 47, 'type' => "", 'data' => "<svg/>"], V1::respError("404", 404)],
|
||||
[['id' => 47, 'type' => null, 'data' => "<svg/>"], V1::respError("404", 404)],
|
||||
[['id' => 47, 'type' => null, 'data' => null], V1::respError("404", 404)],
|
||||
[null, V1::respError("404", 404)],
|
||||
[new ExceptionInput("subjectMissing"), V1::respError("404", 404)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -743,17 +742,17 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$c = (new Context)->limit(100);
|
||||
$o = ["modified_date"]; // the default sort order
|
||||
return [
|
||||
["/entries?after=A", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "after"], 400)],
|
||||
["/entries?before=B", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "before"], 400)],
|
||||
["/entries?category_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "category_id"], 400)],
|
||||
["/entries?after_entry_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "after_entry_id"], 400)],
|
||||
["/entries?before_entry_id=0", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "before_entry_id"], 400)],
|
||||
["/entries?limit=-1", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "limit"], 400)],
|
||||
["/entries?offset=-1", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "offset"], 400)],
|
||||
["/entries?direction=sideways", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "direction"], 400)],
|
||||
["/entries?order=false", null, null, [], false, new ErrorResponse(["InvalidInputValue", 'field' => "order"], 400)],
|
||||
["/entries?starred&starred", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "starred"], 400)],
|
||||
["/entries?after&after=0", null, null, [], false, new ErrorResponse(["DuplicateInputValue", 'field' => "after"], 400)],
|
||||
["/entries?after=A", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "after"], 400)],
|
||||
["/entries?before=B", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "before"], 400)],
|
||||
["/entries?category_id=0", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "category_id"], 400)],
|
||||
["/entries?after_entry_id=0", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "after_entry_id"], 400)],
|
||||
["/entries?before_entry_id=0", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "before_entry_id"], 400)],
|
||||
["/entries?limit=-1", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "limit"], 400)],
|
||||
["/entries?offset=-1", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "offset"], 400)],
|
||||
["/entries?direction=sideways", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "direction"], 400)],
|
||||
["/entries?order=false", null, null, [], false, V1::respError(["InvalidInputValue", 'field' => "order"], 400)],
|
||||
["/entries?starred&starred", null, null, [], false, V1::respError(["DuplicateInputValue", 'field' => "starred"], 400)],
|
||||
["/entries?after&after=0", null, null, [], false, V1::respError(["DuplicateInputValue", 'field' => "after"], 400)],
|
||||
["/entries", $c, $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=47", (clone $c)->folder(46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=1", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
|
@ -790,15 +789,15 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
["/entries?order=category_id&direction=desc", $c, ["top_folder desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=category_title&direction=desc", $c, ["top_folder_name desc"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?order=status&direction=desc", $c, ["hidden desc", "unread"], self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/entries?category_id=2112", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("MissingCategory")],
|
||||
["/entries?category_id=2112", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, V1::respError("MissingCategory")],
|
||||
["/feeds/42/entries", (clone $c)->subscription(42), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/feeds/42/entries?category_id=47", (clone $c)->subscription(42)->folder(46), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/feeds/2112/entries", (clone $c)->subscription(2112), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("404", 404)],
|
||||
["/feeds/2112/entries", (clone $c)->subscription(2112), $o, new ExceptionInput("idMissing"), false, V1::respError("404", 404)],
|
||||
["/categories/42/entries", (clone $c)->folder(41), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/categories/42/entries?category_id=47", (clone $c)->folder(41), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/categories/42/entries?starred", (clone $c)->folder(41)->starred(true), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/categories/1/entries", (clone $c)->folderShallow(0), $o, self::ENTRIES, false, HTTP::respJson(['total' => sizeof(self::ENTRIES_OUT), 'entries' => self::ENTRIES_OUT])],
|
||||
["/categories/2112/entries", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, new ErrorResponse("404", 404)],
|
||||
["/categories/2112/entries", (clone $c)->folder(2111), $o, new ExceptionInput("idMissing"), false, V1::respError("404", 404)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -828,15 +827,15 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$c = new Context;
|
||||
return [
|
||||
["/entries/42", (clone $c)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])],
|
||||
["/entries/2112", (clone $c)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)],
|
||||
["/entries/2112", (clone $c)->article(2112), new ExceptionInput("subjectMissing"), V1::respError("404", 404)],
|
||||
["/feeds/47/entries/42", (clone $c)->subscription(47)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])],
|
||||
["/feeds/47/entries/44", (clone $c)->subscription(47)->article(44), [], new ErrorResponse("404", 404)],
|
||||
["/feeds/47/entries/2112", (clone $c)->subscription(47)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)],
|
||||
["/feeds/2112/entries/47", (clone $c)->subscription(2112)->article(47), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)],
|
||||
["/feeds/47/entries/44", (clone $c)->subscription(47)->article(44), [], V1::respError("404", 404)],
|
||||
["/feeds/47/entries/2112", (clone $c)->subscription(47)->article(2112), new ExceptionInput("subjectMissing"), V1::respError("404", 404)],
|
||||
["/feeds/2112/entries/47", (clone $c)->subscription(2112)->article(47), new ExceptionInput("idMissing"), V1::respError("404", 404)],
|
||||
["/categories/47/entries/42", (clone $c)->folder(46)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])],
|
||||
["/categories/47/entries/44", (clone $c)->folder(46)->article(44), [], new ErrorResponse("404", 404)],
|
||||
["/categories/47/entries/2112", (clone $c)->folder(46)->article(2112), new ExceptionInput("subjectMissing"), new ErrorResponse("404", 404)],
|
||||
["/categories/2112/entries/47", (clone $c)->folder(2111)->article(47), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)],
|
||||
["/categories/47/entries/44", (clone $c)->folder(46)->article(44), [], V1::respError("404", 404)],
|
||||
["/categories/47/entries/2112", (clone $c)->folder(46)->article(2112), new ExceptionInput("subjectMissing"), V1::respError("404", 404)],
|
||||
["/categories/2112/entries/47", (clone $c)->folder(2111)->article(47), new ExceptionInput("idMissing"), V1::respError("404", 404)],
|
||||
["/categories/1/entries/42", (clone $c)->folderShallow(0)->article(42), [self::ENTRIES[1]], HTTP::respJson(self::ENTRIES_OUT[1])],
|
||||
];
|
||||
}
|
||||
|
@ -855,14 +854,14 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function provideEntryMarkings(): iterable {
|
||||
self::clearData();
|
||||
return [
|
||||
[['status' => "read"], null, new ErrorResponse(["MissingInputValue", 'field' => "entry_ids"], 422)],
|
||||
[['entry_ids' => [1]], null, new ErrorResponse(["MissingInputValue", 'field' => "status"], 422)],
|
||||
[['entry_ids' => [], 'status' => "read"], null, new ErrorResponse(["MissingInputValue", 'field' => "entry_ids"], 422)],
|
||||
[['entry_ids' => 1, 'status' => "read"], null, new ErrorResponse(["InvalidInputType", 'field' => "entry_ids", 'expected' => "array", 'actual' => "integer"], 422)],
|
||||
[['entry_ids' => ["1"], 'status' => "read"], null, new ErrorResponse(["InvalidInputType", 'field' => "entry_ids", 'expected' => "integer", 'actual' => "string"], 422)],
|
||||
[['entry_ids' => [1], 'status' => 1], null, new ErrorResponse(["InvalidInputType", 'field' => "status", 'expected' => "string", 'actual' => "integer"], 422)],
|
||||
[['entry_ids' => [0], 'status' => "read"], null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_ids"], 422)],
|
||||
[['entry_ids' => [1], 'status' => "reread"], null, new ErrorResponse(["InvalidInputValue", 'field' => "status"], 422)],
|
||||
[['status' => "read"], null, V1::respError(["MissingInputValue", 'field' => "entry_ids"], 422)],
|
||||
[['entry_ids' => [1]], null, V1::respError(["MissingInputValue", 'field' => "status"], 422)],
|
||||
[['entry_ids' => [], 'status' => "read"], null, V1::respError(["MissingInputValue", 'field' => "entry_ids"], 422)],
|
||||
[['entry_ids' => 1, 'status' => "read"], null, V1::respError(["InvalidInputType", 'field' => "entry_ids", 'expected' => "array", 'actual' => "integer"], 422)],
|
||||
[['entry_ids' => ["1"], 'status' => "read"], null, V1::respError(["InvalidInputType", 'field' => "entry_ids", 'expected' => "integer", 'actual' => "string"], 422)],
|
||||
[['entry_ids' => [1], 'status' => 1], null, V1::respError(["InvalidInputType", 'field' => "status", 'expected' => "string", 'actual' => "integer"], 422)],
|
||||
[['entry_ids' => [0], 'status' => "read"], null, V1::respError(["InvalidInputValue", 'field' => "entry_ids"], 422)],
|
||||
[['entry_ids' => [1], 'status' => "reread"], null, V1::respError(["InvalidInputValue", 'field' => "status"], 422)],
|
||||
[['entry_ids' => [1, 2], 'status' => "read"], ['read' => true, 'hidden' => false], HTTP::respEmpty(204)],
|
||||
[['entry_ids' => [1, 2], 'status' => "unread"], ['read' => false, 'hidden' => false], HTTP::respEmpty(204)],
|
||||
[['entry_ids' => [1, 2], 'status' => "removed"], ['read' => true, 'hidden' => true], HTTP::respEmpty(204)],
|
||||
|
@ -889,11 +888,11 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
$c = (new Context)->hidden(false);
|
||||
return [
|
||||
["/users/42/mark-all-as-read", $c, 1123, HTTP::respEmpty(204)],
|
||||
["/users/2112/mark-all-as-read", $c, null, new ErrorResponse("403", 403)],
|
||||
["/users/2112/mark-all-as-read", $c, null, V1::respError("403", 403)],
|
||||
["/feeds/47/mark-all-as-read", (clone $c)->subscription(47), 2112, HTTP::respEmpty(204)],
|
||||
["/feeds/2112/mark-all-as-read", (clone $c)->subscription(2112), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)],
|
||||
["/feeds/2112/mark-all-as-read", (clone $c)->subscription(2112), new ExceptionInput("idMissing"), V1::respError("404", 404)],
|
||||
["/categories/47/mark-all-as-read", (clone $c)->folder(46), 1337, HTTP::respEmpty(204)],
|
||||
["/categories/2112/mark-all-as-read", (clone $c)->folder(2111), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)],
|
||||
["/categories/2112/mark-all-as-read", (clone $c)->folder(2111), new ExceptionInput("idMissing"), V1::respError("404", 404)],
|
||||
["/categories/1/mark-all-as-read", (clone $c)->folderShallow(0), 6666, HTTP::respEmpty(204)],
|
||||
];
|
||||
}
|
||||
|
@ -930,7 +929,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
return [
|
||||
[1, true, HTTP::respEmpty(204)],
|
||||
[0, false, HTTP::respEmpty(204)],
|
||||
[new ExceptionInput("subjectMissing"), null, new ErrorResponse("404", 404)],
|
||||
[new ExceptionInput("subjectMissing"), null, V1::respError("404", 404)],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -942,7 +941,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
|
||||
public function testRefreshAMissingFeed(): void {
|
||||
$this->dbMock->subscriptionPropertiesGet->throws(new ExceptionInput("subjectMissing"));
|
||||
$this->assertMessage(new ErrorResponse("404", 404), $this->req("PUT", "/feeds/2112/refresh"));
|
||||
$this->assertMessage(V1::respError("404", 404), $this->req("PUT", "/feeds/2112/refresh"));
|
||||
$this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 2112);
|
||||
}
|
||||
|
||||
|
@ -963,12 +962,12 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function provideImports(): iterable {
|
||||
self::clearData();
|
||||
return [
|
||||
[new ImportException("invalidSyntax"), new ErrorResponse("InvalidBodyXML", 400)],
|
||||
[new ImportException("invalidSemantics"), new ErrorResponse("InvalidBodyOPML", 422)],
|
||||
[new ImportException("invalidFolderName"), new ErrorResponse("InvalidImportCategory", 422)],
|
||||
[new ImportException("invalidFolderCopy"), new ErrorResponse("DuplicateImportCategory", 422)],
|
||||
[new ImportException("invalidTagName"), new ErrorResponse("InvalidImportLabel", 422)],
|
||||
[new FeedException("invalidUrl", ['url' => "http://example.com/"]), new ErrorResponse(["FailedImportFeed", 'url' => "http://example.com/", 'code' => 10502], 502)],
|
||||
[new ImportException("invalidSyntax"), V1::respError("InvalidBodyXML", 400)],
|
||||
[new ImportException("invalidSemantics"), V1::respError("InvalidBodyOPML", 422)],
|
||||
[new ImportException("invalidFolderName"), V1::respError("InvalidImportCategory", 422)],
|
||||
[new ImportException("invalidFolderCopy"), V1::respError("DuplicateImportCategory", 422)],
|
||||
[new ImportException("invalidTagName"), V1::respError("InvalidImportLabel", 422)],
|
||||
[new FeedException("invalidUrl", ['url' => "http://example.com/"]), V1::respError(["FailedImportFeed", 'url' => "http://example.com/", 'code' => 10502], 502)],
|
||||
[true, HTTP::respJson(['message' => Arsse::$lang->msg("API.Miniflux.ImportSuccess")])],
|
||||
];
|
||||
}
|
||||
|
@ -976,8 +975,8 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
public function testExport(): void {
|
||||
$opml = $this->mock(OPML::class);
|
||||
$this->objMock->get->with(OPML::class)->returns($opml);
|
||||
$opml->export->returns("EXPORT DATA");
|
||||
$this->assertMessage(new TextResponse("EXPORT DATA", 200, ['Content-Type' => "application/xml"]), $this->req("GET", "/export"));
|
||||
$opml->export->returns("<EXPORT_DATA/>");
|
||||
$this->assertMessage(HTTP::respText("<EXPORT_DATA/>", 200, ['Content-Type' => "application/xml"]), $this->req("GET", "/export"));
|
||||
$opml->export->calledWith(Arsse::$user->id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,7 +242,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => ["Content-Type", "If-None-Match"]], [], [
|
||||
'Access-Control-Allow-Origin' => "http://example",
|
||||
'Access-Control-Allow-Credentials' => "true",
|
||||
'Access-Control-Allow-Headers' => "Content-Type,If-None-Match",
|
||||
'Access-Control-Allow-Headers' => "Content-Type, If-None-Match",
|
||||
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
||||
'Vary' => "Origin",
|
||||
]],
|
||||
|
@ -280,8 +280,8 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
|||
[HTTP::respText("", 200), HTTP::respText("", 200, ['Content-Length' => "0"])],
|
||||
[HTTP::respText("ook", 404), HTTP::respText("ook", 404, ['Content-Length' => "3"])],
|
||||
[HTTP::respText("", 404), HTTP::respText("", 404)],
|
||||
[new Response(200, [], $stream), new Response(200, ['Content-Length' => "3"], $stream), new Request("", "GET")],
|
||||
[new Response(200, [], $stream), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("", "HEAD")],
|
||||
[new Response(200, [], $stream), new Response(200, ['Content-Length' => "3"], $stream), new Request("GET", "")],
|
||||
[new Response(200, [], $stream), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("HEAD", "")],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -1685,10 +1685,10 @@ LONG_STRING;
|
|||
$this->assertMessage($this->outputHeadlines(1), $test);
|
||||
// test 'show_content'
|
||||
$test = $this->req($in[1]);
|
||||
$this->assertArrayHasKey("content", $test->getPayload()['content'][0]);
|
||||
$this->assertArrayHasKey("content", $test->getPayload()['content'][1]);
|
||||
$this->assertArrayHasKey("content", $this->extractMessageJson($test)['content'][0]);
|
||||
$this->assertArrayHasKey("content", $this->extractMessageJson($test)['content'][1]);
|
||||
foreach ($this->generateHeadlines(1) as $key => $row) {
|
||||
$this->assertSame($row['content'], $test->getPayload()['content'][$key]['content']);
|
||||
$this->assertSame($row['content'], $this->extractMessageJson($test)['content'][$key]['content']);
|
||||
}
|
||||
// test 'include_attachments'
|
||||
$test = $this->req($in[2]);
|
||||
|
@ -1704,22 +1704,22 @@ LONG_STRING;
|
|||
'post_id' => "2112",
|
||||
],
|
||||
];
|
||||
$this->assertArrayHasKey("attachments", $test->getPayload()['content'][0]);
|
||||
$this->assertArrayHasKey("attachments", $test->getPayload()['content'][1]);
|
||||
$this->assertSame([], $test->getPayload()['content'][0]['attachments']);
|
||||
$this->assertSame($exp, $test->getPayload()['content'][1]['attachments']);
|
||||
$this->assertArrayHasKey("attachments", $this->extractMessageJson($test)['content'][0]);
|
||||
$this->assertArrayHasKey("attachments", $this->extractMessageJson($test)['content'][1]);
|
||||
$this->assertSame([], $this->extractMessageJson($test)['content'][0]['attachments']);
|
||||
$this->assertSame($exp, $this->extractMessageJson($test)['content'][1]['attachments']);
|
||||
// test 'include_header'
|
||||
$test = $this->req($in[3]);
|
||||
$exp = $this->respGood([
|
||||
['id' => -4, 'is_cat' => false, 'first_id' => 1],
|
||||
$this->outputHeadlines(1)->getPayload()['content'],
|
||||
$this->extractMessageJson($this->outputHeadlines(1))['content'],
|
||||
]);
|
||||
$this->assertMessage($exp, $test);
|
||||
// test 'include_header' with a category
|
||||
$test = $this->req($in[4]);
|
||||
$exp = $this->respGood([
|
||||
['id' => -3, 'is_cat' => true, 'first_id' => 1],
|
||||
$this->outputHeadlines(1)->getPayload()['content'],
|
||||
$this->extractMessageJson($this->outputHeadlines(1))['content'],
|
||||
]);
|
||||
$this->assertMessage($exp, $test);
|
||||
// test 'include_header' with an empty result
|
||||
|
@ -1741,7 +1741,7 @@ LONG_STRING;
|
|||
$test = $this->req($in[7]);
|
||||
$exp = $this->respGood([
|
||||
['id' => -4, 'is_cat' => false, 'first_id' => 0],
|
||||
$this->outputHeadlines(1)->getPayload()['content'],
|
||||
$this->extractMessageJson($this->outputHeadlines(1))['content'],
|
||||
]);
|
||||
$this->assertMessage($exp, $test);
|
||||
// test 'include_header' with skip
|
||||
|
@ -1749,24 +1749,24 @@ LONG_STRING;
|
|||
$test = $this->req($in[8]);
|
||||
$exp = $this->respGood([
|
||||
['id' => 42, 'is_cat' => false, 'first_id' => 1867],
|
||||
$this->outputHeadlines(1)->getPayload()['content'],
|
||||
$this->extractMessageJson($this->outputHeadlines(1))['content'],
|
||||
]);
|
||||
$this->assertMessage($exp, $test);
|
||||
// test 'include_header' with skip and ascending order
|
||||
$test = $this->req($in[9]);
|
||||
$exp = $this->respGood([
|
||||
['id' => 42, 'is_cat' => false, 'first_id' => 0],
|
||||
$this->outputHeadlines(1)->getPayload()['content'],
|
||||
$this->extractMessageJson($this->outputHeadlines(1))['content'],
|
||||
]);
|
||||
$this->assertMessage($exp, $test);
|
||||
// test 'show_excerpt'
|
||||
$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…";
|
||||
$test = $this->req($in[10]);
|
||||
$this->assertArrayHasKey("excerpt", $test->getPayload()['content'][0]);
|
||||
$this->assertArrayHasKey("excerpt", $test->getPayload()['content'][1]);
|
||||
$this->assertSame($exp1, $test->getPayload()['content'][0]['excerpt']);
|
||||
$this->assertSame($exp2, $test->getPayload()['content'][1]['excerpt']);
|
||||
$this->assertArrayHasKey("excerpt", $this->extractMessageJson($test)['content'][0]);
|
||||
$this->assertArrayHasKey("excerpt", $this->extractMessageJson($test)['content'][1]);
|
||||
$this->assertSame($exp1, $this->extractMessageJson($test)['content'][0]['excerpt']);
|
||||
$this->assertSame($exp2, $this->extractMessageJson($test)['content'][1]['excerpt']);
|
||||
}
|
||||
|
||||
protected function generateHeadlines(int $id): Result {
|
||||
|
|
|
@ -24,8 +24,7 @@ use Psr\Http\Message\MessageInterface;
|
|||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Laminas\Diactoros\ServerRequest;
|
||||
use Laminas\Diactoros\Response\XmlResponse;
|
||||
use GuzzleHttp\Psr7\ServerRequest;
|
||||
|
||||
/** @coversNothing */
|
||||
abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||
|
@ -112,7 +111,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
}
|
||||
}
|
||||
$server = array_merge($server, $vars);
|
||||
$req = new ServerRequest($server, [], $url, $method, "php://memory", [], [], $params, $parsedBody);
|
||||
$req = new ServerRequest($method, $url, $headers, $body, "1.1", $server);
|
||||
if (isset($user)) {
|
||||
if (strlen($user)) {
|
||||
$req = $req->withAttribute("authenticated", true)->withAttribute("authenticatedUser", $user);
|
||||
|
@ -192,8 +191,8 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
$this->assertSame($exp->getRequestTarget(), $act->getRequestTarget(), $text);
|
||||
}
|
||||
if ($exp instanceof ResponseInterface && HTTP::matchType($exp, "application/json", "text/json", "+json")) {
|
||||
$expBody = json_decode((string) $exp->getBody(), true);
|
||||
$actBody = json_decode((string) $act->getBody(), true);
|
||||
$expBody = @json_decode((string) $exp->getBody(), true);
|
||||
$actBody = @json_decode((string) $act->getBody(), true);
|
||||
$this->assertSame(\JSON_ERROR_NONE, json_last_error(), "Response body is not valid JSON");
|
||||
$this->assertEquals($expBody, $actBody, $text);
|
||||
$this->assertSame($expBody, $actBody, $text);
|
||||
|
@ -205,6 +204,16 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
|||
$this->assertEquals($exp->getHeaders(), $act->getHeaders(), $text);
|
||||
}
|
||||
|
||||
protected function extractMessageJson(MessageInterface $msg) {
|
||||
if (HTTP::matchType($msg, "application/json", "text/json", "+json")) {
|
||||
$json = @json_decode((string) $msg->getBody(), true);
|
||||
if (json_last_error() === \JSON_ERROR_NONE) {
|
||||
return $json;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function assertTime($exp, $test, string $msg = ''): void {
|
||||
$test = $this->approximateTime($exp, $test);
|
||||
$exp = Date::transform($exp, "iso8601");
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
<file>cases/REST/TestREST.php</file>
|
||||
</testsuite>
|
||||
<testsuite name="Miniflux">
|
||||
<file>cases/REST/Miniflux/TestErrorResponse.php</file>
|
||||
<file>cases/REST/Miniflux/TestStatus.php</file>
|
||||
<file>cases/REST/Miniflux/TestV1.php</file>
|
||||
<file>cases/REST/Miniflux/TestToken.php</file>
|
||||
|
|
Loading…
Reference in a new issue