mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Style fixes
This commit is contained in:
parent
a7f69c845f
commit
bc53a2d24a
89 changed files with 1638 additions and 1664 deletions
14
RoboFile.php
14
RoboFile.php
|
@ -24,7 +24,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
* ./robo test --testsuite TTRSS --exclude-group slow --testdox
|
* ./robo test --testsuite TTRSS --exclude-group slow --testdox
|
||||||
*
|
*
|
||||||
* Please see the PHPUnit documentation for available options.
|
* Please see the PHPUnit documentation for available options.
|
||||||
*/
|
*/
|
||||||
public function test(array $args): Result {
|
public function test(array $args): Result {
|
||||||
return $this->runTests(escapeshellarg(\PHP_BINARY), "typical", $args);
|
return $this->runTests(escapeshellarg(\PHP_BINARY), "typical", $args);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
*
|
*
|
||||||
* This includes pedantic tests which may help to identify problems.
|
* This includes pedantic tests which may help to identify problems.
|
||||||
* See help for the "test" task for more details.
|
* See help for the "test" task for more details.
|
||||||
*/
|
*/
|
||||||
public function testFull(array $args): Result {
|
public function testFull(array $args): Result {
|
||||||
return $this->runTests(escapeshellarg(\PHP_BINARY), "full", $args);
|
return $this->runTests(escapeshellarg(\PHP_BINARY), "full", $args);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
* Runs a quick subset of the test suite
|
* Runs a quick subset of the test suite
|
||||||
*
|
*
|
||||||
* See help for the "test" task for more details.
|
* See help for the "test" task for more details.
|
||||||
*/
|
*/
|
||||||
public function testQuick(array $args): Result {
|
public function testQuick(array $args): Result {
|
||||||
return $this->runTests(escapeshellarg(\PHP_BINARY), "quick", $args);
|
return $this->runTests(escapeshellarg(\PHP_BINARY), "quick", $args);
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
* Robo first tries to use pcov and will fall back first to xdebug then
|
* Robo first tries to use pcov and will fall back first to xdebug then
|
||||||
* phpdbg. Neither pcov nor xdebug need to be enabled to be used; they
|
* phpdbg. Neither pcov nor xdebug need to be enabled to be used; they
|
||||||
* only need to be present in the extension load path to be used.
|
* only need to be present in the extension load path to be used.
|
||||||
*/
|
*/
|
||||||
public function coverage(array $args): Result {
|
public function coverage(array $args): Result {
|
||||||
// run tests with code coverage reporting enabled
|
// run tests with code coverage reporting enabled
|
||||||
$exec = $this->findCoverageEngine();
|
$exec = $this->findCoverageEngine();
|
||||||
|
@ -71,7 +71,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
* run all tests which may cover code.
|
* run all tests which may cover code.
|
||||||
*
|
*
|
||||||
* See also help for the "coverage" task for more details.
|
* See also help for the "coverage" task for more details.
|
||||||
*/
|
*/
|
||||||
public function coverageFull(array $args): Result {
|
public function coverageFull(array $args): Result {
|
||||||
// run tests with code coverage reporting enabled
|
// run tests with code coverage reporting enabled
|
||||||
$exec = $this->findCoverageEngine();
|
$exec = $this->findCoverageEngine();
|
||||||
|
@ -121,7 +121,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
return $all ? ">$hole 2>&1" : "2>$hole";
|
return $all ? ">$hole 2>&1" : "2>$hole";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function runTests(string $executor, string $set, array $args) : Result {
|
protected function runTests(string $executor, string $set, array $args): Result {
|
||||||
switch ($set) {
|
switch ($set) {
|
||||||
case "typical":
|
case "typical":
|
||||||
$set = ["--exclude-group", "optional"];
|
$set = ["--exclude-group", "optional"];
|
||||||
|
@ -153,7 +153,7 @@ class RoboFile extends \Robo\Tasks {
|
||||||
* Note that while it is possible to re-package old versions, the resultant tarball
|
* Note that while it is possible to re-package old versions, the resultant tarball
|
||||||
* may not be equivalent due to subsequent changes in the exclude list, or because
|
* may not be equivalent due to subsequent changes in the exclude list, or because
|
||||||
* of new tooling.
|
* of new tooling.
|
||||||
*/
|
*/
|
||||||
public function package(string $version = null): Result {
|
public function package(string $version = null): Result {
|
||||||
// establish which commit to package
|
// establish which commit to package
|
||||||
$version = $version ?? $this->askDefault("Commit to package:", "HEAD");
|
$version = $version ?? $this->askDefault("Commit to package:", "HEAD");
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
* Copyright 2017 J. King, Dustin Wilson et al.
|
* Copyright 2017 J. King, Dustin Wilson et al.
|
||||||
* See LICENSE and AUTHORS files for details */
|
* See LICENSE and AUTHORS files for details */
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse;
|
namespace JKingWeb\Arsse;
|
||||||
|
|
||||||
const BASE = __DIR__.DIRECTORY_SEPARATOR;
|
const BASE = __DIR__.DIRECTORY_SEPARATOR;
|
||||||
|
@ -13,7 +14,6 @@ ignore_user_abort(true);
|
||||||
ini_set("memory_limit", "-1");
|
ini_set("memory_limit", "-1");
|
||||||
ini_set("max_execution_time", "0");
|
ini_set("max_execution_time", "0");
|
||||||
|
|
||||||
|
|
||||||
if (\PHP_SAPI === "cli") {
|
if (\PHP_SAPI === "cli") {
|
||||||
// initialize the CLI; this automatically handles --help and --version
|
// initialize the CLI; this automatically handles --help and --version
|
||||||
$cli = new CLI;
|
$cli = new CLI;
|
||||||
|
|
|
@ -271,7 +271,7 @@ USAGE_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function userAuthenticate(string $user, string $password, bool $fever = false): int {
|
protected function userAuthenticate(string $user, string $password, bool $fever = false): int {
|
||||||
$result = $fever ? $this->getInstance(Fever::class)->authenticate($user, $password) : Arsse::$user->auth($user, $password);
|
$result = $fever ? $this->getInstance(Fever::class)->authenticate($user, $password) : Arsse::$user->auth($user, $password);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
echo Arsse::$lang->msg("CLI.Auth.Success").\PHP_EOL;
|
echo Arsse::$lang->msg("CLI.Auth.Success").\PHP_EOL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
98
lib/Conf.php
98
lib/Conf.php
|
@ -15,104 +15,104 @@ use JKingWeb\Arsse\Misc\ValueInfo as Value;
|
||||||
* All public properties are configuration parameters that may be set by the server administrator. */
|
* All public properties are configuration parameters that may be set by the server administrator. */
|
||||||
class Conf {
|
class Conf {
|
||||||
/** @var string Default language to use for logging and errors */
|
/** @var string Default language to use for logging and errors */
|
||||||
public $lang = "en";
|
public $lang = "en";
|
||||||
|
|
||||||
/** @var string The database driver to use, one of "sqlite3", "postgresql", or "mysql". A fully-qualified class name may also be used for custom drivers */
|
/** @var string The database driver to use, one of "sqlite3", "postgresql", or "mysql". A fully-qualified class name may also be used for custom drivers */
|
||||||
public $dbDriver = "sqlite3";
|
public $dbDriver = "sqlite3";
|
||||||
/** @var boolean Whether to attempt to automatically update the database when upgrading to a new version with schema changes */
|
/** @var boolean Whether to attempt to automatically update the database when upgrading to a new version with schema changes */
|
||||||
public $dbAutoUpdate = true;
|
public $dbAutoUpdate = true;
|
||||||
/** @var \DateInterval|null Number of seconds to wait before returning a timeout error when connecting to a database (null waits forever; not applicable to SQLite) */
|
/** @var \DateInterval|null Number of seconds to wait before returning a timeout error when connecting to a database (null waits forever; not applicable to SQLite) */
|
||||||
public $dbTimeoutConnect = 5.0;
|
public $dbTimeoutConnect = 5.0;
|
||||||
/** @var \DateInterval|null Number of seconds to wait before returning a timeout error when executing a database operation (null waits forever; not applicable to SQLite) */
|
/** @var \DateInterval|null Number of seconds to wait before returning a timeout error when executing a database operation (null waits forever; not applicable to SQLite) */
|
||||||
public $dbTimeoutExec = null;
|
public $dbTimeoutExec = null;
|
||||||
/** @var \DateInterval|null Number of seconds to wait before returning a timeout error when acquiring a database lock (null waits forever) */
|
/** @var \DateInterval|null Number of seconds to wait before returning a timeout error when acquiring a database lock (null waits forever) */
|
||||||
public $dbTimeoutLock = 60.0;
|
public $dbTimeoutLock = 60.0;
|
||||||
/** @var string|null Full path and file name of SQLite database (if using SQLite) */
|
/** @var string|null Full path and file name of SQLite database (if using SQLite) */
|
||||||
public $dbSQLite3File = null;
|
public $dbSQLite3File = null;
|
||||||
/** @var string Encryption key to use for SQLite database (if using a version of SQLite with SEE) */
|
/** @var string Encryption key to use for SQLite database (if using a version of SQLite with SEE) */
|
||||||
public $dbSQLite3Key = "";
|
public $dbSQLite3Key = "";
|
||||||
/** @var string Host name, address, or socket path of PostgreSQL database server (if using PostgreSQL) */
|
/** @var string Host name, address, or socket path of PostgreSQL database server (if using PostgreSQL) */
|
||||||
public $dbPostgreSQLHost = "";
|
public $dbPostgreSQLHost = "";
|
||||||
/** @var string Log-in user name for PostgreSQL database server (if using PostgreSQL) */
|
/** @var string Log-in user name for PostgreSQL database server (if using PostgreSQL) */
|
||||||
public $dbPostgreSQLUser = "arsse";
|
public $dbPostgreSQLUser = "arsse";
|
||||||
/** @var string Log-in password for PostgreSQL database server (if using PostgreSQL) */
|
/** @var string Log-in password for PostgreSQL database server (if using PostgreSQL) */
|
||||||
public $dbPostgreSQLPass = "";
|
public $dbPostgreSQLPass = "";
|
||||||
/** @var integer Listening port for PostgreSQL database server (if using PostgreSQL over TCP) */
|
/** @var integer Listening port for PostgreSQL database server (if using PostgreSQL over TCP) */
|
||||||
public $dbPostgreSQLPort = 5432;
|
public $dbPostgreSQLPort = 5432;
|
||||||
/** @var string Database name on PostgreSQL database server (if using PostgreSQL) */
|
/** @var string Database name on PostgreSQL database server (if using PostgreSQL) */
|
||||||
public $dbPostgreSQLDb = "arsse";
|
public $dbPostgreSQLDb = "arsse";
|
||||||
/** @var string Schema name in PostgreSQL database (if using PostgreSQL) */
|
/** @var string Schema name in PostgreSQL database (if using PostgreSQL) */
|
||||||
public $dbPostgreSQLSchema = "";
|
public $dbPostgreSQLSchema = "";
|
||||||
/** @var string Service file entry to use (if using PostgreSQL); if using a service entry all above parameters except schema are ignored */
|
/** @var string Service file entry to use (if using PostgreSQL); if using a service entry all above parameters except schema are ignored */
|
||||||
public $dbPostgreSQLService = "";
|
public $dbPostgreSQLService = "";
|
||||||
/** @var string Host name or address of MySQL database server (if using MySQL) */
|
/** @var string Host name or address of MySQL database server (if using MySQL) */
|
||||||
public $dbMySQLHost = "localhost";
|
public $dbMySQLHost = "localhost";
|
||||||
/** @var string Log-in user name for MySQL database server (if using MySQL) */
|
/** @var string Log-in user name for MySQL database server (if using MySQL) */
|
||||||
public $dbMySQLUser = "arsse";
|
public $dbMySQLUser = "arsse";
|
||||||
/** @var string Log-in password for MySQL database server (if using MySQL) */
|
/** @var string Log-in password for MySQL database server (if using MySQL) */
|
||||||
public $dbMySQLPass = "";
|
public $dbMySQLPass = "";
|
||||||
/** @var integer Listening port for MySQL database server (if using MySQL over TCP) */
|
/** @var integer Listening port for MySQL database server (if using MySQL over TCP) */
|
||||||
public $dbMySQLPort = 3306;
|
public $dbMySQLPort = 3306;
|
||||||
/** @var string Database name on MySQL database server (if using MySQL) */
|
/** @var string Database name on MySQL database server (if using MySQL) */
|
||||||
public $dbMySQLDb = "arsse";
|
public $dbMySQLDb = "arsse";
|
||||||
/** @var string Unix domain socket or named pipe to use for MySQL when not connecting over TCP */
|
/** @var string Unix domain socket or named pipe to use for MySQL when not connecting over TCP */
|
||||||
public $dbMySQLSocket = "";
|
public $dbMySQLSocket = "";
|
||||||
|
|
||||||
/** @var string The user management driver to use, currently only "internal". A fully-qualified class name may also be used for custom drivers */
|
/** @var string The user management driver to use, currently only "internal". A fully-qualified class name may also be used for custom drivers */
|
||||||
public $userDriver = "internal";
|
public $userDriver = "internal";
|
||||||
/** @var boolean Whether users are already authenticated by the Web server before the application is executed */
|
/** @var boolean Whether users are already authenticated by the Web server before the application is executed */
|
||||||
public $userPreAuth = false;
|
public $userPreAuth = false;
|
||||||
/** @var boolean Whether to require successful HTTP authentication before processing API-level authentication for protocols which have any. Normally the Tiny Tiny RSS relies on its own session-token authentication scheme, for example */
|
/** @var boolean Whether to require successful HTTP authentication before processing API-level authentication for protocols which have any. Normally the Tiny Tiny RSS relies on its own session-token authentication scheme, for example */
|
||||||
public $userHTTPAuthRequired = false;
|
public $userHTTPAuthRequired = false;
|
||||||
/** @var integer Desired length of temporary user passwords */
|
/** @var integer Desired length of temporary user passwords */
|
||||||
public $userTempPasswordLength = 20;
|
public $userTempPasswordLength = 20;
|
||||||
/** @var boolean Whether invalid or expired API session tokens should prevent logging in when HTTP authentication is used, for protocol which implement their own authentication */
|
/** @var boolean Whether invalid or expired API session tokens should prevent logging in when HTTP authentication is used, for protocol which implement their own authentication */
|
||||||
public $userSessionEnforced = true;
|
public $userSessionEnforced = true;
|
||||||
/** @var \DateInterval Period of inactivity after which log-in sessions should be considered invalid, as an ISO 8601 duration (default: 24 hours)
|
/** @var \DateInterval Period of inactivity after which log-in sessions should be considered invalid, as an ISO 8601 duration (default: 24 hours)
|
||||||
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
||||||
public $userSessionTimeout = "PT24H";
|
public $userSessionTimeout = "PT24H";
|
||||||
/** @var \DateInterval Maximum lifetime of log-in sessions regardless of activity, as an ISO 8601 duration (default: 7 days);
|
/** @var \DateInterval Maximum lifetime of log-in sessions regardless of activity, as an ISO 8601 duration (default: 7 days);
|
||||||
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
||||||
public $userSessionLifetime = "P7D";
|
public $userSessionLifetime = "P7D";
|
||||||
|
|
||||||
/** @var string Feed update service driver to use, one of "serial" or "subprocess". A fully-qualified class name may also be used for custom drivers */
|
/** @var string Feed update service driver to use, one of "serial" or "subprocess". A fully-qualified class name may also be used for custom drivers */
|
||||||
public $serviceDriver = "subprocess";
|
public $serviceDriver = "subprocess";
|
||||||
/** @var \DateInterval The interval between checks for new articles, as an ISO 8601 duration
|
/** @var \DateInterval The interval between checks for new articles, as an ISO 8601 duration
|
||||||
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
||||||
public $serviceFrequency = "PT2M";
|
public $serviceFrequency = "PT2M";
|
||||||
/** @var integer Number of concurrent feed updates to perform */
|
/** @var integer Number of concurrent feed updates to perform */
|
||||||
public $serviceQueueWidth = 5;
|
public $serviceQueueWidth = 5;
|
||||||
|
|
||||||
/** @var \DateInterval Number of seconds to wait for data when fetching feeds from foreign servers */
|
/** @var \DateInterval Number of seconds to wait for data when fetching feeds from foreign servers */
|
||||||
public $fetchTimeout = 10.0;
|
public $fetchTimeout = 10.0;
|
||||||
/** @var integer Maximum size, in bytes, of data when fetching feeds from foreign servers */
|
/** @var integer Maximum size, in bytes, of data when fetching feeds from foreign servers */
|
||||||
public $fetchSizeLimit = 2 * 1024 * 1024;
|
public $fetchSizeLimit = 2 * 1024 * 1024;
|
||||||
/** @var boolean Whether to allow the possibility of fetching full article contents using an item's URL. Whether fetching will actually happen is also governed by a per-feed setting */
|
/** @var boolean Whether to allow the possibility of fetching full article contents using an item's URL. Whether fetching will actually happen is also governed by a per-feed setting */
|
||||||
public $fetchEnableScraping = true;
|
public $fetchEnableScraping = true;
|
||||||
/** @var string|null User-Agent string to use when fetching feeds from foreign servers */
|
/** @var string|null User-Agent string to use when fetching feeds from foreign servers */
|
||||||
public $fetchUserAgentString = null;
|
public $fetchUserAgentString = null;
|
||||||
|
|
||||||
/** @var \DateInterval|null When to delete a feed from the database after all its subscriptions have been deleted, as an ISO 8601 duration (default: 24 hours; null for never)
|
/** @var \DateInterval|null When to delete a feed from the database after all its subscriptions have been deleted, as an ISO 8601 duration (default: 24 hours; null for never)
|
||||||
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
||||||
public $purgeFeeds = "PT24H";
|
public $purgeFeeds = "PT24H";
|
||||||
/** @var \DateInterval|null When to delete an unstarred article in the database after it has been marked read by all users, as an ISO 8601 duration (default: 7 days; null for never)
|
/** @var \DateInterval|null When to delete an unstarred article in the database after it has been marked read by all users, as an ISO 8601 duration (default: 7 days; null for never)
|
||||||
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
||||||
public $purgeArticlesRead = "P7D";
|
public $purgeArticlesRead = "P7D";
|
||||||
/** @var \DateInterval|null When to delete an unstarred article in the database regardless of its read state, as an ISO 8601 duration (default: 21 days; null for never)
|
/** @var \DateInterval|null When to delete an unstarred article in the database regardless of its read state, as an ISO 8601 duration (default: 21 days; null for never)
|
||||||
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
* @see https://en.wikipedia.org/wiki/ISO_8601#Durations */
|
||||||
public $purgeArticlesUnread = "P21D";
|
public $purgeArticlesUnread = "P21D";
|
||||||
|
|
||||||
/** @var string Application name to present to clients during authentication */
|
/** @var string Application name to present to clients during authentication */
|
||||||
public $httpRealm = "The Advanced RSS Environment";
|
public $httpRealm = "The Advanced RSS Environment";
|
||||||
/** @var string Space-separated list of origins from which to allow cross-origin resource sharing */
|
/** @var string Space-separated list of origins from which to allow cross-origin resource sharing */
|
||||||
public $httpOriginsAllowed = "*";
|
public $httpOriginsAllowed = "*";
|
||||||
/** @var string Space-separated list of origins from which to deny cross-origin resource sharing */
|
/** @var string Space-separated list of origins from which to deny cross-origin resource sharing */
|
||||||
public $httpOriginsDenied = "";
|
public $httpOriginsDenied = "";
|
||||||
|
|
||||||
### OBSOLETE SETTINGS
|
### OBSOLETE SETTINGS
|
||||||
|
|
||||||
/** @var \DateInterval|null (OBSOLETE) Number of seconds for SQLite to wait before returning a timeout error when trying to acquire a write lock on the database (zero does not wait) */
|
/** @var \DateInterval|null (OBSOLETE) Number of seconds for SQLite to wait before returning a timeout error when trying to acquire a write lock on the database (zero does not wait) */
|
||||||
public $dbSQLite3Timeout = null; // previously 60.0
|
public $dbSQLite3Timeout = null; // previously 60.0
|
||||||
|
|
||||||
const TYPE_NAMES = [
|
const TYPE_NAMES = [
|
||||||
Value::T_BOOL => "boolean",
|
Value::T_BOOL => "boolean",
|
||||||
|
@ -254,10 +254,10 @@ class Conf {
|
||||||
$match = explode("|", $match[1]);
|
$match = explode("|", $match[1]);
|
||||||
$nullable = (sizeof($match) > 1);
|
$nullable = (sizeof($match) > 1);
|
||||||
$type = [
|
$type = [
|
||||||
'string' => Value::T_STRING | Value::M_STRICT,
|
'string' => Value::T_STRING | Value::M_STRICT,
|
||||||
'integer' => Value::T_INT | Value::M_STRICT,
|
'integer' => Value::T_INT | Value::M_STRICT,
|
||||||
'boolean' => Value::T_BOOL | Value::M_STRICT,
|
'boolean' => Value::T_BOOL | Value::M_STRICT,
|
||||||
'float' => Value::T_FLOAT | Value::M_STRICT,
|
'float' => Value::T_FLOAT | Value::M_STRICT,
|
||||||
'\\DateInterval' => Value::T_INTERVAL | Value::M_LOOSE,
|
'\\DateInterval' => Value::T_INTERVAL | Value::M_LOOSE,
|
||||||
][$match[0]];
|
][$match[0]];
|
||||||
if ($nullable) {
|
if ($nullable) {
|
||||||
|
@ -283,7 +283,7 @@ class Conf {
|
||||||
// it is first converted to an interval and then converted to the numeric type if necessary
|
// it is first converted to an interval and then converted to the numeric type if necessary
|
||||||
$mode = $nullable ? Value::M_STRICT | Value::M_NULL : Value::M_STRICT;
|
$mode = $nullable ? Value::M_STRICT | Value::M_NULL : Value::M_STRICT;
|
||||||
if (is_string($value)) {
|
if (is_string($value)) {
|
||||||
$value = Value::normalize($value, Value::T_INTERVAL | $mode);
|
$value = Value::normalize($value, Value::T_INTERVAL | $mode);
|
||||||
}
|
}
|
||||||
switch (self::EXPECTED_TYPES[$key] ?? gettype($this->$key)) {
|
switch (self::EXPECTED_TYPES[$key] ?? gettype($this->$key)) {
|
||||||
case "integer":
|
case "integer":
|
||||||
|
@ -299,7 +299,7 @@ class Conf {
|
||||||
throw new Conf\Exception("ambiguousDefault", ['param' => $key]); // @codeCoverageIgnore
|
throw new Conf\Exception("ambiguousDefault", ['param' => $key]); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$value = Value::normalize($value, $typeConst);
|
$value = Value::normalize($value, $typeConst);
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
case "dbDriver":
|
case "dbDriver":
|
||||||
$driver = $driver ?? Database::DRIVER_NAMES[strtolower($value)] ?? $value;
|
$driver = $driver ?? Database::DRIVER_NAMES[strtolower($value)] ?? $value;
|
||||||
|
@ -319,7 +319,7 @@ class Conf {
|
||||||
}
|
}
|
||||||
return $value;
|
return $value;
|
||||||
} catch (ExceptionType $e) {
|
} catch (ExceptionType $e) {
|
||||||
$type = static::$types[$key]['const'] & ~(Value::M_STRICT | Value::M_DROP | Value::M_NULL | Value::M_ARRAY);
|
$type = static::$types[$key]['const'] & ~(Value::M_STRICT | Value::M_DROP | Value::M_NULL | Value::M_ARRAY);
|
||||||
throw new Conf\Exception("typeMismatch", ['param' => $key, 'type' => self::TYPE_NAMES[$type], 'file' => $file, 'nullable' => $nullable]);
|
throw new Conf\Exception("typeMismatch", ['param' => $key, 'type' => self::TYPE_NAMES[$type], 'file' => $file, 'nullable' => $nullable]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
120
lib/Database.php
120
lib/Database.php
|
@ -379,7 +379,7 @@ class Database {
|
||||||
$max = Date::add(Arsse::$conf->userSessionTimeout, $now)->getTimestamp();
|
$max = Date::add(Arsse::$conf->userSessionTimeout, $now)->getTimestamp();
|
||||||
$diff = intdiv($max - $now, 2);
|
$diff = intdiv($max - $now, 2);
|
||||||
// determine if the expiry time is less than half the session timeout into the future
|
// determine if the expiry time is less than half the session timeout into the future
|
||||||
return (($now + $diff) >= $expiry->getTimestamp());
|
return ($now + $diff) >= $expiry->getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a new token for the given user in the given class
|
/** Creates a new token for the given user in the given class
|
||||||
|
@ -388,7 +388,7 @@ class Database {
|
||||||
* @param string $class The class of the token e.g. the protocol name
|
* @param string $class The class of the token e.g. the protocol name
|
||||||
* @param string|null $id The value of the token; if none is provided a UUID will be generated
|
* @param string|null $id The value of the token; if none is provided a UUID will be generated
|
||||||
* @param \DateTimeInterface|null $expires An optional expiry date and time for the token
|
* @param \DateTimeInterface|null $expires An optional expiry date and time for the token
|
||||||
*/
|
*/
|
||||||
public function tokenCreate(string $user, string $class, string $id = null, \DateTimeInterface $expires = null): string {
|
public function tokenCreate(string $user, string $class, string $id = null, \DateTimeInterface $expires = null): string {
|
||||||
// If the user isn't authorized to perform this action then throw an exception.
|
// If the user isn't authorized to perform this action then throw an exception.
|
||||||
if (!Arsse::$user->authorize($user, __FUNCTION__)) {
|
if (!Arsse::$user->authorize($user, __FUNCTION__)) {
|
||||||
|
@ -584,10 +584,10 @@ class Database {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$valid = [
|
$valid = [
|
||||||
'name' => "str",
|
'name' => "str",
|
||||||
'parent' => "int",
|
'parent' => "int",
|
||||||
];
|
];
|
||||||
list($setClause, $setTypes, $setValues) = $this->generateSet($in, $valid);
|
[$setClause, $setTypes, $setValues] = $this->generateSet($in, $valid);
|
||||||
return (bool) $this->db->prepare("UPDATE arsse_folders set $setClause, modified = CURRENT_TIMESTAMP where owner = ? and id = ?", $setTypes, "str", "int")->run($setValues, $user, $id)->changes();
|
return (bool) $this->db->prepare("UPDATE arsse_folders set $setClause, modified = CURRENT_TIMESTAMP where owner = ? and id = ?", $setTypes, "str", "int")->run($setValues, $user, $id)->changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -881,7 +881,7 @@ class Database {
|
||||||
'order_type' => "strict int",
|
'order_type' => "strict int",
|
||||||
'pinned' => "strict bool",
|
'pinned' => "strict bool",
|
||||||
];
|
];
|
||||||
list($setClause, $setTypes, $setValues) = $this->generateSet($data, $valid);
|
[$setClause, $setTypes, $setValues] = $this->generateSet($data, $valid);
|
||||||
if (!$setClause) {
|
if (!$setClause) {
|
||||||
// if no changes would actually be applied, just return
|
// if no changes would actually be applied, just return
|
||||||
return false;
|
return false;
|
||||||
|
@ -1220,10 +1220,10 @@ class Database {
|
||||||
*/
|
*/
|
||||||
public function feedMatchIds(int $feedID, array $ids = [], array $hashesUT = [], array $hashesUC = [], array $hashesTC = []): Db\Result {
|
public function feedMatchIds(int $feedID, array $ids = [], array $hashesUT = [], array $hashesUC = [], array $hashesTC = []): Db\Result {
|
||||||
// compile SQL IN() clauses and necessary type bindings for the four identifier lists
|
// compile SQL IN() clauses and necessary type bindings for the four identifier lists
|
||||||
list($cId, $tId, $vId) = $this->generateIn($ids, "str");
|
[$cId, $tId, $vId] = $this->generateIn($ids, "str");
|
||||||
list($cHashUT, $tHashUT, $vHashUT) = $this->generateIn($hashesUT, "str");
|
[$cHashUT, $tHashUT, $vHashUT] = $this->generateIn($hashesUT, "str");
|
||||||
list($cHashUC, $tHashUC, $vHashUC) = $this->generateIn($hashesUC, "str");
|
[$cHashUC, $tHashUC, $vHashUC] = $this->generateIn($hashesUC, "str");
|
||||||
list($cHashTC, $tHashTC, $vHashTC) = $this->generateIn($hashesTC, "str");
|
[$cHashTC, $tHashTC, $vHashTC] = $this->generateIn($hashesTC, "str");
|
||||||
// perform the query
|
// perform the query
|
||||||
return $articles = $this->db->prepare(
|
return $articles = $this->db->prepare(
|
||||||
"SELECT id, edited, guid, url_title_hash, url_content_hash, title_content_hash FROM arsse_articles WHERE feed = ? and (guid in($cId) or url_title_hash in($cHashUT) or url_content_hash in($cHashUC) or title_content_hash in($cHashTC))",
|
"SELECT id, edited, guid, url_title_hash, url_content_hash, title_content_hash FROM arsse_articles WHERE feed = ? and (guid in($cId) or url_title_hash in($cHashUT) or url_content_hash in($cHashUC) or title_content_hash in($cHashTC))",
|
||||||
|
@ -1242,27 +1242,27 @@ class Database {
|
||||||
protected function articleColumns(): array {
|
protected function articleColumns(): array {
|
||||||
$greatest = $this->db->sqlToken("greatest");
|
$greatest = $this->db->sqlToken("greatest");
|
||||||
return [
|
return [
|
||||||
'id' => "arsse_articles.id",
|
'id' => "arsse_articles.id",
|
||||||
'edition' => "latest_editions.edition",
|
'edition' => "latest_editions.edition",
|
||||||
'url' => "arsse_articles.url",
|
'url' => "arsse_articles.url",
|
||||||
'title' => "arsse_articles.title",
|
'title' => "arsse_articles.title",
|
||||||
'author' => "arsse_articles.author",
|
'author' => "arsse_articles.author",
|
||||||
'content' => "arsse_articles.content",
|
'content' => "arsse_articles.content",
|
||||||
'guid' => "arsse_articles.guid",
|
'guid' => "arsse_articles.guid",
|
||||||
'fingerprint' => "arsse_articles.url_title_hash || ':' || arsse_articles.url_content_hash || ':' || arsse_articles.title_content_hash",
|
'fingerprint' => "arsse_articles.url_title_hash || ':' || arsse_articles.url_content_hash || ':' || arsse_articles.title_content_hash",
|
||||||
'folder' => "coalesce(arsse_subscriptions.folder,0)",
|
'folder' => "coalesce(arsse_subscriptions.folder,0)",
|
||||||
'subscription' => "arsse_subscriptions.id",
|
'subscription' => "arsse_subscriptions.id",
|
||||||
'feed' => "arsse_subscriptions.feed",
|
'feed' => "arsse_subscriptions.feed",
|
||||||
'starred' => "coalesce(arsse_marks.starred,0)",
|
'starred' => "coalesce(arsse_marks.starred,0)",
|
||||||
'unread' => "abs(coalesce(arsse_marks.read,0) - 1)",
|
'unread' => "abs(coalesce(arsse_marks.read,0) - 1)",
|
||||||
'note' => "coalesce(arsse_marks.note,'')",
|
'note' => "coalesce(arsse_marks.note,'')",
|
||||||
'published_date' => "arsse_articles.published",
|
'published_date' => "arsse_articles.published",
|
||||||
'edited_date' => "arsse_articles.edited",
|
'edited_date' => "arsse_articles.edited",
|
||||||
'modified_date' => "arsse_articles.modified",
|
'modified_date' => "arsse_articles.modified",
|
||||||
'marked_date' => "$greatest(arsse_articles.modified, coalesce(arsse_marks.modified, '0001-01-01 00:00:00'), coalesce(label_stats.modified, '0001-01-01 00:00:00'))",
|
'marked_date' => "$greatest(arsse_articles.modified, coalesce(arsse_marks.modified, '0001-01-01 00:00:00'), coalesce(label_stats.modified, '0001-01-01 00:00:00'))",
|
||||||
'subscription_title' => "coalesce(arsse_subscriptions.title, arsse_feeds.title)",
|
'subscription_title' => "coalesce(arsse_subscriptions.title, arsse_feeds.title)",
|
||||||
'media_url' => "arsse_enclosures.url",
|
'media_url' => "arsse_enclosures.url",
|
||||||
'media_type' => "arsse_enclosures.type",
|
'media_type' => "arsse_enclosures.type",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1359,7 +1359,7 @@ class Database {
|
||||||
"unread" => ["unread", "=", "bool", ""],
|
"unread" => ["unread", "=", "bool", ""],
|
||||||
"starred" => ["starred", "=", "bool", ""],
|
"starred" => ["starred", "=", "bool", ""],
|
||||||
];
|
];
|
||||||
foreach ($options as $m => list($col, $op, $type, $pair)) {
|
foreach ($options as $m => [$col, $op, $type, $pair]) {
|
||||||
if (!$context->$m()) {
|
if (!$context->$m()) {
|
||||||
// context is not being used
|
// context is not being used
|
||||||
continue;
|
continue;
|
||||||
|
@ -1368,7 +1368,7 @@ class Database {
|
||||||
if (!$context->$m) {
|
if (!$context->$m) {
|
||||||
throw new Db\ExceptionInput("tooShort", ['field' => $m, 'action' => $this->caller(), 'min' => 1]); // must have at least one array element
|
throw new Db\ExceptionInput("tooShort", ['field' => $m, 'action' => $this->caller(), 'min' => 1]); // must have at least one array element
|
||||||
}
|
}
|
||||||
list($clause, $types, $values) = $this->generateIn($context->$m, $type);
|
[$clause, $types, $values] = $this->generateIn($context->$m, $type);
|
||||||
$q->setWhere("{$colDefs[$col]} $op ($clause)", $types, $values);
|
$q->setWhere("{$colDefs[$col]} $op ($clause)", $types, $values);
|
||||||
} elseif ($pair && $context->$pair()) {
|
} elseif ($pair && $context->$pair()) {
|
||||||
// option is paired with another which is also being used
|
// option is paired with another which is also being used
|
||||||
|
@ -1383,7 +1383,7 @@ class Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// further handle exclusionary options if specified
|
// further handle exclusionary options if specified
|
||||||
foreach ($options as $m => list($col, $op, $type, $pair)) {
|
foreach ($options as $m => [$col, $op, $type, $pair]) {
|
||||||
if (!method_exists($context->not, $m) || !$context->not->$m()) {
|
if (!method_exists($context->not, $m) || !$context->not->$m()) {
|
||||||
// context option is not being used
|
// context option is not being used
|
||||||
continue;
|
continue;
|
||||||
|
@ -1392,7 +1392,7 @@ class Database {
|
||||||
// for exclusions we don't care if the array is empty
|
// for exclusions we don't care if the array is empty
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
list($clause, $types, $values) = $this->generateIn($context->not->$m, $type);
|
[$clause, $types, $values] = $this->generateIn($context->not->$m, $type);
|
||||||
$q->setWhereNot("{$colDefs[$col]} $op ($clause)", $types, $values);
|
$q->setWhereNot("{$colDefs[$col]} $op ($clause)", $types, $values);
|
||||||
} elseif ($pair && $context->not->$pair()) {
|
} elseif ($pair && $context->not->$pair()) {
|
||||||
// option is paired with another which is also being used
|
// option is paired with another which is also being used
|
||||||
|
@ -1409,13 +1409,13 @@ class Database {
|
||||||
// handle labels and tags
|
// handle labels and tags
|
||||||
$options = [
|
$options = [
|
||||||
'label' => [
|
'label' => [
|
||||||
'match_col' => "arsse_articles.id",
|
'match_col' => "arsse_articles.id",
|
||||||
'cte_name' => "labelled",
|
'cte_name' => "labelled",
|
||||||
'cte_cols' => ["article", "label_id", "label_name"],
|
'cte_cols' => ["article", "label_id", "label_name"],
|
||||||
'cte_body' => "SELECT m.article, l.id, l.name from arsse_label_members as m join arsse_labels as l on l.id = m.label where l.owner = ? and m.assigned = 1",
|
'cte_body' => "SELECT m.article, l.id, l.name from arsse_label_members as m join arsse_labels as l on l.id = m.label where l.owner = ? and m.assigned = 1",
|
||||||
'cte_types' => ["str"],
|
'cte_types' => ["str"],
|
||||||
'cte_values' => [$user],
|
'cte_values' => [$user],
|
||||||
'options' => [
|
'options' => [
|
||||||
'label' => ['use_name' => false, 'multi' => false],
|
'label' => ['use_name' => false, 'multi' => false],
|
||||||
'labels' => ['use_name' => false, 'multi' => true],
|
'labels' => ['use_name' => false, 'multi' => true],
|
||||||
'labelName' => ['use_name' => true, 'multi' => false],
|
'labelName' => ['use_name' => true, 'multi' => false],
|
||||||
|
@ -1423,13 +1423,13 @@ class Database {
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'tag' => [
|
'tag' => [
|
||||||
'match_col' => "arsse_subscriptions.id",
|
'match_col' => "arsse_subscriptions.id",
|
||||||
'cte_name' => "tagged",
|
'cte_name' => "tagged",
|
||||||
'cte_cols' => ["subscription", "tag_id", "tag_name"],
|
'cte_cols' => ["subscription", "tag_id", "tag_name"],
|
||||||
'cte_body' => "SELECT m.subscription, t.id, t.name from arsse_tag_members as m join arsse_tags as t on t.id = m.tag where t.owner = ? and m.assigned = 1",
|
'cte_body' => "SELECT m.subscription, t.id, t.name from arsse_tag_members as m join arsse_tags as t on t.id = m.tag where t.owner = ? and m.assigned = 1",
|
||||||
'cte_types' => ["str"],
|
'cte_types' => ["str"],
|
||||||
'cte_values' => [$user],
|
'cte_values' => [$user],
|
||||||
'options' => [
|
'options' => [
|
||||||
'tag' => ['use_name' => false, 'multi' => false],
|
'tag' => ['use_name' => false, 'multi' => false],
|
||||||
'tags' => ['use_name' => false, 'multi' => true],
|
'tags' => ['use_name' => false, 'multi' => true],
|
||||||
'tagName' => ['use_name' => true, 'multi' => false],
|
'tagName' => ['use_name' => true, 'multi' => false],
|
||||||
|
@ -1452,7 +1452,7 @@ class Database {
|
||||||
throw new Db\ExceptionInput("tooShort", ['field' => $m, 'action' => $this->caller(), 'min' => 1]); // must have at least one array element
|
throw new Db\ExceptionInput("tooShort", ['field' => $m, 'action' => $this->caller(), 'min' => 1]); // must have at least one array element
|
||||||
}
|
}
|
||||||
if ($multi) {
|
if ($multi) {
|
||||||
list($test, $types, $values) = $this->generateIn($context->$m, $named ? "str" : "int");
|
[$test, $types, $values] = $this->generateIn($context->$m, $named ? "str" : "int");
|
||||||
$test = "in ($test)";
|
$test = "in ($test)";
|
||||||
} else {
|
} else {
|
||||||
$test = "= ?";
|
$test = "= ?";
|
||||||
|
@ -1464,7 +1464,7 @@ class Database {
|
||||||
if ($context->not->$m()) {
|
if ($context->not->$m()) {
|
||||||
$seen = true;
|
$seen = true;
|
||||||
if ($multi) {
|
if ($multi) {
|
||||||
list($test, $types, $values) = $this->generateIn($context->not->$m, $named ? "str" : "int");
|
[$test, $types, $values] = $this->generateIn($context->not->$m, $named ? "str" : "int");
|
||||||
$test = "in ($test)";
|
$test = "in ($test)";
|
||||||
} else {
|
} else {
|
||||||
$test = "= ?";
|
$test = "= ?";
|
||||||
|
@ -1496,7 +1496,7 @@ class Database {
|
||||||
$q->setWhere("coalesce(arsse_subscriptions.folder,0) in (select folder from folders)");
|
$q->setWhere("coalesce(arsse_subscriptions.folder,0) in (select folder from folders)");
|
||||||
}
|
}
|
||||||
if ($context->folders()) {
|
if ($context->folders()) {
|
||||||
list($inClause, $inTypes, $inValues) = $this->generateIn($context->folders, "int");
|
[$inClause, $inTypes, $inValues] = $this->generateIn($context->folders, "int");
|
||||||
// add a common table expression to list the folders and their children so that we select from the entire subtree
|
// add a common table expression to list the folders and their children so that we select from the entire subtree
|
||||||
$q->setCTE("folders_multi(folder)", "SELECT id as folder from (select id from (select 0 as id union select id from arsse_folders where owner = ?) as f where id in ($inClause)) as folders_multi union select id from arsse_folders join folders_multi on coalesce(parent,0) = folder", ["str", $inTypes], [$user, $inValues]);
|
$q->setCTE("folders_multi(folder)", "SELECT id as folder from (select id from (select 0 as id union select id from arsse_folders where owner = ?) as f where id in ($inClause)) as folders_multi union select id from arsse_folders join folders_multi on coalesce(parent,0) = folder", ["str", $inTypes], [$user, $inValues]);
|
||||||
// limit subscriptions to the listed folders
|
// limit subscriptions to the listed folders
|
||||||
|
@ -1509,7 +1509,7 @@ class Database {
|
||||||
$q->setWhereNot("coalesce(arsse_subscriptions.folder,0) in (select folder from folders_excluded)");
|
$q->setWhereNot("coalesce(arsse_subscriptions.folder,0) in (select folder from folders_excluded)");
|
||||||
}
|
}
|
||||||
if ($context->not->folders()) {
|
if ($context->not->folders()) {
|
||||||
list($inClause, $inTypes, $inValues) = $this->generateIn($context->not->folders, "int");
|
[$inClause, $inTypes, $inValues] = $this->generateIn($context->not->folders, "int");
|
||||||
// add a common table expression to list the folders and their children so that we select from the entire subtree
|
// add a common table expression to list the folders and their children so that we select from the entire subtree
|
||||||
$q->setCTE("folders_multi_excluded(folder)", "SELECT id as folder from (select id from (select 0 as id union select id from arsse_folders where owner = ?) as f where id in ($inClause)) as folders_multi_excluded union select id from arsse_folders join folders_multi_excluded on coalesce(parent,0) = folder", ["str", $inTypes], [$user, $inValues]);
|
$q->setCTE("folders_multi_excluded(folder)", "SELECT id as folder from (select id from (select 0 as id union select id from arsse_folders where owner = ?) as f where id in ($inClause)) as folders_multi_excluded union select id from arsse_folders join folders_multi_excluded on coalesce(parent,0) = folder", ["str", $inTypes], [$user, $inValues]);
|
||||||
// limit subscriptions to the listed folders
|
// limit subscriptions to the listed folders
|
||||||
|
@ -1623,9 +1623,9 @@ class Database {
|
||||||
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
||||||
}
|
}
|
||||||
$data = [
|
$data = [
|
||||||
'read' => $data['read'] ?? null,
|
'read' => $data['read'] ?? null,
|
||||||
'starred' => $data['starred'] ?? null,
|
'starred' => $data['starred'] ?? null,
|
||||||
'note' => $data['note'] ?? null,
|
'note' => $data['note'] ?? null,
|
||||||
];
|
];
|
||||||
if (!isset($data['read']) && !isset($data['starred']) && !isset($data['note'])) {
|
if (!isset($data['read']) && !isset($data['starred']) && !isset($data['note'])) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1664,7 +1664,7 @@ class Database {
|
||||||
$data = array_filter($data, function($v) {
|
$data = array_filter($data, function($v) {
|
||||||
return isset($v);
|
return isset($v);
|
||||||
});
|
});
|
||||||
list($set, $setTypes, $setValues) = $this->generateSet($data, ['starred' => "bool", 'note' => "str"]);
|
[$set, $setTypes, $setValues] = $this->generateSet($data, ['starred' => "bool", 'note' => "str"]);
|
||||||
$q->setBody("UPDATE arsse_marks set touched = 1, $set where article in(select article from target_articles) and subscription in(select distinct subscription from target_articles)", $setTypes, $setValues);
|
$q->setBody("UPDATE arsse_marks set touched = 1, $set where article in(select article from target_articles) and subscription in(select distinct subscription from target_articles)", $setTypes, $setValues);
|
||||||
$this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues());
|
$this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues());
|
||||||
}
|
}
|
||||||
|
@ -1688,7 +1688,7 @@ class Database {
|
||||||
$data = array_filter($data, function($v) {
|
$data = array_filter($data, function($v) {
|
||||||
return isset($v);
|
return isset($v);
|
||||||
});
|
});
|
||||||
list($set, $setTypes, $setValues) = $this->generateSet($data, ['read' => "bool", 'starred' => "bool", 'note' => "str"]);
|
[$set, $setTypes, $setValues] = $this->generateSet($data, ['read' => "bool", 'starred' => "bool", 'note' => "str"]);
|
||||||
$q->setBody("UPDATE arsse_marks set $set, modified = CURRENT_TIMESTAMP where article in(select article from target_articles) and subscription in(select distinct subscription from target_articles)", $setTypes, $setValues);
|
$q->setBody("UPDATE arsse_marks set $set, modified = CURRENT_TIMESTAMP where article in(select article from target_articles) and subscription in(select distinct subscription from target_articles)", $setTypes, $setValues);
|
||||||
$out = $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->changes();
|
$out = $this->db->prepare($q->getQuery(), $q->getTypes())->run($q->getValues())->changes();
|
||||||
}
|
}
|
||||||
|
@ -1860,7 +1860,7 @@ class Database {
|
||||||
public function editionArticle(int ...$edition): array {
|
public function editionArticle(int ...$edition): array {
|
||||||
$out = [];
|
$out = [];
|
||||||
$context = (new Context)->editions($edition);
|
$context = (new Context)->editions($edition);
|
||||||
list($in, $inTypes, $inValues) = $this->generateIn($context->editions, "int");
|
[$in, $inTypes, $inValues] = $this->generateIn($context->editions, "int");
|
||||||
$out = $this->db->prepare("SELECT id as edition, article from arsse_editions where id in($in)", $inTypes)->run($inValues)->getAll();
|
$out = $this->db->prepare("SELECT id as edition, article from arsse_editions where id in($in)", $inTypes)->run($inValues)->getAll();
|
||||||
return $out ? array_combine(array_column($out, "edition"), array_column($out, "article")) : [];
|
return $out ? array_combine(array_column($out, "edition"), array_column($out, "article")) : [];
|
||||||
}
|
}
|
||||||
|
@ -2018,7 +2018,7 @@ class Database {
|
||||||
$valid = [
|
$valid = [
|
||||||
'name' => "str",
|
'name' => "str",
|
||||||
];
|
];
|
||||||
list($setClause, $setTypes, $setValues) = $this->generateSet($data, $valid);
|
[$setClause, $setTypes, $setValues] = $this->generateSet($data, $valid);
|
||||||
if (!$setClause) {
|
if (!$setClause) {
|
||||||
// if no changes would actually be applied, just return
|
// if no changes would actually be applied, just return
|
||||||
return false;
|
return false;
|
||||||
|
@ -2086,7 +2086,7 @@ class Database {
|
||||||
$articles = array_column($articles, "id");
|
$articles = array_column($articles, "id");
|
||||||
}
|
}
|
||||||
// prepare up to three queries: removing requires one, adding two, and replacing three
|
// prepare up to three queries: removing requires one, adding two, and replacing three
|
||||||
list($inClause, $inTypes, $inValues) = $this->generateIn($articles, "int");
|
[$inClause, $inTypes, $inValues] = $this->generateIn($articles, "int");
|
||||||
$updateQ = "UPDATE arsse_label_members set assigned = ?, modified = CURRENT_TIMESTAMP where label = ? and assigned <> ? and article %in% ($inClause)";
|
$updateQ = "UPDATE arsse_label_members set assigned = ?, modified = CURRENT_TIMESTAMP where label = ? and assigned <> ? and article %in% ($inClause)";
|
||||||
$updateT = ["bool", "int", "bool", $inTypes];
|
$updateT = ["bool", "int", "bool", $inTypes];
|
||||||
$insertQ = "INSERT INTO arsse_label_members(label,article,subscription) SELECT ?,a.id,s.id from arsse_articles as a join arsse_subscriptions as s on a.feed = s.feed where s.owner = ? and a.id not in (select article from arsse_label_members where label = ?) and a.id in ($inClause)";
|
$insertQ = "INSERT INTO arsse_label_members(label,article,subscription) SELECT ?,a.id,s.id from arsse_articles as a join arsse_subscriptions as s on a.feed = s.feed where s.owner = ? and a.id not in (select article from arsse_label_members where label = ?) and a.id in ($inClause)";
|
||||||
|
@ -2112,7 +2112,7 @@ class Database {
|
||||||
// execute them in a transaction
|
// execute them in a transaction
|
||||||
$out = 0;
|
$out = 0;
|
||||||
$tr = $this->begin();
|
$tr = $this->begin();
|
||||||
foreach ($qList as list($q, $t, $v)) {
|
foreach ($qList as [$q, $t, $v]) {
|
||||||
$out += $this->db->prepare($q, ...$t)->run(...$v)->changes();
|
$out += $this->db->prepare($q, ...$t)->run(...$v)->changes();
|
||||||
}
|
}
|
||||||
$tr->commit();
|
$tr->commit();
|
||||||
|
@ -2321,7 +2321,7 @@ class Database {
|
||||||
$valid = [
|
$valid = [
|
||||||
'name' => "str",
|
'name' => "str",
|
||||||
];
|
];
|
||||||
list($setClause, $setTypes, $setValues) = $this->generateSet($data, $valid);
|
[$setClause, $setTypes, $setValues] = $this->generateSet($data, $valid);
|
||||||
if (!$setClause) {
|
if (!$setClause) {
|
||||||
// if no changes would actually be applied, just return
|
// if no changes would actually be applied, just return
|
||||||
return false;
|
return false;
|
||||||
|
@ -2385,7 +2385,7 @@ class Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prepare up to three queries: removing requires one, adding two, and replacing three
|
// prepare up to three queries: removing requires one, adding two, and replacing three
|
||||||
list($inClause, $inTypes, $inValues) = $this->generateIn($subscriptions, "int");
|
[$inClause, $inTypes, $inValues] = $this->generateIn($subscriptions, "int");
|
||||||
$updateQ = "UPDATE arsse_tag_members set assigned = ?, modified = CURRENT_TIMESTAMP where tag = ? and assigned <> ? and subscription in (select id from arsse_subscriptions where owner = ? and id %in% ($inClause))";
|
$updateQ = "UPDATE arsse_tag_members set assigned = ?, modified = CURRENT_TIMESTAMP where tag = ? and assigned <> ? and subscription in (select id from arsse_subscriptions where owner = ? and id %in% ($inClause))";
|
||||||
$updateT = ["bool", "int", "bool", "str", $inTypes];
|
$updateT = ["bool", "int", "bool", "str", $inTypes];
|
||||||
$insertQ = "INSERT INTO arsse_tag_members(tag,subscription) SELECT ?,id from arsse_subscriptions where id not in (select subscription from arsse_tag_members where tag = ?) and owner = ? and id in ($inClause)";
|
$insertQ = "INSERT INTO arsse_tag_members(tag,subscription) SELECT ?,id from arsse_subscriptions where id not in (select subscription from arsse_tag_members where tag = ?) and owner = ? and id in ($inClause)";
|
||||||
|
@ -2411,7 +2411,7 @@ class Database {
|
||||||
// execute them in a transaction
|
// execute them in a transaction
|
||||||
$out = 0;
|
$out = 0;
|
||||||
$tr = $this->begin();
|
$tr = $this->begin();
|
||||||
foreach ($qList as list($q, $t, $v)) {
|
foreach ($qList as [$q, $t, $v]) {
|
||||||
$out += $this->db->prepare($q, ...$t)->run(...$v)->changes();
|
$out += $this->db->prepare($q, ...$t)->run(...$v)->changes();
|
||||||
}
|
}
|
||||||
$tr->commit();
|
$tr->commit();
|
||||||
|
|
|
@ -40,9 +40,9 @@ abstract class AbstractDriver implements Driver {
|
||||||
throw new Exception("updateFileUnreadable", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
throw new Exception("updateFileUnreadable", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
}
|
}
|
||||||
$sql = @file_get_contents($file);
|
$sql = @file_get_contents($file);
|
||||||
if ($sql===false) {
|
if ($sql === false) {
|
||||||
throw new Exception("updateFileUnusable", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]); // @codeCoverageIgnore
|
throw new Exception("updateFileUnusable", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]); // @codeCoverageIgnore
|
||||||
} elseif ($sql==="") {
|
} elseif ($sql === "") {
|
||||||
throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -50,7 +50,7 @@ abstract class AbstractDriver implements Driver {
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
throw new Exception("updateFileError", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a, 'message' => $e->getMessage()]);
|
throw new Exception("updateFileError", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a, 'message' => $e->getMessage()]);
|
||||||
}
|
}
|
||||||
if ($this->schemaVersion() != $a+1) {
|
if ($this->schemaVersion() != $a + 1) {
|
||||||
throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
throw new Exception("updateFileIncomplete", ['file' => $file, 'driver_name' => $this->driverName(), 'current' => $a]);
|
||||||
}
|
}
|
||||||
} catch (\Throwable $e) {
|
} catch (\Throwable $e) {
|
||||||
|
|
|
@ -13,12 +13,12 @@ abstract class AbstractStatement implements Statement {
|
||||||
use SQLState;
|
use SQLState;
|
||||||
|
|
||||||
const TYPE_NORM_MAP = [
|
const TYPE_NORM_MAP = [
|
||||||
self::T_INTEGER => ValueInfo::M_NULL | ValueInfo::T_INT,
|
self::T_INTEGER => ValueInfo::M_NULL | ValueInfo::T_INT,
|
||||||
self::T_STRING => ValueInfo::M_NULL | ValueInfo::T_STRING,
|
self::T_STRING => ValueInfo::M_NULL | ValueInfo::T_STRING,
|
||||||
self::T_BOOLEAN => ValueInfo::M_NULL | ValueInfo::T_BOOL,
|
self::T_BOOLEAN => ValueInfo::M_NULL | ValueInfo::T_BOOL,
|
||||||
self::T_DATETIME => ValueInfo::M_NULL | ValueInfo::T_DATE,
|
self::T_DATETIME => ValueInfo::M_NULL | ValueInfo::T_DATE,
|
||||||
self::T_FLOAT => ValueInfo::M_NULL | ValueInfo::T_FLOAT,
|
self::T_FLOAT => ValueInfo::M_NULL | ValueInfo::T_FLOAT,
|
||||||
self::T_BINARY => ValueInfo::M_NULL | ValueInfo::T_STRING,
|
self::T_BINARY => ValueInfo::M_NULL | ValueInfo::T_STRING,
|
||||||
self::T_NOT_NULL + self::T_INTEGER => ValueInfo::T_INT,
|
self::T_NOT_NULL + self::T_INTEGER => ValueInfo::T_INT,
|
||||||
self::T_NOT_NULL + self::T_STRING => ValueInfo::T_STRING,
|
self::T_NOT_NULL + self::T_STRING => ValueInfo::T_STRING,
|
||||||
self::T_NOT_NULL + self::T_BOOLEAN => ValueInfo::T_BOOL,
|
self::T_NOT_NULL + self::T_BOOLEAN => ValueInfo::T_BOOL,
|
||||||
|
@ -78,7 +78,7 @@ abstract class AbstractStatement implements Statement {
|
||||||
$value = $this->cast($value, $this->types[$a]);
|
$value = $this->cast($value, $this->types[$a]);
|
||||||
$this->bindValue($value, $this->types[$a] % self::T_NOT_NULL, ++$a);
|
$this->bindValue($value, $this->types[$a] % self::T_NOT_NULL, ++$a);
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("paramTypeMissing", $a+1);
|
throw new Exception("paramTypeMissing", $a + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// once all values are bound, check that all parameters have been supplied values and bind null for any missing ones
|
// once all values are bound, check that all parameters have been supplied values and bind null for any missing ones
|
||||||
|
|
|
@ -163,7 +163,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
$this->db->options(\MYSQLI_OPT_CONNECT_TIMEOUT, ceil(Arsse::$conf->dbTimeoutConnect));
|
$this->db->options(\MYSQLI_OPT_CONNECT_TIMEOUT, ceil(Arsse::$conf->dbTimeoutConnect));
|
||||||
@$this->db->real_connect($host, $user, $password, $db, $port, $socket);
|
@$this->db->real_connect($host, $user, $password, $db, $port, $socket);
|
||||||
if ($this->db->connect_errno) {
|
if ($this->db->connect_errno) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildConnectionException($this->db->connect_errno, $this->db->connect_error);
|
[$excClass, $excMsg, $excData] = $this->buildConnectionException($this->db->connect_errno, $this->db->connect_error);
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
$this->db->set_charset("utf8mb4");
|
$this->db->set_charset("utf8mb4");
|
||||||
|
@ -184,11 +184,11 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
do {
|
do {
|
||||||
if ($this->db->sqlstate !== "00000") {
|
if ($this->db->sqlstate !== "00000") {
|
||||||
if ($this->db->sqlstate === "HY000") {
|
if ($this->db->sqlstate === "HY000") {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildEngineException($this->db->errno, $this->db->error);
|
[$excClass, $excMsg, $excData] = $this->buildEngineException($this->db->errno, $this->db->error);
|
||||||
} else {
|
} else {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildStandardException($this->db->sqlstate, $this->db->error);
|
[$excClass, $excMsg, $excData] = $this->buildStandardException($this->db->sqlstate, $this->db->error);
|
||||||
}
|
}
|
||||||
$e = new $excClass($excMsg, $excData, $e);
|
$e = new $excClass($excMsg, $excData, $e);
|
||||||
}
|
}
|
||||||
$r = $this->db->store_result();
|
$r = $this->db->store_result();
|
||||||
} while ($this->db->more_results() && $this->db->next_result());
|
} while ($this->db->more_results() && $this->db->next_result());
|
||||||
|
|
|
@ -34,7 +34,7 @@ class PDODriver extends Driver {
|
||||||
$msg = $e->getMessage();
|
$msg = $e->getMessage();
|
||||||
$code = (int) substr($msg, 17, 4);
|
$code = (int) substr($msg, 17, 4);
|
||||||
$msg = substr($msg, 23);
|
$msg = substr($msg, 23);
|
||||||
list($excClass, $excMsg, $excData) = $this->buildConnectionException($code, $msg);
|
[$excClass, $excMsg, $excData] = $this->buildConnectionException($code, $msg);
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,6 @@ class Result extends \JKingWeb\Arsse\Db\AbstractResult {
|
||||||
|
|
||||||
public function valid() {
|
public function valid() {
|
||||||
$this->cur = $this->set ? $this->set->fetch_assoc() : null;
|
$this->cur = $this->set ? $this->set->fetch_assoc() : null;
|
||||||
return ($this->cur !== null);
|
return $this->cur !== null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Statement extends \JKingWeb\Arsse\Db\AbstractStatement {
|
||||||
protected function prepare(string $query): bool {
|
protected function prepare(string $query): bool {
|
||||||
$this->st = $this->db->prepare($query);
|
$this->st = $this->db->prepare($query);
|
||||||
if (!$this->st) { // @codeCoverageIgnore
|
if (!$this->st) { // @codeCoverageIgnore
|
||||||
list($excClass, $excMsg, $excData) = $this->buildEngineException($this->db->errno, $this->db->error); // @codeCoverageIgnore
|
[$excClass, $excMsg, $excData] = $this->buildEngineException($this->db->errno, $this->db->error); // @codeCoverageIgnore
|
||||||
throw new $excClass($excMsg, $excData); // @codeCoverageIgnore
|
throw new $excClass($excMsg, $excData); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -76,9 +76,9 @@ class Statement extends \JKingWeb\Arsse\Db\AbstractStatement {
|
||||||
// check for errors
|
// check for errors
|
||||||
if ($this->st->sqlstate !== "00000") {
|
if ($this->st->sqlstate !== "00000") {
|
||||||
if ($this->st->sqlstate === "HY000") {
|
if ($this->st->sqlstate === "HY000") {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildEngineException($this->st->errno, $this->st->error);
|
[$excClass, $excMsg, $excData] = $this->buildEngineException($this->st->errno, $this->st->error);
|
||||||
} else {
|
} else {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildStandardException($this->st->sqlstate, $this->st->error);
|
[$excClass, $excMsg, $excData] = $this->buildStandardException($this->st->sqlstate, $this->st->error);
|
||||||
}
|
}
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ trait PDODriver {
|
||||||
$this->db->exec($query);
|
$this->db->exec($query);
|
||||||
return true;
|
return true;
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildPDOException();
|
[$excClass, $excMsg, $excData] = $this->buildPDOException();
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ trait PDODriver {
|
||||||
try {
|
try {
|
||||||
$r = $this->db->query($query);
|
$r = $this->db->query($query);
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildPDOException();
|
[$excClass, $excMsg, $excData] = $this->buildPDOException();
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
return new PDOResult($this->db, $r);
|
return new PDOResult($this->db, $r);
|
||||||
|
|
|
@ -45,6 +45,6 @@ class PDOResult extends AbstractResult {
|
||||||
|
|
||||||
public function valid() {
|
public function valid() {
|
||||||
$this->cur = $this->set->fetch(\PDO::FETCH_ASSOC);
|
$this->cur = $this->set->fetch(\PDO::FETCH_ASSOC);
|
||||||
return ($this->cur !== false);
|
return $this->cur !== false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ abstract class PDOStatement extends AbstractStatement {
|
||||||
$this->st = $this->db->prepare($query);
|
$this->st = $this->db->prepare($query);
|
||||||
return true;
|
return true;
|
||||||
} catch (\PDOException $e) { // @codeCoverageIgnore
|
} catch (\PDOException $e) { // @codeCoverageIgnore
|
||||||
list($excClass, $excMsg, $excData) = $this->buildPDOException(); // @codeCoverageIgnore
|
[$excClass, $excMsg, $excData] = $this->buildPDOException(); // @codeCoverageIgnore
|
||||||
throw new $excClass($excMsg, $excData); // @codeCoverageIgnore
|
throw new $excClass($excMsg, $excData); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ abstract class PDOStatement extends AbstractStatement {
|
||||||
try {
|
try {
|
||||||
$this->st->execute();
|
$this->st->execute();
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildPDOException(true);
|
[$excClass, $excMsg, $excData] = $this->buildPDOException(true);
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
return new PDOResult($this->db, $this->st);
|
return new PDOResult($this->db, $this->st);
|
||||||
|
|
|
@ -37,9 +37,9 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
|
|
||||||
public static function makeConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service): string {
|
public static function makeConnectionString(bool $pdo, string $user, string $pass, string $db, string $host, int $port, string $service): string {
|
||||||
$base = [
|
$base = [
|
||||||
'client_encoding' => "UTF8",
|
'client_encoding' => "UTF8",
|
||||||
'application_name' => "arsse",
|
'application_name' => "arsse",
|
||||||
'connect_timeout' => (string) (int) ceil(Arsse::$conf->dbTimeoutConnect),
|
'connect_timeout' => (string) (int) ceil(Arsse::$conf->dbTimeoutConnect),
|
||||||
];
|
];
|
||||||
$out = [];
|
$out = [];
|
||||||
if ($service != "") {
|
if ($service != "") {
|
||||||
|
@ -198,7 +198,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
pg_send_query($this->db, $query);
|
pg_send_query($this->db, $query);
|
||||||
while ($result = pg_get_result($this->db)) {
|
while ($result = pg_get_result($this->db)) {
|
||||||
if (($code = pg_result_error_field($result, \PGSQL_DIAG_SQLSTATE)) && isset($code) && $code) {
|
if (($code = pg_result_error_field($result, \PGSQL_DIAG_SQLSTATE)) && isset($code) && $code) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildStandardException($code, pg_result_error($result));
|
[$excClass, $excMsg, $excData] = $this->buildStandardException($code, pg_result_error($result));
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
if (is_resource($r)) {
|
if (is_resource($r)) {
|
||||||
return new Result($this->db, $r);
|
return new Result($this->db, $r);
|
||||||
} else {
|
} else {
|
||||||
list($excClass, $excMsg, $excData) = $r;
|
[$excClass, $excMsg, $excData] = $r;
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ class PDODriver extends Driver {
|
||||||
$dsn = $this->makeconnectionString(true, $user, $pass, $db, $host, $port, $service);
|
$dsn = $this->makeconnectionString(true, $user, $pass, $db, $host, $port, $service);
|
||||||
try {
|
try {
|
||||||
$this->db = new \PDO("pgsql:$dsn", $user, $pass, [
|
$this->db = new \PDO("pgsql:$dsn", $user, $pass, [
|
||||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||||
\PDO::ATTR_PERSISTENT => true,
|
\PDO::ATTR_PERSISTENT => true,
|
||||||
]);
|
]);
|
||||||
} catch (\PDOException $e) {
|
} catch (\PDOException $e) {
|
||||||
|
@ -53,7 +53,6 @@ class PDODriver extends Driver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function driverName(): string {
|
public static function driverName(): string {
|
||||||
return Arsse::$lang->msg("Driver.Db.PostgreSQLPDO.Name");
|
return Arsse::$lang->msg("Driver.Db.PostgreSQLPDO.Name");
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,6 @@ class Result extends \JKingWeb\Arsse\Db\AbstractResult {
|
||||||
|
|
||||||
public function valid() {
|
public function valid() {
|
||||||
$this->cur = pg_fetch_row($this->r, null, \PGSQL_ASSOC);
|
$this->cur = pg_fetch_row($this->r, null, \PGSQL_ASSOC);
|
||||||
return ($this->cur !== false);
|
return $this->cur !== false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ class Statement extends \JKingWeb\Arsse\Db\AbstractStatement {
|
||||||
if (is_resource($r)) {
|
if (is_resource($r)) {
|
||||||
return new Result($this->db, $r);
|
return new Result($this->db, $r);
|
||||||
} else {
|
} else {
|
||||||
list($excClass, $excMsg, $excData) = $r;
|
[$excClass, $excMsg, $excData] = $r;
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\Db;
|
namespace JKingWeb\Arsse\Db;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Db\Exception;
|
|
||||||
use JKingWeb\Arsse\Db\ExceptionInput;
|
|
||||||
use JKingWeb\Arsse\Db\ExceptionTimeout;
|
|
||||||
|
|
||||||
trait SQLState {
|
trait SQLState {
|
||||||
protected static function buildStandardException(string $code, string $msg): array {
|
protected static function buildStandardException(string $code, string $msg): array {
|
||||||
switch ($code) {
|
switch ($code) {
|
||||||
|
|
|
@ -98,7 +98,6 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function driverName(): string {
|
public static function driverName(): string {
|
||||||
return Arsse::$lang->msg("Driver.Db.SQLite3.Name");
|
return Arsse::$lang->msg("Driver.Db.SQLite3.Name");
|
||||||
}
|
}
|
||||||
|
@ -146,7 +145,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
try {
|
try {
|
||||||
return (bool) $this->db->exec($query);
|
return (bool) $this->db->exec($query);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildException();
|
[$excClass, $excMsg, $excData] = $this->buildException();
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,7 +154,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
|
||||||
try {
|
try {
|
||||||
$r = $this->db->query($query);
|
$r = $this->db->query($query);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildException();
|
[$excClass, $excMsg, $excData] = $this->buildException();
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
$changes = $this->db->changes();
|
$changes = $this->db->changes();
|
||||||
|
|
|
@ -37,7 +37,6 @@ class PDODriver extends AbstractPDODriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static function driverName(): string {
|
public static function driverName(): string {
|
||||||
return Arsse::$lang->msg("Driver.Db.SQLite3PDO.Name");
|
return Arsse::$lang->msg("Driver.Db.SQLite3PDO.Name");
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,6 @@ class Result extends \JKingWeb\Arsse\Db\AbstractResult {
|
||||||
|
|
||||||
public function valid() {
|
public function valid() {
|
||||||
$this->cur = $this->set->fetchArray(\SQLITE3_ASSOC);
|
$this->cur = $this->set->fetchArray(\SQLITE3_ASSOC);
|
||||||
return ($this->cur !== false);
|
return $this->cur !== false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ class Statement extends \JKingWeb\Arsse\Db\AbstractStatement {
|
||||||
$this->st = $this->db->prepare($query);
|
$this->st = $this->db->prepare($query);
|
||||||
return true;
|
return true;
|
||||||
} catch (\Exception $e) { // @codeCoverageIgnore
|
} catch (\Exception $e) { // @codeCoverageIgnore
|
||||||
list($excClass, $excMsg, $excData) = $this->buildException(); // @codeCoverageIgnore
|
[$excClass, $excMsg, $excData] = $this->buildException(); // @codeCoverageIgnore
|
||||||
throw new $excClass($excMsg, $excData); // @codeCoverageIgnore
|
throw new $excClass($excMsg, $excData); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class Statement extends \JKingWeb\Arsse\Db\AbstractStatement {
|
||||||
try {
|
try {
|
||||||
$r = $this->st->execute();
|
$r = $this->st->execute();
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
list($excClass, $excMsg, $excData) = $this->buildException();
|
[$excClass, $excMsg, $excData] = $this->buildException();
|
||||||
throw new $excClass($excMsg, $excData);
|
throw new $excClass($excMsg, $excData);
|
||||||
}
|
}
|
||||||
$changes = $this->db->changes();
|
$changes = $this->db->changes();
|
||||||
|
|
16
lib/Feed.php
16
lib/Feed.php
|
@ -221,8 +221,8 @@ class Feed {
|
||||||
// if the two items have the same ID or any one hash matches, they are two versions of the same item
|
// if the two items have the same ID or any one hash matches, they are two versions of the same item
|
||||||
if (
|
if (
|
||||||
($item->id && $check->id && $item->id === $check->id) ||
|
($item->id && $check->id && $item->id === $check->id) ||
|
||||||
($item->urlTitleHash && $item->urlTitleHash === $check->urlTitleHash) ||
|
($item->urlTitleHash && $item->urlTitleHash === $check->urlTitleHash) ||
|
||||||
($item->urlContentHash && $item->urlContentHash === $check->urlContentHash) ||
|
($item->urlContentHash && $item->urlContentHash === $check->urlContentHash) ||
|
||||||
($item->titleContentHash && $item->titleContentHash === $check->titleContentHash)
|
($item->titleContentHash && $item->titleContentHash === $check->titleContentHash)
|
||||||
) {
|
) {
|
||||||
if (// because newsfeeds are usually order newest-first, the later item should only be used if...
|
if (// because newsfeeds are usually order newest-first, the later item should only be used if...
|
||||||
|
@ -259,7 +259,7 @@ class Feed {
|
||||||
// get as many of the latest articles in the database as there are in the feed
|
// get as many of the latest articles in the database as there are in the feed
|
||||||
$articles = Arsse::$db->feedMatchLatest($feedID, sizeof($items))->getAll();
|
$articles = Arsse::$db->feedMatchLatest($feedID, sizeof($items))->getAll();
|
||||||
// perform a first pass matching the latest articles against items in the feed
|
// perform a first pass matching the latest articles against items in the feed
|
||||||
list($this->newItems, $this->changedItems) = $this->matchItems($items, $articles);
|
[$this->newItems, $this->changedItems] = $this->matchItems($items, $articles);
|
||||||
if (sizeof($this->newItems) && sizeof($items) <= sizeof($articles)) {
|
if (sizeof($this->newItems) && sizeof($items) <= sizeof($articles)) {
|
||||||
// if we need to, perform a second pass on the database looking specifically for IDs and hashes of the new items
|
// if we need to, perform a second pass on the database looking specifically for IDs and hashes of the new items
|
||||||
$ids = $hashesUT = $hashesUC = $hashesTC = [];
|
$ids = $hashesUT = $hashesUC = $hashesTC = [];
|
||||||
|
@ -278,7 +278,7 @@ class Feed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$articles = Arsse::$db->feedMatchIds($feedID, $ids, $hashesUT, $hashesUC, $hashesTC)->getAll();
|
$articles = Arsse::$db->feedMatchIds($feedID, $ids, $hashesUT, $hashesUC, $hashesTC)->getAll();
|
||||||
list($this->newItems, $changed) = $this->matchItems($this->newItems, $articles);
|
[$this->newItems, $changed] = $this->matchItems($this->newItems, $articles);
|
||||||
// merge the two change-lists, preserving keys
|
// merge the two change-lists, preserving keys
|
||||||
$this->changedItems = array_combine(array_merge(array_keys($this->changedItems), array_keys($changed)), array_merge($this->changedItems, $changed));
|
$this->changedItems = array_combine(array_merge(array_keys($this->changedItems), array_keys($changed)), array_merge($this->changedItems, $changed));
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,7 @@ class Feed {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function matchItems(array $items, array $articles): array {
|
protected function matchItems(array $items, array $articles): array {
|
||||||
$new = $edited = [];
|
$new = $edited = [];
|
||||||
// iterate through the articles and for each determine whether it is existing, edited, or entirely new
|
// iterate through the articles and for each determine whether it is existing, edited, or entirely new
|
||||||
foreach ($items as $i) {
|
foreach ($items as $i) {
|
||||||
$found = false;
|
$found = false;
|
||||||
|
@ -299,8 +299,8 @@ class Feed {
|
||||||
// the item matches if the GUID matches...
|
// the item matches if the GUID matches...
|
||||||
($i->id && $i->id === $a['guid']) ||
|
($i->id && $i->id === $a['guid']) ||
|
||||||
// ... or if any one of the hashes match
|
// ... or if any one of the hashes match
|
||||||
($i->urlTitleHash && $i->urlTitleHash === $a['url_title_hash']) ||
|
($i->urlTitleHash && $i->urlTitleHash === $a['url_title_hash']) ||
|
||||||
($i->urlContentHash && $i->urlContentHash === $a['url_content_hash']) ||
|
($i->urlContentHash && $i->urlContentHash === $a['url_content_hash']) ||
|
||||||
($i->titleContentHash && $i->titleContentHash === $a['title_content_hash'])
|
($i->titleContentHash && $i->titleContentHash === $a['title_content_hash'])
|
||||||
) {
|
) {
|
||||||
if ($i->updatedDate && Date::transform($i->updatedDate, "sql") !== $a['edited']) {
|
if ($i->updatedDate && Date::transform($i->updatedDate, "sql") !== $a['edited']) {
|
||||||
|
@ -348,7 +348,7 @@ class Feed {
|
||||||
$dates = $this->gatherDates();
|
$dates = $this->gatherDates();
|
||||||
if (sizeof($dates) > 3) {
|
if (sizeof($dates) > 3) {
|
||||||
for ($a = 0; $a < 3; $a++) {
|
for ($a = 0; $a < 3; $a++) {
|
||||||
$diff = $dates[$a] - $dates[$a+1];
|
$diff = $dates[$a] - $dates[$a + 1];
|
||||||
$offsets[] = $this->normalizeDateDiff($diff);
|
$offsets[] = $this->normalizeDateDiff($diff);
|
||||||
}
|
}
|
||||||
if ($offsets[0] === $offsets[1] || $offsets[0] === $offsets[2]) {
|
if ($offsets[0] === $offsets[1] || $offsets[0] === $offsets[2]) {
|
||||||
|
|
|
@ -12,8 +12,8 @@ use GuzzleHttp\Exception\TooManyRedirectsException;
|
||||||
use PicoFeed\PicoFeedException;
|
use PicoFeed\PicoFeedException;
|
||||||
|
|
||||||
class Exception extends \JKingWeb\Arsse\AbstractException {
|
class Exception extends \JKingWeb\Arsse\AbstractException {
|
||||||
const CURL_ERROR_MAP = [1=>"invalidUrl",3=>"invalidUrl",5=>"transmissionError","connectionFailed","connectionFailed","transmissionError","forbidden","unauthorized","transmissionError","transmissionError","transmissionError","transmissionError","connectionFailed","connectionFailed","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError","invalidUrl","transmissionError","transmissionError","transmissionError","transmissionError",28=>"timeout","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError",35=>"invalidCertificate","transmissionError","transmissionError","transmissionError","transmissionError",45=>"transmissionError","unauthorized","maxRedirect",52=>"transmissionError","invalidCertificate","invalidCertificate","transmissionError","transmissionError",58=>"invalidCertificate","invalidCertificate","invalidCertificate","transmissionError","invalidUrl","transmissionError","invalidCertificate","transmissionError","invalidCertificate","forbidden","invalidUrl","forbidden","transmissionError",73=>"transmissionError","transmissionError",77=>"invalidCertificate","invalidUrl",90=>"invalidCertificate","invalidCertificate","transmissionError",94=>"unauthorized","transmissionError","connectionFailed"];
|
const CURL_ERROR_MAP = [1 => "invalidUrl",3 => "invalidUrl",5 => "transmissionError","connectionFailed","connectionFailed","transmissionError","forbidden","unauthorized","transmissionError","transmissionError","transmissionError","transmissionError","connectionFailed","connectionFailed","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError","invalidUrl","transmissionError","transmissionError","transmissionError","transmissionError",28 => "timeout","transmissionError","transmissionError","transmissionError","transmissionError","transmissionError",35 => "invalidCertificate","transmissionError","transmissionError","transmissionError","transmissionError",45 => "transmissionError","unauthorized","maxRedirect",52 => "transmissionError","invalidCertificate","invalidCertificate","transmissionError","transmissionError",58 => "invalidCertificate","invalidCertificate","invalidCertificate","transmissionError","invalidUrl","transmissionError","invalidCertificate","transmissionError","invalidCertificate","forbidden","invalidUrl","forbidden","transmissionError",73 => "transmissionError","transmissionError",77 => "invalidCertificate","invalidUrl",90 => "invalidCertificate","invalidCertificate","transmissionError",94 => "unauthorized","transmissionError","connectionFailed"];
|
||||||
const HTTP_ERROR_MAP = [401=>"unauthorized",403=>"forbidden",404=>"invalidUrl",408=>"timeout",410=>"invalidUrl",414=>"invalidUrl",451=>"invalidUrl"];
|
const HTTP_ERROR_MAP = [401 => "unauthorized",403 => "forbidden",404 => "invalidUrl",408 => "timeout",410 => "invalidUrl",414 => "invalidUrl",451 => "invalidUrl"];
|
||||||
|
|
||||||
public function __construct($url, \Throwable $e) {
|
public function __construct($url, \Throwable $e) {
|
||||||
if ($e instanceof BadResponseException) {
|
if ($e instanceof BadResponseException) {
|
||||||
|
|
|
@ -17,7 +17,7 @@ abstract class AbstractImportExport {
|
||||||
throw new UserException("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
|
throw new UserException("doesNotExist", ["action" => __FUNCTION__, "user" => $user]);
|
||||||
}
|
}
|
||||||
// first extract useful information from the input
|
// first extract useful information from the input
|
||||||
list($feeds, $folders) = $this->parse($data, $flat);
|
[$feeds, $folders] = $this->parse($data, $flat);
|
||||||
$folderMap = [];
|
$folderMap = [];
|
||||||
foreach ($folders as $f) {
|
foreach ($folders as $f) {
|
||||||
// check to make sure folder names are all valid
|
// check to make sure folder names are all valid
|
||||||
|
@ -42,7 +42,7 @@ abstract class AbstractImportExport {
|
||||||
$tr = Arsse::$db->begin();
|
$tr = Arsse::$db->begin();
|
||||||
// get current state of database
|
// get current state of database
|
||||||
$foldersDb = iterator_to_array(Arsse::$db->folderList($user));
|
$foldersDb = iterator_to_array(Arsse::$db->folderList($user));
|
||||||
$feedsDb = iterator_to_array(Arsse::$db->subscriptionList($user));
|
$feedsDb = iterator_to_array(Arsse::$db->subscriptionList($user));
|
||||||
$tagsDb = iterator_to_array(Arsse::$db->tagList($user));
|
$tagsDb = iterator_to_array(Arsse::$db->tagList($user));
|
||||||
// reconcile folders
|
// reconcile folders
|
||||||
$folderMap = [0 => 0];
|
$folderMap = [0 => 0];
|
||||||
|
|
|
@ -97,7 +97,7 @@ class Lang {
|
||||||
}
|
}
|
||||||
$msg = $this->strings[$msgID];
|
$msg = $this->strings[$msgID];
|
||||||
// variables fed to MessageFormatter must be contained in an array
|
// variables fed to MessageFormatter must be contained in an array
|
||||||
if ($vars===null) {
|
if ($vars === null) {
|
||||||
// even though strings not given parameters will not get formatted, we do not optimize this case away: we still want to catch invalid strings
|
// even though strings not given parameters will not get formatted, we do not optimize this case away: we still want to catch invalid strings
|
||||||
$vars = [];
|
$vars = [];
|
||||||
} elseif (!is_array($vars)) {
|
} elseif (!is_array($vars)) {
|
||||||
|
@ -108,7 +108,7 @@ class Lang {
|
||||||
throw new Lang\Exception("stringInvalid", ['error' => $this->formatter->getErrorMessage(), 'msgID' => $msgID, 'fileList' => implode(", ", $this->loaded)]);
|
throw new Lang\Exception("stringInvalid", ['error' => $this->formatter->getErrorMessage(), 'msgID' => $msgID, 'fileList' => implode(", ", $this->loaded)]);
|
||||||
}
|
}
|
||||||
$msg = $this->formatter->format($vars);
|
$msg = $this->formatter->format($vars);
|
||||||
if ($msg===false) {
|
if ($msg === false) {
|
||||||
throw new Lang\Exception("dataInvalid", ['error' => $this->formatter->getErrorMessage(), 'msgID' => $msgID, 'fileList' => implode(", ", $this->loaded)]); // @codeCoverageIgnore
|
throw new Lang\Exception("dataInvalid", ['error' => $this->formatter->getErrorMessage(), 'msgID' => $msgID, 'fileList' => implode(", ", $this->loaded)]); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
return $msg;
|
return $msg;
|
||||||
|
@ -148,7 +148,7 @@ class Lang {
|
||||||
// trim the returned file paths to return just the language tag
|
// trim the returned file paths to return just the language tag
|
||||||
$out = array_map(function($file) {
|
$out = array_map(function($file) {
|
||||||
$file = str_replace(DIRECTORY_SEPARATOR, "/", $file); // we replace the directory separator because we don't use native paths in testing
|
$file = str_replace(DIRECTORY_SEPARATOR, "/", $file); // we replace the directory separator because we don't use native paths in testing
|
||||||
$file = substr($file, strrpos($file, "/")+1);
|
$file = substr($file, strrpos($file, "/") + 1);
|
||||||
return strtolower(substr($file, 0, strrpos($file, ".")));
|
return strtolower(substr($file, 0, strrpos($file, ".")));
|
||||||
}, $out);
|
}, $out);
|
||||||
// sort the results
|
// sort the results
|
||||||
|
|
|
@ -24,7 +24,6 @@ class Query {
|
||||||
protected $limit = 0;
|
protected $limit = 0;
|
||||||
protected $offset = 0;
|
protected $offset = 0;
|
||||||
|
|
||||||
|
|
||||||
public function __construct(string $body = "", $types = null, $values = null) {
|
public function __construct(string $body = "", $types = null, $values = null) {
|
||||||
$this->setBody($body, $types, $values);
|
$this->setBody($body, $types, $values);
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ class URL {
|
||||||
$c = $part[$pos];
|
$c = $part[$pos];
|
||||||
if ($c === "%") {
|
if ($c === "%") {
|
||||||
// the % character signals an encoded character...
|
// the % character signals an encoded character...
|
||||||
$d = substr($part, $pos+1, 2);
|
$d = substr($part, $pos + 1, 2);
|
||||||
if (!preg_match("/^[0-9a-fA-F]{2}$/", $d)) {
|
if (!preg_match("/^[0-9a-fA-F]{2}$/", $d)) {
|
||||||
// unless there are fewer than two characters left in the string or the two characters are not hex digits
|
// unless there are fewer than two characters left in the string or the two characters are not hex digits
|
||||||
$d = ord($c);
|
$d = ord($c);
|
||||||
|
|
|
@ -11,30 +11,30 @@ use JKingWeb\Arsse\ExceptionType;
|
||||||
class ValueInfo {
|
class ValueInfo {
|
||||||
// universal
|
// universal
|
||||||
const VALID = 1 << 0;
|
const VALID = 1 << 0;
|
||||||
const NULL = 1 << 1;
|
const NULL = 1 << 1;
|
||||||
// integers
|
// integers
|
||||||
const ZERO = 1 << 2;
|
const ZERO = 1 << 2;
|
||||||
const NEG = 1 << 3;
|
const NEG = 1 << 3;
|
||||||
const FLOAT = 1 << 4;
|
const FLOAT = 1 << 4;
|
||||||
// strings
|
// strings
|
||||||
const EMPTY = 1 << 2;
|
const EMPTY = 1 << 2;
|
||||||
const WHITE = 1 << 3;
|
const WHITE = 1 << 3;
|
||||||
// normalization types
|
// normalization types
|
||||||
const T_MIXED = 0; // pass through unchanged
|
const T_MIXED = 0; // pass through unchanged
|
||||||
const T_NULL = 1; // convert to null
|
const T_NULL = 1; // convert to null
|
||||||
const T_BOOL = 2; // convert to boolean
|
const T_BOOL = 2; // convert to boolean
|
||||||
const T_INT = 3; // convert to integer
|
const T_INT = 3; // convert to integer
|
||||||
const T_FLOAT = 4; // convert to floating point
|
const T_FLOAT = 4; // convert to floating point
|
||||||
const T_DATE = 5; // convert to DateTimeInterface instance
|
const T_DATE = 5; // convert to DateTimeInterface instance
|
||||||
const T_STRING = 6; // convert to string
|
const T_STRING = 6; // convert to string
|
||||||
const T_ARRAY = 7; // convert to array
|
const T_ARRAY = 7; // convert to array
|
||||||
const T_INTERVAL = 8; // convert to time interval
|
const T_INTERVAL = 8; // convert to time interval
|
||||||
// normalization modes
|
// normalization modes
|
||||||
const M_LOOSE = 0;
|
const M_LOOSE = 0;
|
||||||
const M_NULL = 1 << 28; // pass nulls through regardless of target type
|
const M_NULL = 1 << 28; // pass nulls through regardless of target type
|
||||||
const M_DROP = 1 << 29; // drop the value (return null) if the type doesn't match
|
const M_DROP = 1 << 29; // drop the value (return null) if the type doesn't match
|
||||||
const M_STRICT = 1 << 30; // throw an exception if the type doesn't match
|
const M_STRICT = 1 << 30; // throw an exception if the type doesn't match
|
||||||
const M_ARRAY = 1 << 31; // the value should be a flat array of values of the specified type; indexed and associative are both acceptable
|
const M_ARRAY = 1 << 31; // the value should be a flat array of values of the specified type; indexed and associative are both acceptable
|
||||||
// symbolic date and time formats
|
// symbolic date and time formats
|
||||||
const DATE_FORMATS = [ // in out
|
const DATE_FORMATS = [ // in out
|
||||||
'iso8601' => ["!Y-m-d\TH:i:s", "Y-m-d\TH:i:s\Z" ], // NOTE: ISO 8601 dates require special input processing because of varying formats for timezone offsets
|
'iso8601' => ["!Y-m-d\TH:i:s", "Y-m-d\TH:i:s\Z" ], // NOTE: ISO 8601 dates require special input processing because of varying formats for timezone offsets
|
||||||
|
@ -50,10 +50,10 @@ class ValueInfo {
|
||||||
|
|
||||||
public static function normalize($value, int $type, string $dateInFormat = null, $dateOutFormat = null) {
|
public static function normalize($value, int $type, string $dateInFormat = null, $dateOutFormat = null) {
|
||||||
$allowNull = ($type & self::M_NULL);
|
$allowNull = ($type & self::M_NULL);
|
||||||
$strict = ($type & (self::M_STRICT | self::M_DROP));
|
$strict = ($type & (self::M_STRICT | self::M_DROP));
|
||||||
$drop = ($type & self::M_DROP);
|
$drop = ($type & self::M_DROP);
|
||||||
$arrayVal = ($type & self::M_ARRAY);
|
$arrayVal = ($type & self::M_ARRAY);
|
||||||
$type = ($type & ~(self::M_NULL | self::M_DROP | self::M_STRICT | self::M_ARRAY));
|
$type = ($type & ~(self::M_NULL | self::M_DROP | self::M_STRICT | self::M_ARRAY));
|
||||||
// if the value is null and this is allowed, simply return
|
// if the value is null and this is allowed, simply return
|
||||||
if ($allowNull && is_null($value)) {
|
if ($allowNull && is_null($value)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -166,7 +166,7 @@ class ValueInfo {
|
||||||
throw new ExceptionType("strictFailure", $type);
|
throw new ExceptionType("strictFailure", $type);
|
||||||
}
|
}
|
||||||
$out = filter_var($value, \FILTER_VALIDATE_FLOAT);
|
$out = filter_var($value, \FILTER_VALIDATE_FLOAT);
|
||||||
if ($strict && $out===false) {
|
if ($strict && $out === false) {
|
||||||
// if strict and input is not a float, this is an error
|
// if strict and input is not a float, this is an error
|
||||||
if ($drop) {
|
if ($drop) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse;
|
namespace JKingWeb\Arsse;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Arsse;
|
|
||||||
use JKingWeb\Arsse\Misc\URL;
|
use JKingWeb\Arsse\Misc\URL;
|
||||||
use Psr\Http\Message\RequestInterface;
|
use Psr\Http\Message\RequestInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
@ -71,7 +70,7 @@ class REST {
|
||||||
$req = $req ?? ServerRequestFactory::fromGlobals();
|
$req = $req ?? ServerRequestFactory::fromGlobals();
|
||||||
// find the API to handle
|
// find the API to handle
|
||||||
try {
|
try {
|
||||||
list($api, $target, $class) = $this->apiMatch($req->getRequestTarget(), $this->apis);
|
[$api, $target, $class] = $this->apiMatch($req->getRequestTarget(), $this->apis);
|
||||||
// authenticate the request pre-emptively
|
// authenticate the request pre-emptively
|
||||||
$req = $this->authenticateRequest($req);
|
$req = $this->authenticateRequest($req);
|
||||||
// modify the request to have an uppercase method and a stripped target
|
// modify the request to have an uppercase method and a stripped target
|
||||||
|
@ -108,7 +107,7 @@ class REST {
|
||||||
// find a match
|
// find a match
|
||||||
foreach ($map as $id => $api) {
|
foreach ($map as $id => $api) {
|
||||||
// first try a simple substring match
|
// first try a simple substring match
|
||||||
if (strpos($url, $api['match'])===0) {
|
if (strpos($url, $api['match']) === 0) {
|
||||||
// if it matches, perform a more rigorous match and then strip off any defined prefix
|
// if it matches, perform a more rigorous match and then strip off any defined prefix
|
||||||
$pattern = "<^".preg_quote($api['match'])."([/\?#]|$)>";
|
$pattern = "<^".preg_quote($api['match'])."([/\?#]|$)>";
|
||||||
if ($url === $api['match'] || in_array(substr($api['match'], -1, 1), ["/", "?", "#"]) || preg_match($pattern, $url)) {
|
if ($url === $api['match'] || in_array(substr($api['match'], -1, 1), ["/", "?", "#"]) || preg_match($pattern, $url)) {
|
||||||
|
@ -200,7 +199,7 @@ class REST {
|
||||||
if ($req->hasHeader("Access-Control-Request-Headers")) {
|
if ($req->hasHeader("Access-Control-Request-Headers")) {
|
||||||
$res = $res->withHeader("Access-Control-Allow-Headers", $req->getHeaderLine("Access-Control-Request-Headers"));
|
$res = $res->withHeader("Access-Control-Allow-Headers", $req->getHeaderLine("Access-Control-Request-Headers"));
|
||||||
}
|
}
|
||||||
$res = $res->withHeader("Access-Control-Max-Age", (string) (60 *60 *24)); // one day
|
$res = $res->withHeader("Access-Control-Max-Age", (string) (60 * 60 * 24)); // one day
|
||||||
}
|
}
|
||||||
$res = $res->withHeader("Access-Control-Allow-Origin", $req->getHeaderLine("Origin"));
|
$res = $res->withHeader("Access-Control-Allow-Origin", $req->getHeaderLine("Origin"));
|
||||||
$res = $res->withHeader("Access-Control-Allow-Credentials", "true");
|
$res = $res->withHeader("Access-Control-Allow-Credentials", "true");
|
||||||
|
|
|
@ -67,7 +67,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
switch ($req->getMethod()) {
|
switch ($req->getMethod()) {
|
||||||
case "OPTIONS":
|
case "OPTIONS":
|
||||||
return new EmptyResponse(204, [
|
return new EmptyResponse(204, [
|
||||||
'Allow' => "POST",
|
'Allow' => "POST",
|
||||||
'Accept' => self::ACCEPTED_TYPE,
|
'Accept' => self::ACCEPTED_TYPE,
|
||||||
]);
|
]);
|
||||||
case "POST":
|
case "POST":
|
||||||
|
@ -76,7 +76,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
$out = [
|
$out = [
|
||||||
'api_version' => self::LEVEL,
|
'api_version' => self::LEVEL,
|
||||||
'auth' => 0,
|
'auth' => 0,
|
||||||
];
|
];
|
||||||
if ($req->getAttribute("authenticated", false)) {
|
if ($req->getAttribute("authenticated", false)) {
|
||||||
// if HTTP authentication was successfully used, set the expected user ID
|
// if HTTP authentication was successfully used, set the expected user ID
|
||||||
|
@ -153,7 +153,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// we provide a single blank favicon for now
|
// we provide a single blank favicon for now
|
||||||
$out['favicons'] = [
|
$out['favicons'] = [
|
||||||
[
|
[
|
||||||
'id' => 0,
|
'id' => 0,
|
||||||
'data' => self::GENERIC_ICON_TYPE.",".self::GENERIC_ICON_DATA,
|
'data' => self::GENERIC_ICON_TYPE.",".self::GENERIC_ICON_DATA,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -178,7 +178,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
protected function baseResponse(bool $authenticated): array {
|
protected function baseResponse(bool $authenticated): array {
|
||||||
$out = [
|
$out = [
|
||||||
'api_version' => self::LEVEL,
|
'api_version' => self::LEVEL,
|
||||||
'auth' => (int) $authenticated,
|
'auth' => (int) $authenticated,
|
||||||
];
|
];
|
||||||
if ($authenticated) {
|
if ($authenticated) {
|
||||||
// authenticated requests always include the most recent feed refresh
|
// authenticated requests always include the most recent feed refresh
|
||||||
|
@ -346,7 +346,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$out = [];
|
$out = [];
|
||||||
foreach (Arsse::$db->tagList(Arsse::$user->id) as $member) {
|
foreach (Arsse::$db->tagList(Arsse::$user->id) as $member) {
|
||||||
$out[] = [
|
$out[] = [
|
||||||
'id' => (int) $member['id'],
|
'id' => (int) $member['id'],
|
||||||
'title' => $member['name'],
|
'title' => $member['name'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -215,7 +215,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
return $feed;
|
return $feed;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function articleTranslate(array $article) :array {
|
protected function articleTranslate(array $article): array {
|
||||||
// map fields to proper names
|
// map fields to proper names
|
||||||
$article = $this->fieldMapNames($article, [
|
$article = $this->fieldMapNames($article, [
|
||||||
'id' => "edition",
|
'id' => "edition",
|
||||||
|
@ -616,7 +616,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
$c->article((int) $url[2]);
|
$c->article((int) $url[2]);
|
||||||
// determine whether to mark read or unread
|
// determine whether to mark read or unread
|
||||||
$set = ($url[3] ==="star");
|
$set = ($url[3] === "star");
|
||||||
try {
|
try {
|
||||||
Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
|
Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c);
|
||||||
} catch (ExceptionInput $e) {
|
} catch (ExceptionInput $e) {
|
||||||
|
@ -629,7 +629,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// mark an array of articles as read
|
// mark an array of articles as read
|
||||||
protected function articleMarkReadMulti(array $url, array $data): ResponseInterface {
|
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
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
$c->editions($data['items'] ?? []);
|
$c->editions($data['items'] ?? []);
|
||||||
|
@ -643,7 +643,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// mark an array of articles as starred
|
// mark an array of articles as starred
|
||||||
protected function articleMarkStarredMulti(array $url, array $data): ResponseInterface {
|
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
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
$c->articles(array_column($data['items'] ?? [], "guidHash"));
|
$c->articles(array_column($data['items'] ?? [], "guidHash"));
|
||||||
|
@ -656,10 +656,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
|
|
||||||
protected function userStatus(array $url, array $data): ResponseInterface {
|
protected function userStatus(array $url, array $data): ResponseInterface {
|
||||||
return new Response([
|
return new Response([
|
||||||
'userId' => (string) Arsse::$user->id,
|
'userId' => (string) Arsse::$user->id,
|
||||||
'displayName' => (string) Arsse::$user->id,
|
'displayName' => (string) Arsse::$user->id,
|
||||||
'lastLoginTimestamp' => time(),
|
'lastLoginTimestamp' => time(),
|
||||||
'avatar' => null,
|
'avatar' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,19 +676,19 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// return the server version
|
// return the server version
|
||||||
protected function serverVersion(array $url, array $data): ResponseInterface {
|
protected function serverVersion(array $url, array $data): ResponseInterface {
|
||||||
return new Response([
|
return new Response([
|
||||||
'version' => self::VERSION,
|
'version' => self::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function serverStatus(array $url, array $data): ResponseInterface {
|
protected function serverStatus(array $url, array $data): ResponseInterface {
|
||||||
return new Response([
|
return new Response([
|
||||||
'version' => self::VERSION,
|
'version' => self::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
'warnings' => [
|
'warnings' => [
|
||||||
'improperlyConfiguredCron' => !Service::hasCheckedIn(),
|
'improperlyConfiguredCron' => !Service::hasCheckedIn(),
|
||||||
'incorrectDbCharset' => !Arsse::$db->driverCharsetAcceptable(),
|
'incorrectDbCharset' => !Arsse::$db->driverCharsetAcceptable(),
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ class Versions implements \JKingWeb\Arsse\REST\Handler {
|
||||||
$out = [
|
$out = [
|
||||||
'apiLevels' => [
|
'apiLevels' => [
|
||||||
'v1-2',
|
'v1-2',
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
return new Response($out);
|
return new Response($out);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -135,14 +135,14 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
throw new Exception("UNKNOWN_METHOD", ['method' => $data['op']]);
|
throw new Exception("UNKNOWN_METHOD", ['method' => $data['op']]);
|
||||||
}
|
}
|
||||||
return new Response([
|
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([
|
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) {
|
||||||
|
@ -190,7 +190,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// are not enforced, create a session for the HTTP user regardless
|
// are not enforced, create a session for the HTTP user regardless
|
||||||
// of which user the API call mentions
|
// of which user the API call mentions
|
||||||
$id = Arsse::$db->sessionCreate(Arsse::$user->id);
|
$id = Arsse::$db->sessionCreate(Arsse::$user->id);
|
||||||
} elseif ((!Arsse::$conf->userPreAuth && (Arsse::$user->auth($user, $pass) || Arsse::$user->auth($user, base64_decode($pass)))) || (Arsse::$conf->userPreAuth && Arsse::$user->id===$user)) {
|
} elseif ((!Arsse::$conf->userPreAuth && (Arsse::$user->auth($user, $pass) || Arsse::$user->auth($user, base64_decode($pass)))) || (Arsse::$conf->userPreAuth && Arsse::$user->id === $user)) {
|
||||||
// otherwise both cleartext and base64 passwords are accepted
|
// otherwise both cleartext and base64 passwords are accepted
|
||||||
// if pre-authentication is in use, just make sure the user names match
|
// if pre-authentication is in use, just make sure the user names match
|
||||||
$id = Arsse::$db->sessionCreate($user);
|
$id = Arsse::$db->sessionCreate($user);
|
||||||
|
@ -199,7 +199,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
'session_id' => $id,
|
'session_id' => $id,
|
||||||
'api_level' => self::LEVEL
|
'api_level' => self::LEVEL,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,10 +215,10 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
|
|
||||||
public function opGetConfig(array $data): array {
|
public function opGetConfig(array $data): array {
|
||||||
return [
|
return [
|
||||||
'icons_dir' => "feed-icons",
|
'icons_dir' => "feed-icons",
|
||||||
'icons_url' => "feed-icons",
|
'icons_url' => "feed-icons",
|
||||||
'daemon_is_running' => Service::hasCheckedIn(),
|
'daemon_is_running' => Service::hasCheckedIn(),
|
||||||
'num_feeds' => Arsse::$db->subscriptionCount(Arsse::$user->id),
|
'num_feeds' => Arsse::$db->subscriptionCount(Arsse::$user->id),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +304,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
return array_merge($special, $labels, $feeds, $cats);
|
return array_merge($special, $labels, $feeds, $cats);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function opGetFeedTree(array $data) : array {
|
public function opGetFeedTree(array $data): array {
|
||||||
$all = $data['include_empty'] ?? false;
|
$all = $data['include_empty'] ?? false;
|
||||||
$user = Arsse::$user->id;
|
$user = Arsse::$user->id;
|
||||||
$tSpecial = [
|
$tSpecial = [
|
||||||
|
@ -319,55 +319,55 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$subs = Arsse::$db->subscriptionList($user)->getAll();
|
$subs = Arsse::$db->subscriptionList($user)->getAll();
|
||||||
// start with the special feeds
|
// start with the special feeds
|
||||||
$out[] = [
|
$out[] = [
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Category.Special"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Category.Special"),
|
||||||
'id' => "CAT:".self::CAT_SPECIAL,
|
'id' => "CAT:".self::CAT_SPECIAL,
|
||||||
'bare_id' => self::CAT_SPECIAL,
|
'bare_id' => self::CAT_SPECIAL,
|
||||||
'type' => "category",
|
'type' => "category",
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'items' => [
|
'items' => [
|
||||||
array_merge([ // All articles
|
array_merge([ // All articles
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.All"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Feed.All"),
|
||||||
'id' => "FEED:".self::FEED_ALL,
|
'id' => "FEED:".self::FEED_ALL,
|
||||||
'bare_id' => self::FEED_ALL,
|
'bare_id' => self::FEED_ALL,
|
||||||
'icon' => "images/folder.png",
|
'icon' => "images/folder.png",
|
||||||
'unread' => array_reduce($subs, function($sum, $value) {
|
'unread' => array_reduce($subs, function($sum, $value) {
|
||||||
return $sum + $value['unread'];
|
return $sum + $value['unread'];
|
||||||
}, 0), // the sum of all feeds' unread is the total unread
|
}, 0), // the sum of all feeds' unread is the total unread
|
||||||
], $tSpecial),
|
], $tSpecial),
|
||||||
array_merge([ // Fresh articles
|
array_merge([ // Fresh articles
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Fresh"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Fresh"),
|
||||||
'id' => "FEED:".self::FEED_FRESH,
|
'id' => "FEED:".self::FEED_FRESH,
|
||||||
'bare_id' => self::FEED_FRESH,
|
'bare_id' => self::FEED_FRESH,
|
||||||
'icon' => "images/fresh.png",
|
'icon' => "images/fresh.png",
|
||||||
'unread' => Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedSince(Date::sub("PT24H"))),
|
'unread' => Arsse::$db->articleCount($user, (new Context)->unread(true)->modifiedSince(Date::sub("PT24H"))),
|
||||||
], $tSpecial),
|
], $tSpecial),
|
||||||
array_merge([ // Starred articles
|
array_merge([ // Starred articles
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Starred"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Starred"),
|
||||||
'id' => "FEED:".self::FEED_STARRED,
|
'id' => "FEED:".self::FEED_STARRED,
|
||||||
'bare_id' => self::FEED_STARRED,
|
'bare_id' => self::FEED_STARRED,
|
||||||
'icon' => "images/star.png",
|
'icon' => "images/star.png",
|
||||||
'unread' => (int) Arsse::$db->articleStarred($user)['unread'],
|
'unread' => (int) Arsse::$db->articleStarred($user)['unread'],
|
||||||
], $tSpecial),
|
], $tSpecial),
|
||||||
array_merge([ // Published articles
|
array_merge([ // Published articles
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Published"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Published"),
|
||||||
'id' => "FEED:".self::FEED_PUBLISHED,
|
'id' => "FEED:".self::FEED_PUBLISHED,
|
||||||
'bare_id' => self::FEED_PUBLISHED,
|
'bare_id' => self::FEED_PUBLISHED,
|
||||||
'icon' => "images/feed.png",
|
'icon' => "images/feed.png",
|
||||||
'unread' => 0, // TODO: unread count should be populated if the Published feed is ever implemented
|
'unread' => 0, // TODO: unread count should be populated if the Published feed is ever implemented
|
||||||
], $tSpecial),
|
], $tSpecial),
|
||||||
array_merge([ // Archived articles
|
array_merge([ // Archived articles
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Archived"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Archived"),
|
||||||
'id' => "FEED:".self::FEED_ARCHIVED,
|
'id' => "FEED:".self::FEED_ARCHIVED,
|
||||||
'bare_id' => self::FEED_ARCHIVED,
|
'bare_id' => self::FEED_ARCHIVED,
|
||||||
'icon' => "images/archive.png",
|
'icon' => "images/archive.png",
|
||||||
'unread' => 0, // Article archiving is not exposed by the API, so this is always zero
|
'unread' => 0, // Article archiving is not exposed by the API, so this is always zero
|
||||||
], $tSpecial),
|
], $tSpecial),
|
||||||
array_merge([ // Recently read
|
array_merge([ // Recently read
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Read"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Feed.Read"),
|
||||||
'id' => "FEED:".self::FEED_READ,
|
'id' => "FEED:".self::FEED_READ,
|
||||||
'bare_id' => self::FEED_READ,
|
'bare_id' => self::FEED_READ,
|
||||||
'icon' => "images/time.png",
|
'icon' => "images/time.png",
|
||||||
'unread' => 0, // this is by definition zero; unread articles do not appear in this feed
|
'unread' => 0, // this is by definition zero; unread articles do not appear in this feed
|
||||||
], $tSpecial),
|
], $tSpecial),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -394,12 +394,12 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// if there are labels, all the label category,
|
// if there are labels, all the label category,
|
||||||
if ($items) {
|
if ($items) {
|
||||||
$out[] = [
|
$out[] = [
|
||||||
'name' => Arsse::$lang->msg("API.TTRSS.Category.Labels"),
|
'name' => Arsse::$lang->msg("API.TTRSS.Category.Labels"),
|
||||||
'id' => "CAT:".self::CAT_LABELS,
|
'id' => "CAT:".self::CAT_LABELS,
|
||||||
'bare_id' => self::CAT_LABELS,
|
'bare_id' => self::CAT_LABELS,
|
||||||
'type' => "category",
|
'type' => "category",
|
||||||
'unread' => $unread,
|
'unread' => $unread,
|
||||||
'items' => $items,
|
'items' => $items,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// get the lists of categories and feeds
|
// get the lists of categories and feeds
|
||||||
|
@ -459,7 +459,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
// if the category is the wrong level, or if it's empty and we're not including empties, skip it
|
// if the category is the wrong level, or if it's empty and we're not including empties, skip it
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$children = $c['children'] ? $this->enumerateCategories($cats, $subs, $c['id'], $all) : ['list' => [], 'feeds' => 0];
|
$children = $c['children'] ? $this->enumerateCategories($cats, $subs, $c['id'], $all) : ['list' => [], 'feeds' => 0];
|
||||||
$feeds = $c['feeds'] ? $this->enumerateFeeds($subs, $c['id']) : [];
|
$feeds = $c['feeds'] ? $this->enumerateFeeds($subs, $c['id']) : [];
|
||||||
$count = sizeof($feeds) + (int) $children['feeds'];
|
$count = sizeof($feeds) + (int) $children['feeds'];
|
||||||
$out[] = [
|
$out[] = [
|
||||||
|
@ -843,7 +843,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$subs = Arsse::$db->subscriptionList(Arsse::$user->id);
|
$subs = Arsse::$db->subscriptionList(Arsse::$user->id);
|
||||||
$id = false;
|
$id = false;
|
||||||
foreach ($subs as $sub) {
|
foreach ($subs as $sub) {
|
||||||
if ($sub['url']===$url) {
|
if ($sub['url'] === $url) {
|
||||||
$id = (int) $sub['id'];
|
$id = (int) $sub['id'];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -940,11 +940,11 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (abs($id) - self::LABEL_OFFSET);
|
return abs($id) - self::LABEL_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function labelOut($id): int {
|
protected function labelOut($id): int {
|
||||||
return ((int) $id * -1 - self::LABEL_OFFSET);
|
return (int) $id * -1 - self::LABEL_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function opGetLabels(array $data): array {
|
public function opGetLabels(array $data): array {
|
||||||
|
@ -1201,32 +1201,32 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
];
|
];
|
||||||
foreach (Arsse::$db->articleList(Arsse::$user->id, (new Context)->articles($articles), $columns) as $article) {
|
foreach (Arsse::$db->articleList(Arsse::$user->id, (new Context)->articles($articles), $columns) as $article) {
|
||||||
$out[] = [
|
$out[] = [
|
||||||
'id' => (string) $article['id'], // string cast to be consistent with TTRSS
|
'id' => (string) $article['id'], // string cast to be consistent with TTRSS
|
||||||
'guid' => $article['guid'] ? "SHA256:".$article['guid'] : null,
|
'guid' => $article['guid'] ? "SHA256:".$article['guid'] : null,
|
||||||
'title' => $article['title'],
|
'title' => $article['title'],
|
||||||
'link' => $article['url'],
|
'link' => $article['url'],
|
||||||
'labels' => $this->articleLabelList($labels, $article['id']),
|
'labels' => $this->articleLabelList($labels, $article['id']),
|
||||||
'unread' => (bool) $article['unread'],
|
'unread' => (bool) $article['unread'],
|
||||||
'marked' => (bool) $article['starred'],
|
'marked' => (bool) $article['starred'],
|
||||||
'published' => false, // TODO: if the Published feed is implemented, the getArticle operation should be amended accordingly
|
'published' => false, // TODO: if the Published feed is implemented, the getArticle operation should be amended accordingly
|
||||||
'comments' => "", // FIXME: What is this?
|
'comments' => "", // FIXME: What is this?
|
||||||
'author' => $article['author'],
|
'author' => $article['author'],
|
||||||
'updated' => Date::transform($article['edited_date'], "unix", "sql"),
|
'updated' => Date::transform($article['edited_date'], "unix", "sql"),
|
||||||
'feed_id' => (string) $article['subscription'], // string cast to be consistent with TTRSS
|
'feed_id' => (string) $article['subscription'], // string cast to be consistent with TTRSS
|
||||||
'feed_title' => $article['subscription_title'],
|
'feed_title' => $article['subscription_title'],
|
||||||
'attachments' => $article['media_url'] ? [[
|
'attachments' => $article['media_url'] ? [[
|
||||||
'id' => (string) 0, // string cast to be consistent with TTRSS; nonsense ID because we don't use them for enclosures
|
'id' => (string) 0, // string cast to be consistent with TTRSS; nonsense ID because we don't use them for enclosures
|
||||||
'content_url' => $article['media_url'],
|
'content_url' => $article['media_url'],
|
||||||
'content_type' => $article['media_type'],
|
'content_type' => $article['media_type'],
|
||||||
'title' => "",
|
'title' => "",
|
||||||
'duration' => "",
|
'duration' => "",
|
||||||
'width' => "",
|
'width' => "",
|
||||||
'height' => "",
|
'height' => "",
|
||||||
'post_id' => (string) $article['id'], // string cast to be consistent with TTRSS
|
'post_id' => (string) $article['id'], // string cast to be consistent with TTRSS
|
||||||
]] : [], // TODO: We need to support multiple enclosures
|
]] : [], // TODO: We need to support multiple enclosures
|
||||||
'score' => 0, // score is not implemented as it is not modifiable from the TTRSS API
|
'score' => 0, // score is not implemented as it is not modifiable from the TTRSS API
|
||||||
'note' => strlen((string) $article['note']) ? $article['note'] : null,
|
'note' => strlen((string) $article['note']) ? $article['note'] : null,
|
||||||
'lang' => "", // FIXME: picoFeed should be able to retrieve this information
|
'lang' => "", // FIXME: picoFeed should be able to retrieve this information
|
||||||
'content' => $article['content'],
|
'content' => $article['content'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -1302,25 +1302,25 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
];
|
];
|
||||||
foreach ($this->fetchArticles($data, $columns) as $article) {
|
foreach ($this->fetchArticles($data, $columns) as $article) {
|
||||||
$row = [
|
$row = [
|
||||||
'id' => (int) $article['id'],
|
'id' => (int) $article['id'],
|
||||||
'guid' => $article['guid'] ? "SHA256:".$article['guid'] : "",
|
'guid' => $article['guid'] ? "SHA256:".$article['guid'] : "",
|
||||||
'title' => $article['title'],
|
'title' => $article['title'],
|
||||||
'link' => $article['url'],
|
'link' => $article['url'],
|
||||||
'labels' => $this->articleLabelList($labels, $article['id']),
|
'labels' => $this->articleLabelList($labels, $article['id']),
|
||||||
'unread' => (bool) $article['unread'],
|
'unread' => (bool) $article['unread'],
|
||||||
'marked' => (bool) $article['starred'],
|
'marked' => (bool) $article['starred'],
|
||||||
'published' => false, // TODO: if the Published feed is implemented, the getHeadlines operation should be amended accordingly
|
'published' => false, // TODO: if the Published feed is implemented, the getHeadlines operation should be amended accordingly
|
||||||
'author' => $article['author'],
|
'author' => $article['author'],
|
||||||
'updated' => Date::transform($article['edited_date'], "unix", "sql"),
|
'updated' => Date::transform($article['edited_date'], "unix", "sql"),
|
||||||
'is_updated' => ($article['published_date'] < $article['edited_date']),
|
'is_updated' => ($article['published_date'] < $article['edited_date']),
|
||||||
'feed_id' => (string) $article['subscription'], // string cast to be consistent with TTRSS
|
'feed_id' => (string) $article['subscription'], // string cast to be consistent with TTRSS
|
||||||
'feed_title' => $article['subscription_title'],
|
'feed_title' => $article['subscription_title'],
|
||||||
'score' => 0, // score is not implemented as it is not modifiable from the TTRSS API
|
'score' => 0, // score is not implemented as it is not modifiable from the TTRSS API
|
||||||
'note' => strlen((string) $article['note']) ? $article['note'] : null,
|
'note' => strlen((string) $article['note']) ? $article['note'] : null,
|
||||||
'lang' => "", // FIXME: picoFeed should be able to retrieve this information
|
'lang' => "", // FIXME: picoFeed should be able to retrieve this information
|
||||||
'tags' => Arsse::$db->articleCategoriesGet(Arsse::$user->id, $article['id']),
|
'tags' => Arsse::$db->articleCategoriesGet(Arsse::$user->id, $article['id']),
|
||||||
'comments_count' => 0,
|
'comments_count' => 0,
|
||||||
'comments_link' => "",
|
'comments_link' => "",
|
||||||
'always_display_attachments' => false,
|
'always_display_attachments' => false,
|
||||||
];
|
];
|
||||||
if ($data['show_content']) {
|
if ($data['show_content']) {
|
||||||
|
@ -1336,14 +1336,14 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
if ($data['include_attachments']) {
|
if ($data['include_attachments']) {
|
||||||
$row['attachments'] = $article['media_url'] ? [[
|
$row['attachments'] = $article['media_url'] ? [[
|
||||||
'id' => (string) 0, // string cast to be consistent with TTRSS; nonsense ID because we don't use them for enclosures
|
'id' => (string) 0, // string cast to be consistent with TTRSS; nonsense ID because we don't use them for enclosures
|
||||||
'content_url' => $article['media_url'],
|
'content_url' => $article['media_url'],
|
||||||
'content_type' => $article['media_type'],
|
'content_type' => $article['media_type'],
|
||||||
'title' => "",
|
'title' => "",
|
||||||
'duration' => "",
|
'duration' => "",
|
||||||
'width' => "",
|
'width' => "",
|
||||||
'height' => "",
|
'height' => "",
|
||||||
'post_id' => (string) $article['id'], // string cast to be consistent with TTRSS
|
'post_id' => (string) $article['id'], // string cast to be consistent with TTRSS
|
||||||
]] : []; // TODO: We need to support multiple enclosures
|
]] : []; // TODO: We need to support multiple enclosures
|
||||||
}
|
}
|
||||||
$out[] = $row;
|
$out[] = $row;
|
||||||
|
|
|
@ -66,7 +66,7 @@ class Service {
|
||||||
$limit->sub($int);
|
$limit->sub($int);
|
||||||
$limit->sub($int);
|
$limit->sub($int);
|
||||||
// return whether the check-in time is within the acceptable limit
|
// return whether the check-in time is within the acceptable limit
|
||||||
return ($checkin >= $limit);
|
return $checkin >= $limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function cleanupPre(): bool {
|
public static function cleanupPre(): bool {
|
||||||
|
|
|
@ -15,9 +15,7 @@ class User {
|
||||||
|
|
||||||
public $id = null;
|
public $id = null;
|
||||||
|
|
||||||
/**
|
/** @var User\Driver */
|
||||||
* @var User\Driver
|
|
||||||
*/
|
|
||||||
protected $u;
|
protected $u;
|
||||||
|
|
||||||
public function __construct(\JKingWeb\Arsse\User\Driver $driver = null) {
|
public function __construct(\JKingWeb\Arsse\User\Driver $driver = null) {
|
||||||
|
|
|
@ -26,7 +26,7 @@ class Driver implements \JKingWeb\Arsse\User\Driver {
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ($password==="" && $hash==="") {
|
if ($password === "" && $hash === "") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return password_verify($password, $hash);
|
return password_verify($password, $hash);
|
||||||
|
|
|
@ -163,10 +163,10 @@ class TestCLI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
// FIXME: Phake is somehow unable to mock the User class correctly, so we use PHPUnit's mocks instead
|
||||||
Arsse::$user = $this->createMock(User::class);
|
Arsse::$user = $this->createMock(User::class);
|
||||||
Arsse::$user->method("auth")->will($this->returnCallback(function($user, $pass) {
|
Arsse::$user->method("auth")->will($this->returnCallback(function($user, $pass) {
|
||||||
return (
|
return
|
||||||
($user === "john.doe@example.com" && $pass === "secret") ||
|
($user === "john.doe@example.com" && $pass === "secret") ||
|
||||||
($user === "jane.doe@example.com" && $pass === "superman")
|
($user === "jane.doe@example.com" && $pass === "superman")
|
||||||
);
|
;
|
||||||
}));
|
}));
|
||||||
$fever = \Phake::mock(FeverUser::class);
|
$fever = \Phake::mock(FeverUser::class);
|
||||||
\Phake::when($fever)->authenticate->thenReturn(false);
|
\Phake::when($fever)->authenticate->thenReturn(false);
|
||||||
|
|
|
@ -45,7 +45,7 @@ class TestConf extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
/** @depends testLoadDefaultValues */
|
/** @depends testLoadDefaultValues */
|
||||||
public function testImportFromArray(): void {
|
public function testImportFromArray(): void {
|
||||||
$arr = [
|
$arr = [
|
||||||
'lang' => "xx",
|
'lang' => "xx",
|
||||||
'purgeFeeds' => "P2D",
|
'purgeFeeds' => "P2D",
|
||||||
];
|
];
|
||||||
$conf = new Conf;
|
$conf = new Conf;
|
||||||
|
@ -125,9 +125,9 @@ class TestConf extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$conf->serviceFrequency = new \DateInterval("PT1H"); // should be exported (as string): value changed
|
$conf->serviceFrequency = new \DateInterval("PT1H"); // should be exported (as string): value changed
|
||||||
$conf->someCustomProperty = "Look at me!"; // should be exported: unknown property
|
$conf->someCustomProperty = "Look at me!"; // should be exported: unknown property
|
||||||
$exp = [
|
$exp = [
|
||||||
'dbSQLite3File' => "test.db",
|
'dbSQLite3File' => "test.db",
|
||||||
'userDriver' => null,
|
'userDriver' => null,
|
||||||
'serviceFrequency' => "PT1H",
|
'serviceFrequency' => "PT1H",
|
||||||
'someCustomProperty' => "Look at me!",
|
'someCustomProperty' => "Look at me!",
|
||||||
];
|
];
|
||||||
$this->assertSame($exp, $conf->export());
|
$this->assertSame($exp, $conf->export());
|
||||||
|
@ -147,8 +147,8 @@ class TestConf extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$conf->exportFile(self::$path."confNotArray");
|
$conf->exportFile(self::$path."confNotArray");
|
||||||
$arr = (include self::$path."confNotArray");
|
$arr = (include self::$path."confNotArray");
|
||||||
$exp = [
|
$exp = [
|
||||||
'dbSQLite3File' => "test.db",
|
'dbSQLite3File' => "test.db",
|
||||||
'userDriver' => null,
|
'userDriver' => null,
|
||||||
'someCustomProperty' => "Look at me!",
|
'someCustomProperty' => "Look at me!",
|
||||||
];
|
];
|
||||||
$this->assertSame($exp, $arr);
|
$this->assertSame($exp, $arr);
|
||||||
|
|
|
@ -47,7 +47,7 @@ trait SeriesArticle {
|
||||||
[11,"http://example.com/11", "Feed 11"],
|
[11,"http://example.com/11", "Feed 11"],
|
||||||
[12,"http://example.com/12", "Feed 12"],
|
[12,"http://example.com/12", "Feed 12"],
|
||||||
[13,"http://example.com/13", "Feed 13"],
|
[13,"http://example.com/13", "Feed 13"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_folders' => [
|
'arsse_folders' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -66,7 +66,7 @@ trait SeriesArticle {
|
||||||
[7, "john.doe@example.net", null, "Technology"],
|
[7, "john.doe@example.net", null, "Technology"],
|
||||||
[8, "john.doe@example.net", 7, "Software"],
|
[8, "john.doe@example.net", 7, "Software"],
|
||||||
[9, "john.doe@example.net", null, "Politics"],
|
[9, "john.doe@example.net", null, "Politics"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_tags' => [
|
'arsse_tags' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -83,7 +83,7 @@ trait SeriesArticle {
|
||||||
[6, "john.doe@example.net", "Technology"],
|
[6, "john.doe@example.net", "Technology"],
|
||||||
[7, "john.doe@example.net", "Software"],
|
[7, "john.doe@example.net", "Software"],
|
||||||
[8, "john.doe@example.net", "Politics"],
|
[8, "john.doe@example.net", "Politics"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -108,7 +108,7 @@ trait SeriesArticle {
|
||||||
[12,"john.doe@example.net",2, 9,null],
|
[12,"john.doe@example.net",2, 9,null],
|
||||||
[13,"john.doe@example.net",3, 8,"Subscription 13"],
|
[13,"john.doe@example.net",3, 8,"Subscription 13"],
|
||||||
[14,"john.doe@example.net",4, 7,null],
|
[14,"john.doe@example.net",4, 7,null],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_tag_members' => [
|
'arsse_tag_members' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -171,7 +171,7 @@ trait SeriesArticle {
|
||||||
[103,12,'http://example.com/3','Article title 3','','2000-01-03 00:00:00','2000-01-03 00:00:03','<p>Article content 3</p>','31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92','f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b','b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406','ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b','2000-01-03 03:00:00'],
|
[103,12,'http://example.com/3','Article title 3','','2000-01-03 00:00:00','2000-01-03 00:00:03','<p>Article content 3</p>','31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92','f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b','b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406','ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b','2000-01-03 03:00:00'],
|
||||||
[104,12,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:04','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9','2000-01-04 04:00:00'],
|
[104,12,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:04','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9','2000-01-04 04:00:00'],
|
||||||
[105,13,'http://example.com/5','Article title 5','','2000-01-05 00:00:00','2000-01-05 00:00:05','<p>Article content 5</p>','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41','d40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022','834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900','43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba','2000-01-05 05:00:00'],
|
[105,13,'http://example.com/5','Article title 5','','2000-01-05 00:00:00','2000-01-05 00:00:05','<p>Article content 5</p>','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41','d40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022','834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900','43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba','2000-01-05 05:00:00'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_enclosures' => [
|
'arsse_enclosures' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -185,7 +185,7 @@ trait SeriesArticle {
|
||||||
[104,"http://example.com/image","image/svg+xml"],
|
[104,"http://example.com/image","image/svg+xml"],
|
||||||
[105,"http://example.com/audio","audio/ogg"],
|
[105,"http://example.com/audio","audio/ogg"],
|
||||||
|
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_editions' => [
|
'arsse_editions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -224,7 +224,7 @@ trait SeriesArticle {
|
||||||
[205,105],
|
[205,105],
|
||||||
[305,105],
|
[305,105],
|
||||||
[1001,20],
|
[1001,20],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_marks' => [
|
'arsse_marks' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -249,7 +249,7 @@ trait SeriesArticle {
|
||||||
[12, 3,0,1,'2017-01-01 00:00:00','ack'],
|
[12, 3,0,1,'2017-01-01 00:00:00','ack'],
|
||||||
[12, 4,1,1,'2017-01-01 00:00:00','ach'],
|
[12, 4,1,1,'2017-01-01 00:00:00','ach'],
|
||||||
[1, 2,0,0,'2010-01-01 00:00:00','Some Note'],
|
[1, 2,0,0,'2010-01-01 00:00:00','Some Note'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_categories' => [ // author-supplied categories
|
'arsse_categories' => [ // author-supplied categories
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -298,104 +298,104 @@ trait SeriesArticle {
|
||||||
];
|
];
|
||||||
$this->matches = [
|
$this->matches = [
|
||||||
[
|
[
|
||||||
'id' => 101,
|
'id' => 101,
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'subscription_title' => "Feed 11",
|
'subscription_title' => "Feed 11",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 1</p>',
|
'content' => '<p>Article content 1</p>',
|
||||||
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
||||||
'published_date' => '2000-01-01 00:00:00',
|
'published_date' => '2000-01-01 00:00:00',
|
||||||
'edited_date' => '2000-01-01 00:00:01',
|
'edited_date' => '2000-01-01 00:00:01',
|
||||||
'modified_date' => '2000-01-01 01:00:00',
|
'modified_date' => '2000-01-01 01:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 101,
|
'edition' => 101,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
||||||
'media_url' => null,
|
'media_url' => null,
|
||||||
'media_type' => null,
|
'media_type' => null,
|
||||||
'note' => "",
|
'note' => "",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 102,
|
'id' => 102,
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'subscription_title' => "Feed 11",
|
'subscription_title' => "Feed 11",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 2</p>',
|
'content' => '<p>Article content 2</p>',
|
||||||
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
||||||
'published_date' => '2000-01-02 00:00:00',
|
'published_date' => '2000-01-02 00:00:00',
|
||||||
'edited_date' => '2000-01-02 00:00:02',
|
'edited_date' => '2000-01-02 00:00:02',
|
||||||
'modified_date' => '2000-01-02 02:00:00',
|
'modified_date' => '2000-01-02 02:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 202,
|
'edition' => 202,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
||||||
'media_url' => "http://example.com/text",
|
'media_url' => "http://example.com/text",
|
||||||
'media_type' => "text/plain",
|
'media_type' => "text/plain",
|
||||||
'note' => "Note 2",
|
'note' => "Note 2",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 103,
|
'id' => 103,
|
||||||
'url' => 'http://example.com/3',
|
'url' => 'http://example.com/3',
|
||||||
'title' => 'Article title 3',
|
'title' => 'Article title 3',
|
||||||
'subscription_title' => "Subscription 9",
|
'subscription_title' => "Subscription 9",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 3</p>',
|
'content' => '<p>Article content 3</p>',
|
||||||
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
||||||
'published_date' => '2000-01-03 00:00:00',
|
'published_date' => '2000-01-03 00:00:00',
|
||||||
'edited_date' => '2000-01-03 00:00:03',
|
'edited_date' => '2000-01-03 00:00:03',
|
||||||
'modified_date' => '2000-01-03 03:00:00',
|
'modified_date' => '2000-01-03 03:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'edition' => 203,
|
'edition' => 203,
|
||||||
'subscription' => 9,
|
'subscription' => 9,
|
||||||
'fingerprint' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b:b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406:ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
'fingerprint' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b:b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406:ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
||||||
'media_url' => "http://example.com/video",
|
'media_url' => "http://example.com/video",
|
||||||
'media_type' => "video/webm",
|
'media_type' => "video/webm",
|
||||||
'note' => "Note 3",
|
'note' => "Note 3",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 104,
|
'id' => 104,
|
||||||
'url' => 'http://example.com/4',
|
'url' => 'http://example.com/4',
|
||||||
'title' => 'Article title 4',
|
'title' => 'Article title 4',
|
||||||
'subscription_title' => "Subscription 9",
|
'subscription_title' => "Subscription 9",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 4</p>',
|
'content' => '<p>Article content 4</p>',
|
||||||
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
||||||
'published_date' => '2000-01-04 00:00:00',
|
'published_date' => '2000-01-04 00:00:00',
|
||||||
'edited_date' => '2000-01-04 00:00:04',
|
'edited_date' => '2000-01-04 00:00:04',
|
||||||
'modified_date' => '2000-01-04 04:00:00',
|
'modified_date' => '2000-01-04 04:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'edition' => 204,
|
'edition' => 204,
|
||||||
'subscription' => 9,
|
'subscription' => 9,
|
||||||
'fingerprint' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8:f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3:ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
'fingerprint' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8:f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3:ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
||||||
'media_url' => "http://example.com/image",
|
'media_url' => "http://example.com/image",
|
||||||
'media_type' => "image/svg+xml",
|
'media_type' => "image/svg+xml",
|
||||||
'note' => "Note 4",
|
'note' => "Note 4",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 105,
|
'id' => 105,
|
||||||
'url' => 'http://example.com/5',
|
'url' => 'http://example.com/5',
|
||||||
'title' => 'Article title 5',
|
'title' => 'Article title 5',
|
||||||
'subscription_title' => "Feed 13",
|
'subscription_title' => "Feed 13",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 5</p>',
|
'content' => '<p>Article content 5</p>',
|
||||||
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
||||||
'published_date' => '2000-01-05 00:00:00',
|
'published_date' => '2000-01-05 00:00:00',
|
||||||
'edited_date' => '2000-01-05 00:00:05',
|
'edited_date' => '2000-01-05 00:00:05',
|
||||||
'modified_date' => '2000-01-05 05:00:00',
|
'modified_date' => '2000-01-05 05:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 305,
|
'edition' => 305,
|
||||||
'subscription' => 10,
|
'subscription' => 10,
|
||||||
'fingerprint' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022:834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900:43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
'fingerprint' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022:834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900:43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
||||||
'media_url' => "http://example.com/audio",
|
'media_url' => "http://example.com/audio",
|
||||||
'media_type' => "audio/ogg",
|
'media_type' => "audio/ogg",
|
||||||
'note' => "",
|
'note' => "",
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$this->fields = [
|
$this->fields = [
|
||||||
|
@ -404,7 +404,7 @@ trait SeriesArticle {
|
||||||
"content", "media_url", "media_type",
|
"content", "media_url", "media_type",
|
||||||
"note",
|
"note",
|
||||||
];
|
];
|
||||||
$this->checkTables = ['arsse_marks' => ["subscription","article","read","starred","modified","note"],];
|
$this->checkTables = ['arsse_marks' => ["subscription","article","read","starred","modified","note"]];
|
||||||
$this->user = "john.doe@example.net";
|
$this->user = "john.doe@example.net";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,132 +422,132 @@ trait SeriesArticle {
|
||||||
|
|
||||||
public function provideContextMatches(): iterable {
|
public function provideContextMatches(): iterable {
|
||||||
return [
|
return [
|
||||||
'Blank context' => [new Context, [1,2,3,4,5,6,7,8,19,20]],
|
'Blank context' => [new Context, [1,2,3,4,5,6,7,8,19,20]],
|
||||||
'Folder tree' => [(new Context)->folder(1), [5,6,7,8]],
|
'Folder tree' => [(new Context)->folder(1), [5,6,7,8]],
|
||||||
'Entire folder tree' => [(new Context)->folder(0), [1,2,3,4,5,6,7,8,19,20]],
|
'Entire folder tree' => [(new Context)->folder(0), [1,2,3,4,5,6,7,8,19,20]],
|
||||||
'Leaf folder' => [(new Context)->folder(6), [7,8]],
|
'Leaf folder' => [(new Context)->folder(6), [7,8]],
|
||||||
'Multiple folder trees' => [(new Context)->folders([1,5]), [5,6,7,8,19,20]],
|
'Multiple folder trees' => [(new Context)->folders([1,5]), [5,6,7,8,19,20]],
|
||||||
'Multiple folder trees including root' => [(new Context)->folders([0,1,5]), [1,2,3,4,5,6,7,8,19,20]],
|
'Multiple folder trees including root' => [(new Context)->folders([0,1,5]), [1,2,3,4,5,6,7,8,19,20]],
|
||||||
'Shallow folder' => [(new Context)->folderShallow(1), [5,6]],
|
'Shallow folder' => [(new Context)->folderShallow(1), [5,6]],
|
||||||
'Root folder only' => [(new Context)->folderShallow(0), [1,2,3,4]],
|
'Root folder only' => [(new Context)->folderShallow(0), [1,2,3,4]],
|
||||||
'Multiple shallow folders' => [(new Context)->foldersShallow([1,6]), [5,6,7,8]],
|
'Multiple shallow folders' => [(new Context)->foldersShallow([1,6]), [5,6,7,8]],
|
||||||
'Subscription' => [(new Context)->subscription(5), [19,20]],
|
'Subscription' => [(new Context)->subscription(5), [19,20]],
|
||||||
'Multiple subscriptions' => [(new Context)->subscriptions([4,5]), [7,8,19,20]],
|
'Multiple subscriptions' => [(new Context)->subscriptions([4,5]), [7,8,19,20]],
|
||||||
'Unread' => [(new Context)->subscription(5)->unread(true), [20]],
|
'Unread' => [(new Context)->subscription(5)->unread(true), [20]],
|
||||||
'Read' => [(new Context)->subscription(5)->unread(false), [19]],
|
'Read' => [(new Context)->subscription(5)->unread(false), [19]],
|
||||||
'Starred' => [(new Context)->starred(true), [1,20]],
|
'Starred' => [(new Context)->starred(true), [1,20]],
|
||||||
'Unstarred' => [(new Context)->starred(false), [2,3,4,5,6,7,8,19]],
|
'Unstarred' => [(new Context)->starred(false), [2,3,4,5,6,7,8,19]],
|
||||||
'Starred and Read' => [(new Context)->starred(true)->unread(false), [1]],
|
'Starred and Read' => [(new Context)->starred(true)->unread(false), [1]],
|
||||||
'Starred and Read in subscription' => [(new Context)->starred(true)->unread(false)->subscription(5), []],
|
'Starred and Read in subscription' => [(new Context)->starred(true)->unread(false)->subscription(5), []],
|
||||||
'Annotated' => [(new Context)->annotated(true), [2]],
|
'Annotated' => [(new Context)->annotated(true), [2]],
|
||||||
'Not annotated' => [(new Context)->annotated(false), [1,3,4,5,6,7,8,19,20]],
|
'Not annotated' => [(new Context)->annotated(false), [1,3,4,5,6,7,8,19,20]],
|
||||||
'Labelled' => [(new Context)->labelled(true), [1,5,8,19,20]],
|
'Labelled' => [(new Context)->labelled(true), [1,5,8,19,20]],
|
||||||
'Not labelled' => [(new Context)->labelled(false), [2,3,4,6,7]],
|
'Not labelled' => [(new Context)->labelled(false), [2,3,4,6,7]],
|
||||||
'Not after edition 999' => [(new Context)->subscription(5)->latestEdition(999), [19]],
|
'Not after edition 999' => [(new Context)->subscription(5)->latestEdition(999), [19]],
|
||||||
'Not after edition 19' => [(new Context)->subscription(5)->latestEdition(19), [19]],
|
'Not after edition 19' => [(new Context)->subscription(5)->latestEdition(19), [19]],
|
||||||
'Not before edition 999' => [(new Context)->subscription(5)->oldestEdition(999), [20]],
|
'Not before edition 999' => [(new Context)->subscription(5)->oldestEdition(999), [20]],
|
||||||
'Not before edition 1001' => [(new Context)->subscription(5)->oldestEdition(1001), [20]],
|
'Not before edition 1001' => [(new Context)->subscription(5)->oldestEdition(1001), [20]],
|
||||||
'Not after article 3' => [(new Context)->latestArticle(3), [1,2,3]],
|
'Not after article 3' => [(new Context)->latestArticle(3), [1,2,3]],
|
||||||
'Not before article 19' => [(new Context)->oldestArticle(19), [19,20]],
|
'Not before article 19' => [(new Context)->oldestArticle(19), [19,20]],
|
||||||
'Modified by author since 2005' => [(new Context)->modifiedSince("2005-01-01T00:00:00Z"), [2,4,6,8,20]],
|
'Modified by author since 2005' => [(new Context)->modifiedSince("2005-01-01T00:00:00Z"), [2,4,6,8,20]],
|
||||||
'Modified by author since 2010' => [(new Context)->modifiedSince("2010-01-01T00:00:00Z"), [2,4,6,8,20]],
|
'Modified by author since 2010' => [(new Context)->modifiedSince("2010-01-01T00:00:00Z"), [2,4,6,8,20]],
|
||||||
'Not modified by author since 2005' => [(new Context)->notModifiedSince("2005-01-01T00:00:00Z"), [1,3,5,7,19]],
|
'Not modified by author since 2005' => [(new Context)->notModifiedSince("2005-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||||
'Not modified by author since 2000' => [(new Context)->notModifiedSince("2000-01-01T00:00:00Z"), [1,3,5,7,19]],
|
'Not modified by author since 2000' => [(new Context)->notModifiedSince("2000-01-01T00:00:00Z"), [1,3,5,7,19]],
|
||||||
'Marked or labelled since 2014' => [(new Context)->markedSince("2014-01-01T00:00:00Z"), [8,19]],
|
'Marked or labelled since 2014' => [(new Context)->markedSince("2014-01-01T00:00:00Z"), [8,19]],
|
||||||
'Marked or labelled since 2010' => [(new Context)->markedSince("2010-01-01T00:00:00Z"), [2,4,6,8,19,20]],
|
'Marked or labelled since 2010' => [(new Context)->markedSince("2010-01-01T00:00:00Z"), [2,4,6,8,19,20]],
|
||||||
'Not marked or labelled since 2014' => [(new Context)->notMarkedSince("2014-01-01T00:00:00Z"), [1,2,3,4,5,6,7,20]],
|
'Not marked or labelled since 2014' => [(new Context)->notMarkedSince("2014-01-01T00:00:00Z"), [1,2,3,4,5,6,7,20]],
|
||||||
'Not marked or labelled since 2005' => [(new Context)->notMarkedSince("2005-01-01T00:00:00Z"), [1,3,5,7]],
|
'Not marked or labelled since 2005' => [(new Context)->notMarkedSince("2005-01-01T00:00:00Z"), [1,3,5,7]],
|
||||||
'Marked or labelled between 2000 and 2015' => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59Z"), [1,2,3,4,5,6,7,8,20]],
|
'Marked or labelled between 2000 and 2015' => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59Z"), [1,2,3,4,5,6,7,8,20]],
|
||||||
'Marked or labelled in 2010' => [(new Context)->markedSince("2010-01-01T00:00:00Z")->notMarkedSince("2010-12-31T23:59:59Z"), [2,4,6,20]],
|
'Marked or labelled in 2010' => [(new Context)->markedSince("2010-01-01T00:00:00Z")->notMarkedSince("2010-12-31T23:59:59Z"), [2,4,6,20]],
|
||||||
'Paged results' => [(new Context)->limit(2)->oldestEdition(4), [4,5]],
|
'Paged results' => [(new Context)->limit(2)->oldestEdition(4), [4,5]],
|
||||||
'With label ID 1' => [(new Context)->label(1), [1,19]],
|
'With label ID 1' => [(new Context)->label(1), [1,19]],
|
||||||
'With label ID 2' => [(new Context)->label(2), [1,5,20]],
|
'With label ID 2' => [(new Context)->label(2), [1,5,20]],
|
||||||
'With label ID 1 or 2' => [(new Context)->labels([1,2]), [1,5,19,20]],
|
'With label ID 1 or 2' => [(new Context)->labels([1,2]), [1,5,19,20]],
|
||||||
'With label "Interesting"' => [(new Context)->labelName("Interesting"), [1,19]],
|
'With label "Interesting"' => [(new Context)->labelName("Interesting"), [1,19]],
|
||||||
'With label "Fascinating"' => [(new Context)->labelName("Fascinating"), [1,5,20]],
|
'With label "Fascinating"' => [(new Context)->labelName("Fascinating"), [1,5,20]],
|
||||||
'With label "Interesting" or "Fascinating"' => [(new Context)->labelNames(["Interesting","Fascinating"]), [1,5,19,20]],
|
'With label "Interesting" or "Fascinating"' => [(new Context)->labelNames(["Interesting","Fascinating"]), [1,5,19,20]],
|
||||||
'Article ID 20' => [(new Context)->article(20), [20]],
|
'Article ID 20' => [(new Context)->article(20), [20]],
|
||||||
'Edition ID 1001' => [(new Context)->edition(1001), [20]],
|
'Edition ID 1001' => [(new Context)->edition(1001), [20]],
|
||||||
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
||||||
'Multiple starred articles' => [(new Context)->articles([1,2,3])->starred(true), [1]],
|
'Multiple starred articles' => [(new Context)->articles([1,2,3])->starred(true), [1]],
|
||||||
'Multiple unstarred articles' => [(new Context)->articles([1,2,3])->starred(false), [2,3]],
|
'Multiple unstarred articles' => [(new Context)->articles([1,2,3])->starred(false), [2,3]],
|
||||||
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
'Multiple articles' => [(new Context)->articles([1,20,50]), [1,20]],
|
||||||
'Multiple editions' => [(new Context)->editions([1,1001,50]), [1,20]],
|
'Multiple editions' => [(new Context)->editions([1,1001,50]), [1,20]],
|
||||||
'150 articles' => [(new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)), [1,2,3,4,5,6,7,8,19,20]],
|
'150 articles' => [(new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3)), [1,2,3,4,5,6,7,8,19,20]],
|
||||||
'Search title or content 1' => [(new Context)->searchTerms(["Article"]), [1,2,3]],
|
'Search title or content 1' => [(new Context)->searchTerms(["Article"]), [1,2,3]],
|
||||||
'Search title or content 2' => [(new Context)->searchTerms(["one", "first"]), [1]],
|
'Search title or content 2' => [(new Context)->searchTerms(["one", "first"]), [1]],
|
||||||
'Search title or content 3' => [(new Context)->searchTerms(["one first"]), []],
|
'Search title or content 3' => [(new Context)->searchTerms(["one first"]), []],
|
||||||
'Search title 1' => [(new Context)->titleTerms(["two"]), [2]],
|
'Search title 1' => [(new Context)->titleTerms(["two"]), [2]],
|
||||||
'Search title 2' => [(new Context)->titleTerms(["title two"]), [2]],
|
'Search title 2' => [(new Context)->titleTerms(["title two"]), [2]],
|
||||||
'Search title 3' => [(new Context)->titleTerms(["two", "title"]), [2]],
|
'Search title 3' => [(new Context)->titleTerms(["two", "title"]), [2]],
|
||||||
'Search title 4' => [(new Context)->titleTerms(["two title"]), []],
|
'Search title 4' => [(new Context)->titleTerms(["two title"]), []],
|
||||||
'Search note 1' => [(new Context)->annotationTerms(["some"]), [2]],
|
'Search note 1' => [(new Context)->annotationTerms(["some"]), [2]],
|
||||||
'Search note 2' => [(new Context)->annotationTerms(["some Note"]), [2]],
|
'Search note 2' => [(new Context)->annotationTerms(["some Note"]), [2]],
|
||||||
'Search note 3' => [(new Context)->annotationTerms(["note", "some"]), [2]],
|
'Search note 3' => [(new Context)->annotationTerms(["note", "some"]), [2]],
|
||||||
'Search note 4' => [(new Context)->annotationTerms(["some", "sauce"]), []],
|
'Search note 4' => [(new Context)->annotationTerms(["some", "sauce"]), []],
|
||||||
'Search author 1' => [(new Context)->authorTerms(["doe"]), [4,5,6,7]],
|
'Search author 1' => [(new Context)->authorTerms(["doe"]), [4,5,6,7]],
|
||||||
'Search author 2' => [(new Context)->authorTerms(["jane doe"]), [6,7]],
|
'Search author 2' => [(new Context)->authorTerms(["jane doe"]), [6,7]],
|
||||||
'Search author 3' => [(new Context)->authorTerms(["doe", "jane"]), [6,7]],
|
'Search author 3' => [(new Context)->authorTerms(["doe", "jane"]), [6,7]],
|
||||||
'Search author 4' => [(new Context)->authorTerms(["doe jane"]), []],
|
'Search author 4' => [(new Context)->authorTerms(["doe jane"]), []],
|
||||||
'Folder tree 1 excluding subscription 4' => [(new Context)->not->subscription(4)->folder(1), [5,6]],
|
'Folder tree 1 excluding subscription 4' => [(new Context)->not->subscription(4)->folder(1), [5,6]],
|
||||||
'Folder tree 1 excluding articles 7 and 8' => [(new Context)->folder(1)->not->articles([7,8]), [5,6]],
|
'Folder tree 1 excluding articles 7 and 8' => [(new Context)->folder(1)->not->articles([7,8]), [5,6]],
|
||||||
'Folder tree 1 excluding no articles' => [(new Context)->folder(1)->not->articles([]), [5,6,7,8]],
|
'Folder tree 1 excluding no articles' => [(new Context)->folder(1)->not->articles([]), [5,6,7,8]],
|
||||||
'Marked or labelled between 2000 and 2015 excluding in 2010' => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59")->not->markedSince("2010-01-01T00:00:00Z")->not->notMarkedSince("2010-12-31T23:59:59Z"), [1,3,5,7,8]],
|
'Marked or labelled between 2000 and 2015 excluding in 2010' => [(new Context)->markedSince("2000-01-01T00:00:00Z")->notMarkedSince("2015-12-31T23:59:59")->not->markedSince("2010-01-01T00:00:00Z")->not->notMarkedSince("2010-12-31T23:59:59Z"), [1,3,5,7,8]],
|
||||||
'Search with exclusion' => [(new Context)->searchTerms(["Article"])->not->searchTerms(["one", "two"]), [3]],
|
'Search with exclusion' => [(new Context)->searchTerms(["Article"])->not->searchTerms(["one", "two"]), [3]],
|
||||||
'Excluded folder tree' => [(new Context)->not->folder(1), [1,2,3,4,19,20]],
|
'Excluded folder tree' => [(new Context)->not->folder(1), [1,2,3,4,19,20]],
|
||||||
'Excluding label ID 2' => [(new Context)->not->label(2), [2,3,4,6,7,8,19]],
|
'Excluding label ID 2' => [(new Context)->not->label(2), [2,3,4,6,7,8,19]],
|
||||||
'Excluding label "Fascinating"' => [(new Context)->not->labelName("Fascinating"), [2,3,4,6,7,8,19]],
|
'Excluding label "Fascinating"' => [(new Context)->not->labelName("Fascinating"), [2,3,4,6,7,8,19]],
|
||||||
'Search 501 terms' => [(new Context)->searchTerms(array_merge(range(1, 500), [str_repeat("a", 1000)])), []],
|
'Search 501 terms' => [(new Context)->searchTerms(array_merge(range(1, 500), [str_repeat("a", 1000)])), []],
|
||||||
'With tag ID 1' => [(new Context)->tag(1), [5,6,7,8]],
|
'With tag ID 1' => [(new Context)->tag(1), [5,6,7,8]],
|
||||||
'With tag ID 5' => [(new Context)->tag(5), [7,8,19,20]],
|
'With tag ID 5' => [(new Context)->tag(5), [7,8,19,20]],
|
||||||
'With tag ID 1 or 5' => [(new Context)->tags([1,5]), [5,6,7,8,19,20]],
|
'With tag ID 1 or 5' => [(new Context)->tags([1,5]), [5,6,7,8,19,20]],
|
||||||
'With tag "Technology"' => [(new Context)->tagName("Technology"), [5,6,7,8]],
|
'With tag "Technology"' => [(new Context)->tagName("Technology"), [5,6,7,8]],
|
||||||
'With tag "Politics"' => [(new Context)->tagName("Politics"), [7,8,19,20]],
|
'With tag "Politics"' => [(new Context)->tagName("Politics"), [7,8,19,20]],
|
||||||
'With tag "Technology" or "Politics"' => [(new Context)->tagNames(["Technology","Politics"]), [5,6,7,8,19,20]],
|
'With tag "Technology" or "Politics"' => [(new Context)->tagNames(["Technology","Politics"]), [5,6,7,8,19,20]],
|
||||||
'Excluding tag ID 1' => [(new Context)->not->tag(1), [1,2,3,4,19,20]],
|
'Excluding tag ID 1' => [(new Context)->not->tag(1), [1,2,3,4,19,20]],
|
||||||
'Excluding tag ID 5' => [(new Context)->not->tag(5), [1,2,3,4,5,6]],
|
'Excluding tag ID 5' => [(new Context)->not->tag(5), [1,2,3,4,5,6]],
|
||||||
'Excluding tag "Technology"' => [(new Context)->not->tagName("Technology"), [1,2,3,4,19,20]],
|
'Excluding tag "Technology"' => [(new Context)->not->tagName("Technology"), [1,2,3,4,19,20]],
|
||||||
'Excluding tag "Politics"' => [(new Context)->not->tagName("Politics"), [1,2,3,4,5,6]],
|
'Excluding tag "Politics"' => [(new Context)->not->tagName("Politics"), [1,2,3,4,5,6]],
|
||||||
'Excluding tags ID 1 and 5' => [(new Context)->not->tags([1,5]), [1,2,3,4]],
|
'Excluding tags ID 1 and 5' => [(new Context)->not->tags([1,5]), [1,2,3,4]],
|
||||||
'Excluding tags "Technology" and "Politics"' => [(new Context)->not->tagNames(["Technology","Politics"]), [1,2,3,4]],
|
'Excluding tags "Technology" and "Politics"' => [(new Context)->not->tagNames(["Technology","Politics"]), [1,2,3,4]],
|
||||||
'Excluding entire folder tree' => [(new Context)->not->folder(0), []],
|
'Excluding entire folder tree' => [(new Context)->not->folder(0), []],
|
||||||
'Excluding multiple folder trees' => [(new Context)->not->folders([1,5]), [1,2,3,4]],
|
'Excluding multiple folder trees' => [(new Context)->not->folders([1,5]), [1,2,3,4]],
|
||||||
'Excluding multiple folder trees including root' => [(new Context)->not->folders([0,1,5]), []],
|
'Excluding multiple folder trees including root' => [(new Context)->not->folders([0,1,5]), []],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRetrieveArticleIdsForEditions(): void {
|
public function testRetrieveArticleIdsForEditions(): void {
|
||||||
$exp = [
|
$exp = [
|
||||||
1 => 1,
|
1 => 1,
|
||||||
2 => 2,
|
2 => 2,
|
||||||
3 => 3,
|
3 => 3,
|
||||||
4 => 4,
|
4 => 4,
|
||||||
5 => 5,
|
5 => 5,
|
||||||
6 => 6,
|
6 => 6,
|
||||||
7 => 7,
|
7 => 7,
|
||||||
8 => 8,
|
8 => 8,
|
||||||
9 => 9,
|
9 => 9,
|
||||||
10 => 10,
|
10 => 10,
|
||||||
11 => 11,
|
11 => 11,
|
||||||
12 => 12,
|
12 => 12,
|
||||||
13 => 13,
|
13 => 13,
|
||||||
14 => 14,
|
14 => 14,
|
||||||
15 => 15,
|
15 => 15,
|
||||||
16 => 16,
|
16 => 16,
|
||||||
17 => 17,
|
17 => 17,
|
||||||
18 => 18,
|
18 => 18,
|
||||||
19 => 19,
|
19 => 19,
|
||||||
20 => 20,
|
20 => 20,
|
||||||
101 => 101,
|
101 => 101,
|
||||||
102 => 102,
|
102 => 102,
|
||||||
103 => 103,
|
103 => 103,
|
||||||
104 => 104,
|
104 => 104,
|
||||||
105 => 105,
|
105 => 105,
|
||||||
202 => 102,
|
202 => 102,
|
||||||
203 => 103,
|
203 => 103,
|
||||||
204 => 104,
|
204 => 104,
|
||||||
205 => 105,
|
205 => 105,
|
||||||
305 => 105,
|
305 => 105,
|
||||||
1001 => 20,
|
1001 => 20,
|
||||||
];
|
];
|
||||||
$this->assertEquals($exp, Arsse::$db->editionArticle(...range(1, 1001)));
|
$this->assertEquals($exp, Arsse::$db->editionArticle(...range(1, 1001)));
|
||||||
|
@ -606,7 +606,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesUnread(): void {
|
public function testMarkAllArticlesUnread(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false]);
|
Arsse::$db->articleMark($this->user, ['read' => false]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][2] = 0;
|
$state['arsse_marks']['rows'][9][2] = 0;
|
||||||
|
@ -617,7 +617,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesRead(): void {
|
public function testMarkAllArticlesRead(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true]);
|
Arsse::$db->articleMark($this->user, ['read' => true]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][2] = 1;
|
$state['arsse_marks']['rows'][8][2] = 1;
|
||||||
|
@ -632,7 +632,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesUnstarred(): void {
|
public function testMarkAllArticlesUnstarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>false]);
|
Arsse::$db->articleMark($this->user, ['starred' => false]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][10][3] = 0;
|
$state['arsse_marks']['rows'][10][3] = 0;
|
||||||
|
@ -643,7 +643,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesStarred(): void {
|
public function testMarkAllArticlesStarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true]);
|
Arsse::$db->articleMark($this->user, ['starred' => true]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][3] = 1;
|
$state['arsse_marks']['rows'][8][3] = 1;
|
||||||
|
@ -658,7 +658,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesUnreadAndUnstarred(): void {
|
public function testMarkAllArticlesUnreadAndUnstarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>false]);
|
Arsse::$db->articleMark($this->user, ['read' => false,'starred' => false]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][2] = 0;
|
$state['arsse_marks']['rows'][9][2] = 0;
|
||||||
|
@ -672,7 +672,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesReadAndStarred(): void {
|
public function testMarkAllArticlesReadAndStarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true,'starred'=>true]);
|
Arsse::$db->articleMark($this->user, ['read' => true,'starred' => true]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][2] = 1;
|
$state['arsse_marks']['rows'][8][2] = 1;
|
||||||
|
@ -690,7 +690,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesUnreadAndStarred(): void {
|
public function testMarkAllArticlesUnreadAndStarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true]);
|
Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][3] = 1;
|
$state['arsse_marks']['rows'][8][3] = 1;
|
||||||
|
@ -708,7 +708,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAllArticlesReadAndUnstarred(): void {
|
public function testMarkAllArticlesReadAndUnstarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true,'starred'=>false]);
|
Arsse::$db->articleMark($this->user, ['read' => true,'starred' => false]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][2] = 1;
|
$state['arsse_marks']['rows'][8][2] = 1;
|
||||||
|
@ -726,7 +726,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetNoteForAllArticles(): void {
|
public function testSetNoteForAllArticles(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['note'=>"New note"]);
|
Arsse::$db->articleMark($this->user, ['note' => "New note"]);
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][5] = "New note";
|
$state['arsse_marks']['rows'][8][5] = "New note";
|
||||||
|
@ -745,7 +745,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkATreeFolder(): void {
|
public function testMarkATreeFolder(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(7));
|
Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->folder(7));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
|
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
|
||||||
|
@ -756,7 +756,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkALeafFolder(): void {
|
public function testMarkALeafFolder(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(8));
|
Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->folder(8));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
|
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
|
||||||
|
@ -766,11 +766,11 @@ trait SeriesArticle {
|
||||||
|
|
||||||
public function testMarkAMissingFolder(): void {
|
public function testMarkAMissingFolder(): void {
|
||||||
$this->assertException("idMissing", "Db", "ExceptionInput");
|
$this->assertException("idMissing", "Db", "ExceptionInput");
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(42));
|
Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->folder(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkASubscription(): void {
|
public function testMarkASubscription(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->subscription(13));
|
Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->subscription(13));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
|
$state['arsse_marks']['rows'][] = [13,5,1,0,$now,''];
|
||||||
|
@ -780,11 +780,11 @@ trait SeriesArticle {
|
||||||
|
|
||||||
public function testMarkAMissingSubscription(): void {
|
public function testMarkAMissingSubscription(): void {
|
||||||
$this->assertException("idMissing", "Db", "ExceptionInput");
|
$this->assertException("idMissing", "Db", "ExceptionInput");
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>true], (new Context)->folder(2112));
|
Arsse::$db->articleMark($this->user, ['read' => true], (new Context)->folder(2112));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAnArticle(): void {
|
public function testMarkAnArticle(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(20));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->article(20));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -793,7 +793,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleArticles(): void {
|
public function testMarkMultipleArticles(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->articles([2,4,7,20]));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->articles([2,4,7,20]));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -803,7 +803,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleArticlessUnreadAndStarred(): void {
|
public function testMarkMultipleArticlessUnreadAndStarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles([2,4,7,20]));
|
Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->articles([2,4,7,20]));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][2] = 0;
|
$state['arsse_marks']['rows'][9][2] = 0;
|
||||||
|
@ -816,16 +816,16 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkTooManyMultipleArticles(): void {
|
public function testMarkTooManyMultipleArticles(): void {
|
||||||
$this->assertSame(7, Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3))));
|
$this->assertSame(7, Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->articles(range(1, Database::LIMIT_SET_SIZE * 3))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAMissingArticle(): void {
|
public function testMarkAMissingArticle(): void {
|
||||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->article(1));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->article(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAnEdition(): void {
|
public function testMarkAnEdition(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(1001));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->edition(1001));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -834,7 +834,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleEditions(): void {
|
public function testMarkMultipleEditions(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->editions([2,4,7,20]));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->editions([2,4,7,20]));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -844,13 +844,13 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleMissingEditions(): void {
|
public function testMarkMultipleMissingEditions(): void {
|
||||||
$this->assertSame(0, Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->editions([500,501])));
|
$this->assertSame(0, Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->editions([500,501])));
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$this->compareExpectations(static::$drv, $state);
|
$this->compareExpectations(static::$drv, $state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleEditionsUnread(): void {
|
public function testMarkMultipleEditionsUnread(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->editions([2,4,7,1001]));
|
Arsse::$db->articleMark($this->user, ['read' => false], (new Context)->editions([2,4,7,1001]));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][2] = 0;
|
$state['arsse_marks']['rows'][9][2] = 0;
|
||||||
|
@ -861,7 +861,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleEditionsUnreadWithStale(): void {
|
public function testMarkMultipleEditionsUnreadWithStale(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->editions([2,4,7,20]));
|
Arsse::$db->articleMark($this->user, ['read' => false], (new Context)->editions([2,4,7,20]));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][11][2] = 0;
|
$state['arsse_marks']['rows'][11][2] = 0;
|
||||||
|
@ -870,7 +870,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkMultipleEditionsUnreadAndStarredWithStale(): void {
|
public function testMarkMultipleEditionsUnreadAndStarredWithStale(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions([2,4,7,20]));
|
Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->editions([2,4,7,20]));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -882,17 +882,17 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkTooManyMultipleEditions(): void {
|
public function testMarkTooManyMultipleEditions(): void {
|
||||||
$this->assertSame(7, Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->editions(range(1, 51))));
|
$this->assertSame(7, Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->editions(range(1, 51))));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAStaleEditionUnread(): void {
|
public function testMarkAStaleEditionUnread(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false], (new Context)->edition(20)); // no changes occur
|
Arsse::$db->articleMark($this->user, ['read' => false], (new Context)->edition(20)); // no changes occur
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$this->compareExpectations(static::$drv, $state);
|
$this->compareExpectations(static::$drv, $state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAStaleEditionStarred(): void {
|
public function testMarkAStaleEditionStarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(20));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->edition(20));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -901,7 +901,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAStaleEditionUnreadAndStarred(): void {
|
public function testMarkAStaleEditionUnreadAndStarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>true], (new Context)->edition(20)); // only starred is changed
|
Arsse::$db->articleMark($this->user, ['read' => false,'starred' => true], (new Context)->edition(20)); // only starred is changed
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][9][3] = 1;
|
$state['arsse_marks']['rows'][9][3] = 1;
|
||||||
|
@ -910,18 +910,18 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAStaleEditionUnreadAndUnstarred(): void {
|
public function testMarkAStaleEditionUnreadAndUnstarred(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false,'starred'=>false], (new Context)->edition(20)); // no changes occur
|
Arsse::$db->articleMark($this->user, ['read' => false,'starred' => false], (new Context)->edition(20)); // no changes occur
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$this->compareExpectations(static::$drv, $state);
|
$this->compareExpectations(static::$drv, $state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkAMissingEdition(): void {
|
public function testMarkAMissingEdition(): void {
|
||||||
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
$this->assertException("subjectMissing", "Db", "ExceptionInput");
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->edition(2));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->edition(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkByOldestEdition(): void {
|
public function testMarkByOldestEdition(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->oldestEdition(19));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->oldestEdition(19));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][3] = 1;
|
$state['arsse_marks']['rows'][8][3] = 1;
|
||||||
|
@ -932,7 +932,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkByLatestEdition(): void {
|
public function testMarkByLatestEdition(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->latestEdition(20));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->latestEdition(20));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][3] = 1;
|
$state['arsse_marks']['rows'][8][3] = 1;
|
||||||
|
@ -945,7 +945,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkByLastMarked(): void {
|
public function testMarkByLastMarked(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->markedSince('2017-01-01T00:00:00Z'));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->markedSince('2017-01-01T00:00:00Z'));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][8][3] = 1;
|
$state['arsse_marks']['rows'][8][3] = 1;
|
||||||
|
@ -956,7 +956,7 @@ trait SeriesArticle {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testMarkByNotLastMarked(): void {
|
public function testMarkByNotLastMarked(): void {
|
||||||
Arsse::$db->articleMark($this->user, ['starred'=>true], (new Context)->notMarkedSince('2000-01-01T00:00:00Z'));
|
Arsse::$db->articleMark($this->user, ['starred' => true], (new Context)->notMarkedSince('2000-01-01T00:00:00Z'));
|
||||||
$now = Date::transform(time(), "sql");
|
$now = Date::transform(time(), "sql");
|
||||||
$state = $this->primeExpectations($this->data, $this->checkTables);
|
$state = $this->primeExpectations($this->data, $this->checkTables);
|
||||||
$state['arsse_marks']['rows'][] = [13,5,0,1,$now,''];
|
$state['arsse_marks']['rows'][] = [13,5,0,1,$now,''];
|
||||||
|
@ -967,7 +967,7 @@ trait SeriesArticle {
|
||||||
public function testMarkArticlesWithoutAuthority(): void {
|
public function testMarkArticlesWithoutAuthority(): void {
|
||||||
\Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
\Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
Arsse::$db->articleMark($this->user, ['read'=>false]);
|
Arsse::$db->articleMark($this->user, ['read' => false]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCountArticles(): void {
|
public function testCountArticles(): void {
|
||||||
|
|
|
@ -16,7 +16,7 @@ trait SeriesCleanup {
|
||||||
'userSessionLifetime' => "PT24H",
|
'userSessionLifetime' => "PT24H",
|
||||||
]);
|
]);
|
||||||
// set up the test data
|
// set up the test data
|
||||||
$nowish = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
$nowish = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
||||||
$yesterday = gmdate("Y-m-d H:i:s", strtotime("now - 1 day"));
|
$yesterday = gmdate("Y-m-d H:i:s", strtotime("now - 1 day"));
|
||||||
$daybefore = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
$daybefore = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
||||||
$daysago = gmdate("Y-m-d H:i:s", strtotime("now - 7 days"));
|
$daysago = gmdate("Y-m-d H:i:s", strtotime("now - 7 days"));
|
||||||
|
@ -53,7 +53,7 @@ trait SeriesCleanup {
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'id' => "str",
|
'id' => "str",
|
||||||
'class' => "str",
|
'class' => "str",
|
||||||
'user' => "str",
|
'user' => "str",
|
||||||
'expires' => "datetime",
|
'expires' => "datetime",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
|
@ -76,7 +76,7 @@ trait SeriesCleanup {
|
||||||
[2,"http://example.com/2","",$yesterday,0],
|
[2,"http://example.com/2","",$yesterday,0],
|
||||||
[3,"http://example.com/3","",null,0],
|
[3,"http://example.com/3","",null,0],
|
||||||
[4,"http://example.com/4","",$nowish,0],
|
[4,"http://example.com/4","",$nowish,0],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -89,7 +89,7 @@ trait SeriesCleanup {
|
||||||
[1,'jane.doe@example.com',1],
|
[1,'jane.doe@example.com',1],
|
||||||
// other subscriptions exist for article cleanup tests
|
// other subscriptions exist for article cleanup tests
|
||||||
[2,'john.doe@example.com',1],
|
[2,'john.doe@example.com',1],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_articles' => [
|
'arsse_articles' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -110,7 +110,7 @@ trait SeriesCleanup {
|
||||||
[7,1,"","","",$weeksago], // meets the unread threshold without marks, thus is deleted
|
[7,1,"","","",$weeksago], // meets the unread threshold without marks, thus is deleted
|
||||||
[8,1,"","","",$weeksago], // meets the unread threshold even with marks, thus is deleted
|
[8,1,"","","",$weeksago], // meets the unread threshold even with marks, thus is deleted
|
||||||
[9,1,"","","",$weeksago], // meets the read threshold, thus is deleted
|
[9,1,"","","",$weeksago], // meets the read threshold, thus is deleted
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_editions' => [
|
'arsse_editions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -124,7 +124,7 @@ trait SeriesCleanup {
|
||||||
[4,4],
|
[4,4],
|
||||||
[201,1],
|
[201,1],
|
||||||
[102,2],
|
[102,2],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_marks' => [
|
'arsse_marks' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -142,7 +142,7 @@ trait SeriesCleanup {
|
||||||
[8,1,1,0,$weeksago],
|
[8,1,1,0,$weeksago],
|
||||||
[9,1,1,0,$daysago],
|
[9,1,1,0,$daysago],
|
||||||
[9,2,1,0,$daysago],
|
[9,2,1,0,$daysago],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ trait SeriesCleanup {
|
||||||
Arsse::$db->feedCleanup();
|
Arsse::$db->feedCleanup();
|
||||||
$now = gmdate("Y-m-d H:i:s");
|
$now = gmdate("Y-m-d H:i:s");
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_feeds' => ["id","orphaned"]
|
'arsse_feeds' => ["id","orphaned"],
|
||||||
]);
|
]);
|
||||||
$state['arsse_feeds']['rows'][0][1] = null;
|
$state['arsse_feeds']['rows'][0][1] = null;
|
||||||
unset($state['arsse_feeds']['rows'][1]);
|
unset($state['arsse_feeds']['rows'][1]);
|
||||||
|
@ -170,7 +170,7 @@ trait SeriesCleanup {
|
||||||
Arsse::$db->feedCleanup();
|
Arsse::$db->feedCleanup();
|
||||||
$now = gmdate("Y-m-d H:i:s");
|
$now = gmdate("Y-m-d H:i:s");
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_feeds' => ["id","orphaned"]
|
'arsse_feeds' => ["id","orphaned"],
|
||||||
]);
|
]);
|
||||||
$state['arsse_feeds']['rows'][0][1] = null;
|
$state['arsse_feeds']['rows'][0][1] = null;
|
||||||
$state['arsse_feeds']['rows'][2][1] = $now;
|
$state['arsse_feeds']['rows'][2][1] = $now;
|
||||||
|
@ -180,7 +180,7 @@ trait SeriesCleanup {
|
||||||
public function testCleanUpOldArticlesWithStandardRetention(): void {
|
public function testCleanUpOldArticlesWithStandardRetention(): void {
|
||||||
Arsse::$db->articleCleanup();
|
Arsse::$db->articleCleanup();
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_articles' => ["id"]
|
'arsse_articles' => ["id"],
|
||||||
]);
|
]);
|
||||||
foreach ([7,8,9] as $id) {
|
foreach ([7,8,9] as $id) {
|
||||||
unset($state['arsse_articles']['rows'][$id - 1]);
|
unset($state['arsse_articles']['rows'][$id - 1]);
|
||||||
|
@ -194,7 +194,7 @@ trait SeriesCleanup {
|
||||||
]);
|
]);
|
||||||
Arsse::$db->articleCleanup();
|
Arsse::$db->articleCleanup();
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_articles' => ["id"]
|
'arsse_articles' => ["id"],
|
||||||
]);
|
]);
|
||||||
foreach ([7,8] as $id) {
|
foreach ([7,8] as $id) {
|
||||||
unset($state['arsse_articles']['rows'][$id - 1]);
|
unset($state['arsse_articles']['rows'][$id - 1]);
|
||||||
|
@ -208,7 +208,7 @@ trait SeriesCleanup {
|
||||||
]);
|
]);
|
||||||
Arsse::$db->articleCleanup();
|
Arsse::$db->articleCleanup();
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_articles' => ["id"]
|
'arsse_articles' => ["id"],
|
||||||
]);
|
]);
|
||||||
foreach ([9] as $id) {
|
foreach ([9] as $id) {
|
||||||
unset($state['arsse_articles']['rows'][$id - 1]);
|
unset($state['arsse_articles']['rows'][$id - 1]);
|
||||||
|
@ -218,12 +218,12 @@ trait SeriesCleanup {
|
||||||
|
|
||||||
public function testCleanUpOldArticlesWithUnlimitedRetention(): void {
|
public function testCleanUpOldArticlesWithUnlimitedRetention(): void {
|
||||||
Arsse::$conf->import([
|
Arsse::$conf->import([
|
||||||
'purgeArticlesRead' => null,
|
'purgeArticlesRead' => null,
|
||||||
'purgeArticlesUnread' => null,
|
'purgeArticlesUnread' => null,
|
||||||
]);
|
]);
|
||||||
Arsse::$db->articleCleanup();
|
Arsse::$db->articleCleanup();
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_articles' => ["id"]
|
'arsse_articles' => ["id"],
|
||||||
]);
|
]);
|
||||||
$this->compareExpectations(static::$drv, $state);
|
$this->compareExpectations(static::$drv, $state);
|
||||||
}
|
}
|
||||||
|
@ -231,7 +231,7 @@ trait SeriesCleanup {
|
||||||
public function testCleanUpExpiredSessions(): void {
|
public function testCleanUpExpiredSessions(): void {
|
||||||
Arsse::$db->sessionCleanup();
|
Arsse::$db->sessionCleanup();
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_sessions' => ["id"]
|
'arsse_sessions' => ["id"],
|
||||||
]);
|
]);
|
||||||
foreach ([3,4,5] as $id) {
|
foreach ([3,4,5] as $id) {
|
||||||
unset($state['arsse_sessions']['rows'][$id - 1]);
|
unset($state['arsse_sessions']['rows'][$id - 1]);
|
||||||
|
@ -242,7 +242,7 @@ trait SeriesCleanup {
|
||||||
public function testCleanUpExpiredTokens(): void {
|
public function testCleanUpExpiredTokens(): void {
|
||||||
Arsse::$db->tokenCleanup();
|
Arsse::$db->tokenCleanup();
|
||||||
$state = $this->primeExpectations($this->data, [
|
$state = $this->primeExpectations($this->data, [
|
||||||
'arsse_tokens' => ["id", "class"]
|
'arsse_tokens' => ["id", "class"],
|
||||||
]);
|
]);
|
||||||
foreach ([2] as $id) {
|
foreach ([2] as $id) {
|
||||||
unset($state['arsse_tokens']['rows'][$id - 1]);
|
unset($state['arsse_tokens']['rows'][$id - 1]);
|
||||||
|
|
|
@ -11,7 +11,7 @@ use JKingWeb\Arsse\Arsse;
|
||||||
trait SeriesFeed {
|
trait SeriesFeed {
|
||||||
protected function setUpSeriesFeed(): void {
|
protected function setUpSeriesFeed(): void {
|
||||||
// set up the test data
|
// set up the test data
|
||||||
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
||||||
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
||||||
$now = gmdate("Y-m-d H:i:s", strtotime("now"));
|
$now = gmdate("Y-m-d H:i:s", strtotime("now"));
|
||||||
$this->data = [
|
$this->data = [
|
||||||
|
@ -42,7 +42,7 @@ trait SeriesFeed {
|
||||||
[3,"http://localhost:8000/Feed/Fetching/Error?code=404","Ack",0,"",$past,$now,0],
|
[3,"http://localhost:8000/Feed/Fetching/Error?code=404","Ack",0,"",$past,$now,0],
|
||||||
[4,"http://localhost:8000/Feed/NextFetch/NotModified?t=".time(),"Ooook",0,"",$past,$past,0],
|
[4,"http://localhost:8000/Feed/NextFetch/NotModified?t=".time(),"Ooook",0,"",$past,$past,0],
|
||||||
[5,"http://localhost:8000/Feed/Parsing/Valid","Ooook",0,"",$past,$future,0],
|
[5,"http://localhost:8000/Feed/Parsing/Valid","Ooook",0,"",$past,$future,0],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -57,7 +57,7 @@ trait SeriesFeed {
|
||||||
[4,'john.doe@example.com',4],
|
[4,'john.doe@example.com',4],
|
||||||
[5,'john.doe@example.com',5],
|
[5,'john.doe@example.com',5],
|
||||||
[6,'jane.doe@example.com',1],
|
[6,'jane.doe@example.com',1],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_articles' => [
|
'arsse_articles' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -82,8 +82,8 @@ trait SeriesFeed {
|
||||||
[4,1,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:00','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',$past],
|
[4,1,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:00','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',$past],
|
||||||
[5,1,'http://example.com/5','Article title 5','','2000-01-05 00:00:00','2000-01-05 00:00:00','<p>Article content 5</p>','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41','d40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022','834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900','43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',$past],
|
[5,1,'http://example.com/5','Article title 5','','2000-01-05 00:00:00','2000-01-05 00:00:00','<p>Article content 5</p>','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41','d40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022','834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900','43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',$past],
|
||||||
[6,2,'http://example.com/1','Article title 1','','2000-01-01 00:00:00','2000-01-01 00:00:00','<p>Article content 1</p>','e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda','f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6','fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4','18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',$past],
|
[6,2,'http://example.com/1','Article title 1','','2000-01-01 00:00:00','2000-01-01 00:00:00','<p>Article content 1</p>','e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda','f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6','fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4','18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',$past],
|
||||||
[7,5,'' ,'' ,'','2000-01-01 00:00:00','2000-01-01 00:00:00','' ,'205e986f4f8b3acfa281227beadb14f5e8c32c8dae4737f888c94c0df49c56f8','' ,'' ,'' ,$past],
|
[7,5,'', '', '','2000-01-01 00:00:00','2000-01-01 00:00:00','', '205e986f4f8b3acfa281227beadb14f5e8c32c8dae4737f888c94c0df49c56f8','', '', '', $past],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_editions' => [
|
'arsse_editions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -97,7 +97,7 @@ trait SeriesFeed {
|
||||||
[3,3,$past],
|
[3,3,$past],
|
||||||
[4,4,$past],
|
[4,4,$past],
|
||||||
[5,5,$past],
|
[5,5,$past],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_marks' => [
|
'arsse_marks' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -118,7 +118,7 @@ trait SeriesFeed {
|
||||||
[1,1,1,0,$past],
|
[1,1,1,0,$past],
|
||||||
[3,1,1,0,$past],
|
[3,1,1,0,$past],
|
||||||
[4,1,0,1,$past],
|
[4,1,0,1,$past],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_enclosures' => [
|
'arsse_enclosures' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -128,16 +128,16 @@ trait SeriesFeed {
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[7,'http://example.com/png','image/png'],
|
[7,'http://example.com/png','image/png'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_categories' => [
|
'arsse_categories' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'article' => "int",
|
'article' => "int",
|
||||||
'name' => "str",
|
'name' => "str",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[7,'Syrinx']
|
[7,'Syrinx'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$this->matches = [
|
$this->matches = [
|
||||||
|
@ -191,7 +191,7 @@ trait SeriesFeed {
|
||||||
]);
|
]);
|
||||||
$state['arsse_articles']['rows'][2] = [3,1,'http://example.com/3','Article title 3 (updated)','','2000-01-03 00:00:00','2000-01-03 00:00:00','<p>Article content 3</p>','31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92','6cc99be662ef3486fef35a890123f18d74c29a32d714802d743c5b4ef713315a','b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406','d5faccc13bf8267850a1e8e61f95950a0f34167df2c8c58011c0aaa6367026ac',$now];
|
$state['arsse_articles']['rows'][2] = [3,1,'http://example.com/3','Article title 3 (updated)','','2000-01-03 00:00:00','2000-01-03 00:00:00','<p>Article content 3</p>','31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92','6cc99be662ef3486fef35a890123f18d74c29a32d714802d743c5b4ef713315a','b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406','d5faccc13bf8267850a1e8e61f95950a0f34167df2c8c58011c0aaa6367026ac',$now];
|
||||||
$state['arsse_articles']['rows'][3] = [4,1,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:01','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',$now];
|
$state['arsse_articles']['rows'][3] = [4,1,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:01','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',$now];
|
||||||
$state['arsse_articles']['rows'][] = [8,1,'http://example.com/6','Article title 6','','2000-01-06 00:00:00','2000-01-06 00:00:00','<p>Article content 6</p>','b3461ab8e8759eeb1d65a818c65051ec00c1dfbbb32a3c8f6999434e3e3b76ab','91d051a8e6749d014506848acd45e959af50bf876427c4f0e3a1ec0f04777b51','211d78b1a040d40d17e747a363cc283f58767b2e502630d8de9b8f1d5e941d18','5ed68ccb64243b8c1931241d2c9276274c3b1d87f223634aa7a1ab0141292ca7',$now];
|
$state['arsse_articles']['rows'][] = [8,1,'http://example.com/6','Article title 6','','2000-01-06 00:00:00','2000-01-06 00:00:00','<p>Article content 6</p>','b3461ab8e8759eeb1d65a818c65051ec00c1dfbbb32a3c8f6999434e3e3b76ab','91d051a8e6749d014506848acd45e959af50bf876427c4f0e3a1ec0f04777b51','211d78b1a040d40d17e747a363cc283f58767b2e502630d8de9b8f1d5e941d18','5ed68ccb64243b8c1931241d2c9276274c3b1d87f223634aa7a1ab0141292ca7',$now];
|
||||||
$state['arsse_editions']['rows'] = array_merge($state['arsse_editions']['rows'], [
|
$state['arsse_editions']['rows'] = array_merge($state['arsse_editions']['rows'], [
|
||||||
[6,8,$now],
|
[6,8,$now],
|
||||||
[7,3,$now],
|
[7,3,$now],
|
||||||
|
|
|
@ -45,7 +45,7 @@ trait SeriesFolder {
|
||||||
[4, "jane.doe@example.com", null, "Politics"],
|
[4, "jane.doe@example.com", null, "Politics"],
|
||||||
[5, "john.doe@example.com", null, "Politics"],
|
[5, "john.doe@example.com", null, "Politics"],
|
||||||
[6, "john.doe@example.com", 2, "Politics"],
|
[6, "john.doe@example.com", 2, "Politics"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_feeds' => [
|
'arsse_feeds' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -67,7 +67,7 @@ trait SeriesFolder {
|
||||||
[11,"http://example.com/11", "Feed 11"],
|
[11,"http://example.com/11", "Feed 11"],
|
||||||
[12,"http://example.com/12", "Feed 12"],
|
[12,"http://example.com/12", "Feed 12"],
|
||||||
[13,"http://example.com/13", "Feed 13"],
|
[13,"http://example.com/13", "Feed 13"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -88,7 +88,7 @@ trait SeriesFolder {
|
||||||
[9, "jane.doe@example.com",2, 4],
|
[9, "jane.doe@example.com",2, 4],
|
||||||
[10,"jane.doe@example.com",3, 4],
|
[10,"jane.doe@example.com",3, 4],
|
||||||
[11,"jane.doe@example.com",4, 4],
|
[11,"jane.doe@example.com",4, 4],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ trait SeriesLabel {
|
||||||
[7, "john.doe@example.net", null, "Technology"],
|
[7, "john.doe@example.net", null, "Technology"],
|
||||||
[8, "john.doe@example.net", 7, "Software"],
|
[8, "john.doe@example.net", 7, "Software"],
|
||||||
[9, "john.doe@example.net", null, "Politics"],
|
[9, "john.doe@example.net", null, "Politics"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_feeds' => [
|
'arsse_feeds' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -63,7 +63,7 @@ trait SeriesLabel {
|
||||||
[11,"http://example.com/11"],
|
[11,"http://example.com/11"],
|
||||||
[12,"http://example.com/12"],
|
[12,"http://example.com/12"],
|
||||||
[13,"http://example.com/13"],
|
[13,"http://example.com/13"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -87,7 +87,7 @@ trait SeriesLabel {
|
||||||
[12,"john.doe@example.net",2,9],
|
[12,"john.doe@example.net",2,9],
|
||||||
[13,"john.doe@example.net",3,8],
|
[13,"john.doe@example.net",3,8],
|
||||||
[14,"john.doe@example.net",4,7],
|
[14,"john.doe@example.net",4,7],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_articles' => [
|
'arsse_articles' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -131,7 +131,7 @@ trait SeriesLabel {
|
||||||
[103,12,'http://example.com/3','Article title 3','','2000-01-03 00:00:00','2000-01-03 00:00:03','<p>Article content 3</p>','31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92','f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b','b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406','ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b','2000-01-03 03:00:00'],
|
[103,12,'http://example.com/3','Article title 3','','2000-01-03 00:00:00','2000-01-03 00:00:03','<p>Article content 3</p>','31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92','f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b','b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406','ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b','2000-01-03 03:00:00'],
|
||||||
[104,12,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:04','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9','2000-01-04 04:00:00'],
|
[104,12,'http://example.com/4','Article title 4','','2000-01-04 00:00:00','2000-01-04 00:00:04','<p>Article content 4</p>','804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180','f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8','f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3','ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9','2000-01-04 04:00:00'],
|
||||||
[105,13,'http://example.com/5','Article title 5','','2000-01-05 00:00:00','2000-01-05 00:00:05','<p>Article content 5</p>','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41','d40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022','834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900','43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba','2000-01-05 05:00:00'],
|
[105,13,'http://example.com/5','Article title 5','','2000-01-05 00:00:00','2000-01-05 00:00:05','<p>Article content 5</p>','db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41','d40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022','834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900','43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba','2000-01-05 05:00:00'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_enclosures' => [
|
'arsse_enclosures' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -145,7 +145,7 @@ trait SeriesLabel {
|
||||||
[104,"http://example.com/image","image/svg+xml"],
|
[104,"http://example.com/image","image/svg+xml"],
|
||||||
[105,"http://example.com/audio","audio/ogg"],
|
[105,"http://example.com/audio","audio/ogg"],
|
||||||
|
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_editions' => [
|
'arsse_editions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -184,7 +184,7 @@ trait SeriesLabel {
|
||||||
[205,105],
|
[205,105],
|
||||||
[305,105],
|
[305,105],
|
||||||
[1001,20],
|
[1001,20],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_marks' => [
|
'arsse_marks' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -192,7 +192,7 @@ trait SeriesLabel {
|
||||||
'article' => "int",
|
'article' => "int",
|
||||||
'read' => "bool",
|
'read' => "bool",
|
||||||
'starred' => "bool",
|
'starred' => "bool",
|
||||||
'modified' => "datetime"
|
'modified' => "datetime",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[1, 1,1,1,'2000-01-01 00:00:00'],
|
[1, 1,1,1,'2000-01-01 00:00:00'],
|
||||||
|
@ -207,7 +207,7 @@ trait SeriesLabel {
|
||||||
[11, 20,1,0,'2017-01-01 00:00:00'],
|
[11, 20,1,0,'2017-01-01 00:00:00'],
|
||||||
[12, 3,0,1,'2017-01-01 00:00:00'],
|
[12, 3,0,1,'2017-01-01 00:00:00'],
|
||||||
[12, 4,1,1,'2017-01-01 00:00:00'],
|
[12, 4,1,1,'2017-01-01 00:00:00'],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_labels' => [
|
'arsse_labels' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -224,10 +224,10 @@ trait SeriesLabel {
|
||||||
],
|
],
|
||||||
'arsse_label_members' => [
|
'arsse_label_members' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'label' => "int",
|
'label' => "int",
|
||||||
'article' => "int",
|
'article' => "int",
|
||||||
'subscription' => "int",
|
'subscription' => "int",
|
||||||
'assigned' => "bool",
|
'assigned' => "bool",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[1, 1,1,1],
|
[1, 1,1,1],
|
||||||
|
|
|
@ -17,7 +17,7 @@ trait SeriesSession {
|
||||||
'userSessionLifetime' => "PT24H",
|
'userSessionLifetime' => "PT24H",
|
||||||
]);
|
]);
|
||||||
// set up the test data
|
// set up the test data
|
||||||
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
||||||
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
||||||
$faroff = gmdate("Y-m-d H:i:s", strtotime("now + 1 hour"));
|
$faroff = gmdate("Y-m-d H:i:s", strtotime("now + 1 hour"));
|
||||||
$old = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
$old = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
||||||
|
@ -55,12 +55,12 @@ trait SeriesSession {
|
||||||
|
|
||||||
public function testResumeAValidSession(): void {
|
public function testResumeAValidSession(): void {
|
||||||
$exp1 = [
|
$exp1 = [
|
||||||
'id' => "80fa94c1a11f11e78667001e673b2560",
|
'id' => "80fa94c1a11f11e78667001e673b2560",
|
||||||
'user' => "jane.doe@example.com"
|
'user' => "jane.doe@example.com",
|
||||||
];
|
];
|
||||||
$exp2 = [
|
$exp2 = [
|
||||||
'id' => "da772f8fa13c11e78667001e673b2560",
|
'id' => "da772f8fa13c11e78667001e673b2560",
|
||||||
'user' => "john.doe@example.com"
|
'user' => "john.doe@example.com",
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($exp1, Arsse::$db->sessionResume("80fa94c1a11f11e78667001e673b2560"));
|
$this->assertArraySubset($exp1, Arsse::$db->sessionResume("80fa94c1a11f11e78667001e673b2560"));
|
||||||
$this->assertArraySubset($exp2, Arsse::$db->sessionResume("da772f8fa13c11e78667001e673b2560"));
|
$this->assertArraySubset($exp2, Arsse::$db->sessionResume("da772f8fa13c11e78667001e673b2560"));
|
||||||
|
|
|
@ -38,7 +38,7 @@ trait SeriesSubscription {
|
||||||
[4, "jane.doe@example.com", null, "Politics"],
|
[4, "jane.doe@example.com", null, "Politics"],
|
||||||
[5, "john.doe@example.com", null, "Politics"],
|
[5, "john.doe@example.com", null, "Politics"],
|
||||||
[6, "john.doe@example.com", 2, "Politics"],
|
[6, "john.doe@example.com", 2, "Politics"],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_feeds' => [
|
'arsse_feeds' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -51,7 +51,7 @@ trait SeriesSubscription {
|
||||||
'next_fetch' => "datetime",
|
'next_fetch' => "datetime",
|
||||||
'favicon' => "str",
|
'favicon' => "str",
|
||||||
],
|
],
|
||||||
'rows' => [] // filled in the series setup
|
'rows' => [], // filled in the series setup
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -67,7 +67,7 @@ trait SeriesSubscription {
|
||||||
[1,"john.doe@example.com",2,null,null,1,2],
|
[1,"john.doe@example.com",2,null,null,1,2],
|
||||||
[2,"jane.doe@example.com",2,null,null,0,0],
|
[2,"jane.doe@example.com",2,null,null,0,0],
|
||||||
[3,"john.doe@example.com",3,"Ook",2,0,1],
|
[3,"john.doe@example.com",3,"Ook",2,0,1],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_tags' => [
|
'arsse_tags' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -84,9 +84,9 @@ trait SeriesSubscription {
|
||||||
],
|
],
|
||||||
'arsse_tag_members' => [
|
'arsse_tag_members' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'tag' => "int",
|
'tag' => "int",
|
||||||
'subscription' => "int",
|
'subscription' => "int",
|
||||||
'assigned' => "bool",
|
'assigned' => "bool",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[1,1,1],
|
[1,1,1],
|
||||||
|
@ -113,7 +113,7 @@ trait SeriesSubscription {
|
||||||
[6,3,"","",""],
|
[6,3,"","",""],
|
||||||
[7,3,"","",""],
|
[7,3,"","",""],
|
||||||
[8,3,"","",""],
|
[8,3,"","",""],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_marks' => [
|
'arsse_marks' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -131,7 +131,7 @@ trait SeriesSubscription {
|
||||||
[1,1,1,0],
|
[1,1,1,0],
|
||||||
[7,3,1,0],
|
[7,3,1,0],
|
||||||
[8,3,0,0],
|
[8,3,0,0],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
$this->data['arsse_feeds']['rows'] = [
|
$this->data['arsse_feeds']['rows'] = [
|
||||||
|
@ -379,9 +379,9 @@ trait SeriesSubscription {
|
||||||
|
|
||||||
public function testSetThePropertiesOfASubscription(): void {
|
public function testSetThePropertiesOfASubscription(): void {
|
||||||
Arsse::$db->subscriptionPropertiesSet($this->user, 1, [
|
Arsse::$db->subscriptionPropertiesSet($this->user, 1, [
|
||||||
'title' => "Ook Ook",
|
'title' => "Ook Ook",
|
||||||
'folder' => 3,
|
'folder' => 3,
|
||||||
'pinned' => false,
|
'pinned' => false,
|
||||||
'order_type' => 0,
|
'order_type' => 0,
|
||||||
]);
|
]);
|
||||||
\Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionPropertiesSet");
|
\Phake::verify(Arsse::$user)->authorize($this->user, "subscriptionPropertiesSet");
|
||||||
|
|
|
@ -44,7 +44,7 @@ trait SeriesTag {
|
||||||
[11,"http://example.com/11",""],
|
[11,"http://example.com/11",""],
|
||||||
[12,"http://example.com/12",""],
|
[12,"http://example.com/12",""],
|
||||||
[13,"http://example.com/13",""],
|
[13,"http://example.com/13",""],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_subscriptions' => [
|
'arsse_subscriptions' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -68,7 +68,7 @@ trait SeriesTag {
|
||||||
[12,"john.doe@example.net", 2,null],
|
[12,"john.doe@example.net", 2,null],
|
||||||
[13,"john.doe@example.net", 3,null],
|
[13,"john.doe@example.net", 3,null],
|
||||||
[14,"john.doe@example.net", 4,null],
|
[14,"john.doe@example.net", 4,null],
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
'arsse_tags' => [
|
'arsse_tags' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
|
@ -85,9 +85,9 @@ trait SeriesTag {
|
||||||
],
|
],
|
||||||
'arsse_tag_members' => [
|
'arsse_tag_members' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'tag' => "int",
|
'tag' => "int",
|
||||||
'subscription' => "int",
|
'subscription' => "int",
|
||||||
'assigned' => "bool",
|
'assigned' => "bool",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[1,1,1],
|
[1,1,1],
|
||||||
|
|
|
@ -11,7 +11,7 @@ use JKingWeb\Arsse\Arsse;
|
||||||
trait SeriesToken {
|
trait SeriesToken {
|
||||||
protected function setUpSeriesToken(): void {
|
protected function setUpSeriesToken(): void {
|
||||||
// set up the test data
|
// set up the test data
|
||||||
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
$past = gmdate("Y-m-d H:i:s", strtotime("now - 1 minute"));
|
||||||
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
$future = gmdate("Y-m-d H:i:s", strtotime("now + 1 minute"));
|
||||||
$faroff = gmdate("Y-m-d H:i:s", strtotime("now + 1 hour"));
|
$faroff = gmdate("Y-m-d H:i:s", strtotime("now + 1 hour"));
|
||||||
$old = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
$old = gmdate("Y-m-d H:i:s", strtotime("now - 2 days"));
|
||||||
|
@ -30,7 +30,7 @@ trait SeriesToken {
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'id' => "str",
|
'id' => "str",
|
||||||
'class' => "str",
|
'class' => "str",
|
||||||
'user' => "str",
|
'user' => "str",
|
||||||
'expires' => "datetime",
|
'expires' => "datetime",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
|
@ -49,19 +49,19 @@ trait SeriesToken {
|
||||||
|
|
||||||
public function testLookUpAValidToken(): void {
|
public function testLookUpAValidToken(): void {
|
||||||
$exp1 = [
|
$exp1 = [
|
||||||
'id' => "80fa94c1a11f11e78667001e673b2560",
|
'id' => "80fa94c1a11f11e78667001e673b2560",
|
||||||
'class' => "fever.login",
|
'class' => "fever.login",
|
||||||
'user' => "jane.doe@example.com"
|
'user' => "jane.doe@example.com",
|
||||||
];
|
];
|
||||||
$exp2 = [
|
$exp2 = [
|
||||||
'id' => "da772f8fa13c11e78667001e673b2560",
|
'id' => "da772f8fa13c11e78667001e673b2560",
|
||||||
'class' => "class.class",
|
'class' => "class.class",
|
||||||
'user' => "john.doe@example.com"
|
'user' => "john.doe@example.com",
|
||||||
];
|
];
|
||||||
$exp3 = [
|
$exp3 = [
|
||||||
'id' => "ab3b3eb8a13311e78667001e673b2560",
|
'id' => "ab3b3eb8a13311e78667001e673b2560",
|
||||||
'class' => "class.class",
|
'class' => "class.class",
|
||||||
'user' => "jane.doe@example.com"
|
'user' => "jane.doe@example.com",
|
||||||
];
|
];
|
||||||
$this->assertArraySubset($exp1, Arsse::$db->tokenLookup("fever.login", "80fa94c1a11f11e78667001e673b2560"));
|
$this->assertArraySubset($exp1, Arsse::$db->tokenLookup("fever.login", "80fa94c1a11f11e78667001e673b2560"));
|
||||||
$this->assertArraySubset($exp2, Arsse::$db->tokenLookup("class.class", "da772f8fa13c11e78667001e673b2560"));
|
$this->assertArraySubset($exp2, Arsse::$db->tokenLookup("class.class", "da772f8fa13c11e78667001e673b2560"));
|
||||||
|
|
|
@ -49,7 +49,7 @@ class TestDatabase extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
["?,?", [null, null], [null, null], "str"],
|
["?,?", [null, null], [null, null], "str"],
|
||||||
["null", [], array_fill(0, $l, null), "str"],
|
["null", [], array_fill(0, $l, null), "str"],
|
||||||
["$intList", [], $ints, "int"],
|
["$intList", [], $ints, "int"],
|
||||||
["$intList,".($l+1), [], array_merge($ints, [$l+1]), "int"],
|
["$intList,".($l + 1), [], array_merge($ints, [$l + 1]), "int"],
|
||||||
["$intList,0", [], array_merge($ints, ["OOK"]), "int"],
|
["$intList,0", [], array_merge($ints, ["OOK"]), "int"],
|
||||||
["$intList", [], array_merge($ints, [null]), "int"],
|
["$intList", [], array_merge($ints, [null]), "int"],
|
||||||
["$stringList,''", [], array_merge($strings, [""]), "str"],
|
["$stringList,''", [], array_merge($strings, [""]), "str"],
|
||||||
|
|
|
@ -17,8 +17,8 @@ abstract class BaseDriver extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected $lock;
|
protected $lock;
|
||||||
protected $setVersion;
|
protected $setVersion;
|
||||||
protected static $conf = [
|
protected static $conf = [
|
||||||
'dbTimeoutExec' => 0.5,
|
'dbTimeoutExec' => 0.5,
|
||||||
'dbTimeoutLock' => 0.001,
|
'dbTimeoutLock' => 0.001,
|
||||||
'dbSQLite3Timeout' => 0,
|
'dbSQLite3Timeout' => 0,
|
||||||
//'dbSQLite3File' => "(temporary file)",
|
//'dbSQLite3File' => "(temporary file)",
|
||||||
];
|
];
|
||||||
|
|
|
@ -134,138 +134,138 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$dateImmutable = new \DateTimeImmutable("Noon Today", new \DateTimezone("America/Toronto"));
|
$dateImmutable = new \DateTimeImmutable("Noon Today", new \DateTimezone("America/Toronto"));
|
||||||
$dateUTC = new \DateTime("@".$dateMutable->getTimestamp(), new \DateTimezone("UTC"));
|
$dateUTC = new \DateTime("@".$dateMutable->getTimestamp(), new \DateTimezone("UTC"));
|
||||||
$tests = [
|
$tests = [
|
||||||
'Null as integer' => [null, "integer", "null"],
|
'Null as integer' => [null, "integer", "null"],
|
||||||
'Null as float' => [null, "float", "null"],
|
'Null as float' => [null, "float", "null"],
|
||||||
'Null as string' => [null, "string", "null"],
|
'Null as string' => [null, "string", "null"],
|
||||||
'Null as datetime' => [null, "datetime", "null"],
|
'Null as datetime' => [null, "datetime", "null"],
|
||||||
'Null as boolean' => [null, "boolean", "null"],
|
'Null as boolean' => [null, "boolean", "null"],
|
||||||
'Null as strict integer' => [null, "strict integer", "0"],
|
'Null as strict integer' => [null, "strict integer", "0"],
|
||||||
'Null as strict float' => [null, "strict float", "0.0"],
|
'Null as strict float' => [null, "strict float", "0.0"],
|
||||||
'Null as strict string' => [null, "strict string", "''"],
|
'Null as strict string' => [null, "strict string", "''"],
|
||||||
'Null as strict datetime' => [null, "strict datetime", "'0001-01-01 00:00:00'"],
|
'Null as strict datetime' => [null, "strict datetime", "'0001-01-01 00:00:00'"],
|
||||||
'Null as strict boolean' => [null, "strict boolean", "0"],
|
'Null as strict boolean' => [null, "strict boolean", "0"],
|
||||||
'True as integer' => [true, "integer", "1"],
|
'True as integer' => [true, "integer", "1"],
|
||||||
'True as float' => [true, "float", "1.0"],
|
'True as float' => [true, "float", "1.0"],
|
||||||
'True as string' => [true, "string", "'1'"],
|
'True as string' => [true, "string", "'1'"],
|
||||||
'True as datetime' => [true, "datetime", "null"],
|
'True as datetime' => [true, "datetime", "null"],
|
||||||
'True as boolean' => [true, "boolean", "1"],
|
'True as boolean' => [true, "boolean", "1"],
|
||||||
'True as strict integer' => [true, "strict integer", "1"],
|
'True as strict integer' => [true, "strict integer", "1"],
|
||||||
'True as strict float' => [true, "strict float", "1.0"],
|
'True as strict float' => [true, "strict float", "1.0"],
|
||||||
'True as strict string' => [true, "strict string", "'1'"],
|
'True as strict string' => [true, "strict string", "'1'"],
|
||||||
'True as strict datetime' => [true, "strict datetime", "'0001-01-01 00:00:00'"],
|
'True as strict datetime' => [true, "strict datetime", "'0001-01-01 00:00:00'"],
|
||||||
'True as strict boolean' => [true, "strict boolean", "1"],
|
'True as strict boolean' => [true, "strict boolean", "1"],
|
||||||
'False as integer' => [false, "integer", "0"],
|
'False as integer' => [false, "integer", "0"],
|
||||||
'False as float' => [false, "float", "0.0"],
|
'False as float' => [false, "float", "0.0"],
|
||||||
'False as string' => [false, "string", "''"],
|
'False as string' => [false, "string", "''"],
|
||||||
'False as datetime' => [false, "datetime", "null"],
|
'False as datetime' => [false, "datetime", "null"],
|
||||||
'False as boolean' => [false, "boolean", "0"],
|
'False as boolean' => [false, "boolean", "0"],
|
||||||
'False as strict integer' => [false, "strict integer", "0"],
|
'False as strict integer' => [false, "strict integer", "0"],
|
||||||
'False as strict float' => [false, "strict float", "0.0"],
|
'False as strict float' => [false, "strict float", "0.0"],
|
||||||
'False as strict string' => [false, "strict string", "''"],
|
'False as strict string' => [false, "strict string", "''"],
|
||||||
'False as strict datetime' => [false, "strict datetime", "'0001-01-01 00:00:00'"],
|
'False as strict datetime' => [false, "strict datetime", "'0001-01-01 00:00:00'"],
|
||||||
'False as strict boolean' => [false, "strict boolean", "0"],
|
'False as strict boolean' => [false, "strict boolean", "0"],
|
||||||
'Integer as integer' => [2112, "integer", "2112"],
|
'Integer as integer' => [2112, "integer", "2112"],
|
||||||
'Integer as float' => [2112, "float", "2112.0"],
|
'Integer as float' => [2112, "float", "2112.0"],
|
||||||
'Integer as string' => [2112, "string", "'2112'"],
|
'Integer as string' => [2112, "string", "'2112'"],
|
||||||
'Integer as datetime' => [2112, "datetime", "'1970-01-01 00:35:12'"],
|
'Integer as datetime' => [2112, "datetime", "'1970-01-01 00:35:12'"],
|
||||||
'Integer as boolean' => [2112, "boolean", "1"],
|
'Integer as boolean' => [2112, "boolean", "1"],
|
||||||
'Integer as strict integer' => [2112, "strict integer", "2112"],
|
'Integer as strict integer' => [2112, "strict integer", "2112"],
|
||||||
'Integer as strict float' => [2112, "strict float", "2112.0"],
|
'Integer as strict float' => [2112, "strict float", "2112.0"],
|
||||||
'Integer as strict string' => [2112, "strict string", "'2112'"],
|
'Integer as strict string' => [2112, "strict string", "'2112'"],
|
||||||
'Integer as strict datetime' => [2112, "strict datetime", "'1970-01-01 00:35:12'"],
|
'Integer as strict datetime' => [2112, "strict datetime", "'1970-01-01 00:35:12'"],
|
||||||
'Integer as strict boolean' => [2112, "strict boolean", "1"],
|
'Integer as strict boolean' => [2112, "strict boolean", "1"],
|
||||||
'Integer zero as integer' => [0, "integer", "0"],
|
'Integer zero as integer' => [0, "integer", "0"],
|
||||||
'Integer zero as float' => [0, "float", "0.0"],
|
'Integer zero as float' => [0, "float", "0.0"],
|
||||||
'Integer zero as string' => [0, "string", "'0'"],
|
'Integer zero as string' => [0, "string", "'0'"],
|
||||||
'Integer zero as datetime' => [0, "datetime", "'1970-01-01 00:00:00'"],
|
'Integer zero as datetime' => [0, "datetime", "'1970-01-01 00:00:00'"],
|
||||||
'Integer zero as boolean' => [0, "boolean", "0"],
|
'Integer zero as boolean' => [0, "boolean", "0"],
|
||||||
'Integer zero as strict integer' => [0, "strict integer", "0"],
|
'Integer zero as strict integer' => [0, "strict integer", "0"],
|
||||||
'Integer zero as strict float' => [0, "strict float", "0.0"],
|
'Integer zero as strict float' => [0, "strict float", "0.0"],
|
||||||
'Integer zero as strict string' => [0, "strict string", "'0'"],
|
'Integer zero as strict string' => [0, "strict string", "'0'"],
|
||||||
'Integer zero as strict datetime' => [0, "strict datetime", "'1970-01-01 00:00:00'"],
|
'Integer zero as strict datetime' => [0, "strict datetime", "'1970-01-01 00:00:00'"],
|
||||||
'Integer zero as strict boolean' => [0, "strict boolean", "0"],
|
'Integer zero as strict boolean' => [0, "strict boolean", "0"],
|
||||||
'Float as integer' => [2112.5, "integer", "2112"],
|
'Float as integer' => [2112.5, "integer", "2112"],
|
||||||
'Float as float' => [2112.5, "float", "2112.5"],
|
'Float as float' => [2112.5, "float", "2112.5"],
|
||||||
'Float as string' => [2112.5, "string", "'2112.5'"],
|
'Float as string' => [2112.5, "string", "'2112.5'"],
|
||||||
'Float as datetime' => [2112.5, "datetime", "'1970-01-01 00:35:12'"],
|
'Float as datetime' => [2112.5, "datetime", "'1970-01-01 00:35:12'"],
|
||||||
'Float as boolean' => [2112.5, "boolean", "1"],
|
'Float as boolean' => [2112.5, "boolean", "1"],
|
||||||
'Float as strict integer' => [2112.5, "strict integer", "2112"],
|
'Float as strict integer' => [2112.5, "strict integer", "2112"],
|
||||||
'Float as strict float' => [2112.5, "strict float", "2112.5"],
|
'Float as strict float' => [2112.5, "strict float", "2112.5"],
|
||||||
'Float as strict string' => [2112.5, "strict string", "'2112.5'"],
|
'Float as strict string' => [2112.5, "strict string", "'2112.5'"],
|
||||||
'Float as strict datetime' => [2112.5, "strict datetime", "'1970-01-01 00:35:12'"],
|
'Float as strict datetime' => [2112.5, "strict datetime", "'1970-01-01 00:35:12'"],
|
||||||
'Float as strict boolean' => [2112.5, "strict boolean", "1"],
|
'Float as strict boolean' => [2112.5, "strict boolean", "1"],
|
||||||
'Float zero as integer' => [0.0, "integer", "0"],
|
'Float zero as integer' => [0.0, "integer", "0"],
|
||||||
'Float zero as float' => [0.0, "float", "0.0"],
|
'Float zero as float' => [0.0, "float", "0.0"],
|
||||||
'Float zero as string' => [0.0, "string", "'0'"],
|
'Float zero as string' => [0.0, "string", "'0'"],
|
||||||
'Float zero as datetime' => [0.0, "datetime", "'1970-01-01 00:00:00'"],
|
'Float zero as datetime' => [0.0, "datetime", "'1970-01-01 00:00:00'"],
|
||||||
'Float zero as boolean' => [0.0, "boolean", "0"],
|
'Float zero as boolean' => [0.0, "boolean", "0"],
|
||||||
'Float zero as strict integer' => [0.0, "strict integer", "0"],
|
'Float zero as strict integer' => [0.0, "strict integer", "0"],
|
||||||
'Float zero as strict float' => [0.0, "strict float", "0.0"],
|
'Float zero as strict float' => [0.0, "strict float", "0.0"],
|
||||||
'Float zero as strict string' => [0.0, "strict string", "'0'"],
|
'Float zero as strict string' => [0.0, "strict string", "'0'"],
|
||||||
'Float zero as strict datetime' => [0.0, "strict datetime", "'1970-01-01 00:00:00'"],
|
'Float zero as strict datetime' => [0.0, "strict datetime", "'1970-01-01 00:00:00'"],
|
||||||
'Float zero as strict boolean' => [0.0, "strict boolean", "0"],
|
'Float zero as strict boolean' => [0.0, "strict boolean", "0"],
|
||||||
'ASCII string as integer' => ["Random string", "integer", "0"],
|
'ASCII string as integer' => ["Random string", "integer", "0"],
|
||||||
'ASCII string as float' => ["Random string", "float", "0.0"],
|
'ASCII string as float' => ["Random string", "float", "0.0"],
|
||||||
'ASCII string as string' => ["Random string", "string", "'Random string'"],
|
'ASCII string as string' => ["Random string", "string", "'Random string'"],
|
||||||
'ASCII string as datetime' => ["Random string", "datetime", "null"],
|
'ASCII string as datetime' => ["Random string", "datetime", "null"],
|
||||||
'ASCII string as boolean' => ["Random string", "boolean", "1"],
|
'ASCII string as boolean' => ["Random string", "boolean", "1"],
|
||||||
'ASCII string as strict integer' => ["Random string", "strict integer", "0"],
|
'ASCII string as strict integer' => ["Random string", "strict integer", "0"],
|
||||||
'ASCII string as strict float' => ["Random string", "strict float", "0.0"],
|
'ASCII string as strict float' => ["Random string", "strict float", "0.0"],
|
||||||
'ASCII string as strict string' => ["Random string", "strict string", "'Random string'"],
|
'ASCII string as strict string' => ["Random string", "strict string", "'Random string'"],
|
||||||
'ASCII string as strict datetime' => ["Random string", "strict datetime", "'0001-01-01 00:00:00'"],
|
'ASCII string as strict datetime' => ["Random string", "strict datetime", "'0001-01-01 00:00:00'"],
|
||||||
'ASCII string as strict boolean' => ["Random string", "strict boolean", "1"],
|
'ASCII string as strict boolean' => ["Random string", "strict boolean", "1"],
|
||||||
'UTF-8 string as integer' => ["\u{e9}", "integer", "0"],
|
'UTF-8 string as integer' => ["\u{e9}", "integer", "0"],
|
||||||
'UTF-8 string as float' => ["\u{e9}", "float", "0.0"],
|
'UTF-8 string as float' => ["\u{e9}", "float", "0.0"],
|
||||||
'UTF-8 string as string' => ["\u{e9}", "string", "char(233)"],
|
'UTF-8 string as string' => ["\u{e9}", "string", "char(233)"],
|
||||||
'UTF-8 string as datetime' => ["\u{e9}", "datetime", "null"],
|
'UTF-8 string as datetime' => ["\u{e9}", "datetime", "null"],
|
||||||
'UTF-8 string as boolean' => ["\u{e9}", "boolean", "1"],
|
'UTF-8 string as boolean' => ["\u{e9}", "boolean", "1"],
|
||||||
'UTF-8 string as strict integer' => ["\u{e9}", "strict integer", "0"],
|
'UTF-8 string as strict integer' => ["\u{e9}", "strict integer", "0"],
|
||||||
'UTF-8 string as strict float' => ["\u{e9}", "strict float", "0.0"],
|
'UTF-8 string as strict float' => ["\u{e9}", "strict float", "0.0"],
|
||||||
'UTF-8 string as strict string' => ["\u{e9}", "strict string", "char(233)"],
|
'UTF-8 string as strict string' => ["\u{e9}", "strict string", "char(233)"],
|
||||||
'UTF-8 string as strict datetime' => ["\u{e9}", "strict datetime", "'0001-01-01 00:00:00'"],
|
'UTF-8 string as strict datetime' => ["\u{e9}", "strict datetime", "'0001-01-01 00:00:00'"],
|
||||||
'UTF-8 string as strict boolean' => ["\u{e9}", "strict boolean", "1"],
|
'UTF-8 string as strict boolean' => ["\u{e9}", "strict boolean", "1"],
|
||||||
'ISO 8601 string as integer' => ["2017-01-09T13:11:17", "integer", "0"],
|
'ISO 8601 string as integer' => ["2017-01-09T13:11:17", "integer", "0"],
|
||||||
'ISO 8601 string as float' => ["2017-01-09T13:11:17", "float", "0.0"],
|
'ISO 8601 string as float' => ["2017-01-09T13:11:17", "float", "0.0"],
|
||||||
'ISO 8601 string as string' => ["2017-01-09T13:11:17", "string", "'2017-01-09T13:11:17'"],
|
'ISO 8601 string as string' => ["2017-01-09T13:11:17", "string", "'2017-01-09T13:11:17'"],
|
||||||
'ISO 8601 string as datetime' => ["2017-01-09T13:11:17", "datetime", "'2017-01-09 13:11:17'"],
|
'ISO 8601 string as datetime' => ["2017-01-09T13:11:17", "datetime", "'2017-01-09 13:11:17'"],
|
||||||
'ISO 8601 string as boolean' => ["2017-01-09T13:11:17", "boolean", "1"],
|
'ISO 8601 string as boolean' => ["2017-01-09T13:11:17", "boolean", "1"],
|
||||||
'ISO 8601 string as strict integer' => ["2017-01-09T13:11:17", "strict integer", "0"],
|
'ISO 8601 string as strict integer' => ["2017-01-09T13:11:17", "strict integer", "0"],
|
||||||
'ISO 8601 string as strict float' => ["2017-01-09T13:11:17", "strict float", "0.0"],
|
'ISO 8601 string as strict float' => ["2017-01-09T13:11:17", "strict float", "0.0"],
|
||||||
'ISO 8601 string as strict string' => ["2017-01-09T13:11:17", "strict string", "'2017-01-09T13:11:17'"],
|
'ISO 8601 string as strict string' => ["2017-01-09T13:11:17", "strict string", "'2017-01-09T13:11:17'"],
|
||||||
'ISO 8601 string as strict datetime' => ["2017-01-09T13:11:17", "strict datetime", "'2017-01-09 13:11:17'"],
|
'ISO 8601 string as strict datetime' => ["2017-01-09T13:11:17", "strict datetime", "'2017-01-09 13:11:17'"],
|
||||||
'ISO 8601 string as strict boolean' => ["2017-01-09T13:11:17", "strict boolean", "1"],
|
'ISO 8601 string as strict boolean' => ["2017-01-09T13:11:17", "strict boolean", "1"],
|
||||||
'Arbitrary date string as integer' => ["Today", "integer", "0"],
|
'Arbitrary date string as integer' => ["Today", "integer", "0"],
|
||||||
'Arbitrary date string as float' => ["Today", "float", "0.0"],
|
'Arbitrary date string as float' => ["Today", "float", "0.0"],
|
||||||
'Arbitrary date string as string' => ["Today", "string", "'Today'"],
|
'Arbitrary date string as string' => ["Today", "string", "'Today'"],
|
||||||
'Arbitrary date string as datetime' => ["Today", "datetime", "'".date_create("Today", new \DateTimezone("UTC"))->format("Y-m-d H:i:s")."'"],
|
'Arbitrary date string as datetime' => ["Today", "datetime", "'".date_create("Today", new \DateTimezone("UTC"))->format("Y-m-d H:i:s")."'"],
|
||||||
'Arbitrary date string as boolean' => ["Today", "boolean", "1"],
|
'Arbitrary date string as boolean' => ["Today", "boolean", "1"],
|
||||||
'Arbitrary date string as strict integer' => ["Today", "strict integer", "0"],
|
'Arbitrary date string as strict integer' => ["Today", "strict integer", "0"],
|
||||||
'Arbitrary date string as strict float' => ["Today", "strict float", "0.0"],
|
'Arbitrary date string as strict float' => ["Today", "strict float", "0.0"],
|
||||||
'Arbitrary date string as strict string' => ["Today", "strict string", "'Today'"],
|
'Arbitrary date string as strict string' => ["Today", "strict string", "'Today'"],
|
||||||
'Arbitrary date string as strict datetime' => ["Today", "strict datetime", "'".date_create("Today", new \DateTimezone("UTC"))->format("Y-m-d H:i:s")."'"],
|
'Arbitrary date string as strict datetime' => ["Today", "strict datetime", "'".date_create("Today", new \DateTimezone("UTC"))->format("Y-m-d H:i:s")."'"],
|
||||||
'Arbitrary date string as strict boolean' => ["Today", "strict boolean", "1"],
|
'Arbitrary date string as strict boolean' => ["Today", "strict boolean", "1"],
|
||||||
'DateTime as integer' => [$dateMutable, "integer", (string) $dateUTC->getTimestamp()],
|
'DateTime as integer' => [$dateMutable, "integer", (string) $dateUTC->getTimestamp()],
|
||||||
'DateTime as float' => [$dateMutable, "float", $dateUTC->getTimestamp().".0"],
|
'DateTime as float' => [$dateMutable, "float", $dateUTC->getTimestamp().".0"],
|
||||||
'DateTime as string' => [$dateMutable, "string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTime as string' => [$dateMutable, "string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTime as datetime' => [$dateMutable, "datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTime as datetime' => [$dateMutable, "datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTime as boolean' => [$dateMutable, "boolean", "1"],
|
'DateTime as boolean' => [$dateMutable, "boolean", "1"],
|
||||||
'DateTime as strict integer' => [$dateMutable, "strict integer", (string) $dateUTC->getTimestamp()],
|
'DateTime as strict integer' => [$dateMutable, "strict integer", (string) $dateUTC->getTimestamp()],
|
||||||
'DateTime as strict float' => [$dateMutable, "strict float", $dateUTC->getTimestamp().".0"],
|
'DateTime as strict float' => [$dateMutable, "strict float", $dateUTC->getTimestamp().".0"],
|
||||||
'DateTime as strict string' => [$dateMutable, "strict string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTime as strict string' => [$dateMutable, "strict string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTime as strict datetime' => [$dateMutable, "strict datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTime as strict datetime' => [$dateMutable, "strict datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTime as strict boolean' => [$dateMutable, "strict boolean", "1"],
|
'DateTime as strict boolean' => [$dateMutable, "strict boolean", "1"],
|
||||||
'DateTimeImmutable as integer' => [$dateImmutable, "integer", (string) $dateUTC->getTimestamp()],
|
'DateTimeImmutable as integer' => [$dateImmutable, "integer", (string) $dateUTC->getTimestamp()],
|
||||||
'DateTimeImmutable as float' => [$dateImmutable, "float", $dateUTC->getTimestamp().".0"],
|
'DateTimeImmutable as float' => [$dateImmutable, "float", $dateUTC->getTimestamp().".0"],
|
||||||
'DateTimeImmutable as string' => [$dateImmutable, "string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTimeImmutable as string' => [$dateImmutable, "string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTimeImmutable as datetime' => [$dateImmutable, "datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTimeImmutable as datetime' => [$dateImmutable, "datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTimeImmutable as boolean' => [$dateImmutable, "boolean", "1"],
|
'DateTimeImmutable as boolean' => [$dateImmutable, "boolean", "1"],
|
||||||
'DateTimeImmutable as strict integer' => [$dateImmutable, "strict integer", (string) $dateUTC->getTimestamp()],
|
'DateTimeImmutable as strict integer' => [$dateImmutable, "strict integer", (string) $dateUTC->getTimestamp()],
|
||||||
'DateTimeImmutable as strict float' => [$dateImmutable, "strict float", $dateUTC->getTimestamp().".0"],
|
'DateTimeImmutable as strict float' => [$dateImmutable, "strict float", $dateUTC->getTimestamp().".0"],
|
||||||
'DateTimeImmutable as strict string' => [$dateImmutable, "strict string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTimeImmutable as strict string' => [$dateImmutable, "strict string", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTimeImmutable as strict datetime' => [$dateImmutable, "strict datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
'DateTimeImmutable as strict datetime' => [$dateImmutable, "strict datetime", "'".$dateUTC->format("Y-m-d H:i:s")."'"],
|
||||||
'DateTimeImmutable as strict boolean' => [$dateImmutable, "strict boolean", "1"],
|
'DateTimeImmutable as strict boolean' => [$dateImmutable, "strict boolean", "1"],
|
||||||
];
|
];
|
||||||
foreach ($tests as $index => list($value, $type, $exp)) {
|
foreach ($tests as $index => [$value, $type, $exp]) {
|
||||||
$t = preg_replace("<^strict >", "", $type);
|
$t = preg_replace("<^strict >", "", $type);
|
||||||
$exp = ($exp === "null") ? $exp : $this->decorateTypeSyntax($exp, $t);
|
$exp = ($exp === "null") ? $exp : $this->decorateTypeSyntax($exp, $t);
|
||||||
yield $index => [$value, $type, $exp];
|
yield $index => [$value, $type, $exp];
|
||||||
|
@ -277,46 +277,46 @@ abstract class BaseStatement extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$dateImmutable = new \DateTimeImmutable("Noon Today", new \DateTimezone("America/Toronto"));
|
$dateImmutable = new \DateTimeImmutable("Noon Today", new \DateTimezone("America/Toronto"));
|
||||||
$dateUTC = new \DateTime("@".$dateMutable->getTimestamp(), new \DateTimezone("UTC"));
|
$dateUTC = new \DateTime("@".$dateMutable->getTimestamp(), new \DateTimezone("UTC"));
|
||||||
$tests = [
|
$tests = [
|
||||||
'Null as binary' => [null, "binary", "null"],
|
'Null as binary' => [null, "binary", "null"],
|
||||||
'Null as strict binary' => [null, "strict binary", "x''"],
|
'Null as strict binary' => [null, "strict binary", "x''"],
|
||||||
'True as binary' => [true, "binary", "x'31'"],
|
'True as binary' => [true, "binary", "x'31'"],
|
||||||
'True as strict binary' => [true, "strict binary", "x'31'"],
|
'True as strict binary' => [true, "strict binary", "x'31'"],
|
||||||
'False as binary' => [false, "binary", "x''"],
|
'False as binary' => [false, "binary", "x''"],
|
||||||
'False as strict binary' => [false, "strict binary", "x''"],
|
'False as strict binary' => [false, "strict binary", "x''"],
|
||||||
'Integer as binary' => [2112, "binary", "x'32313132'"],
|
'Integer as binary' => [2112, "binary", "x'32313132'"],
|
||||||
'Integer as strict binary' => [2112, "strict binary", "x'32313132'"],
|
'Integer as strict binary' => [2112, "strict binary", "x'32313132'"],
|
||||||
'Integer zero as binary' => [0, "binary", "x'30'"],
|
'Integer zero as binary' => [0, "binary", "x'30'"],
|
||||||
'Integer zero as strict binary' => [0, "strict binary", "x'30'"],
|
'Integer zero as strict binary' => [0, "strict binary", "x'30'"],
|
||||||
'Float as binary' => [2112.5, "binary", "x'323131322e35'"],
|
'Float as binary' => [2112.5, "binary", "x'323131322e35'"],
|
||||||
'Float as strict binary' => [2112.5, "strict binary", "x'323131322e35'"],
|
'Float as strict binary' => [2112.5, "strict binary", "x'323131322e35'"],
|
||||||
'Float zero as binary' => [0.0, "binary", "x'30'"],
|
'Float zero as binary' => [0.0, "binary", "x'30'"],
|
||||||
'Float zero as strict binary' => [0.0, "strict binary", "x'30'"],
|
'Float zero as strict binary' => [0.0, "strict binary", "x'30'"],
|
||||||
'ASCII string as binary' => ["Random string", "binary", "x'52616e646f6d20737472696e67'"],
|
'ASCII string as binary' => ["Random string", "binary", "x'52616e646f6d20737472696e67'"],
|
||||||
'ASCII string as strict binary' => ["Random string", "strict binary", "x'52616e646f6d20737472696e67'"],
|
'ASCII string as strict binary' => ["Random string", "strict binary", "x'52616e646f6d20737472696e67'"],
|
||||||
'UTF-8 string as binary' => ["\u{e9}", "binary", "x'c3a9'"],
|
'UTF-8 string as binary' => ["\u{e9}", "binary", "x'c3a9'"],
|
||||||
'UTF-8 string as strict binary' => ["\u{e9}", "strict binary", "x'c3a9'"],
|
'UTF-8 string as strict binary' => ["\u{e9}", "strict binary", "x'c3a9'"],
|
||||||
'Binary string as integer' => [chr(233).chr(233), "integer", "0"],
|
'Binary string as integer' => [chr(233).chr(233), "integer", "0"],
|
||||||
'Binary string as float' => [chr(233).chr(233), "float", "0.0"],
|
'Binary string as float' => [chr(233).chr(233), "float", "0.0"],
|
||||||
'Binary string as string' => [chr(233).chr(233), "string", "'".chr(233).chr(233)."'"],
|
'Binary string as string' => [chr(233).chr(233), "string", "'".chr(233).chr(233)."'"],
|
||||||
'Binary string as binary' => [chr(233).chr(233), "binary", "x'e9e9'"],
|
'Binary string as binary' => [chr(233).chr(233), "binary", "x'e9e9'"],
|
||||||
'Binary string as datetime' => [chr(233).chr(233), "datetime", "null"],
|
'Binary string as datetime' => [chr(233).chr(233), "datetime", "null"],
|
||||||
'Binary string as boolean' => [chr(233).chr(233), "boolean", "1"],
|
'Binary string as boolean' => [chr(233).chr(233), "boolean", "1"],
|
||||||
'Binary string as strict integer' => [chr(233).chr(233), "strict integer", "0"],
|
'Binary string as strict integer' => [chr(233).chr(233), "strict integer", "0"],
|
||||||
'Binary string as strict float' => [chr(233).chr(233), "strict float", "0.0"],
|
'Binary string as strict float' => [chr(233).chr(233), "strict float", "0.0"],
|
||||||
'Binary string as strict string' => [chr(233).chr(233), "strict string", "'".chr(233).chr(233)."'"],
|
'Binary string as strict string' => [chr(233).chr(233), "strict string", "'".chr(233).chr(233)."'"],
|
||||||
'Binary string as strict binary' => [chr(233).chr(233), "strict binary", "x'e9e9'"],
|
'Binary string as strict binary' => [chr(233).chr(233), "strict binary", "x'e9e9'"],
|
||||||
'Binary string as strict datetime' => [chr(233).chr(233), "strict datetime", "'0001-01-01 00:00:00'"],
|
'Binary string as strict datetime' => [chr(233).chr(233), "strict datetime", "'0001-01-01 00:00:00'"],
|
||||||
'Binary string as strict boolean' => [chr(233).chr(233), "strict boolean", "1"],
|
'Binary string as strict boolean' => [chr(233).chr(233), "strict boolean", "1"],
|
||||||
'ISO 8601 string as binary' => ["2017-01-09T13:11:17", "binary", "x'323031372d30312d30395431333a31313a3137'"],
|
'ISO 8601 string as binary' => ["2017-01-09T13:11:17", "binary", "x'323031372d30312d30395431333a31313a3137'"],
|
||||||
'ISO 8601 string as strict binary' => ["2017-01-09T13:11:17", "strict binary", "x'323031372d30312d30395431333a31313a3137'"],
|
'ISO 8601 string as strict binary' => ["2017-01-09T13:11:17", "strict binary", "x'323031372d30312d30395431333a31313a3137'"],
|
||||||
'Arbitrary date string as binary' => ["Today", "binary", "x'546f646179'"],
|
'Arbitrary date string as binary' => ["Today", "binary", "x'546f646179'"],
|
||||||
'Arbitrary date string as strict binary' => ["Today", "strict binary", "x'546f646179'"],
|
'Arbitrary date string as strict binary' => ["Today", "strict binary", "x'546f646179'"],
|
||||||
'DateTime as binary' => [$dateMutable, "binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
'DateTime as binary' => [$dateMutable, "binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
||||||
'DateTime as strict binary' => [$dateMutable, "strict binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
'DateTime as strict binary' => [$dateMutable, "strict binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
||||||
'DateTimeImmutable as binary' => [$dateImmutable, "binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
'DateTimeImmutable as binary' => [$dateImmutable, "binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
||||||
'DateTimeImmutable as strict binary' => [$dateImmutable, "strict binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
'DateTimeImmutable as strict binary' => [$dateImmutable, "strict binary", "x'".bin2hex($dateUTC->format("Y-m-d H:i:s"))."'"],
|
||||||
];
|
];
|
||||||
foreach ($tests as $index => list($value, $type, $exp)) {
|
foreach ($tests as $index => [$value, $type, $exp]) {
|
||||||
$t = preg_replace("<^strict >", "", $type);
|
$t = preg_replace("<^strict >", "", $type);
|
||||||
$exp = ($exp === "null") ? $exp : $this->decorateTypeSyntax($exp, $t);
|
$exp = ($exp === "null") ? $exp : $this->decorateTypeSyntax($exp, $t);
|
||||||
yield $index => [$value, $type, $exp];
|
yield $index => [$value, $type, $exp];
|
||||||
|
|
|
@ -27,8 +27,8 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->files = [
|
$this->files = [
|
||||||
// cannot create files
|
// cannot create files
|
||||||
'Cmain' => [],
|
'Cmain' => [],
|
||||||
'Cshm' => [
|
'Cshm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
],
|
],
|
||||||
'Cwal' => [
|
'Cwal' => [
|
||||||
|
@ -36,55 +36,55 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
],
|
],
|
||||||
// cannot write to files
|
// cannot write to files
|
||||||
'Wmain' => [
|
'Wmain' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Wwal' => [
|
'Wwal' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Wshm' => [
|
'Wshm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
// cannot read from files
|
// cannot read from files
|
||||||
'Rmain' => [
|
'Rmain' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Rwal' => [
|
'Rwal' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Rshm' => [
|
'Rshm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
// can neither read from or write to files
|
// can neither read from or write to files
|
||||||
'Amain' => [
|
'Amain' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Awal' => [
|
'Awal' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Ashm' => [
|
'Ashm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
// non-filesystem errors
|
// non-filesystem errors
|
||||||
'corrupt' => [
|
'corrupt' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
|
|
|
@ -29,8 +29,8 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->files = [
|
$this->files = [
|
||||||
// cannot create files
|
// cannot create files
|
||||||
'Cmain' => [],
|
'Cmain' => [],
|
||||||
'Cshm' => [
|
'Cshm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
],
|
],
|
||||||
'Cwal' => [
|
'Cwal' => [
|
||||||
|
@ -38,55 +38,55 @@ class TestCreation extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
],
|
],
|
||||||
// cannot write to files
|
// cannot write to files
|
||||||
'Wmain' => [
|
'Wmain' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Wwal' => [
|
'Wwal' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Wshm' => [
|
'Wshm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
// cannot read from files
|
// cannot read from files
|
||||||
'Rmain' => [
|
'Rmain' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Rwal' => [
|
'Rwal' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Rshm' => [
|
'Rshm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
// can neither read from or write to files
|
// can neither read from or write to files
|
||||||
'Amain' => [
|
'Amain' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Awal' => [
|
'Awal' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
'Ashm' => [
|
'Ashm' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
// non-filesystem errors
|
// non-filesystem errors
|
||||||
'corrupt' => [
|
'corrupt' => [
|
||||||
'arsse.db' => "",
|
'arsse.db' => "",
|
||||||
'arsse.db-wal' => "",
|
'arsse.db-wal' => "",
|
||||||
'arsse.db-shm' => "",
|
'arsse.db-shm' => "",
|
||||||
],
|
],
|
||||||
|
|
|
@ -130,7 +130,7 @@ class TestException extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
408 => "timeout",
|
408 => "timeout",
|
||||||
410 => "invalidUrl",
|
410 => "invalidUrl",
|
||||||
414 => "invalidUrl",
|
414 => "invalidUrl",
|
||||||
451 => "invalidUrl"
|
451 => "invalidUrl",
|
||||||
];
|
];
|
||||||
$out = array_fill(400, (600 - 400), "transmissionError");
|
$out = array_fill(400, (600 - 400), "transmissionError");
|
||||||
foreach ($specials as $k => $t) {
|
foreach ($specials as $k => $t) {
|
||||||
|
|
|
@ -20,69 +20,69 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected $base = "";
|
protected $base = "";
|
||||||
protected $latest = [
|
protected $latest = [
|
||||||
[
|
[
|
||||||
'id' => 1,
|
'id' => 1,
|
||||||
'edited' => '2000-01-01 00:00:00',
|
'edited' => '2000-01-01 00:00:00',
|
||||||
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
||||||
'url_title_hash' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6',
|
'url_title_hash' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6',
|
||||||
'url_content_hash' => 'fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4',
|
'url_content_hash' => 'fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4',
|
||||||
'title_content_hash' => '18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
'title_content_hash' => '18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 2,
|
'id' => 2,
|
||||||
'edited' => '2000-01-02 00:00:00',
|
'edited' => '2000-01-02 00:00:00',
|
||||||
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
||||||
'url_title_hash' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153',
|
'url_title_hash' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153',
|
||||||
'url_content_hash' => '13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9',
|
'url_content_hash' => '13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9',
|
||||||
'title_content_hash' => '2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
'title_content_hash' => '2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 3,
|
'id' => 3,
|
||||||
'edited' => '2000-01-03 00:00:00',
|
'edited' => '2000-01-03 00:00:00',
|
||||||
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
||||||
'url_title_hash' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b',
|
'url_title_hash' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b',
|
||||||
'url_content_hash' => 'b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406',
|
'url_content_hash' => 'b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406',
|
||||||
'title_content_hash' => 'ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
'title_content_hash' => 'ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 4,
|
'id' => 4,
|
||||||
'edited' => '2000-01-04 00:00:00',
|
'edited' => '2000-01-04 00:00:00',
|
||||||
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
||||||
'url_title_hash' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8',
|
'url_title_hash' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8',
|
||||||
'url_content_hash' => 'f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3',
|
'url_content_hash' => 'f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3',
|
||||||
'title_content_hash' => 'ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
'title_content_hash' => 'ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 5,
|
'id' => 5,
|
||||||
'edited' => '2000-01-05 00:00:00',
|
'edited' => '2000-01-05 00:00:00',
|
||||||
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
||||||
'url_title_hash' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022',
|
'url_title_hash' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022',
|
||||||
'url_content_hash' => '834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900',
|
'url_content_hash' => '834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900',
|
||||||
'title_content_hash' => '43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
'title_content_hash' => '43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
protected $others = [
|
protected $others = [
|
||||||
[
|
[
|
||||||
'id' => 6,
|
'id' => 6,
|
||||||
'edited' => '2000-01-06 00:00:00',
|
'edited' => '2000-01-06 00:00:00',
|
||||||
'guid' => 'b3461ab8e8759eeb1d65a818c65051ec00c1dfbbb32a3c8f6999434e3e3b76ab',
|
'guid' => 'b3461ab8e8759eeb1d65a818c65051ec00c1dfbbb32a3c8f6999434e3e3b76ab',
|
||||||
'url_title_hash' => '91d051a8e6749d014506848acd45e959af50bf876427c4f0e3a1ec0f04777b51',
|
'url_title_hash' => '91d051a8e6749d014506848acd45e959af50bf876427c4f0e3a1ec0f04777b51',
|
||||||
'url_content_hash' => '211d78b1a040d40d17e747a363cc283f58767b2e502630d8de9b8f1d5e941d18',
|
'url_content_hash' => '211d78b1a040d40d17e747a363cc283f58767b2e502630d8de9b8f1d5e941d18',
|
||||||
'title_content_hash' => '5ed68ccb64243b8c1931241d2c9276274c3b1d87f223634aa7a1ab0141292ca7',
|
'title_content_hash' => '5ed68ccb64243b8c1931241d2c9276274c3b1d87f223634aa7a1ab0141292ca7',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 7,
|
'id' => 7,
|
||||||
'edited' => '2000-01-07 00:00:00',
|
'edited' => '2000-01-07 00:00:00',
|
||||||
'guid' => 'f4fae999d6531747523f4ff0c74f3f0c7c588b67e4f32d8f7dba5f6f36e8a45d',
|
'guid' => 'f4fae999d6531747523f4ff0c74f3f0c7c588b67e4f32d8f7dba5f6f36e8a45d',
|
||||||
'url_title_hash' => 'b92f805f0d0643dad1d6c0bb5cbaec24729f5f71b37b831cf7ad31f6c9403ac8',
|
'url_title_hash' => 'b92f805f0d0643dad1d6c0bb5cbaec24729f5f71b37b831cf7ad31f6c9403ac8',
|
||||||
'url_content_hash' => '4fc8789b787246e9be08ca1bac0d4a1ac4db1984f0db07f7142417598cf7211f',
|
'url_content_hash' => '4fc8789b787246e9be08ca1bac0d4a1ac4db1984f0db07f7142417598cf7211f',
|
||||||
'title_content_hash' => '491df9338740b5297b3a3e8292be992ac112eb676c34595f7a38f3ee646ffe84',
|
'title_content_hash' => '491df9338740b5297b3a3e8292be992ac112eb676c34595f7a38f3ee646ffe84',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 8,
|
'id' => 8,
|
||||||
'edited' => '2000-01-08 00:00:00',
|
'edited' => '2000-01-08 00:00:00',
|
||||||
'guid' => 'b9d2d58e3172096b1d23b42a59961fabc89962836c3cd5de54f3d3a98ff08e6c',
|
'guid' => 'b9d2d58e3172096b1d23b42a59961fabc89962836c3cd5de54f3d3a98ff08e6c',
|
||||||
'url_title_hash' => '53a6cbcfeb66b46d09cbb7b25035df0562da35786933319c83b04be29acfb6f4',
|
'url_title_hash' => '53a6cbcfeb66b46d09cbb7b25035df0562da35786933319c83b04be29acfb6f4',
|
||||||
'url_content_hash' => 'c6f3722b4445b49d19d39c3bf5b11a7cf23dd69873e2a0a458aab662f1cd9438',
|
'url_content_hash' => 'c6f3722b4445b49d19d39c3bf5b11a7cf23dd69873e2a0a458aab662f1cd9438',
|
||||||
'title_content_hash' => '607d2da48807ca984ce2a9faa1d291bd9e3de9e912f83306167f4f5cd3c23bbd',
|
'title_content_hash' => '607d2da48807ca984ce2a9faa1d291bd9e3de9e912f83306167f4f5cd3c23bbd',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -209,10 +209,10 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function provide304ResponseURLs() {
|
public function provide304ResponseURLs() {
|
||||||
return [
|
return [
|
||||||
'Control' => ["Caching/304Conditional"],
|
'Control' => ["Caching/304Conditional"],
|
||||||
'Random last-mod and ETag' => ["Caching/304Random"],
|
'Random last-mod and ETag' => ["Caching/304Random"],
|
||||||
'ETag only' => ["Caching/304ETagOnly"],
|
'ETag only' => ["Caching/304ETagOnly"],
|
||||||
'Last-mod only' => ["Caching/304LastModOnly"],
|
'Last-mod only' => ["Caching/304LastModOnly"],
|
||||||
'Neither last-mod nor ETag' => ["Caching/304None"],
|
'Neither last-mod nor ETag' => ["Caching/304None"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -267,16 +267,16 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function provide304Timestamps(): iterable {
|
public function provide304Timestamps(): iterable {
|
||||||
return [
|
return [
|
||||||
'less than half an hour 1' => ["now", "now + 15 minutes"],
|
'less than half an hour 1' => ["now", "now + 15 minutes"],
|
||||||
'less than half an hour 2' => ["now - 29 minutes", "now + 15 minutes"],
|
'less than half an hour 2' => ["now - 29 minutes", "now + 15 minutes"],
|
||||||
'less than one hour 1' => ["now - 30 minutes", "now + 30 minutes"],
|
'less than one hour 1' => ["now - 30 minutes", "now + 30 minutes"],
|
||||||
'less than one hour 2' => ["now - 59 minutes", "now + 30 minutes"],
|
'less than one hour 2' => ["now - 59 minutes", "now + 30 minutes"],
|
||||||
'less than three hours 1' => ["now - 1 hour", "now + 1 hour"],
|
'less than three hours 1' => ["now - 1 hour", "now + 1 hour"],
|
||||||
'less than three hours 2' => ["now - 2 hours 59 minutes", "now + 1 hour"],
|
'less than three hours 2' => ["now - 2 hours 59 minutes", "now + 1 hour"],
|
||||||
'more than thirty-six hours 1' => ["now - 36 hours", "now + 1 day"],
|
'more than thirty-six hours 1' => ["now - 36 hours", "now + 1 day"],
|
||||||
'more than thirty-six hours 2' => ["now - 2 years", "now + 1 day"],
|
'more than thirty-six hours 2' => ["now - 2 years", "now + 1 day"],
|
||||||
'fallback 1' => ["now - 3 hours", "now + 3 hours"],
|
'fallback 1' => ["now - 3 hours", "now + 3 hours"],
|
||||||
'fallback 2' => ["now - 35 hours", "now + 3 hours"],
|
'fallback 2' => ["now - 35 hours", "now + 3 hours"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,9 +117,9 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
],
|
],
|
||||||
'arsse_tag_members' => [
|
'arsse_tag_members' => [
|
||||||
'columns' => [
|
'columns' => [
|
||||||
'tag' => "int",
|
'tag' => "int",
|
||||||
'subscription' => "int",
|
'subscription' => "int",
|
||||||
'assigned' => "bool",
|
'assigned' => "bool",
|
||||||
],
|
],
|
||||||
'rows' => [
|
'rows' => [
|
||||||
[1, 2, 1],
|
[1, 2, 1],
|
||||||
|
@ -181,7 +181,7 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
['url' => "http://localhost:8000/Import/citizen", 'title' => "Ottawa Citizen", 'folder' => 6, 'tags' => ["news", "canada"]],
|
['url' => "http://localhost:8000/Import/citizen", 'title' => "Ottawa Citizen", 'folder' => 6, 'tags' => ["news", "canada"]],
|
||||||
['url' => "http://localhost:8000/Import/eurogamer", 'title' => "Eurogamer", 'folder' => 0, 'tags' => ["gaming", "frequent"]],
|
['url' => "http://localhost:8000/Import/eurogamer", 'title' => "Eurogamer", 'folder' => 0, 'tags' => ["gaming", "frequent"]],
|
||||||
['url' => "http://localhost:8000/Import/cbc", 'title' => "CBC News", 'folder' => 6, 'tags' => ["news", "canada"]],
|
['url' => "http://localhost:8000/Import/cbc", 'title' => "CBC News", 'folder' => 6, 'tags' => ["news", "canada"]],
|
||||||
], [1 =>
|
], [1 =>
|
||||||
['id' => 1, 'name' => "Photography", 'parent' => 0],
|
['id' => 1, 'name' => "Photography", 'parent' => 0],
|
||||||
['id' => 2, 'name' => "Science", 'parent' => 0],
|
['id' => 2, 'name' => "Science", 'parent' => 0],
|
||||||
['id' => 3, 'name' => "Rocketry", 'parent' => 2],
|
['id' => 3, 'name' => "Rocketry", 'parent' => 2],
|
||||||
|
@ -205,7 +205,7 @@ class TestImportExport extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
['url' => "http://localhost:8000/Import/citizen", 'title' => "Ottawa Citizen", 'folder' => 6, 'tags' => ["news", "canada"]],
|
['url' => "http://localhost:8000/Import/citizen", 'title' => "Ottawa Citizen", 'folder' => 6, 'tags' => ["news", "canada"]],
|
||||||
['url' => "http://localhost:8000/Import/eurogamer", 'title' => "Eurogamer", 'folder' => 0, 'tags' => ["gaming", "frequent"]],
|
['url' => "http://localhost:8000/Import/eurogamer", 'title' => "Eurogamer", 'folder' => 0, 'tags' => ["gaming", "frequent"]],
|
||||||
['url' => "http://localhost:8000/Import/cbc", 'title' => "CBC", 'folder' => 0, 'tags' => ["news", "canada"]], // moved to root and renamed
|
['url' => "http://localhost:8000/Import/cbc", 'title' => "CBC", 'folder' => 0, 'tags' => ["news", "canada"]], // moved to root and renamed
|
||||||
], [1 =>
|
], [1 =>
|
||||||
['id' => 1, 'name' => "Photography", 'parent' => 0],
|
['id' => 1, 'name' => "Photography", 'parent' => 0],
|
||||||
['id' => 2, 'name' => "Science", 'parent' => 0],
|
['id' => 2, 'name' => "Science", 'parent' => 0],
|
||||||
['id' => 3, 'name' => "Rocketry", 'parent' => 2],
|
['id' => 3, 'name' => "Rocketry", 'parent' => 2],
|
||||||
|
|
|
@ -152,7 +152,7 @@ OPML_EXPORT_SERIALIZATION;
|
||||||
['url' => "https://www.thestar.com/content/thestar/feed.RSSManagerServlet.topstories.rss", 'title' => "Toronto Star", 'folder' => 5, 'tags' => ["news", "canada", "toronto"]],
|
['url' => "https://www.thestar.com/content/thestar/feed.RSSManagerServlet.topstories.rss", 'title' => "Toronto Star", 'folder' => 5, 'tags' => ["news", "canada", "toronto"]],
|
||||||
['url' => "http://rss.canada.com/get/?F239", 'title' => "Ottawa Citizen", 'folder' => 6, 'tags' => ["news", "canada"]],
|
['url' => "http://rss.canada.com/get/?F239", 'title' => "Ottawa Citizen", 'folder' => 6, 'tags' => ["news", "canada"]],
|
||||||
['url' => "https://www.eurogamer.net/?format=rss", 'title' => "Eurogamer", 'folder' => 0, 'tags' => ["gaming", "frequent"]],
|
['url' => "https://www.eurogamer.net/?format=rss", 'title' => "Eurogamer", 'folder' => 0, 'tags' => ["gaming", "frequent"]],
|
||||||
], [1 =>
|
], [1 =>
|
||||||
['id' => 1, 'name' => "Photography", 'parent' => 0],
|
['id' => 1, 'name' => "Photography", 'parent' => 0],
|
||||||
['id' => 2, 'name' => "Science", 'parent' => 0],
|
['id' => 2, 'name' => "Science", 'parent' => 0],
|
||||||
['id' => 3, 'name' => "Rocketry", 'parent' => 2],
|
['id' => 3, 'name' => "Rocketry", 'parent' => 2],
|
||||||
|
|
|
@ -25,44 +25,44 @@ class TestContext extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function testSetContextOptions(): void {
|
public function testSetContextOptions(): void {
|
||||||
$v = [
|
$v = [
|
||||||
'reverse' => true,
|
'reverse' => true,
|
||||||
'limit' => 10,
|
'limit' => 10,
|
||||||
'offset' => 5,
|
'offset' => 5,
|
||||||
'folder' => 42,
|
'folder' => 42,
|
||||||
'folders' => [12,22],
|
'folders' => [12,22],
|
||||||
'folderShallow' => 42,
|
'folderShallow' => 42,
|
||||||
'foldersShallow' => [0,1],
|
'foldersShallow' => [0,1],
|
||||||
'tag' => 44,
|
'tag' => 44,
|
||||||
'tags' => [44, 2112],
|
'tags' => [44, 2112],
|
||||||
'tagName' => "XLIV",
|
'tagName' => "XLIV",
|
||||||
'tagNames' => ["XLIV", "MMCXII"],
|
'tagNames' => ["XLIV", "MMCXII"],
|
||||||
'subscription' => 2112,
|
'subscription' => 2112,
|
||||||
'subscriptions' => [44, 2112],
|
'subscriptions' => [44, 2112],
|
||||||
'article' => 255,
|
'article' => 255,
|
||||||
'edition' => 65535,
|
'edition' => 65535,
|
||||||
'latestArticle' => 47,
|
'latestArticle' => 47,
|
||||||
'oldestArticle' => 1337,
|
'oldestArticle' => 1337,
|
||||||
'latestEdition' => 47,
|
'latestEdition' => 47,
|
||||||
'oldestEdition' => 1337,
|
'oldestEdition' => 1337,
|
||||||
'unread' => true,
|
'unread' => true,
|
||||||
'starred' => true,
|
'starred' => true,
|
||||||
'modifiedSince' => new \DateTime(),
|
'modifiedSince' => new \DateTime(),
|
||||||
'notModifiedSince' => new \DateTime(),
|
'notModifiedSince' => new \DateTime(),
|
||||||
'markedSince' => new \DateTime(),
|
'markedSince' => new \DateTime(),
|
||||||
'notMarkedSince' => new \DateTime(),
|
'notMarkedSince' => new \DateTime(),
|
||||||
'editions' => [1,2],
|
'editions' => [1,2],
|
||||||
'articles' => [1,2],
|
'articles' => [1,2],
|
||||||
'label' => 2112,
|
'label' => 2112,
|
||||||
'labels' => [2112, 1984],
|
'labels' => [2112, 1984],
|
||||||
'labelName' => "Rush",
|
'labelName' => "Rush",
|
||||||
'labelNames' => ["Rush", "Orwell"],
|
'labelNames' => ["Rush", "Orwell"],
|
||||||
'labelled' => true,
|
'labelled' => true,
|
||||||
'annotated' => true,
|
'annotated' => true,
|
||||||
'searchTerms' => ["foo", "bar"],
|
'searchTerms' => ["foo", "bar"],
|
||||||
'annotationTerms' => ["foo", "bar"],
|
'annotationTerms' => ["foo", "bar"],
|
||||||
'titleTerms' => ["foo", "bar"],
|
'titleTerms' => ["foo", "bar"],
|
||||||
'authorTerms' => ["foo", "bar"],
|
'authorTerms' => ["foo", "bar"],
|
||||||
'not' => (new Context)->subscription(5),
|
'not' => (new Context)->subscription(5),
|
||||||
];
|
];
|
||||||
$times = ['modifiedSince','notModifiedSince','markedSince','notMarkedSince'];
|
$times = ['modifiedSince','notModifiedSince','markedSince','notMarkedSince'];
|
||||||
$c = new Context;
|
$c = new Context;
|
||||||
|
|
|
@ -7,7 +7,6 @@ declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\TestCase\Misc;
|
namespace JKingWeb\Arsse\TestCase\Misc;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Misc\HTTP;
|
use JKingWeb\Arsse\Misc\HTTP;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\Misc\HTTP */
|
/** @covers \JKingWeb\Arsse\Misc\HTTP */
|
||||||
class TestHTTP extends \JKingWeb\Arsse\Test\AbstractTest {
|
class TestHTTP extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
|
@ -7,7 +7,6 @@ declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\TestCase\Misc;
|
namespace JKingWeb\Arsse\TestCase\Misc;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Misc\Query;
|
use JKingWeb\Arsse\Misc\Query;
|
||||||
use JKingWeb\Arsse\Misc\ValueInfo;
|
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\Misc\Query */
|
/** @covers \JKingWeb\Arsse\Misc\Query */
|
||||||
class TestQuery extends \JKingWeb\Arsse\Test\AbstractTest {
|
class TestQuery extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
|
@ -87,7 +87,7 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[" 1 ", I::VALID],
|
[" 1 ", I::VALID],
|
||||||
];
|
];
|
||||||
foreach ($tests as $test) {
|
foreach ($tests as $test) {
|
||||||
list($value, $exp) = $test;
|
[$value, $exp] = $test;
|
||||||
$this->assertSame($exp, I::int($value), "Test returned ".decbin(I::int($value))." for value: ".var_export($value, true));
|
$this->assertSame($exp, I::int($value), "Test returned ".decbin(I::int($value))." for value: ".var_export($value, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[new StrClass(" "), I::VALID | I::WHITE],
|
[new StrClass(" "), I::VALID | I::WHITE],
|
||||||
];
|
];
|
||||||
foreach ($tests as $test) {
|
foreach ($tests as $test) {
|
||||||
list($value, $exp) = $test;
|
[$value, $exp] = $test;
|
||||||
$this->assertSame($exp, I::str($value), "Test returned ".decbin(I::str($value))." for value: ".var_export($value, true));
|
$this->assertSame($exp, I::str($value), "Test returned ".decbin(I::str($value))." for value: ".var_export($value, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,7 +228,7 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[new StrClass(" "), false, false],
|
[new StrClass(" "), false, false],
|
||||||
];
|
];
|
||||||
foreach ($tests as $test) {
|
foreach ($tests as $test) {
|
||||||
list($value, $exp, $expNull) = $test;
|
[$value, $exp, $expNull] = $test;
|
||||||
$this->assertSame($exp, I::id($value), "Non-null test failed for value: ".var_export($value, true));
|
$this->assertSame($exp, I::id($value), "Non-null test failed for value: ".var_export($value, true));
|
||||||
$this->assertSame($expNull, I::id($value, true), "Null test failed for value: ".var_export($value, true));
|
$this->assertSame($expNull, I::id($value, true), "Null test failed for value: ".var_export($value, true));
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[new StrClass(" "), null],
|
[new StrClass(" "), null],
|
||||||
];
|
];
|
||||||
foreach ($tests as $test) {
|
foreach ($tests as $test) {
|
||||||
list($value, $exp) = $test;
|
[$value, $exp] = $test;
|
||||||
$this->assertSame($exp, I::bool($value), "Null Test failed for value: ".var_export($value, true));
|
$this->assertSame($exp, I::bool($value), "Null Test failed for value: ".var_export($value, true));
|
||||||
if (is_null($exp)) {
|
if (is_null($exp)) {
|
||||||
$this->assertTrue(I::bool($value, true), "True Test failed for value: ".var_export($value, true));
|
$this->assertTrue(I::bool($value, true), "True Test failed for value: ".var_export($value, true));
|
||||||
|
@ -400,14 +400,14 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testNormalizeComplexValues(): void {
|
public function testNormalizeComplexValues(): void {
|
||||||
// Array-mode tests
|
// Array-mode tests
|
||||||
$tests = [
|
$tests = [
|
||||||
[I::T_INT | I::M_DROP, [1, 2, 2.2, 3], [1,2,null,3] ],
|
[I::T_INT | I::M_DROP, [1, 2, 2.2, 3], [1,2,null,3] ],
|
||||||
[I::T_INT, [1, 2, 2.2, 3], [1,2,2,3] ],
|
[I::T_INT, [1, 2, 2.2, 3], [1,2,2,3] ],
|
||||||
[I::T_INT | I::M_DROP, new Result([1, 2, 2.2, 3]), [1,2,null,3] ],
|
[I::T_INT | I::M_DROP, new Result([1, 2, 2.2, 3]), [1,2,null,3] ],
|
||||||
[I::T_INT, new Result([1, 2, 2.2, 3]), [1,2,2,3] ],
|
[I::T_INT, new Result([1, 2, 2.2, 3]), [1,2,2,3] ],
|
||||||
[I::T_STRING | I::M_STRICT, "Bare string", ["Bare string"]],
|
[I::T_STRING | I::M_STRICT, "Bare string", ["Bare string"]],
|
||||||
];
|
];
|
||||||
foreach ($tests as $index => $test) {
|
foreach ($tests as $index => $test) {
|
||||||
list($type, $value, $exp) = $test;
|
[$type, $value, $exp] = $test;
|
||||||
$this->assertEquals($exp, I::normalize($value, $type | I::M_ARRAY, "iso8601"), "Failed test #$index");
|
$this->assertEquals($exp, I::normalize($value, $type | I::M_ARRAY, "iso8601"), "Failed test #$index");
|
||||||
}
|
}
|
||||||
// Date-to-string format tests
|
// Date-to-string format tests
|
||||||
|
@ -525,15 +525,15 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[$this->d("2010-01-01T00:00:00", 0, 1), [null,true], [true, false], [1262304000, false], [1262304000.0, false], ["2010-01-01T00:00:00Z",true], [[$this->d("2010-01-01T00:00:00", 0, 1)],false], [null, false]],
|
[$this->d("2010-01-01T00:00:00", 0, 1), [null,true], [true, false], [1262304000, false], [1262304000.0, false], ["2010-01-01T00:00:00Z",true], [[$this->d("2010-01-01T00:00:00", 0, 1)],false], [null, false]],
|
||||||
[$this->d("2010-01-01T00:00:00", 1, 0), [null,true], [true, false], [1262322000, false], [1262322000.0, false], ["2010-01-01T05:00:00Z",true], [[$this->d("2010-01-01T00:00:00", 1, 0)],false], [null, false]],
|
[$this->d("2010-01-01T00:00:00", 1, 0), [null,true], [true, false], [1262322000, false], [1262322000.0, false], ["2010-01-01T05:00:00Z",true], [[$this->d("2010-01-01T00:00:00", 1, 0)],false], [null, false]],
|
||||||
[$this->d("2010-01-01T00:00:00", 1, 1), [null,true], [true, false], [1262322000, false], [1262322000.0, false], ["2010-01-01T05:00:00Z",true], [[$this->d("2010-01-01T00:00:00", 1, 1)],false], [null, false]],
|
[$this->d("2010-01-01T00:00:00", 1, 1), [null,true], [true, false], [1262322000, false], [1262322000.0, false], ["2010-01-01T05:00:00Z",true], [[$this->d("2010-01-01T00:00:00", 1, 1)],false], [null, false]],
|
||||||
[1e14, [null,true], [true, false], [pow(10, 14), true], [1e14, true], ["100000000000000", true], [[1e14], false], [$this->i("P1157407407DT9H46M40S"), false]],
|
[1e14, [null,true], [true, false], [10 ** 14, true], [1e14, true], ["100000000000000", true], [[1e14], false], [$this->i("P1157407407DT9H46M40S"), false]],
|
||||||
[1e-6, [null,true], [true, false], [0, false], [1e-6, true], ["0.000001", true], [[1e-6], false], [$this->i("PT0S", 1e-6), false]],
|
[1e-6, [null,true], [true, false], [0, false], [1e-6, true], ["0.000001", true], [[1e-6], false], [$this->i("PT0S", 1e-6), false]],
|
||||||
[[1,2,3], [null,true], [true, false], [0, false], [0.0, false], ["", false], [[1,2,3], true], [null, false]],
|
[[1,2,3], [null,true], [true, false], [0, false], [0.0, false], ["", false], [[1,2,3], true], [null, false]],
|
||||||
[['a'=>1,'b'=>2], [null,true], [true, false], [0, false], [0.0, false], ["", false], [['a'=>1,'b'=>2], true], [null, false]],
|
[['a' => 1,'b' => 2], [null,true], [true, false], [0, false], [0.0, false], ["", false], [['a' => 1,'b' => 2], true], [null, false]],
|
||||||
[new Result([['a'=>1,'b'=>2]]), [null,true], [true, false], [0, false], [0.0, false], ["", false], [[['a'=>1,'b'=>2]], true], [null, false]],
|
[new Result([['a' => 1,'b' => 2]]), [null,true], [true, false], [0, false], [0.0, false], ["", false], [[['a' => 1,'b' => 2]], true], [null, false]],
|
||||||
[$this->i("PT1H"), [null,true], [true, false], [60*60, false], [60.0*60.0, false], ["PT1H", true], [[$this->i("PT1H")], false], [$this->i("PT1H"), true]],
|
[$this->i("PT1H"), [null,true], [true, false], [60 * 60, false], [60.0 * 60.0, false], ["PT1H", true], [[$this->i("PT1H")], false], [$this->i("PT1H"), true]],
|
||||||
[$this->i("P2DT1H"), [null,true], [true, false], [(48+1)*60*60, false], [1.0*(48+1)*60*60, false], ["P2DT1H", true], [[$this->i("P2DT1H")], false], [$this->i("P2DT1H"), true]],
|
[$this->i("P2DT1H"), [null,true], [true, false], [(48 + 1) * 60 * 60, false], [1.0 * (48 + 1) * 60 * 60, false], ["P2DT1H", true], [[$this->i("P2DT1H")], false], [$this->i("P2DT1H"), true]],
|
||||||
[$this->i("PT0H"), [null,true], [true, false], [0, false], [0.0, false], ["PT0S", true], [[$this->i("PT0H")], false], [$this->i("PT0H"), true]],
|
[$this->i("PT0H"), [null,true], [true, false], [0, false], [0.0, false], ["PT0S", true], [[$this->i("PT0H")], false], [$this->i("PT0H"), true]],
|
||||||
[$dateDiff, [null,true], [true, false], [366*24*60*60, false], [1.0*366*24*60*60, false], ["P366D", true], [[$dateDiff], false], [$dateNorm, true]],
|
[$dateDiff, [null,true], [true, false], [366 * 24 * 60 * 60, false], [1.0 * 366 * 24 * 60 * 60, false], ["P366D", true], [[$dateDiff], false], [$dateNorm, true]],
|
||||||
["1 year, 2 days", [null,true], [true, false], [0, false], [0.0, false], ["1 year, 2 days", true], [["1 year, 2 days"], false], [$this->i("P1Y2D"), false]],
|
["1 year, 2 days", [null,true], [true, false], [0, false], [0.0, false], ["1 year, 2 days", true], [["1 year, 2 days"], false], [$this->i("P1Y2D"), false]],
|
||||||
["P1Y2D", [null,true], [true, false], [0, false], [0.0, false], ["P1Y2D", true], [["P1Y2D"], false], [$this->i("P1Y2D"), true]],
|
["P1Y2D", [null,true], [true, false], [0, false], [0.0, false], ["P1Y2D", true], [["P1Y2D"], false], [$this->i("P1Y2D"), true]],
|
||||||
] as $set) {
|
] as $set) {
|
||||||
|
@ -542,14 +542,14 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
// shift a mixed-type passthrough test onto the set
|
// shift a mixed-type passthrough test onto the set
|
||||||
array_unshift($set, [$input, true]);
|
array_unshift($set, [$input, true]);
|
||||||
// generate a set of tests for each target data type
|
// generate a set of tests for each target data type
|
||||||
foreach ($set as $type => list($exp, $pass)) {
|
foreach ($set as $type => [$exp, $pass]) {
|
||||||
// emit one test each for loose mode, strict mode, drop mode, and strict+drop mode
|
// emit one test each for loose mode, strict mode, drop mode, and strict+drop mode
|
||||||
foreach ([
|
foreach ([
|
||||||
[false, false],
|
[false, false],
|
||||||
[true, false],
|
[true, false],
|
||||||
[false, true],
|
[false, true],
|
||||||
[true, true],
|
[true, true],
|
||||||
] as list($strict, $drop)) {
|
] as [$strict, $drop]) {
|
||||||
yield [$input, $types[$type], $exp, $pass, $strict, $drop];
|
yield [$input, $types[$type], $exp, $pass, $strict, $drop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -572,37 +572,37 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
];
|
];
|
||||||
foreach ([
|
foreach ([
|
||||||
/* Input value microtime iso8601 iso8601m http sql date time unix float '!M j, Y (D)' *strtotime* (null) */
|
/* Input value microtime iso8601 iso8601m http sql date time unix float '!M j, Y (D)' *strtotime* (null) */
|
||||||
[null, null, null, null, null, null, null, null, null, null, null, null, ],
|
[null, null, null, null, null, null, null, null, null, null, null, null],
|
||||||
[INF, null, null, null, null, null, null, null, null, null, null, null, ],
|
[INF, null, null, null, null, null, null, null, null, null, null, null],
|
||||||
[NAN, null, null, null, null, null, null, null, null, null, null, null, ],
|
[NAN, null, null, null, null, null, null, null, null, null, null, null],
|
||||||
[$this->d("2010-01-01T00:00:00", 0, 0), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), ],
|
[$this->d("2010-01-01T00:00:00", 0, 0), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000)],
|
||||||
[$this->d("2010-01-01T00:00:00", 0, 1), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), ],
|
[$this->d("2010-01-01T00:00:00", 0, 1), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000)],
|
||||||
[$this->d("2010-01-01T00:00:00", 1, 0), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), ],
|
[$this->d("2010-01-01T00:00:00", 1, 0), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000)],
|
||||||
[$this->d("2010-01-01T00:00:00", 1, 1), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), ],
|
[$this->d("2010-01-01T00:00:00", 1, 1), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000), $this->t(1262322000)],
|
||||||
[1262304000, $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), ],
|
[1262304000, $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000), $this->t(1262304000)],
|
||||||
[1262304000.123456, $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), ],
|
[1262304000.123456, $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456), $this->t(1262304000.123456)],
|
||||||
[1262304000.42, $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), ],
|
[1262304000.42, $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42), $this->t(1262304000.42)],
|
||||||
["0.12345600 1262304000", $this->t(1262304000.123456), null, null, null, null, null, null, null, null, null, null, ],
|
["0.12345600 1262304000", $this->t(1262304000.123456), null, null, null, null, null, null, null, null, null, null],
|
||||||
["0.42 1262304000", null, null, null, null, null, null, null, null, null, null, null, ],
|
["0.42 1262304000", null, null, null, null, null, null, null, null, null, null, null],
|
||||||
["2010-01-01T00:00:00", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01T00:00:00", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01T00:00:00Z", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01T00:00:00Z", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01T00:00:00+0000", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01T00:00:00+0000", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01T00:00:00-0000", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01T00:00:00-0000", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01T00:00:00+00:00", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01T00:00:00+00:00", null, $this->t(1262304000), $this->t(1262304000), null, null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01T00:00:00-05:00", null, $this->t(1262322000), $this->t(1262322000), null, null, null, null, null, null, null, $this->t(1262322000), ],
|
["2010-01-01T00:00:00-05:00", null, $this->t(1262322000), $this->t(1262322000), null, null, null, null, null, null, null, $this->t(1262322000)],
|
||||||
["2010-01-01T00:00:00.123456Z", null, null, $this->t(1262304000.123456), null, null, null, null, null, null, null, $this->t(1262304000.123456), ],
|
["2010-01-01T00:00:00.123456Z", null, null, $this->t(1262304000.123456), null, null, null, null, null, null, null, $this->t(1262304000.123456)],
|
||||||
["Fri, 01 Jan 2010 00:00:00 GMT", null, null, null, $this->t(1262304000), null, null, null, null, null, null, $this->t(1262304000), ],
|
["Fri, 01 Jan 2010 00:00:00 GMT", null, null, null, $this->t(1262304000), null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01 00:00:00", null, null, null, null, $this->t(1262304000), null, null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01 00:00:00", null, null, null, null, $this->t(1262304000), null, null, null, null, null, $this->t(1262304000)],
|
||||||
["2010-01-01", null, null, null, null, null, $this->t(1262304000), null, null, null, null, $this->t(1262304000), ],
|
["2010-01-01", null, null, null, null, null, $this->t(1262304000), null, null, null, null, $this->t(1262304000)],
|
||||||
["12:34:56", null, null, null, null, null, null, $this->t(45296), null, null, null, $this->t(date_create("today", new \DateTimezone("UTC"))->getTimestamp()+45296), ],
|
["12:34:56", null, null, null, null, null, null, $this->t(45296), null, null, null, $this->t(date_create("today", new \DateTimezone("UTC"))->getTimestamp() + 45296)],
|
||||||
["1262304000", null, null, null, null, null, null, null, $this->t(1262304000), null, null, null, ],
|
["1262304000", null, null, null, null, null, null, null, $this->t(1262304000), null, null, null],
|
||||||
["1262304000.123456", null, null, null, null, null, null, null, null, $this->t(1262304000.123456), null, null, ],
|
["1262304000.123456", null, null, null, null, null, null, null, null, $this->t(1262304000.123456), null, null],
|
||||||
["1262304000.42", null, null, null, null, null, null, null, null, $this->t(1262304000.42), null, null, ],
|
["1262304000.42", null, null, null, null, null, null, null, null, $this->t(1262304000.42), null, null],
|
||||||
["Jan 1, 2010 (Fri)", null, null, null, null, null, null, null, null, null, $this->t(1262304000), null, ],
|
["Jan 1, 2010 (Fri)", null, null, null, null, null, null, null, null, null, $this->t(1262304000), null],
|
||||||
["First day of Jan 2010 12AM", null, null, null, null, null, null, null, null, null, null, $this->t(1262304000), ],
|
["First day of Jan 2010 12AM", null, null, null, null, null, null, null, null, null, null, $this->t(1262304000)],
|
||||||
[[], null, null, null, null, null, null, null, null, null, null, null, ],
|
[[], null, null, null, null, null, null, null, null, null, null, null],
|
||||||
[$this->i("P1Y2D"), null, null, null, null, null, null, null, null, null, null, null, ],
|
[$this->i("P1Y2D"), null, null, null, null, null, null, null, null, null, null, null],
|
||||||
["P1Y2D", null, null, null, null, null, null, null, null, null, null, null, ],
|
["P1Y2D", null, null, null, null, null, null, null, null, null, null, null],
|
||||||
] as $set) {
|
] as $set) {
|
||||||
// shift the input value off the set
|
// shift the input value off the set
|
||||||
$input = array_shift($set);
|
$input = array_shift($set);
|
||||||
|
@ -614,7 +614,7 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[true, false],
|
[true, false],
|
||||||
[false, true],
|
[false, true],
|
||||||
[true, true],
|
[true, true],
|
||||||
] as list($strict, $drop)) {
|
] as [$strict, $drop]) {
|
||||||
yield [$input, $formats[$format], $exp, $strict, $drop];
|
yield [$input, $formats[$format], $exp, $strict, $drop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,115 +28,115 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected $articles = [
|
protected $articles = [
|
||||||
'db' => [
|
'db' => [
|
||||||
[
|
[
|
||||||
'id' => 101,
|
'id' => 101,
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 1</p>',
|
'content' => '<p>Article content 1</p>',
|
||||||
'published_date' => '2000-01-01 00:00:00',
|
'published_date' => '2000-01-01 00:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 102,
|
'id' => 102,
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 2</p>',
|
'content' => '<p>Article content 2</p>',
|
||||||
'published_date' => '2000-01-02 00:00:00',
|
'published_date' => '2000-01-02 00:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 103,
|
'id' => 103,
|
||||||
'url' => 'http://example.com/3',
|
'url' => 'http://example.com/3',
|
||||||
'title' => 'Article title 3',
|
'title' => 'Article title 3',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 3</p>',
|
'content' => '<p>Article content 3</p>',
|
||||||
'published_date' => '2000-01-03 00:00:00',
|
'published_date' => '2000-01-03 00:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'subscription' => 9,
|
'subscription' => 9,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 104,
|
'id' => 104,
|
||||||
'url' => 'http://example.com/4',
|
'url' => 'http://example.com/4',
|
||||||
'title' => 'Article title 4',
|
'title' => 'Article title 4',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 4</p>',
|
'content' => '<p>Article content 4</p>',
|
||||||
'published_date' => '2000-01-04 00:00:00',
|
'published_date' => '2000-01-04 00:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'subscription' => 9,
|
'subscription' => 9,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 105,
|
'id' => 105,
|
||||||
'url' => 'http://example.com/5',
|
'url' => 'http://example.com/5',
|
||||||
'title' => 'Article title 5',
|
'title' => 'Article title 5',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 5</p>',
|
'content' => '<p>Article content 5</p>',
|
||||||
'published_date' => '2000-01-05 00:00:00',
|
'published_date' => '2000-01-05 00:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'subscription' => 10,
|
'subscription' => 10,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'rest' => [
|
'rest' => [
|
||||||
[
|
[
|
||||||
'id' => 101,
|
'id' => 101,
|
||||||
'feed_id' => 8,
|
'feed_id' => 8,
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'html' => '<p>Article content 1</p>',
|
'html' => '<p>Article content 1</p>',
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'is_saved' => 0,
|
'is_saved' => 0,
|
||||||
'is_read' => 0,
|
'is_read' => 0,
|
||||||
'created_on_time' => 946684800,
|
'created_on_time' => 946684800,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 102,
|
'id' => 102,
|
||||||
'feed_id' => 8,
|
'feed_id' => 8,
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'html' => '<p>Article content 2</p>',
|
'html' => '<p>Article content 2</p>',
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'is_saved' => 0,
|
'is_saved' => 0,
|
||||||
'is_read' => 1,
|
'is_read' => 1,
|
||||||
'created_on_time' => 946771200,
|
'created_on_time' => 946771200,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 103,
|
'id' => 103,
|
||||||
'feed_id' => 9,
|
'feed_id' => 9,
|
||||||
'title' => 'Article title 3',
|
'title' => 'Article title 3',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'html' => '<p>Article content 3</p>',
|
'html' => '<p>Article content 3</p>',
|
||||||
'url' => 'http://example.com/3',
|
'url' => 'http://example.com/3',
|
||||||
'is_saved' => 1,
|
'is_saved' => 1,
|
||||||
'is_read' => 0,
|
'is_read' => 0,
|
||||||
'created_on_time' => 946857600,
|
'created_on_time' => 946857600,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 104,
|
'id' => 104,
|
||||||
'feed_id' => 9,
|
'feed_id' => 9,
|
||||||
'title' => 'Article title 4',
|
'title' => 'Article title 4',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'html' => '<p>Article content 4</p>',
|
'html' => '<p>Article content 4</p>',
|
||||||
'url' => 'http://example.com/4',
|
'url' => 'http://example.com/4',
|
||||||
'is_saved' => 1,
|
'is_saved' => 1,
|
||||||
'is_read' => 1,
|
'is_read' => 1,
|
||||||
'created_on_time' => 946944000,
|
'created_on_time' => 946944000,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 105,
|
'id' => 105,
|
||||||
'feed_id' => 10,
|
'feed_id' => 10,
|
||||||
'title' => 'Article title 5',
|
'title' => 'Article title 5',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'html' => '<p>Article content 5</p>',
|
'html' => '<p>Article content 5</p>',
|
||||||
'url' => 'http://example.com/5',
|
'url' => 'http://example.com/5',
|
||||||
'is_saved' => 0,
|
'is_saved' => 0,
|
||||||
'is_read' => 0,
|
'is_read' => 0,
|
||||||
'created_on_time' => 947030400,
|
'created_on_time' => 947030400,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -176,7 +176,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testAuthenticateAUserToken(bool $httpRequired, bool $tokenEnforced, string $httpUser = null, array $dataPost, array $dataGet, ResponseInterface $exp): void {
|
public function testAuthenticateAUserToken(bool $httpRequired, bool $tokenEnforced, string $httpUser = null, array $dataPost, array $dataGet, ResponseInterface $exp): void {
|
||||||
self::setConf([
|
self::setConf([
|
||||||
'userHTTPAuthRequired' => $httpRequired,
|
'userHTTPAuthRequired' => $httpRequired,
|
||||||
'userSessionEnforced' => $tokenEnforced,
|
'userSessionEnforced' => $tokenEnforced,
|
||||||
], true);
|
], true);
|
||||||
Arsse::$user->id = null;
|
Arsse::$user->id = null;
|
||||||
\Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("subjectMissing"));
|
\Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("subjectMissing"));
|
||||||
|
@ -305,7 +305,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
\Phake::when(Arsse::$db)->articleList->thenReturn(new Result($this->articles['db']));
|
\Phake::when(Arsse::$db)->articleList->thenReturn(new Result($this->articles['db']));
|
||||||
\Phake::when(Arsse::$db)->articleCount(Arsse::$user->id)->thenReturn(1024);
|
\Phake::when(Arsse::$db)->articleCount(Arsse::$user->id)->thenReturn(1024);
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse([
|
||||||
'items' => $this->articles['rest'],
|
'items' => $this->articles['rest'],
|
||||||
'total_items' => 1024,
|
'total_items' => 1024,
|
||||||
]);
|
]);
|
||||||
$act = $this->h->dispatch($this->req("api&$url"));
|
$act = $this->h->dispatch($this->req("api&$url"));
|
||||||
|
@ -334,21 +334,15 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$unread = [['id' => 4],['id' => 5],['id' => 6]];
|
$unread = [['id' => 4],['id' => 5],['id' => 6]];
|
||||||
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->starred(true))->thenReturn(new Result($saved));
|
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->starred(true))->thenReturn(new Result($saved));
|
||||||
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->unread(true))->thenReturn(new Result($unread));
|
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->unread(true))->thenReturn(new Result($unread));
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse(['saved_item_ids' => "1,2,3"]);
|
||||||
'saved_item_ids' => "1,2,3"
|
|
||||||
]);
|
|
||||||
$this->assertMessage($exp, $this->h->dispatch($this->req("api&saved_item_ids")));
|
$this->assertMessage($exp, $this->h->dispatch($this->req("api&saved_item_ids")));
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse(['unread_item_ids' => "4,5,6"]);
|
||||||
'unread_item_ids' => "4,5,6"
|
|
||||||
]);
|
|
||||||
$this->assertMessage($exp, $this->h->dispatch($this->req("api&unread_item_ids")));
|
$this->assertMessage($exp, $this->h->dispatch($this->req("api&unread_item_ids")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListHotLinks(): void {
|
public function testListHotLinks(): void {
|
||||||
// hot links are not actually implemented, so an empty array should be all we get
|
// hot links are not actually implemented, so an empty array should be all we get
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse(['links' => []]);
|
||||||
'links' => []
|
|
||||||
]);
|
|
||||||
$this->assertMessage($exp, $this->h->dispatch($this->req("api&links")));
|
$this->assertMessage($exp, $this->h->dispatch($this->req("api&links")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,16 +438,16 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
\Phake::when($this->h)->logIn->thenReturn(true);
|
\Phake::when($this->h)->logIn->thenReturn(true);
|
||||||
\Phake::when(Arsse::$db)->subscriptionRefreshed(Arsse::$user->id)->thenReturn(new \DateTimeImmutable("2000-01-01T00:00:00Z"));
|
\Phake::when(Arsse::$db)->subscriptionRefreshed(Arsse::$user->id)->thenReturn(new \DateTimeImmutable("2000-01-01T00:00:00Z"));
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse([
|
||||||
'api_version' => API::LEVEL,
|
'api_version' => API::LEVEL,
|
||||||
'auth' => 1,
|
'auth' => 1,
|
||||||
'last_refreshed_on_time' => 946684800,
|
'last_refreshed_on_time' => 946684800,
|
||||||
]);
|
]);
|
||||||
$act = $this->h->dispatch($this->req("api"));
|
$act = $this->h->dispatch($this->req("api"));
|
||||||
$this->assertMessage($exp, $act);
|
$this->assertMessage($exp, $act);
|
||||||
\Phake::when(Arsse::$db)->subscriptionRefreshed(Arsse::$user->id)->thenReturn(null); // no subscriptions
|
\Phake::when(Arsse::$db)->subscriptionRefreshed(Arsse::$user->id)->thenReturn(null); // no subscriptions
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse([
|
||||||
'api_version' => API::LEVEL,
|
'api_version' => API::LEVEL,
|
||||||
'auth' => 1,
|
'auth' => 1,
|
||||||
'last_refreshed_on_time' => null,
|
'last_refreshed_on_time' => null,
|
||||||
]);
|
]);
|
||||||
$act = $this->h->dispatch($this->req("api"));
|
$act = $this->h->dispatch($this->req("api"));
|
||||||
|
@ -461,7 +455,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
\Phake::when($this->h)->logIn->thenReturn(false);
|
\Phake::when($this->h)->logIn->thenReturn(false);
|
||||||
$exp = new JsonResponse([
|
$exp = new JsonResponse([
|
||||||
'api_version' => API::LEVEL,
|
'api_version' => API::LEVEL,
|
||||||
'auth' => 0,
|
'auth' => 0,
|
||||||
]);
|
]);
|
||||||
$act = $this->h->dispatch($this->req("api"));
|
$act = $this->h->dispatch($this->req("api"));
|
||||||
$this->assertMessage($exp, $act);
|
$this->assertMessage($exp, $act);
|
||||||
|
@ -485,7 +479,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function testOutputToXml(): void {
|
public function testOutputToXml(): void {
|
||||||
\Phake::when($this->h)->processRequest->thenReturn([
|
\Phake::when($this->h)->processRequest->thenReturn([
|
||||||
'items' => $this->articles['rest'],
|
'items' => $this->articles['rest'],
|
||||||
'total_items' => 1024,
|
'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 = 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>");
|
||||||
|
@ -502,7 +496,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testAnswerOptionsRequest(): void {
|
public function testAnswerOptionsRequest(): void {
|
||||||
$act = $this->h->dispatch($this->req("api", "", "OPTIONS"));
|
$act = $this->h->dispatch($this->req("api", "", "OPTIONS"));
|
||||||
$exp = new EmptyResponse(204, [
|
$exp = new EmptyResponse(204, [
|
||||||
'Allow' => "POST",
|
'Allow' => "POST",
|
||||||
'Accept' => "application/x-www-form-urlencoded",
|
'Accept' => "application/x-www-form-urlencoded",
|
||||||
]);
|
]);
|
||||||
$this->assertMessage($exp, $act);
|
$this->assertMessage($exp, $act);
|
||||||
|
|
|
@ -26,274 +26,274 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected $feeds = [ // expected sample output of a feed list from the database, and the resultant expected transformation by the REST handler
|
protected $feeds = [ // expected sample output of a feed list from the database, and the resultant expected transformation by the REST handler
|
||||||
'db' => [
|
'db' => [
|
||||||
[
|
[
|
||||||
'id' => 2112,
|
'id' => 2112,
|
||||||
'url' => 'http://example.com/news.atom',
|
'url' => 'http://example.com/news.atom',
|
||||||
'favicon' => 'http://example.com/favicon.png',
|
'favicon' => 'http://example.com/favicon.png',
|
||||||
'source' => 'http://example.com/',
|
'source' => 'http://example.com/',
|
||||||
'folder' => null,
|
'folder' => null,
|
||||||
'top_folder' => null,
|
'top_folder' => null,
|
||||||
'pinned' => 0,
|
'pinned' => 0,
|
||||||
'err_count' => 0,
|
'err_count' => 0,
|
||||||
'err_msg' => '',
|
'err_msg' => '',
|
||||||
'order_type' => 0,
|
'order_type' => 0,
|
||||||
'added' => '2017-05-20 13:35:54',
|
'added' => '2017-05-20 13:35:54',
|
||||||
'title' => 'First example feed',
|
'title' => 'First example feed',
|
||||||
'unread' => 50048,
|
'unread' => 50048,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 42,
|
'id' => 42,
|
||||||
'url' => 'http://example.org/news.atom',
|
'url' => 'http://example.org/news.atom',
|
||||||
'favicon' => 'http://example.org/favicon.png',
|
'favicon' => 'http://example.org/favicon.png',
|
||||||
'source' => 'http://example.org/',
|
'source' => 'http://example.org/',
|
||||||
'folder' => 12,
|
'folder' => 12,
|
||||||
'top_folder' => 8,
|
'top_folder' => 8,
|
||||||
'pinned' => 1,
|
'pinned' => 1,
|
||||||
'err_count' => 0,
|
'err_count' => 0,
|
||||||
'err_msg' => '',
|
'err_msg' => '',
|
||||||
'order_type' => 2,
|
'order_type' => 2,
|
||||||
'added' => '2017-05-20 13:35:54',
|
'added' => '2017-05-20 13:35:54',
|
||||||
'title' => 'Second example feed',
|
'title' => 'Second example feed',
|
||||||
'unread' => 23,
|
'unread' => 23,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 47,
|
'id' => 47,
|
||||||
'url' => 'http://example.net/news.atom',
|
'url' => 'http://example.net/news.atom',
|
||||||
'favicon' => 'http://example.net/favicon.png',
|
'favicon' => 'http://example.net/favicon.png',
|
||||||
'source' => 'http://example.net/',
|
'source' => 'http://example.net/',
|
||||||
'folder' => null,
|
'folder' => null,
|
||||||
'top_folder' => null,
|
'top_folder' => null,
|
||||||
'pinned' => 0,
|
'pinned' => 0,
|
||||||
'err_count' => 0,
|
'err_count' => 0,
|
||||||
'err_msg' => null,
|
'err_msg' => null,
|
||||||
'order_type' => 1,
|
'order_type' => 1,
|
||||||
'added' => '2017-05-20 13:35:54',
|
'added' => '2017-05-20 13:35:54',
|
||||||
'title' => 'Third example feed',
|
'title' => 'Third example feed',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'rest' => [
|
'rest' => [
|
||||||
[
|
[
|
||||||
'id' => 2112,
|
'id' => 2112,
|
||||||
'url' => 'http://example.com/news.atom',
|
'url' => 'http://example.com/news.atom',
|
||||||
'title' => 'First example feed',
|
'title' => 'First example feed',
|
||||||
'added' => 1495287354,
|
'added' => 1495287354,
|
||||||
'pinned' => false,
|
'pinned' => false,
|
||||||
'link' => 'http://example.com/',
|
'link' => 'http://example.com/',
|
||||||
'faviconLink' => 'http://example.com/favicon.png',
|
'faviconLink' => 'http://example.com/favicon.png',
|
||||||
'folderId' => 0,
|
'folderId' => 0,
|
||||||
'unreadCount' => 50048,
|
'unreadCount' => 50048,
|
||||||
'ordering' => 0,
|
'ordering' => 0,
|
||||||
'updateErrorCount' => 0,
|
'updateErrorCount' => 0,
|
||||||
'lastUpdateError' => '',
|
'lastUpdateError' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 42,
|
'id' => 42,
|
||||||
'url' => 'http://example.org/news.atom',
|
'url' => 'http://example.org/news.atom',
|
||||||
'title' => 'Second example feed',
|
'title' => 'Second example feed',
|
||||||
'added' => 1495287354,
|
'added' => 1495287354,
|
||||||
'pinned' => true,
|
'pinned' => true,
|
||||||
'link' => 'http://example.org/',
|
'link' => 'http://example.org/',
|
||||||
'faviconLink' => 'http://example.org/favicon.png',
|
'faviconLink' => 'http://example.org/favicon.png',
|
||||||
'folderId' => 8,
|
'folderId' => 8,
|
||||||
'unreadCount' => 23,
|
'unreadCount' => 23,
|
||||||
'ordering' => 2,
|
'ordering' => 2,
|
||||||
'updateErrorCount' => 0,
|
'updateErrorCount' => 0,
|
||||||
'lastUpdateError' => '',
|
'lastUpdateError' => '',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 47,
|
'id' => 47,
|
||||||
'url' => 'http://example.net/news.atom',
|
'url' => 'http://example.net/news.atom',
|
||||||
'title' => 'Third example feed',
|
'title' => 'Third example feed',
|
||||||
'added' => 1495287354,
|
'added' => 1495287354,
|
||||||
'pinned' => false,
|
'pinned' => false,
|
||||||
'link' => 'http://example.net/',
|
'link' => 'http://example.net/',
|
||||||
'faviconLink' => 'http://example.net/favicon.png',
|
'faviconLink' => 'http://example.net/favicon.png',
|
||||||
'folderId' => 0,
|
'folderId' => 0,
|
||||||
'unreadCount' => 0,
|
'unreadCount' => 0,
|
||||||
'ordering' => 1,
|
'ordering' => 1,
|
||||||
'updateErrorCount' => 0,
|
'updateErrorCount' => 0,
|
||||||
'lastUpdateError' => '',
|
'lastUpdateError' => '',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
protected $articles = [
|
protected $articles = [
|
||||||
'db' => [
|
'db' => [
|
||||||
[
|
[
|
||||||
'id' => 101,
|
'id' => 101,
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 1</p>',
|
'content' => '<p>Article content 1</p>',
|
||||||
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
||||||
'published_date' => '2000-01-01 00:00:00',
|
'published_date' => '2000-01-01 00:00:00',
|
||||||
'edited_date' => '2000-01-01 00:00:01',
|
'edited_date' => '2000-01-01 00:00:01',
|
||||||
'modified_date' => '2000-01-01 01:00:00',
|
'modified_date' => '2000-01-01 01:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 101,
|
'edition' => 101,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
||||||
'media_url' => null,
|
'media_url' => null,
|
||||||
'media_type' => null,
|
'media_type' => null,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 102,
|
'id' => 102,
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 2</p>',
|
'content' => '<p>Article content 2</p>',
|
||||||
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
||||||
'published_date' => '2000-01-02 00:00:00',
|
'published_date' => '2000-01-02 00:00:00',
|
||||||
'edited_date' => '2000-01-02 00:00:02',
|
'edited_date' => '2000-01-02 00:00:02',
|
||||||
'modified_date' => '2000-01-02 02:00:00',
|
'modified_date' => '2000-01-02 02:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 202,
|
'edition' => 202,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
||||||
'media_url' => "http://example.com/text",
|
'media_url' => "http://example.com/text",
|
||||||
'media_type' => "text/plain",
|
'media_type' => "text/plain",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 103,
|
'id' => 103,
|
||||||
'url' => 'http://example.com/3',
|
'url' => 'http://example.com/3',
|
||||||
'title' => 'Article title 3',
|
'title' => 'Article title 3',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 3</p>',
|
'content' => '<p>Article content 3</p>',
|
||||||
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
||||||
'published_date' => '2000-01-03 00:00:00',
|
'published_date' => '2000-01-03 00:00:00',
|
||||||
'edited_date' => '2000-01-03 00:00:03',
|
'edited_date' => '2000-01-03 00:00:03',
|
||||||
'modified_date' => '2000-01-03 03:00:00',
|
'modified_date' => '2000-01-03 03:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'edition' => 203,
|
'edition' => 203,
|
||||||
'subscription' => 9,
|
'subscription' => 9,
|
||||||
'fingerprint' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b:b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406:ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
'fingerprint' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b:b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406:ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
||||||
'media_url' => "http://example.com/video",
|
'media_url' => "http://example.com/video",
|
||||||
'media_type' => "video/webm",
|
'media_type' => "video/webm",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 104,
|
'id' => 104,
|
||||||
'url' => 'http://example.com/4',
|
'url' => 'http://example.com/4',
|
||||||
'title' => 'Article title 4',
|
'title' => 'Article title 4',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 4</p>',
|
'content' => '<p>Article content 4</p>',
|
||||||
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
||||||
'published_date' => '2000-01-04 00:00:00',
|
'published_date' => '2000-01-04 00:00:00',
|
||||||
'edited_date' => '2000-01-04 00:00:04',
|
'edited_date' => '2000-01-04 00:00:04',
|
||||||
'modified_date' => '2000-01-04 04:00:00',
|
'modified_date' => '2000-01-04 04:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'edition' => 204,
|
'edition' => 204,
|
||||||
'subscription' => 9,
|
'subscription' => 9,
|
||||||
'fingerprint' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8:f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3:ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
'fingerprint' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8:f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3:ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
||||||
'media_url' => "http://example.com/image",
|
'media_url' => "http://example.com/image",
|
||||||
'media_type' => "image/svg+xml",
|
'media_type' => "image/svg+xml",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 105,
|
'id' => 105,
|
||||||
'url' => 'http://example.com/5',
|
'url' => 'http://example.com/5',
|
||||||
'title' => 'Article title 5',
|
'title' => 'Article title 5',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 5</p>',
|
'content' => '<p>Article content 5</p>',
|
||||||
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
||||||
'published_date' => '2000-01-05 00:00:00',
|
'published_date' => '2000-01-05 00:00:00',
|
||||||
'edited_date' => '2000-01-05 00:00:05',
|
'edited_date' => '2000-01-05 00:00:05',
|
||||||
'modified_date' => '2000-01-05 05:00:00',
|
'modified_date' => '2000-01-05 05:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 305,
|
'edition' => 305,
|
||||||
'subscription' => 10,
|
'subscription' => 10,
|
||||||
'fingerprint' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022:834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900:43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
'fingerprint' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022:834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900:43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
||||||
'media_url' => "http://example.com/audio",
|
'media_url' => "http://example.com/audio",
|
||||||
'media_type' => "audio/ogg",
|
'media_type' => "audio/ogg",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'rest' => [
|
'rest' => [
|
||||||
[
|
[
|
||||||
'id' => 101,
|
'id' => 101,
|
||||||
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
'guid' => 'e433653cef2e572eee4215fa299a4a5af9137b2cefd6283c85bd69a32915beda',
|
||||||
'guidHash' => "101",
|
'guidHash' => "101",
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'pubDate' => 946684801,
|
'pubDate' => 946684801,
|
||||||
'body' => '<p>Article content 1</p>',
|
'body' => '<p>Article content 1</p>',
|
||||||
'enclosureMime' => "",
|
'enclosureMime' => "",
|
||||||
'enclosureLink' => "",
|
'enclosureLink' => "",
|
||||||
'feedId' => 8,
|
'feedId' => 8,
|
||||||
'unread' => true,
|
'unread' => true,
|
||||||
'starred' => false,
|
'starred' => false,
|
||||||
'lastModified' => 946688400,
|
'lastModified' => 946688400,
|
||||||
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 202,
|
'id' => 202,
|
||||||
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
||||||
'guidHash' => "102",
|
'guidHash' => "102",
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'pubDate' => 946771202,
|
'pubDate' => 946771202,
|
||||||
'body' => '<p>Article content 2</p>',
|
'body' => '<p>Article content 2</p>',
|
||||||
'enclosureMime' => "text/plain",
|
'enclosureMime' => "text/plain",
|
||||||
'enclosureLink' => "http://example.com/text",
|
'enclosureLink' => "http://example.com/text",
|
||||||
'feedId' => 8,
|
'feedId' => 8,
|
||||||
'unread' => false,
|
'unread' => false,
|
||||||
'starred' => false,
|
'starred' => false,
|
||||||
'lastModified' => 946778400,
|
'lastModified' => 946778400,
|
||||||
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 203,
|
'id' => 203,
|
||||||
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
'guid' => '31a6594500a48b59fcc8a075ce82b946c9c3c782460d088bd7b8ef3ede97ad92',
|
||||||
'guidHash' => "103",
|
'guidHash' => "103",
|
||||||
'url' => 'http://example.com/3',
|
'url' => 'http://example.com/3',
|
||||||
'title' => 'Article title 3',
|
'title' => 'Article title 3',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'pubDate' => 946857603,
|
'pubDate' => 946857603,
|
||||||
'body' => '<p>Article content 3</p>',
|
'body' => '<p>Article content 3</p>',
|
||||||
'enclosureMime' => "video/webm",
|
'enclosureMime' => "video/webm",
|
||||||
'enclosureLink' => "http://example.com/video",
|
'enclosureLink' => "http://example.com/video",
|
||||||
'feedId' => 9,
|
'feedId' => 9,
|
||||||
'unread' => true,
|
'unread' => true,
|
||||||
'starred' => true,
|
'starred' => true,
|
||||||
'lastModified' => 946868400,
|
'lastModified' => 946868400,
|
||||||
'fingerprint' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b:b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406:ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
'fingerprint' => 'f74b06b240bd08abf4d3fdfc20dba6a6f6eb8b4f1a00e9a617efd63a87180a4b:b278380e984cefe63f0e412b88ffc9cb0befdfa06fdc00bace1da99a8daff406:ad622b31e739cd3a3f3c788991082cf4d2f7a8773773008e75f0572e58cd373b',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 204,
|
'id' => 204,
|
||||||
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
'guid' => '804e517d623390e71497982c77cf6823180342ebcd2e7d5e32da1e55b09dd180',
|
||||||
'guidHash' => "104",
|
'guidHash' => "104",
|
||||||
'url' => 'http://example.com/4',
|
'url' => 'http://example.com/4',
|
||||||
'title' => 'Article title 4',
|
'title' => 'Article title 4',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'pubDate' => 946944004,
|
'pubDate' => 946944004,
|
||||||
'body' => '<p>Article content 4</p>',
|
'body' => '<p>Article content 4</p>',
|
||||||
'enclosureMime' => "image/svg+xml",
|
'enclosureMime' => "image/svg+xml",
|
||||||
'enclosureLink' => "http://example.com/image",
|
'enclosureLink' => "http://example.com/image",
|
||||||
'feedId' => 9,
|
'feedId' => 9,
|
||||||
'unread' => false,
|
'unread' => false,
|
||||||
'starred' => true,
|
'starred' => true,
|
||||||
'lastModified' => 946958400,
|
'lastModified' => 946958400,
|
||||||
'fingerprint' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8:f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3:ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
'fingerprint' => 'f3615c7f16336d3ea242d35cf3fc17dbc4ee3afb78376bf49da2dd7a5a25dec8:f11c2b4046f207579aeb9c69a8c20ca5461cef49756ccfa5ba5e2344266da3b3:ab2da63276acce431250b18d3d49b988b226a99c7faadf275c90b751aee05be9',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 305,
|
'id' => 305,
|
||||||
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
'guid' => 'db3e736c2c492f5def5c5da33ddcbea1824040e9ced2142069276b0a6e291a41',
|
||||||
'guidHash' => "105",
|
'guidHash' => "105",
|
||||||
'url' => 'http://example.com/5',
|
'url' => 'http://example.com/5',
|
||||||
'title' => 'Article title 5',
|
'title' => 'Article title 5',
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'pubDate' => 947030405,
|
'pubDate' => 947030405,
|
||||||
'body' => '<p>Article content 5</p>',
|
'body' => '<p>Article content 5</p>',
|
||||||
'enclosureMime' => "audio/ogg",
|
'enclosureMime' => "audio/ogg",
|
||||||
'enclosureLink' => "http://example.com/audio",
|
'enclosureLink' => "http://example.com/audio",
|
||||||
'feedId' => 10,
|
'feedId' => 10,
|
||||||
'unread' => true,
|
'unread' => true,
|
||||||
'starred' => false,
|
'starred' => false,
|
||||||
'lastModified' => 947048400,
|
'lastModified' => 947048400,
|
||||||
'fingerprint' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022:834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900:43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
'fingerprint' => 'd40da96e39eea6c55948ccbe9b3d275b5f931298288dbe953990c5f496097022:834240f84501b5341d375414718204ec421561f3825d34c22bf9182203e42900:43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -430,10 +430,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function provideFolderCreations(): array {
|
public function provideFolderCreations(): array {
|
||||||
return [
|
return [
|
||||||
[['name' => "Software"], true, 1, new Response(['folders' => [['id'=> 1, 'name' => "Software"]]])],
|
[['name' => "Software"], true, 1, new Response(['folders' => [['id' => 1, 'name' => "Software"]]])],
|
||||||
[['name' => "Software"], false, 1, new Response(['folders' => [['id'=> 1, 'name' => "Software"]]])],
|
[['name' => "Software"], false, 1, new Response(['folders' => [['id' => 1, 'name' => "Software"]]])],
|
||||||
[['name' => "Hardware"], true, "2", new Response(['folders' => [['id'=> 2, 'name' => "Hardware"]]])],
|
[['name' => "Hardware"], true, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])],
|
||||||
[['name' => "Hardware"], false, "2", new Response(['folders' => [['id'=> 2, 'name' => "Hardware"]]])],
|
[['name' => "Hardware"], false, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])],
|
||||||
[['name' => "Software"], true, new ExceptionInput("constraintViolation"), new EmptyResponse(409)],
|
[['name' => "Software"], true, new ExceptionInput("constraintViolation"), new EmptyResponse(409)],
|
||||||
[['name' => ""], true, new ExceptionInput("whitespace"), new EmptyResponse(422)],
|
[['name' => ""], true, new ExceptionInput("whitespace"), new EmptyResponse(422)],
|
||||||
[['name' => " "], true, new ExceptionInput("whitespace"), new EmptyResponse(422)],
|
[['name' => " "], true, new ExceptionInput("whitespace"), new EmptyResponse(422)],
|
||||||
|
@ -476,7 +476,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function testRetrieveServerVersion(): void {
|
public function testRetrieveServerVersion(): void {
|
||||||
$exp = new Response([
|
$exp = new Response([
|
||||||
'version' => V1_2::VERSION,
|
'version' => V1_2::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
]);
|
]);
|
||||||
$this->assertMessage($exp, $this->req("GET", "/version"));
|
$this->assertMessage($exp, $this->req("GET", "/version"));
|
||||||
|
@ -484,7 +484,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
||||||
public function testListSubscriptions(): void {
|
public function testListSubscriptions(): void {
|
||||||
$exp1 = [
|
$exp1 = [
|
||||||
'feeds' => [],
|
'feeds' => [],
|
||||||
'starredCount' => 0,
|
'starredCount' => 0,
|
||||||
];
|
];
|
||||||
$exp2 = [
|
$exp2 = [
|
||||||
|
@ -558,10 +558,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testMoveASubscription(): void {
|
public function testMoveASubscription(): void {
|
||||||
$in = [
|
$in = [
|
||||||
['folderId' => 0],
|
['folderId' => 0],
|
||||||
['folderId' => 42],
|
['folderId' => 42],
|
||||||
['folderId' => 2112],
|
['folderId' => 2112],
|
||||||
['folderId' => 42],
|
['folderId' => 42],
|
||||||
['folderId' => -1],
|
['folderId' => -1],
|
||||||
[],
|
[],
|
||||||
];
|
];
|
||||||
\Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => 42])->thenReturn(true);
|
\Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 1, ['folder' => 42])->thenReturn(true);
|
||||||
|
@ -616,11 +616,11 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testListStaleFeeds(): void {
|
public function testListStaleFeeds(): void {
|
||||||
$out = [
|
$out = [
|
||||||
[
|
[
|
||||||
'id' => 42,
|
'id' => 42,
|
||||||
'userId' => "",
|
'userId' => "",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 2112,
|
'id' => 2112,
|
||||||
'userId' => "",
|
'userId' => "",
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -632,10 +632,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testUpdateAFeed(): void {
|
public function testUpdateAFeed(): void {
|
||||||
$in = [
|
$in = [
|
||||||
['feedId' => 42], // valid
|
['feedId' => 42], // valid
|
||||||
['feedId' => 2112], // feed does not exist
|
['feedId' => 2112], // feed does not exist
|
||||||
['feedId' => "ook"], // invalid ID
|
['feedId' => "ook"], // invalid ID
|
||||||
['feedId' => -1], // invalid ID
|
['feedId' => -1], // invalid ID
|
||||||
['feed' => 42], // invalid input
|
['feed' => 42], // invalid input
|
||||||
];
|
];
|
||||||
\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"));
|
||||||
|
@ -654,17 +654,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$t = new \DateTime;
|
$t = new \DateTime;
|
||||||
$in = [
|
$in = [
|
||||||
['type' => 0, 'id' => 42], // type=0 => subscription/feed
|
['type' => 0, 'id' => 42], // type=0 => subscription/feed
|
||||||
['type' => 1, 'id' => 2112], // type=1 => folder
|
['type' => 1, 'id' => 2112], // type=1 => folder
|
||||||
['type' => 0, 'id' => -1], // type=0 => subscription/feed; invalid ID
|
['type' => 0, 'id' => -1], // type=0 => subscription/feed; invalid ID
|
||||||
['type' => 1, 'id' => -1], // type=1 => folder; invalid ID
|
['type' => 1, 'id' => -1], // type=1 => folder; invalid ID
|
||||||
['type' => 2, 'id' => 0], // type=2 => starred
|
['type' => 2, 'id' => 0], // type=2 => starred
|
||||||
['type' => 3, 'id' => 0], // type=3 => all (default); base context
|
['type' => 3, 'id' => 0], // type=3 => all (default); base context
|
||||||
['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5],
|
['oldestFirst' => true, 'batchSize' => 10, 'offset' => 5],
|
||||||
['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5],
|
['oldestFirst' => false, 'batchSize' => 5, 'offset' => 5],
|
||||||
['getRead' => true], // base context
|
['getRead' => true], // base context
|
||||||
['getRead' => false],
|
['getRead' => false],
|
||||||
['lastModified' => $t->getTimestamp()],
|
['lastModified' => $t->getTimestamp()],
|
||||||
['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], // offset=0 should not set the latestEdition context
|
['oldestFirst' => false, 'batchSize' => 5, 'offset' => 0], // offset=0 should not set the latestEdition context
|
||||||
];
|
];
|
||||||
\Phake::when(Arsse::$db)->articleList->thenReturn(new Result($this->v($this->articles['db'])));
|
\Phake::when(Arsse::$db)->articleList->thenReturn(new Result($this->v($this->articles['db'])));
|
||||||
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->subscription(42), $this->anything(), ["edition desc"])->thenThrow(new ExceptionInput("idMissing"));
|
\Phake::when(Arsse::$db)->articleList(Arsse::$user->id, (new Context)->subscription(42), $this->anything(), ["edition desc"])->thenThrow(new ExceptionInput("idMissing"));
|
||||||
|
@ -834,12 +834,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
\Phake::when(Arsse::$db)->metaGet("service_last_checkin")->thenReturn(Date::transform($valid, "sql"))->thenReturn(Date::transform($invalid, "sql"));
|
\Phake::when(Arsse::$db)->metaGet("service_last_checkin")->thenReturn(Date::transform($valid, "sql"))->thenReturn(Date::transform($invalid, "sql"));
|
||||||
\Phake::when(Arsse::$db)->driverCharsetAcceptable->thenReturn(true)->thenReturn(false);
|
\Phake::when(Arsse::$db)->driverCharsetAcceptable->thenReturn(true)->thenReturn(false);
|
||||||
$arr1 = $arr2 = [
|
$arr1 = $arr2 = [
|
||||||
'version' => V1_2::VERSION,
|
'version' => V1_2::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
'warnings' => [
|
'warnings' => [
|
||||||
'improperlyConfiguredCron' => false,
|
'improperlyConfiguredCron' => false,
|
||||||
'incorrectDbCharset' => false,
|
'incorrectDbCharset' => false,
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
$arr2['warnings']['improperlyConfiguredCron'] = true;
|
$arr2['warnings']['improperlyConfiguredCron'] = true;
|
||||||
$arr2['warnings']['incorrectDbCharset'] = true;
|
$arr2['warnings']['incorrectDbCharset'] = true;
|
||||||
|
@ -864,10 +864,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function testQueryTheUserStatus(): void {
|
public function testQueryTheUserStatus(): void {
|
||||||
$act = $this->req("GET", "/user");
|
$act = $this->req("GET", "/user");
|
||||||
$exp = new Response([
|
$exp = new Response([
|
||||||
'userId' => Arsse::$user->id,
|
'userId' => Arsse::$user->id,
|
||||||
'displayName' => Arsse::$user->id,
|
'displayName' => Arsse::$user->id,
|
||||||
'lastLoginTimestamp' => $this->approximateTime($act->getPayload()['lastLoginTimestamp'], new \DateTimeImmutable),
|
'lastLoginTimestamp' => $this->approximateTime($act->getPayload()['lastLoginTimestamp'], new \DateTimeImmutable),
|
||||||
'avatar' => null,
|
'avatar' => null,
|
||||||
]);
|
]);
|
||||||
$this->assertMessage($exp, $act);
|
$this->assertMessage($exp, $act);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ namespace JKingWeb\Arsse\TestCase\REST\NextcloudNews;
|
||||||
|
|
||||||
use JKingWeb\Arsse\REST\NextcloudNews\Versions;
|
use JKingWeb\Arsse\REST\NextcloudNews\Versions;
|
||||||
use Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Laminas\Diactoros\ServerRequest;
|
|
||||||
use Laminas\Diactoros\Response\JsonResponse as Response;
|
use Laminas\Diactoros\Response\JsonResponse as Response;
|
||||||
use Laminas\Diactoros\Response\EmptyResponse;
|
use Laminas\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
|
|
|
@ -199,53 +199,53 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function provideCorsHeaders(): iterable {
|
public function provideCorsHeaders(): iterable {
|
||||||
return [
|
return [
|
||||||
["GET", ['Origin' => "null"], [], [
|
["GET", ['Origin' => "null"], [], [
|
||||||
'Access-Control-Allow-Origin' => "null",
|
'Access-Control-Allow-Origin' => "null",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'Access-Control-Allow-Credentials' => "true",
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
]],
|
]],
|
||||||
["GET", ['Origin' => "http://example"], [], [
|
["GET", ['Origin' => "http://example"], [], [
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'Access-Control-Allow-Credentials' => "true",
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
]],
|
]],
|
||||||
["GET", ['Origin' => "http://example"], ['Content-Type' => "text/plain; charset=utf-8"], [
|
["GET", ['Origin' => "http://example"], ['Content-Type' => "text/plain; charset=utf-8"], [
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'Access-Control-Allow-Credentials' => "true",
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
'Content-Type' => "text/plain; charset=utf-8",
|
'Content-Type' => "text/plain; charset=utf-8",
|
||||||
]],
|
]],
|
||||||
["GET", ['Origin' => "http://example"], ['Vary' => "Content-Type"], [
|
["GET", ['Origin' => "http://example"], ['Vary' => "Content-Type"], [
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'Access-Control-Allow-Credentials' => "true",
|
||||||
'Vary' => ["Content-Type", "Origin"],
|
'Vary' => ["Content-Type", "Origin"],
|
||||||
]],
|
]],
|
||||||
["OPTIONS", ['Origin' => "http://example"], [], [
|
["OPTIONS", ['Origin' => "http://example"], [], [
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'Access-Control-Allow-Credentials' => "true",
|
||||||
'Access-Control-Max-Age' => (string) (60 *60 *24),
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
]],
|
]],
|
||||||
["OPTIONS", ['Origin' => "http://example"], ['Allow' => "GET, PUT, HEAD, OPTIONS"], [
|
["OPTIONS", ['Origin' => "http://example"], ['Allow' => "GET, PUT, HEAD, OPTIONS"], [
|
||||||
'Allow' => "GET, PUT, HEAD, OPTIONS",
|
'Allow' => "GET, PUT, HEAD, OPTIONS",
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'Access-Control-Allow-Credentials' => "true",
|
||||||
'Access-Control-Allow-Methods' => "GET, PUT, HEAD, OPTIONS",
|
'Access-Control-Allow-Methods' => "GET, PUT, HEAD, OPTIONS",
|
||||||
'Access-Control-Max-Age' => (string) (60 *60 *24),
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
]],
|
]],
|
||||||
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => "Content-Type, If-None-Match"], [], [
|
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => "Content-Type, If-None-Match"], [], [
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'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),
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
]],
|
]],
|
||||||
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => ["Content-Type", "If-None-Match"]], [], [
|
["OPTIONS", ['Origin' => "http://example", 'Access-Control-Request-Headers' => ["Content-Type", "If-None-Match"]], [], [
|
||||||
'Access-Control-Allow-Origin' => "http://example",
|
'Access-Control-Allow-Origin' => "http://example",
|
||||||
'Access-Control-Allow-Credentials' => "true",
|
'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),
|
'Access-Control-Max-Age' => (string) (60 * 60 * 24),
|
||||||
'Vary' => "Origin",
|
'Vary' => "Origin",
|
||||||
]],
|
]],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider provideMockRequests */
|
/** @dataProvider provideMockRequests */
|
||||||
public function testDispatchRequests(ServerRequest $req, string $method, bool $called, string $class = "", string $target =""): void {
|
public function testDispatchRequests(ServerRequest $req, string $method, bool $called, string $class = "", string $target = ""): void {
|
||||||
$r = \Phake::partialMock(REST::class);
|
$r = \Phake::partialMock(REST::class);
|
||||||
\Phake::when($r)->normalizeResponse->thenReturnCallback(function($res) {
|
\Phake::when($r)->normalizeResponse->thenReturnCallback(function($res) {
|
||||||
return $res;
|
return $res;
|
||||||
|
|
|
@ -17,7 +17,6 @@ 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 Psr\Http\Message\ResponseInterface;
|
||||||
use Laminas\Diactoros\ServerRequest;
|
|
||||||
use Laminas\Diactoros\Response\JsonResponse as Response;
|
use Laminas\Diactoros\Response\JsonResponse as Response;
|
||||||
use Laminas\Diactoros\Response\EmptyResponse;
|
use Laminas\Diactoros\Response\EmptyResponse;
|
||||||
|
|
||||||
|
@ -58,44 +57,44 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected $starred = ['total' => 10, 'unread' => 4, 'read' => 6];
|
protected $starred = ['total' => 10, 'unread' => 4, 'read' => 6];
|
||||||
protected $articles = [
|
protected $articles = [
|
||||||
[
|
[
|
||||||
'id' => 101,
|
'id' => 101,
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'subscription_title' => "Feed 11",
|
'subscription_title' => "Feed 11",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>Article content 1</p>',
|
'content' => '<p>Article content 1</p>',
|
||||||
'guid' => '',
|
'guid' => '',
|
||||||
'published_date' => '2000-01-01 00:00:00',
|
'published_date' => '2000-01-01 00:00:00',
|
||||||
'edited_date' => '2000-01-01 00:00:01',
|
'edited_date' => '2000-01-01 00:00:01',
|
||||||
'modified_date' => '2000-01-01 01:00:00',
|
'modified_date' => '2000-01-01 01:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 101,
|
'edition' => 101,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
||||||
'media_url' => null,
|
'media_url' => null,
|
||||||
'media_type' => null,
|
'media_type' => null,
|
||||||
'note' => "",
|
'note' => "",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 102,
|
'id' => 102,
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'subscription_title' => "Feed 11",
|
'subscription_title' => "Feed 11",
|
||||||
'author' => 'J. King',
|
'author' => 'J. King',
|
||||||
'content' => '<p>Article content 2</p>',
|
'content' => '<p>Article content 2</p>',
|
||||||
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
||||||
'published_date' => '2000-01-02 00:00:00',
|
'published_date' => '2000-01-02 00:00:00',
|
||||||
'edited_date' => '2000-01-02 00:00:02',
|
'edited_date' => '2000-01-02 00:00:02',
|
||||||
'modified_date' => '2000-01-02 02:00:00',
|
'modified_date' => '2000-01-02 02:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 202,
|
'edition' => 202,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
||||||
'media_url' => "http://example.com/text",
|
'media_url' => "http://example.com/text",
|
||||||
'media_type' => "text/plain",
|
'media_type' => "text/plain",
|
||||||
'note' => "Note 2",
|
'note' => "Note 2",
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
// text from https://corrigeur.fr/lorem-ipsum-traduction-origine.php
|
// text from https://corrigeur.fr/lorem-ipsum-traduction-origine.php
|
||||||
|
@ -140,8 +139,8 @@ LONG_STRING;
|
||||||
|
|
||||||
protected function respGood($content = null, $seq = 0): Response {
|
protected function respGood($content = null, $seq = 0): Response {
|
||||||
return new Response([
|
return new Response([
|
||||||
'seq' => $seq,
|
'seq' => $seq,
|
||||||
'status' => 0,
|
'status' => 0,
|
||||||
'content' => $content,
|
'content' => $content,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -149,8 +148,8 @@ 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([
|
return new Response([
|
||||||
'seq' => $seq,
|
'seq' => $seq,
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
'content' => array_merge($err, $content, $err),
|
'content' => array_merge($err, $content, $err),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -167,7 +166,7 @@ LONG_STRING;
|
||||||
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(Transaction::class));
|
\Phake::when(Arsse::$db)->begin->thenReturn(\Phake::mock(Transaction::class));
|
||||||
\Phake::when(Arsse::$db)->sessionResume->thenThrow(new \JKingWeb\Arsse\User\ExceptionSession("invalid"));
|
\Phake::when(Arsse::$db)->sessionResume->thenThrow(new \JKingWeb\Arsse\User\ExceptionSession("invalid"));
|
||||||
\Phake::when(Arsse::$db)->sessionResume("PriestsOfSyrinx")->thenReturn([
|
\Phake::when(Arsse::$db)->sessionResume("PriestsOfSyrinx")->thenReturn([
|
||||||
'id' => "PriestsOfSyrinx",
|
'id' => "PriestsOfSyrinx",
|
||||||
'created' => "2000-01-01 00:00:00",
|
'created' => "2000-01-01 00:00:00",
|
||||||
'expires' => "2112-12-21 21:12:00",
|
'expires' => "2112-12-21 21:12:00",
|
||||||
'user' => Arsse::$user->id,
|
'user' => Arsse::$user->id,
|
||||||
|
@ -241,13 +240,13 @@ LONG_STRING;
|
||||||
Arsse::$user->id = null;
|
Arsse::$user->id = null;
|
||||||
self::setConf($conf);
|
self::setConf($conf);
|
||||||
\Phake::when(Arsse::$db)->sessionResume("PriestsOfSyrinx")->thenReturn([
|
\Phake::when(Arsse::$db)->sessionResume("PriestsOfSyrinx")->thenReturn([
|
||||||
'id' => "PriestsOfSyrinx",
|
'id' => "PriestsOfSyrinx",
|
||||||
'created' => "2000-01-01 00:00:00",
|
'created' => "2000-01-01 00:00:00",
|
||||||
'expires' => "2112-12-21 21:12:00",
|
'expires' => "2112-12-21 21:12:00",
|
||||||
'user' => "john.doe@example.com",
|
'user' => "john.doe@example.com",
|
||||||
]);
|
]);
|
||||||
\Phake::when(Arsse::$db)->sessionResume("ClockworkAngels")->thenReturn([
|
\Phake::when(Arsse::$db)->sessionResume("ClockworkAngels")->thenReturn([
|
||||||
'id' => "ClockworkAngels",
|
'id' => "ClockworkAngels",
|
||||||
'created' => "2000-01-01 00:00:00",
|
'created' => "2000-01-01 00:00:00",
|
||||||
'expires' => "2112-12-21 21:12:00",
|
'expires' => "2112-12-21 21:12:00",
|
||||||
'user' => "jane.doe@example.com",
|
'user' => "jane.doe@example.com",
|
||||||
|
@ -277,21 +276,21 @@ LONG_STRING;
|
||||||
public function generateLoginRequests(string $type): array {
|
public function generateLoginRequests(string $type): array {
|
||||||
$john = "john.doe@example.com";
|
$john = "john.doe@example.com";
|
||||||
$johnGood = [
|
$johnGood = [
|
||||||
'user' => $john,
|
'user' => $john,
|
||||||
'password' => "secret",
|
'password' => "secret",
|
||||||
];
|
];
|
||||||
$johnBad = [
|
$johnBad = [
|
||||||
'user' => $john,
|
'user' => $john,
|
||||||
'password' => "superman",
|
'password' => "superman",
|
||||||
];
|
];
|
||||||
$johnSess = ["PriestsOfSyrinx", "SolarFederation"];
|
$johnSess = ["PriestsOfSyrinx", "SolarFederation"];
|
||||||
$jane = "jane.doe@example.com";
|
$jane = "jane.doe@example.com";
|
||||||
$janeGood = [
|
$janeGood = [
|
||||||
'user' => $jane,
|
'user' => $jane,
|
||||||
'password' => "superman",
|
'password' => "superman",
|
||||||
];
|
];
|
||||||
$janeBad = [
|
$janeBad = [
|
||||||
'user' => $jane,
|
'user' => $jane,
|
||||||
'password' => "secret",
|
'password' => "secret",
|
||||||
];
|
];
|
||||||
$janeSess = ["ClockworkAngels", "SevenCitiesOfGold"];
|
$janeSess = ["ClockworkAngels", "SevenCitiesOfGold"];
|
||||||
|
@ -305,29 +304,29 @@ LONG_STRING;
|
||||||
$sidJane = "ClockworkAngels";
|
$sidJane = "ClockworkAngels";
|
||||||
$sidBad = "TheWatchmaker";
|
$sidBad = "TheWatchmaker";
|
||||||
$defaults = [
|
$defaults = [
|
||||||
'userPreAuth' => false,
|
'userPreAuth' => false,
|
||||||
'userHTTPAuthRequired' => false,
|
'userHTTPAuthRequired' => false,
|
||||||
'userSessionEnforced' => true,
|
'userSessionEnforced' => true,
|
||||||
];
|
];
|
||||||
$preAuth = [
|
$preAuth = [
|
||||||
'userPreAuth' => true,
|
'userPreAuth' => true,
|
||||||
'userHTTPAuthRequired' => false, // implied true by pre-auth
|
'userHTTPAuthRequired' => false, // implied true by pre-auth
|
||||||
'userSessionEnforced' => true,
|
'userSessionEnforced' => true,
|
||||||
];
|
];
|
||||||
$httpReq = [
|
$httpReq = [
|
||||||
'userPreAuth' => false,
|
'userPreAuth' => false,
|
||||||
'userHTTPAuthRequired' => true,
|
'userHTTPAuthRequired' => true,
|
||||||
'userSessionEnforced' => true,
|
'userSessionEnforced' => true,
|
||||||
];
|
];
|
||||||
$noSess = [
|
$noSess = [
|
||||||
'userPreAuth' => false,
|
'userPreAuth' => false,
|
||||||
'userHTTPAuthRequired' => false,
|
'userHTTPAuthRequired' => false,
|
||||||
'userSessionEnforced' => false,
|
'userSessionEnforced' => false,
|
||||||
];
|
];
|
||||||
$fullHttp = [
|
$fullHttp = [
|
||||||
'userPreAuth' => false,
|
'userPreAuth' => false,
|
||||||
'userHTTPAuthRequired' => true,
|
'userHTTPAuthRequired' => true,
|
||||||
'userSessionEnforced' => false,
|
'userSessionEnforced' => false,
|
||||||
];
|
];
|
||||||
$http401 = new EmptyResponse(401);
|
$http401 = new EmptyResponse(401);
|
||||||
if ($type === "login") {
|
if ($type === "login") {
|
||||||
|
@ -573,7 +572,7 @@ LONG_STRING;
|
||||||
'sid' => "PriestsOfSyrinx",
|
'sid' => "PriestsOfSyrinx",
|
||||||
];
|
];
|
||||||
$exp = $this->respGood([
|
$exp = $this->respGood([
|
||||||
'version' => \JKingWeb\Arsse\REST\TinyTinyRSS\API::VERSION,
|
'version' => \JKingWeb\Arsse\REST\TinyTinyRSS\API::VERSION,
|
||||||
'arsse_version' => Arsse::VERSION,
|
'arsse_version' => Arsse::VERSION,
|
||||||
]);
|
]);
|
||||||
$this->assertMessage($exp, $this->req($data));
|
$this->assertMessage($exp, $this->req($data));
|
||||||
|
@ -984,7 +983,7 @@ LONG_STRING;
|
||||||
public function testAddALabel(): void {
|
public function testAddALabel(): void {
|
||||||
$in = [
|
$in = [
|
||||||
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => "Software"],
|
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => "Software"],
|
||||||
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => "Hardware",],
|
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => "Hardware"],
|
||||||
['op' => "addLabel", 'sid' => "PriestsOfSyrinx"],
|
['op' => "addLabel", 'sid' => "PriestsOfSyrinx"],
|
||||||
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => ""],
|
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => ""],
|
||||||
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => " "],
|
['op' => "addLabel", 'sid' => "PriestsOfSyrinx", 'caption' => " "],
|
||||||
|
@ -1301,9 +1300,9 @@ LONG_STRING;
|
||||||
\Phake::when(Arsse::$db)->articleCount($this->anything(), $this->equalTo((new Context)->unread(true)->modifiedSince(Date::sub("PT24H")), 2))->thenReturn(7);
|
\Phake::when(Arsse::$db)->articleCount($this->anything(), $this->equalTo((new Context)->unread(true)->modifiedSince(Date::sub("PT24H")), 2))->thenReturn(7);
|
||||||
\Phake::when(Arsse::$db)->articleStarred($this->anything())->thenReturn($this->v($this->starred));
|
\Phake::when(Arsse::$db)->articleStarred($this->anything())->thenReturn($this->v($this->starred));
|
||||||
// the expectations are packed tightly since they're very verbose; one can use var_export() (or convert to JSON) to pretty-print them
|
// the expectations are packed tightly since they're very verbose; one can use var_export() (or convert to JSON) to pretty-print them
|
||||||
$exp = ['categories'=>['identifier'=>'id','label'=>'name','items'=>[['name'=>'Special','id'=>'CAT:-1','bare_id'=>-1,'type'=>'category','unread'=>0,'items'=>[['name'=>'All articles','id'=>'FEED:-4','bare_id'=>-4,'icon'=>'images/folder.png','unread'=>35,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Fresh articles','id'=>'FEED:-3','bare_id'=>-3,'icon'=>'images/fresh.png','unread'=>7,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Starred articles','id'=>'FEED:-1','bare_id'=>-1,'icon'=>'images/star.png','unread'=>4,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Published articles','id'=>'FEED:-2','bare_id'=>-2,'icon'=>'images/feed.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Archived articles','id'=>'FEED:0','bare_id'=>0,'icon'=>'images/archive.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Recently read','id'=>'FEED:-6','bare_id'=>-6,'icon'=>'images/time.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],],],['name'=>'Labels','id'=>'CAT:-2','bare_id'=>-2,'type'=>'category','unread'=>6,'items'=>[['name'=>'Fascinating','id'=>'FEED:-1027','bare_id'=>-1027,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],['name'=>'Interesting','id'=>'FEED:-1029','bare_id'=>-1029,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],['name'=>'Logical','id'=>'FEED:-1025','bare_id'=>-1025,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],],],['name'=>'Photography','id'=>'CAT:4','bare_id'=>4,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(0 feeds)','items'=>[],],['name'=>'Politics','id'=>'CAT:3','bare_id'=>3,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(3 feeds)','items'=>[['name'=>'Local','id'=>'CAT:5','bare_id'=>5,'parent_id'=>3,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(1 feed)','items'=>[['name'=>'Toronto Star','id'=>'FEED:2','bare_id'=>2,'icon'=>'feed-icons/2.ico','error'=>'oops','param'=>'2011-11-11T11:11:11Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'National','id'=>'CAT:6','bare_id'=>6,'parent_id'=>3,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(2 feeds)','items'=>[['name'=>'CBC News','id'=>'FEED:4','bare_id'=>4,'icon'=>'feed-icons/4.ico','error'=>'','param'=>'2017-10-09T15:58:34Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],['name'=>'Ottawa Citizen','id'=>'FEED:5','bare_id'=>5,'icon'=>false,'error'=>'','param'=>'2017-07-07T17:07:17Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],],],['name'=>'Science','id'=>'CAT:1','bare_id'=>1,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(2 feeds)','items'=>[['name'=>'Rocketry','id'=>'CAT:2','bare_id'=>2,'parent_id'=>1,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(1 feed)','items'=>[['name'=>'NASA JPL','id'=>'FEED:1','bare_id'=>1,'icon'=>false,'error'=>'','param'=>'2017-09-15T22:54:16Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'Ars Technica','id'=>'FEED:3','bare_id'=>3,'icon'=>'feed-icons/3.ico','error'=>'argh','param'=>'2016-05-23T06:40:02Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'Uncategorized','id'=>'CAT:0','bare_id'=>0,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'parent_id'=>null,'param'=>'(1 feed)','items'=>[['name'=>'Eurogamer','id'=>'FEED:6','bare_id'=>6,'icon'=>'feed-icons/6.ico','error'=>'','param'=>'2010-02-12T20:08:47Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],],],];
|
$exp = ['categories' => ['identifier' => 'id','label' => 'name','items' => [['name' => 'Special','id' => 'CAT:-1','bare_id' => -1,'type' => 'category','unread' => 0,'items' => [['name' => 'All articles','id' => 'FEED:-4','bare_id' => -4,'icon' => 'images/folder.png','unread' => 35,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Fresh articles','id' => 'FEED:-3','bare_id' => -3,'icon' => 'images/fresh.png','unread' => 7,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Starred articles','id' => 'FEED:-1','bare_id' => -1,'icon' => 'images/star.png','unread' => 4,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Published articles','id' => 'FEED:-2','bare_id' => -2,'icon' => 'images/feed.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Archived articles','id' => 'FEED:0','bare_id' => 0,'icon' => 'images/archive.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Recently read','id' => 'FEED:-6','bare_id' => -6,'icon' => 'images/time.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => '']]],['name' => 'Labels','id' => 'CAT:-2','bare_id' => -2,'type' => 'category','unread' => 6,'items' => [['name' => 'Fascinating','id' => 'FEED:-1027','bare_id' => -1027,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => ''],['name' => 'Interesting','id' => 'FEED:-1029','bare_id' => -1029,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => ''],['name' => 'Logical','id' => 'FEED:-1025','bare_id' => -1025,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => '']]],['name' => 'Photography','id' => 'CAT:4','bare_id' => 4,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(0 feeds)','items' => []],['name' => 'Politics','id' => 'CAT:3','bare_id' => 3,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(3 feeds)','items' => [['name' => 'Local','id' => 'CAT:5','bare_id' => 5,'parent_id' => 3,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(1 feed)','items' => [['name' => 'Toronto Star','id' => 'FEED:2','bare_id' => 2,'icon' => 'feed-icons/2.ico','error' => 'oops','param' => '2011-11-11T11:11:11Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'National','id' => 'CAT:6','bare_id' => 6,'parent_id' => 3,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(2 feeds)','items' => [['name' => 'CBC News','id' => 'FEED:4','bare_id' => 4,'icon' => 'feed-icons/4.ico','error' => '','param' => '2017-10-09T15:58:34Z','unread' => 0,'auxcounter' => 0,'checkbox' => false],['name' => 'Ottawa Citizen','id' => 'FEED:5','bare_id' => 5,'icon' => false,'error' => '','param' => '2017-07-07T17:07:17Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]]]],['name' => 'Science','id' => 'CAT:1','bare_id' => 1,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(2 feeds)','items' => [['name' => 'Rocketry','id' => 'CAT:2','bare_id' => 2,'parent_id' => 1,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(1 feed)','items' => [['name' => 'NASA JPL','id' => 'FEED:1','bare_id' => 1,'icon' => false,'error' => '','param' => '2017-09-15T22:54:16Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'Ars Technica','id' => 'FEED:3','bare_id' => 3,'icon' => 'feed-icons/3.ico','error' => 'argh','param' => '2016-05-23T06:40:02Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'Uncategorized','id' => 'CAT:0','bare_id' => 0,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'parent_id' => null,'param' => '(1 feed)','items' => [['name' => 'Eurogamer','id' => 'FEED:6','bare_id' => 6,'icon' => 'feed-icons/6.ico','error' => '','param' => '2010-02-12T20:08:47Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]]]]];
|
||||||
$this->assertMessage($this->respGood($exp), $this->req($in[0]));
|
$this->assertMessage($this->respGood($exp), $this->req($in[0]));
|
||||||
$exp = ['categories'=>['identifier'=>'id','label'=>'name','items'=>[['name'=>'Special','id'=>'CAT:-1','bare_id'=>-1,'type'=>'category','unread'=>0,'items'=>[['name'=>'All articles','id'=>'FEED:-4','bare_id'=>-4,'icon'=>'images/folder.png','unread'=>35,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Fresh articles','id'=>'FEED:-3','bare_id'=>-3,'icon'=>'images/fresh.png','unread'=>7,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Starred articles','id'=>'FEED:-1','bare_id'=>-1,'icon'=>'images/star.png','unread'=>4,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Published articles','id'=>'FEED:-2','bare_id'=>-2,'icon'=>'images/feed.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Archived articles','id'=>'FEED:0','bare_id'=>0,'icon'=>'images/archive.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],['name'=>'Recently read','id'=>'FEED:-6','bare_id'=>-6,'icon'=>'images/time.png','unread'=>0,'type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'',],],],['name'=>'Labels','id'=>'CAT:-2','bare_id'=>-2,'type'=>'category','unread'=>6,'items'=>[['name'=>'Fascinating','id'=>'FEED:-1027','bare_id'=>-1027,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],['name'=>'Interesting','id'=>'FEED:-1029','bare_id'=>-1029,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],['name'=>'Logical','id'=>'FEED:-1025','bare_id'=>-1025,'unread'=>0,'icon'=>'images/label.png','type'=>'feed','auxcounter'=>0,'error'=>'','updated'=>'','fg_color'=>'','bg_color'=>'',],],],['name'=>'Politics','id'=>'CAT:3','bare_id'=>3,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(3 feeds)','items'=>[['name'=>'Local','id'=>'CAT:5','bare_id'=>5,'parent_id'=>3,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(1 feed)','items'=>[['name'=>'Toronto Star','id'=>'FEED:2','bare_id'=>2,'icon'=>'feed-icons/2.ico','error'=>'oops','param'=>'2011-11-11T11:11:11Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'National','id'=>'CAT:6','bare_id'=>6,'parent_id'=>3,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(2 feeds)','items'=>[['name'=>'CBC News','id'=>'FEED:4','bare_id'=>4,'icon'=>'feed-icons/4.ico','error'=>'','param'=>'2017-10-09T15:58:34Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],['name'=>'Ottawa Citizen','id'=>'FEED:5','bare_id'=>5,'icon'=>false,'error'=>'','param'=>'2017-07-07T17:07:17Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],],],['name'=>'Science','id'=>'CAT:1','bare_id'=>1,'parent_id'=>null,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(2 feeds)','items'=>[['name'=>'Rocketry','id'=>'CAT:2','bare_id'=>2,'parent_id'=>1,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'param'=>'(1 feed)','items'=>[['name'=>'NASA JPL','id'=>'FEED:1','bare_id'=>1,'icon'=>false,'error'=>'','param'=>'2017-09-15T22:54:16Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'Ars Technica','id'=>'FEED:3','bare_id'=>3,'icon'=>'feed-icons/3.ico','error'=>'argh','param'=>'2016-05-23T06:40:02Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],['name'=>'Uncategorized','id'=>'CAT:0','bare_id'=>0,'type'=>'category','auxcounter'=>0,'unread'=>0,'child_unread'=>0,'checkbox'=>false,'parent_id'=>null,'param'=>'(1 feed)','items'=>[['name'=>'Eurogamer','id'=>'FEED:6','bare_id'=>6,'icon'=>'feed-icons/6.ico','error'=>'','param'=>'2010-02-12T20:08:47Z','unread'=>0,'auxcounter'=>0,'checkbox'=>false,],],],],],];
|
$exp = ['categories' => ['identifier' => 'id','label' => 'name','items' => [['name' => 'Special','id' => 'CAT:-1','bare_id' => -1,'type' => 'category','unread' => 0,'items' => [['name' => 'All articles','id' => 'FEED:-4','bare_id' => -4,'icon' => 'images/folder.png','unread' => 35,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Fresh articles','id' => 'FEED:-3','bare_id' => -3,'icon' => 'images/fresh.png','unread' => 7,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Starred articles','id' => 'FEED:-1','bare_id' => -1,'icon' => 'images/star.png','unread' => 4,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Published articles','id' => 'FEED:-2','bare_id' => -2,'icon' => 'images/feed.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Archived articles','id' => 'FEED:0','bare_id' => 0,'icon' => 'images/archive.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => ''],['name' => 'Recently read','id' => 'FEED:-6','bare_id' => -6,'icon' => 'images/time.png','unread' => 0,'type' => 'feed','auxcounter' => 0,'error' => '','updated' => '']]],['name' => 'Labels','id' => 'CAT:-2','bare_id' => -2,'type' => 'category','unread' => 6,'items' => [['name' => 'Fascinating','id' => 'FEED:-1027','bare_id' => -1027,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => ''],['name' => 'Interesting','id' => 'FEED:-1029','bare_id' => -1029,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => ''],['name' => 'Logical','id' => 'FEED:-1025','bare_id' => -1025,'unread' => 0,'icon' => 'images/label.png','type' => 'feed','auxcounter' => 0,'error' => '','updated' => '','fg_color' => '','bg_color' => '']]],['name' => 'Politics','id' => 'CAT:3','bare_id' => 3,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(3 feeds)','items' => [['name' => 'Local','id' => 'CAT:5','bare_id' => 5,'parent_id' => 3,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(1 feed)','items' => [['name' => 'Toronto Star','id' => 'FEED:2','bare_id' => 2,'icon' => 'feed-icons/2.ico','error' => 'oops','param' => '2011-11-11T11:11:11Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'National','id' => 'CAT:6','bare_id' => 6,'parent_id' => 3,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(2 feeds)','items' => [['name' => 'CBC News','id' => 'FEED:4','bare_id' => 4,'icon' => 'feed-icons/4.ico','error' => '','param' => '2017-10-09T15:58:34Z','unread' => 0,'auxcounter' => 0,'checkbox' => false],['name' => 'Ottawa Citizen','id' => 'FEED:5','bare_id' => 5,'icon' => false,'error' => '','param' => '2017-07-07T17:07:17Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]]]],['name' => 'Science','id' => 'CAT:1','bare_id' => 1,'parent_id' => null,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(2 feeds)','items' => [['name' => 'Rocketry','id' => 'CAT:2','bare_id' => 2,'parent_id' => 1,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'param' => '(1 feed)','items' => [['name' => 'NASA JPL','id' => 'FEED:1','bare_id' => 1,'icon' => false,'error' => '','param' => '2017-09-15T22:54:16Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'Ars Technica','id' => 'FEED:3','bare_id' => 3,'icon' => 'feed-icons/3.ico','error' => 'argh','param' => '2016-05-23T06:40:02Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]],['name' => 'Uncategorized','id' => 'CAT:0','bare_id' => 0,'type' => 'category','auxcounter' => 0,'unread' => 0,'child_unread' => 0,'checkbox' => false,'parent_id' => null,'param' => '(1 feed)','items' => [['name' => 'Eurogamer','id' => 'FEED:6','bare_id' => 6,'icon' => 'feed-icons/6.ico','error' => '','param' => '2010-02-12T20:08:47Z','unread' => 0,'auxcounter' => 0,'checkbox' => false]]]]]];
|
||||||
$this->assertMessage($this->respGood($exp), $this->req($in[1]));
|
$this->assertMessage($this->respGood($exp), $this->req($in[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1413,7 +1412,7 @@ LONG_STRING;
|
||||||
['id' => -3, 'title' => "Fresh articles", 'unread' => "7", 'cat_id' => -1],
|
['id' => -3, 'title' => "Fresh articles", 'unread' => "7", 'cat_id' => -1],
|
||||||
['id' => -4, 'title' => "All articles", 'unread' => "35", 'cat_id' => -1],
|
['id' => -4, 'title' => "All articles", 'unread' => "35", 'cat_id' => -1],
|
||||||
['id' => -6, 'title' => "Recently read", 'unread' => 0, 'cat_id' => -1],
|
['id' => -6, 'title' => "Recently read", 'unread' => 0, 'cat_id' => -1],
|
||||||
['id' => 0, 'title' => "Archived articles", 'unread' => "0", 'cat_id' => -1],
|
['id' => 0, 'title' => "Archived articles", 'unread' => "0", 'cat_id' => -1],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
['id' => -1, 'title' => "Starred articles", 'unread' => "4", 'cat_id' => -1],
|
['id' => -1, 'title' => "Starred articles", 'unread' => "4", 'cat_id' => -1],
|
||||||
|
@ -1450,7 +1449,7 @@ LONG_STRING;
|
||||||
['id' => -3, 'title' => "Fresh articles", 'unread' => "7", 'cat_id' => -1],
|
['id' => -3, 'title' => "Fresh articles", 'unread' => "7", 'cat_id' => -1],
|
||||||
['id' => -4, 'title' => "All articles", 'unread' => "35", 'cat_id' => -1],
|
['id' => -4, 'title' => "All articles", 'unread' => "35", 'cat_id' => -1],
|
||||||
['id' => -6, 'title' => "Recently read", 'unread' => 0, 'cat_id' => -1],
|
['id' => -6, 'title' => "Recently read", 'unread' => 0, 'cat_id' => -1],
|
||||||
['id' => 0, 'title' => "Archived articles", 'unread' => "0", 'cat_id' => -1],
|
['id' => 0, 'title' => "Archived articles", 'unread' => "0", 'cat_id' => -1],
|
||||||
['id' => 3, 'title' => 'Ars Technica', 'unread' => 2, 'cat_id' => 1, 'feed_url' => " http://example.com/3", 'has_icon' => true, 'last_updated' => 1463985602, 'order_id' => 1],
|
['id' => 3, 'title' => 'Ars Technica', 'unread' => 2, 'cat_id' => 1, 'feed_url' => " http://example.com/3", 'has_icon' => true, 'last_updated' => 1463985602, 'order_id' => 1],
|
||||||
['id' => 4, 'title' => 'CBC News', 'unread' => 6, 'cat_id' => 6, 'feed_url' => " http://example.com/4", 'has_icon' => true, 'last_updated' => 1507564714, 'order_id' => 2],
|
['id' => 4, 'title' => 'CBC News', 'unread' => 6, 'cat_id' => 6, 'feed_url' => " http://example.com/4", 'has_icon' => true, 'last_updated' => 1507564714, 'order_id' => 2],
|
||||||
['id' => 6, 'title' => 'Eurogamer', 'unread' => 0, 'cat_id' => 0, 'feed_url' => " http://example.com/6", 'has_icon' => true, 'last_updated' => 1266005327, 'order_id' => 3],
|
['id' => 6, 'title' => 'Eurogamer', 'unread' => 0, 'cat_id' => 0, 'feed_url' => " http://example.com/6", 'has_icon' => true, 'last_updated' => 1266005327, 'order_id' => 3],
|
||||||
|
@ -1507,7 +1506,7 @@ LONG_STRING;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function reduceFolders(int $id = null) : int {
|
protected function reduceFolders(int $id = null): int {
|
||||||
$out = 0;
|
$out = 0;
|
||||||
foreach ($this->filterFolders($id) as $f) {
|
foreach ($this->filterFolders($id) as $f) {
|
||||||
$out += $this->reduceFolders($f['id']);
|
$out += $this->reduceFolders($f['id']);
|
||||||
|
@ -1631,42 +1630,42 @@ LONG_STRING;
|
||||||
$this->assertMessage($exp, $this->req($in[3]));
|
$this->assertMessage($exp, $this->req($in[3]));
|
||||||
$exp = [
|
$exp = [
|
||||||
[
|
[
|
||||||
'id' => "101",
|
'id' => "101",
|
||||||
'guid' => null,
|
'guid' => null,
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'link' => 'http://example.com/1',
|
'link' => 'http://example.com/1',
|
||||||
'labels' => [],
|
'labels' => [],
|
||||||
'unread' => true,
|
'unread' => true,
|
||||||
'marked' => false,
|
'marked' => false,
|
||||||
'published' => false,
|
'published' => false,
|
||||||
'comments' => "",
|
'comments' => "",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'updated' => strtotime('2000-01-01T00:00:01Z'),
|
'updated' => strtotime('2000-01-01T00:00:01Z'),
|
||||||
'feed_id' => "8",
|
'feed_id' => "8",
|
||||||
'feed_title' => "Feed 11",
|
'feed_title' => "Feed 11",
|
||||||
'attachments' => [],
|
'attachments' => [],
|
||||||
'score' => 0,
|
'score' => 0,
|
||||||
'note' => null,
|
'note' => null,
|
||||||
'lang' => "",
|
'lang' => "",
|
||||||
'content' => '<p>Article content 1</p>',
|
'content' => '<p>Article content 1</p>',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => "102",
|
'id' => "102",
|
||||||
'guid' => "SHA256:5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7",
|
'guid' => "SHA256:5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7",
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'link' => 'http://example.com/2',
|
'link' => 'http://example.com/2',
|
||||||
'labels' => [
|
'labels' => [
|
||||||
[-1025, "Logical", "", ""],
|
[-1025, "Logical", "", ""],
|
||||||
[-1027, "Fascinating", "", ""],
|
[-1027, "Fascinating", "", ""],
|
||||||
],
|
],
|
||||||
'unread' => false,
|
'unread' => false,
|
||||||
'marked' => false,
|
'marked' => false,
|
||||||
'published' => false,
|
'published' => false,
|
||||||
'comments' => "",
|
'comments' => "",
|
||||||
'author' => "J. King",
|
'author' => "J. King",
|
||||||
'updated' => strtotime('2000-01-02T00:00:02Z'),
|
'updated' => strtotime('2000-01-02T00:00:02Z'),
|
||||||
'feed_id' => "8",
|
'feed_id' => "8",
|
||||||
'feed_title' => "Feed 11",
|
'feed_title' => "Feed 11",
|
||||||
'attachments' => [
|
'attachments' => [
|
||||||
[
|
[
|
||||||
'id' => "0",
|
'id' => "0",
|
||||||
|
@ -1679,9 +1678,9 @@ LONG_STRING;
|
||||||
'post_id' => "102",
|
'post_id' => "102",
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
'score' => 0,
|
'score' => 0,
|
||||||
'note' => "Note 2",
|
'note' => "Note 2",
|
||||||
'lang' => "",
|
'lang' => "",
|
||||||
'content' => '<p>Article content 2</p>',
|
'content' => '<p>Article content 2</p>',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
@ -2012,44 +2011,44 @@ LONG_STRING;
|
||||||
protected function generateHeadlines(int $id): Result {
|
protected function generateHeadlines(int $id): Result {
|
||||||
return new Result($this->v([
|
return new Result($this->v([
|
||||||
[
|
[
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'url' => 'http://example.com/1',
|
'url' => 'http://example.com/1',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'subscription_title' => "Feed 2112",
|
'subscription_title' => "Feed 2112",
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'content' => '<p>“This & that, you know‽”</p>',
|
'content' => '<p>“This & that, you know‽”</p>',
|
||||||
'guid' => null,
|
'guid' => null,
|
||||||
'published_date' => '2000-01-01 00:00:00',
|
'published_date' => '2000-01-01 00:00:00',
|
||||||
'edited_date' => '2000-01-01 00:00:00',
|
'edited_date' => '2000-01-01 00:00:00',
|
||||||
'modified_date' => '2000-01-01 01:00:00',
|
'modified_date' => '2000-01-01 01:00:00',
|
||||||
'unread' => 0,
|
'unread' => 0,
|
||||||
'starred' => 0,
|
'starred' => 0,
|
||||||
'edition' => 101,
|
'edition' => 101,
|
||||||
'subscription' => 12,
|
'subscription' => 12,
|
||||||
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
'fingerprint' => 'f5cb8bfc1c7396dc9816af212a3e2ac5221585c2a00bf7ccb6aabd95dcfcd6a6:fb0bc8f8cb08913dc5a497db700e327f1d34e4987402687d494a5891f24714d4:18fdd4fa93d693128c43b004399e5c9cea6c261ddfa002518d3669f55d8c2207',
|
||||||
'media_url' => null,
|
'media_url' => null,
|
||||||
'media_type' => null,
|
'media_type' => null,
|
||||||
'note' => "",
|
'note' => "",
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 2112,
|
'id' => 2112,
|
||||||
'url' => 'http://example.com/2',
|
'url' => 'http://example.com/2',
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'subscription_title' => "Feed 11",
|
'subscription_title' => "Feed 11",
|
||||||
'author' => 'J. King',
|
'author' => 'J. King',
|
||||||
'content' => $this->richContent,
|
'content' => $this->richContent,
|
||||||
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
'guid' => '5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7',
|
||||||
'published_date' => '2000-01-02 00:00:00',
|
'published_date' => '2000-01-02 00:00:00',
|
||||||
'edited_date' => '2000-01-02 00:00:02',
|
'edited_date' => '2000-01-02 00:00:02',
|
||||||
'modified_date' => '2000-01-02 02:00:00',
|
'modified_date' => '2000-01-02 02:00:00',
|
||||||
'unread' => 1,
|
'unread' => 1,
|
||||||
'starred' => 1,
|
'starred' => 1,
|
||||||
'edition' => 202,
|
'edition' => 202,
|
||||||
'subscription' => 8,
|
'subscription' => 8,
|
||||||
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
'fingerprint' => '0e86d2de822a174fe3c44a466953e63ca1f1a58a19cbf475fce0855d4e3d5153:13075894189c47ffcfafd1dfe7fbb539f7c74a69d35a399b3abf8518952714f9:2abd0a8cba83b8214a66c8f0293ba63e467d720540e29ff8ddcdab069d4f1c9e',
|
||||||
'media_url' => "http://example.com/text",
|
'media_url' => "http://example.com/text",
|
||||||
'media_type' => "text/plain",
|
'media_type' => "text/plain",
|
||||||
'note' => "Note 2",
|
'note' => "Note 2",
|
||||||
],
|
],
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
@ -2057,50 +2056,50 @@ LONG_STRING;
|
||||||
protected function outputHeadlines(int $id): Response {
|
protected function outputHeadlines(int $id): Response {
|
||||||
return $this->respGood([
|
return $this->respGood([
|
||||||
[
|
[
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
'guid' => '',
|
'guid' => '',
|
||||||
'title' => 'Article title 1',
|
'title' => 'Article title 1',
|
||||||
'link' => 'http://example.com/1',
|
'link' => 'http://example.com/1',
|
||||||
'labels' => [],
|
'labels' => [],
|
||||||
'unread' => false,
|
'unread' => false,
|
||||||
'marked' => false,
|
'marked' => false,
|
||||||
'published' => false,
|
'published' => false,
|
||||||
'author' => '',
|
'author' => '',
|
||||||
'updated' => strtotime('2000-01-01T00:00:00Z'),
|
'updated' => strtotime('2000-01-01T00:00:00Z'),
|
||||||
'is_updated' => false,
|
'is_updated' => false,
|
||||||
'feed_id' => "12",
|
'feed_id' => "12",
|
||||||
'feed_title' => "Feed 2112",
|
'feed_title' => "Feed 2112",
|
||||||
'score' => 0,
|
'score' => 0,
|
||||||
'note' => null,
|
'note' => null,
|
||||||
'lang' => "",
|
'lang' => "",
|
||||||
'tags' => [],
|
'tags' => [],
|
||||||
'comments_count' => 0,
|
'comments_count' => 0,
|
||||||
'comments_link' => "",
|
'comments_link' => "",
|
||||||
'always_display_attachments' => false,
|
'always_display_attachments' => false,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => 2112,
|
'id' => 2112,
|
||||||
'guid' => "SHA256:5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7",
|
'guid' => "SHA256:5be8a5a46ecd52ed132191c8d27fb1af6b3d4edc00234c5d9f8f0e10562ed3b7",
|
||||||
'title' => 'Article title 2',
|
'title' => 'Article title 2',
|
||||||
'link' => 'http://example.com/2',
|
'link' => 'http://example.com/2',
|
||||||
'labels' => [
|
'labels' => [
|
||||||
[-1025, "Logical", "", ""],
|
[-1025, "Logical", "", ""],
|
||||||
[-1027, "Fascinating", "", ""],
|
[-1027, "Fascinating", "", ""],
|
||||||
],
|
],
|
||||||
'unread' => true,
|
'unread' => true,
|
||||||
'marked' => true,
|
'marked' => true,
|
||||||
'published' => false,
|
'published' => false,
|
||||||
'author' => "J. King",
|
'author' => "J. King",
|
||||||
'updated' => strtotime('2000-01-02T00:00:02Z'),
|
'updated' => strtotime('2000-01-02T00:00:02Z'),
|
||||||
'is_updated' => true,
|
'is_updated' => true,
|
||||||
'feed_id' => "8",
|
'feed_id' => "8",
|
||||||
'feed_title' => "Feed 11",
|
'feed_title' => "Feed 11",
|
||||||
'score' => 0,
|
'score' => 0,
|
||||||
'note' => "Note 2",
|
'note' => "Note 2",
|
||||||
'lang' => "",
|
'lang' => "",
|
||||||
'tags' => ["Boring", "Illogical"],
|
'tags' => ["Boring", "Illogical"],
|
||||||
'comments_count' => 0,
|
'comments_count' => 0,
|
||||||
'comments_link' => "",
|
'comments_link' => "",
|
||||||
'always_display_attachments' => false,
|
'always_display_attachments' => false,
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -11,7 +11,6 @@ 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 Psr\Http\Message\ResponseInterface;
|
use Psr\Http\Message\ResponseInterface;
|
||||||
use Laminas\Diactoros\ServerRequest;
|
|
||||||
use Laminas\Diactoros\Response\EmptyResponse as Response;
|
use Laminas\Diactoros\Response\EmptyResponse as Response;
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Icon<extended> */
|
/** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Icon<extended> */
|
||||||
|
|
|
@ -13,107 +13,107 @@ use JKingWeb\Arsse\REST\TinyTinyRSS\Search;
|
||||||
class TestSearch extends \JKingWeb\Arsse\Test\AbstractTest {
|
class TestSearch extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function provideSearchStrings(): iterable {
|
public function provideSearchStrings(): iterable {
|
||||||
return [
|
return [
|
||||||
'Blank string' => ["", new Context],
|
'Blank string' => ["", new Context],
|
||||||
'Whitespace only' => [" \n \t", new Context],
|
'Whitespace only' => [" \n \t", new Context],
|
||||||
'Simple bare token' => ['OOK', (new Context)->searchTerms(["ook"])],
|
'Simple bare token' => ['OOK', (new Context)->searchTerms(["ook"])],
|
||||||
'Simple negative bare token' => ['-OOK', (new Context)->not->searchTerms(["ook"])],
|
'Simple negative bare token' => ['-OOK', (new Context)->not->searchTerms(["ook"])],
|
||||||
'Simple quoted token' => ['"OOK eek"', (new Context)->searchTerms(["ook eek"])],
|
'Simple quoted token' => ['"OOK eek"', (new Context)->searchTerms(["ook eek"])],
|
||||||
'Simple negative quoted token' => ['"-OOK eek"', (new Context)->not->searchTerms(["ook eek"])],
|
'Simple negative quoted token' => ['"-OOK eek"', (new Context)->not->searchTerms(["ook eek"])],
|
||||||
'Simple bare tokens' => ['OOK eek', (new Context)->searchTerms(["ook", "eek"])],
|
'Simple bare tokens' => ['OOK eek', (new Context)->searchTerms(["ook", "eek"])],
|
||||||
'Simple mixed bare tokens' => ['-OOK eek', (new Context)->not->searchTerms(["ook"])->searchTerms(["eek"])],
|
'Simple mixed bare tokens' => ['-OOK eek', (new Context)->not->searchTerms(["ook"])->searchTerms(["eek"])],
|
||||||
'Unclosed quoted token' => ['"OOK eek', (new Context)->searchTerms(["ook eek"])],
|
'Unclosed quoted token' => ['"OOK eek', (new Context)->searchTerms(["ook eek"])],
|
||||||
'Unclosed quoted token 2' => ['"OOK eek" "', (new Context)->searchTerms(["ook eek"])],
|
'Unclosed quoted token 2' => ['"OOK eek" "', (new Context)->searchTerms(["ook eek"])],
|
||||||
'Broken quoted token 1' => ['"-OOK"eek"', (new Context)->not->searchTerms(["ookeek\""])],
|
'Broken quoted token 1' => ['"-OOK"eek"', (new Context)->not->searchTerms(["ookeek\""])],
|
||||||
'Broken quoted token 2' => ['""eek"', (new Context)->searchTerms(["eek\""])],
|
'Broken quoted token 2' => ['""eek"', (new Context)->searchTerms(["eek\""])],
|
||||||
'Broken quoted token 3' => ['"-"eek"', (new Context)->not->searchTerms(["eek\""])],
|
'Broken quoted token 3' => ['"-"eek"', (new Context)->not->searchTerms(["eek\""])],
|
||||||
'Empty quoted token' => ['""', new Context],
|
'Empty quoted token' => ['""', new Context],
|
||||||
'Simple quoted tokens' => ['"OOK eek" "eek ack"', (new Context)->searchTerms(["ook eek", "eek ack"])],
|
'Simple quoted tokens' => ['"OOK eek" "eek ack"', (new Context)->searchTerms(["ook eek", "eek ack"])],
|
||||||
'Bare blank tag' => [':ook', (new Context)->searchTerms([":ook"])],
|
'Bare blank tag' => [':ook', (new Context)->searchTerms([":ook"])],
|
||||||
'Quoted blank tag' => ['":ook"', (new Context)->searchTerms([":ook"])],
|
'Quoted blank tag' => ['":ook"', (new Context)->searchTerms([":ook"])],
|
||||||
'Bare negative blank tag' => ['-:ook', (new Context)->not->searchTerms([":ook"])],
|
'Bare negative blank tag' => ['-:ook', (new Context)->not->searchTerms([":ook"])],
|
||||||
'Quoted negative blank tag' => ['"-:ook"', (new Context)->not->searchTerms([":ook"])],
|
'Quoted negative blank tag' => ['"-:ook"', (new Context)->not->searchTerms([":ook"])],
|
||||||
'Bare valueless blank tag' => [':', (new Context)->searchTerms([":"])],
|
'Bare valueless blank tag' => [':', (new Context)->searchTerms([":"])],
|
||||||
'Quoted valueless blank tag' => ['":"', (new Context)->searchTerms([":"])],
|
'Quoted valueless blank tag' => ['":"', (new Context)->searchTerms([":"])],
|
||||||
'Bare negative valueless blank tag' => ['-:', (new Context)->not->searchTerms([":"])],
|
'Bare negative valueless blank tag' => ['-:', (new Context)->not->searchTerms([":"])],
|
||||||
'Quoted negative valueless blank tag' => ['"-:"', (new Context)->not->searchTerms([":"])],
|
'Quoted negative valueless blank tag' => ['"-:"', (new Context)->not->searchTerms([":"])],
|
||||||
'Double negative' => ['--eek', (new Context)->not->searchTerms(["-eek"])],
|
'Double negative' => ['--eek', (new Context)->not->searchTerms(["-eek"])],
|
||||||
'Double negative 2' => ['--@eek', (new Context)->not->searchTerms(["-@eek"])],
|
'Double negative 2' => ['--@eek', (new Context)->not->searchTerms(["-@eek"])],
|
||||||
'Double negative 3' => ['"--@eek"', (new Context)->not->searchTerms(["-@eek"])],
|
'Double negative 3' => ['"--@eek"', (new Context)->not->searchTerms(["-@eek"])],
|
||||||
'Double negative 4' => ['"--eek"', (new Context)->not->searchTerms(["-eek"])],
|
'Double negative 4' => ['"--eek"', (new Context)->not->searchTerms(["-eek"])],
|
||||||
'Negative before quote' => ['-"ook"', (new Context)->not->searchTerms(["\"ook\""])],
|
'Negative before quote' => ['-"ook"', (new Context)->not->searchTerms(["\"ook\""])],
|
||||||
'Bare unread tag true' => ['UNREAD:true', (new Context)->unread(true)],
|
'Bare unread tag true' => ['UNREAD:true', (new Context)->unread(true)],
|
||||||
'Bare unread tag false' => ['UNREAD:false', (new Context)->unread(false)],
|
'Bare unread tag false' => ['UNREAD:false', (new Context)->unread(false)],
|
||||||
'Bare negative unread tag true' => ['-unread:true', (new Context)->unread(false)],
|
'Bare negative unread tag true' => ['-unread:true', (new Context)->unread(false)],
|
||||||
'Bare negative unread tag false' => ['-unread:false', (new Context)->unread(true)],
|
'Bare negative unread tag false' => ['-unread:false', (new Context)->unread(true)],
|
||||||
'Quoted unread tag true' => ['"UNREAD:true"', (new Context)->unread(true)],
|
'Quoted unread tag true' => ['"UNREAD:true"', (new Context)->unread(true)],
|
||||||
'Quoted unread tag false' => ['"UNREAD:false"', (new Context)->unread(false)],
|
'Quoted unread tag false' => ['"UNREAD:false"', (new Context)->unread(false)],
|
||||||
'Quoted negative unread tag true' => ['"-unread:true"', (new Context)->unread(false)],
|
'Quoted negative unread tag true' => ['"-unread:true"', (new Context)->unread(false)],
|
||||||
'Quoted negative unread tag false' => ['"-unread:false"', (new Context)->unread(true)],
|
'Quoted negative unread tag false' => ['"-unread:false"', (new Context)->unread(true)],
|
||||||
'Bare star tag true' => ['STAR:true', (new Context)->starred(true)],
|
'Bare star tag true' => ['STAR:true', (new Context)->starred(true)],
|
||||||
'Bare star tag false' => ['STAR:false', (new Context)->starred(false)],
|
'Bare star tag false' => ['STAR:false', (new Context)->starred(false)],
|
||||||
'Bare negative star tag true' => ['-star:true', (new Context)->starred(false)],
|
'Bare negative star tag true' => ['-star:true', (new Context)->starred(false)],
|
||||||
'Bare negative star tag false' => ['-star:false', (new Context)->starred(true)],
|
'Bare negative star tag false' => ['-star:false', (new Context)->starred(true)],
|
||||||
'Quoted star tag true' => ['"STAR:true"', (new Context)->starred(true)],
|
'Quoted star tag true' => ['"STAR:true"', (new Context)->starred(true)],
|
||||||
'Quoted star tag false' => ['"STAR:false"', (new Context)->starred(false)],
|
'Quoted star tag false' => ['"STAR:false"', (new Context)->starred(false)],
|
||||||
'Quoted negative star tag true' => ['"-star:true"', (new Context)->starred(false)],
|
'Quoted negative star tag true' => ['"-star:true"', (new Context)->starred(false)],
|
||||||
'Quoted negative star tag false' => ['"-star:false"', (new Context)->starred(true)],
|
'Quoted negative star tag false' => ['"-star:false"', (new Context)->starred(true)],
|
||||||
'Bare note tag true' => ['NOTE:true', (new Context)->annotated(true)],
|
'Bare note tag true' => ['NOTE:true', (new Context)->annotated(true)],
|
||||||
'Bare note tag false' => ['NOTE:false', (new Context)->annotated(false)],
|
'Bare note tag false' => ['NOTE:false', (new Context)->annotated(false)],
|
||||||
'Bare negative note tag true' => ['-note:true', (new Context)->annotated(false)],
|
'Bare negative note tag true' => ['-note:true', (new Context)->annotated(false)],
|
||||||
'Bare negative note tag false' => ['-note:false', (new Context)->annotated(true)],
|
'Bare negative note tag false' => ['-note:false', (new Context)->annotated(true)],
|
||||||
'Quoted note tag true' => ['"NOTE:true"', (new Context)->annotated(true)],
|
'Quoted note tag true' => ['"NOTE:true"', (new Context)->annotated(true)],
|
||||||
'Quoted note tag false' => ['"NOTE:false"', (new Context)->annotated(false)],
|
'Quoted note tag false' => ['"NOTE:false"', (new Context)->annotated(false)],
|
||||||
'Quoted negative note tag true' => ['"-note:true"', (new Context)->annotated(false)],
|
'Quoted negative note tag true' => ['"-note:true"', (new Context)->annotated(false)],
|
||||||
'Quoted negative note tag false' => ['"-note:false"', (new Context)->annotated(true)],
|
'Quoted negative note tag false' => ['"-note:false"', (new Context)->annotated(true)],
|
||||||
'Bare pub tag true' => ['PUB:true', null],
|
'Bare pub tag true' => ['PUB:true', null],
|
||||||
'Bare pub tag false' => ['PUB:false', new Context],
|
'Bare pub tag false' => ['PUB:false', new Context],
|
||||||
'Bare negative pub tag true' => ['-pub:true', new Context],
|
'Bare negative pub tag true' => ['-pub:true', new Context],
|
||||||
'Bare negative pub tag false' => ['-pub:false', null],
|
'Bare negative pub tag false' => ['-pub:false', null],
|
||||||
'Quoted pub tag true' => ['"PUB:true"', null],
|
'Quoted pub tag true' => ['"PUB:true"', null],
|
||||||
'Quoted pub tag false' => ['"PUB:false"', new Context],
|
'Quoted pub tag false' => ['"PUB:false"', new Context],
|
||||||
'Quoted negative pub tag true' => ['"-pub:true"', new Context],
|
'Quoted negative pub tag true' => ['"-pub:true"', new Context],
|
||||||
'Quoted negative pub tag false' => ['"-pub:false"', null],
|
'Quoted negative pub tag false' => ['"-pub:false"', null],
|
||||||
'Non-boolean unread tag' => ['unread:maybe', (new Context)->searchTerms(["unread:maybe"])],
|
'Non-boolean unread tag' => ['unread:maybe', (new Context)->searchTerms(["unread:maybe"])],
|
||||||
'Non-boolean star tag' => ['star:maybe', (new Context)->searchTerms(["star:maybe"])],
|
'Non-boolean star tag' => ['star:maybe', (new Context)->searchTerms(["star:maybe"])],
|
||||||
'Non-boolean pub tag' => ['pub:maybe', (new Context)->searchTerms(["pub:maybe"])],
|
'Non-boolean pub tag' => ['pub:maybe', (new Context)->searchTerms(["pub:maybe"])],
|
||||||
'Non-boolean note tag' => ['note:maybe', (new Context)->annotationTerms(["maybe"])],
|
'Non-boolean note tag' => ['note:maybe', (new Context)->annotationTerms(["maybe"])],
|
||||||
'Valueless unread tag' => ['unread:', (new Context)->searchTerms(["unread:"])],
|
'Valueless unread tag' => ['unread:', (new Context)->searchTerms(["unread:"])],
|
||||||
'Valueless star tag' => ['star:', (new Context)->searchTerms(["star:"])],
|
'Valueless star tag' => ['star:', (new Context)->searchTerms(["star:"])],
|
||||||
'Valueless pub tag' => ['pub:', (new Context)->searchTerms(["pub:"])],
|
'Valueless pub tag' => ['pub:', (new Context)->searchTerms(["pub:"])],
|
||||||
'Valueless note tag' => ['note:', (new Context)->searchTerms(["note:"])],
|
'Valueless note tag' => ['note:', (new Context)->searchTerms(["note:"])],
|
||||||
'Valueless title tag' => ['title:', (new Context)->searchTerms(["title:"])],
|
'Valueless title tag' => ['title:', (new Context)->searchTerms(["title:"])],
|
||||||
'Valueless author tag' => ['author:', (new Context)->searchTerms(["author:"])],
|
'Valueless author tag' => ['author:', (new Context)->searchTerms(["author:"])],
|
||||||
'Escaped quote 1' => ['"""I say, Jeeves!"""', (new Context)->searchTerms(["\"i say, jeeves!\""])],
|
'Escaped quote 1' => ['"""I say, Jeeves!"""', (new Context)->searchTerms(["\"i say, jeeves!\""])],
|
||||||
'Escaped quote 2' => ['"\\"I say, Jeeves!\\""', (new Context)->searchTerms(["\"i say, jeeves!\""])],
|
'Escaped quote 2' => ['"\\"I say, Jeeves!\\""', (new Context)->searchTerms(["\"i say, jeeves!\""])],
|
||||||
'Escaped quote 3' => ['\\"I say, Jeeves!\\"', (new Context)->searchTerms(["\\\"i", "say,", "jeeves!\\\""])],
|
'Escaped quote 3' => ['\\"I say, Jeeves!\\"', (new Context)->searchTerms(["\\\"i", "say,", "jeeves!\\\""])],
|
||||||
'Escaped quote 4' => ['"\\"\\I say, Jeeves!\\""', (new Context)->searchTerms(["\"\\i say, jeeves!\""])],
|
'Escaped quote 4' => ['"\\"\\I say, Jeeves!\\""', (new Context)->searchTerms(["\"\\i say, jeeves!\""])],
|
||||||
'Escaped quote 5' => ['"\\I say, Jeeves!"', (new Context)->searchTerms(["\\i say, jeeves!"])],
|
'Escaped quote 5' => ['"\\I say, Jeeves!"', (new Context)->searchTerms(["\\i say, jeeves!"])],
|
||||||
'Escaped quote 6' => ['"\\"I say, Jeeves!\\', (new Context)->searchTerms(["\"i say, jeeves!\\"])],
|
'Escaped quote 6' => ['"\\"I say, Jeeves!\\', (new Context)->searchTerms(["\"i say, jeeves!\\"])],
|
||||||
'Escaped quote 7' => ['"\\', (new Context)->searchTerms(["\\"])],
|
'Escaped quote 7' => ['"\\', (new Context)->searchTerms(["\\"])],
|
||||||
'Quoted author tag 1' => ['"author:Neal Stephenson"', (new Context)->authorTerms(["neal stephenson"])],
|
'Quoted author tag 1' => ['"author:Neal Stephenson"', (new Context)->authorTerms(["neal stephenson"])],
|
||||||
'Quoted author tag 2' => ['"author:Jo ""Cap\'n Tripps"" Ashburn"', (new Context)->authorTerms(["jo \"cap'n tripps\" ashburn"])],
|
'Quoted author tag 2' => ['"author:Jo ""Cap\'n Tripps"" Ashburn"', (new Context)->authorTerms(["jo \"cap'n tripps\" ashburn"])],
|
||||||
'Quoted author tag 3' => ['"author:Jo \\"Cap\'n Tripps\\" Ashburn"', (new Context)->authorTerms(["jo \"cap'n tripps\" ashburn"])],
|
'Quoted author tag 3' => ['"author:Jo \\"Cap\'n Tripps\\" Ashburn"', (new Context)->authorTerms(["jo \"cap'n tripps\" ashburn"])],
|
||||||
'Quoted author tag 4' => ['"author:Jo ""Cap\'n Tripps"Ashburn"', (new Context)->authorTerms(["jo \"cap'n trippsashburn\""])],
|
'Quoted author tag 4' => ['"author:Jo ""Cap\'n Tripps"Ashburn"', (new Context)->authorTerms(["jo \"cap'n trippsashburn\""])],
|
||||||
'Quoted author tag 5' => ['"author:Jo ""Cap\'n Tripps\ Ashburn"', (new Context)->authorTerms(["jo \"cap'n tripps\\ ashburn"])],
|
'Quoted author tag 5' => ['"author:Jo ""Cap\'n Tripps\ Ashburn"', (new Context)->authorTerms(["jo \"cap'n tripps\\ ashburn"])],
|
||||||
'Quoted author tag 6' => ['"author:Neal Stephenson\\', (new Context)->authorTerms(["neal stephenson\\"])],
|
'Quoted author tag 6' => ['"author:Neal Stephenson\\', (new Context)->authorTerms(["neal stephenson\\"])],
|
||||||
'Quoted title tag' => ['"title:Generic title"', (new Context)->titleTerms(["generic title"])],
|
'Quoted title tag' => ['"title:Generic title"', (new Context)->titleTerms(["generic title"])],
|
||||||
'Contradictory booleans' => ['unread:true -unread:true', null],
|
'Contradictory booleans' => ['unread:true -unread:true', null],
|
||||||
'Doubled boolean' => ['unread:true unread:true', (new Context)->unread(true)],
|
'Doubled boolean' => ['unread:true unread:true', (new Context)->unread(true)],
|
||||||
'Bare blank date' => ['@', new Context],
|
'Bare blank date' => ['@', new Context],
|
||||||
'Quoted blank date' => ['"@"', new Context],
|
'Quoted blank date' => ['"@"', new Context],
|
||||||
'Bare ISO date' => ['@2019-03-01', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
'Bare ISO date' => ['@2019-03-01', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||||
'Quoted ISO date' => ['"@March 1st, 2019"', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
'Quoted ISO date' => ['"@March 1st, 2019"', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||||
'Bare negative ISO date' => ['-@2019-03-01', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
'Bare negative ISO date' => ['-@2019-03-01', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||||
'Quoted negative English date' => ['"-@March 1st, 2019"', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
'Quoted negative English date' => ['"-@March 1st, 2019"', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||||
'Invalid date' => ['@Bugaboo', new Context],
|
'Invalid date' => ['@Bugaboo', new Context],
|
||||||
'Escaped quoted date 1' => ['"@""Yesterday" and today', (new Context)->searchTerms(["and", "today"])],
|
'Escaped quoted date 1' => ['"@""Yesterday" and today', (new Context)->searchTerms(["and", "today"])],
|
||||||
'Escaped quoted date 2' => ['"@\\"Yesterday" and today', (new Context)->searchTerms(["and", "today"])],
|
'Escaped quoted date 2' => ['"@\\"Yesterday" and today', (new Context)->searchTerms(["and", "today"])],
|
||||||
'Escaped quoted date 3' => ['"@Yesterday\\', new Context],
|
'Escaped quoted date 3' => ['"@Yesterday\\', new Context],
|
||||||
'Escaped quoted date 4' => ['"@Yesterday\\and today', new Context],
|
'Escaped quoted date 4' => ['"@Yesterday\\and today', new Context],
|
||||||
'Escaped quoted date 5' => ['"@Yesterday"and today', (new Context)->searchTerms(["today"])],
|
'Escaped quoted date 5' => ['"@Yesterday"and today', (new Context)->searchTerms(["today"])],
|
||||||
'Contradictory dates' => ['@Yesterday @Today', null],
|
'Contradictory dates' => ['@Yesterday @Today', null],
|
||||||
'Doubled date' => ['"@March 1st, 2019" @2019-03-01', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
'Doubled date' => ['"@March 1st, 2019" @2019-03-01', (new Context)->modifiedSince("2019-03-01T00:00:00Z")->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||||
'Doubled negative date' => ['"-@March 1st, 2019" -@2019-03-01', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
'Doubled negative date' => ['"-@March 1st, 2019" -@2019-03-01', (new Context)->not->modifiedSince("2019-03-01T00:00:00Z")->not->notModifiedSince("2019-03-01T23:59:59Z")],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\TestCase\Service;
|
namespace JKingWeb\Arsse\TestCase\Service;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Arsse;
|
use JKingWeb\Arsse\Arsse;
|
||||||
use JKingWeb\Arsse\Database;
|
|
||||||
use JKingWeb\Arsse\Service\Driver as DriverInterface;
|
use JKingWeb\Arsse\Service\Driver as DriverInterface;
|
||||||
use JKingWeb\Arsse\Service\Subprocess\Driver;
|
use JKingWeb\Arsse\Service\Subprocess\Driver;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ use JKingWeb\Arsse\Conf;
|
||||||
use JKingWeb\Arsse\Lang;
|
use JKingWeb\Arsse\Lang;
|
||||||
use JKingWeb\Arsse\User;
|
use JKingWeb\Arsse\User;
|
||||||
use JKingWeb\Arsse\Database;
|
use JKingWeb\Arsse\Database;
|
||||||
use JKingWeb\Arsse\Service;
|
|
||||||
|
|
||||||
/** @covers \JKingWeb\Arsse\Arsse */
|
/** @covers \JKingWeb\Arsse\Arsse */
|
||||||
class TestArsse extends \JKingWeb\Arsse\Test\AbstractTest {
|
class TestArsse extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
|
|
|
@ -32,7 +32,7 @@ class TestInternal extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
/**
|
/**
|
||||||
* @dataProvider provideAuthentication
|
* @dataProvider provideAuthentication
|
||||||
* @group slow
|
* @group slow
|
||||||
*/
|
*/
|
||||||
public function testAuthenticateAUser(bool $authorized, string $user, $password, bool $exp): void {
|
public function testAuthenticateAUser(bool $authorized, string $user, $password, bool $exp): void {
|
||||||
if ($authorized) {
|
if ($authorized) {
|
||||||
\Phake::when(Arsse::$db)->userPasswordGet("john.doe@example.com")->thenReturn('$2y$10$1zbqRJhxM8uUjeSBPp4IhO90xrqK0XjEh9Z16iIYEFRV4U.zeAFom'); // hash of "secret"
|
\Phake::when(Arsse::$db)->userPasswordGet("john.doe@example.com")->thenReturn('$2y$10$1zbqRJhxM8uUjeSBPp4IhO90xrqK0XjEh9Z16iIYEFRV4U.zeAFom'); // hash of "secret"
|
||||||
|
|
|
@ -147,7 +147,7 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$calls = 2;
|
$calls = 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$calls = 4;
|
$calls = 4;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$pass1 = $u->add($user, null);
|
$pass1 = $u->add($user, null);
|
||||||
|
@ -255,7 +255,7 @@ class TestUser extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$calls = 2;
|
$calls = 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$calls = 4;
|
$calls = 4;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
$pass1 = $u->passwordSet($user, null);
|
$pass1 = $u->passwordSet($user, null);
|
||||||
|
|
|
@ -14,8 +14,8 @@ if (
|
||||||
} else {
|
} else {
|
||||||
return [
|
return [
|
||||||
'code' => 304,
|
'code' => 304,
|
||||||
'lastMod' => random_int(0, 2^31),
|
'lastMod' => random_int(0, 2 ^ 31),
|
||||||
'fields' => [
|
'fields' => [
|
||||||
"ETag: ".bin2hex(random_bytes(8)),
|
"ETag: ".bin2hex(random_bytes(8)),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<?php return [
|
<?php return [
|
||||||
'code' => 304,
|
'code' => 304,
|
||||||
'lastMod' => random_int(0, 2^31),
|
'lastMod' => random_int(0, 2 ^ 31),
|
||||||
'fields' => [
|
'fields' => [
|
||||||
"ETag: ".bin2hex(random_bytes(8)),
|
"ETag: ".bin2hex(random_bytes(8)),
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
'cache' => false,
|
'cache' => false,
|
||||||
'fields' => [
|
'fields' => [
|
||||||
'Location: http://localhost:'.$_SERVER['SERVER_PORT'].$_SERVER['REQUEST_URI']."0",
|
'Location: http://localhost:'.$_SERVER['SERVER_PORT'].$_SERVER['REQUEST_URI']."0",
|
||||||
]
|
],
|
||||||
];
|
];
|
||||||
|
|
|
@ -70,7 +70,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
protected function serverRequest(string $method, string $url, string $urlPrefix, array $headers = [], array $vars = [], $body = null, string $type = "", $params = [], string $user = null): ServerRequestInterface {
|
protected function serverRequest(string $method, string $url, string $urlPrefix, array $headers = [], array $vars = [], $body = null, string $type = "", $params = [], string $user = null): ServerRequestInterface {
|
||||||
$server = [
|
$server = [
|
||||||
'REQUEST_METHOD' => $method,
|
'REQUEST_METHOD' => $method,
|
||||||
'REQUEST_URI' => $url,
|
'REQUEST_URI' => $url,
|
||||||
];
|
];
|
||||||
if (strlen($type)) {
|
if (strlen($type)) {
|
||||||
$server['HTTP_CONTENT_TYPE'] = $type;
|
$server['HTTP_CONTENT_TYPE'] = $type;
|
||||||
|
@ -109,7 +109,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
$req = $req->withAttribute("authenticationFailed", true);
|
$req = $req->withAttribute("authenticationFailed", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strlen($type) &&strlen($body ?? "")) {
|
if (strlen($type) && strlen($body ?? "")) {
|
||||||
$req = $req->withHeader("Content-Type", $type);
|
$req = $req->withHeader("Content-Type", $type);
|
||||||
}
|
}
|
||||||
foreach ($headers as $key => $value) {
|
foreach ($headers as $key => $value) {
|
||||||
|
@ -135,8 +135,8 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
$this->expectException(get_class($msg));
|
$this->expectException(get_class($msg));
|
||||||
$this->expectExceptionCode($msg->getCode());
|
$this->expectExceptionCode($msg->getCode());
|
||||||
} else {
|
} else {
|
||||||
$class = \JKingWeb\Arsse\NS_BASE . ($prefix !== "" ? str_replace("/", "\\", $prefix) . "\\" : "") . $type;
|
$class = \JKingWeb\Arsse\NS_BASE.($prefix !== "" ? str_replace("/", "\\", $prefix)."\\" : "").$type;
|
||||||
$msgID = ($prefix !== "" ? $prefix . "/" : "") . $type. ".$msg";
|
$msgID = ($prefix !== "" ? $prefix."/" : "").$type.".$msg";
|
||||||
if (array_key_exists($msgID, Exception::CODES)) {
|
if (array_key_exists($msgID, Exception::CODES)) {
|
||||||
$code = Exception::CODES[$msgID];
|
$code = Exception::CODES[$msgID];
|
||||||
} else {
|
} else {
|
||||||
|
@ -177,7 +177,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
|
|
||||||
public function assertTime($exp, $test, string $msg = ''): void {
|
public function assertTime($exp, $test, string $msg = ''): void {
|
||||||
$test = $this->approximateTime($exp, $test);
|
$test = $this->approximateTime($exp, $test);
|
||||||
$exp = Date::transform($exp, "iso8601");
|
$exp = Date::transform($exp, "iso8601");
|
||||||
$test = Date::transform($test, "iso8601");
|
$test = Date::transform($test, "iso8601");
|
||||||
$this->assertSame($exp, $test, $msg);
|
$this->assertSame($exp, $test, $msg);
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ abstract class AbstractTest extends \PHPUnit\Framework\TestCase {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($row===$test) {
|
if ($row === $test) {
|
||||||
$data[$index] = $test;
|
$data[$index] = $test;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ declare(strict_types=1);
|
||||||
namespace JKingWeb\Arsse\Test\DatabaseDrivers;
|
namespace JKingWeb\Arsse\Test\DatabaseDrivers;
|
||||||
|
|
||||||
use JKingWeb\Arsse\Arsse;
|
use JKingWeb\Arsse\Arsse;
|
||||||
use JKingWeb\Arsse\Db\Driver;
|
|
||||||
|
|
||||||
trait MySQLPDO {
|
trait MySQLPDO {
|
||||||
protected static $implementation = "PDO MySQL";
|
protected static $implementation = "PDO MySQL";
|
||||||
|
@ -22,16 +21,16 @@ trait MySQLPDO {
|
||||||
$dsn = [];
|
$dsn = [];
|
||||||
$params = [
|
$params = [
|
||||||
'charset' => "utf8mb4",
|
'charset' => "utf8mb4",
|
||||||
'host' => Arsse::$conf->dbMySQLHost,
|
'host' => Arsse::$conf->dbMySQLHost,
|
||||||
'port' => Arsse::$conf->dbMySQLPort,
|
'port' => Arsse::$conf->dbMySQLPort,
|
||||||
'dbname' => Arsse::$conf->dbMySQLDb,
|
'dbname' => Arsse::$conf->dbMySQLDb,
|
||||||
];
|
];
|
||||||
foreach ($params as $k => $v) {
|
foreach ($params as $k => $v) {
|
||||||
$dsn[] = "$k=$v";
|
$dsn[] = "$k=$v";
|
||||||
}
|
}
|
||||||
$dsn = "mysql:".implode(";", $dsn);
|
$dsn = "mysql:".implode(";", $dsn);
|
||||||
$d = new \PDO($dsn, Arsse::$conf->dbMySQLUser, Arsse::$conf->dbMySQLPass, [
|
$d = new \PDO($dsn, Arsse::$conf->dbMySQLUser, Arsse::$conf->dbMySQLPass, [
|
||||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||||
\PDO::MYSQL_ATTR_MULTI_STATEMENTS => false,
|
\PDO::MYSQL_ATTR_MULTI_STATEMENTS => false,
|
||||||
]);
|
]);
|
||||||
foreach (\JKingWeb\Arsse\Db\MySQL\PDODriver::makeSetupQueries() as $q) {
|
foreach (\JKingWeb\Arsse\Db\MySQL\PDODriver::makeSetupQueries() as $q) {
|
||||||
|
|
|
@ -29,7 +29,6 @@ which include the following data:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
ignore_user_abort(false);
|
ignore_user_abort(false);
|
||||||
ob_start();
|
ob_start();
|
||||||
$defaults = [ // default values for response
|
$defaults = [ // default values for response
|
||||||
|
|
Loading…
Reference in a new issue