mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 05:02:40 +00:00
Whitespace cleanup
This commit is contained in:
parent
3fee77bac2
commit
f64f0c6a22
36 changed files with 139 additions and 139 deletions
8
dist/nginx.conf
vendored
8
dist/nginx.conf
vendored
|
@ -7,7 +7,7 @@ server {
|
||||||
#auth_basic "Advanced RSS Environment";
|
#auth_basic "Advanced RSS Environment";
|
||||||
root /usr/share/arsse/www;
|
root /usr/share/arsse/www;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ =404;
|
try_files $uri $uri/ =404;
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,11 @@ server {
|
||||||
auth_basic off;
|
auth_basic off;
|
||||||
include /usr/share/arsse/dist/nginx-fcgi.conf;
|
include /usr/share/arsse/dist/nginx-fcgi.conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
# NextCloud News protocol
|
# NextCloud News protocol
|
||||||
location /index.php/apps/news/api {
|
location /index.php/apps/news/api {
|
||||||
try_files $uri @arsse_auth;
|
try_files $uri @arsse_auth;
|
||||||
|
|
||||||
location ~ ^/index\.php/apps/news/api/?$ {
|
location ~ ^/index\.php/apps/news/api/?$ {
|
||||||
try_files $uri @arsse_no_auth;
|
try_files $uri @arsse_no_auth;
|
||||||
}
|
}
|
||||||
|
@ -48,4 +48,4 @@ server {
|
||||||
root /usr/share/arsse/www;
|
root /usr/share/arsse/www;
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace JKingWeb\Arsse;
|
||||||
|
|
||||||
class Arsse {
|
class Arsse {
|
||||||
const VERSION = "0.4.0";
|
const VERSION = "0.4.0";
|
||||||
|
|
||||||
/** @var Lang */
|
/** @var Lang */
|
||||||
public static $lang;
|
public static $lang;
|
||||||
/** @var Conf */
|
/** @var Conf */
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace JKingWeb\Arsse;
|
||||||
|
|
||||||
class CLI {
|
class CLI {
|
||||||
protected $args = [];
|
protected $args = [];
|
||||||
|
|
||||||
protected function usage(): string {
|
protected function usage(): string {
|
||||||
$prog = basename($_SERVER['argv'][0]);
|
$prog = basename($_SERVER['argv'][0]);
|
||||||
return <<<USAGE_TEXT
|
return <<<USAGE_TEXT
|
||||||
|
@ -21,7 +21,7 @@ Usage:
|
||||||
$prog --help | -h
|
$prog --help | -h
|
||||||
|
|
||||||
The Arsse command-line interface currently allows you to start the refresh
|
The Arsse command-line interface currently allows you to start the refresh
|
||||||
daemon, refresh a specific feed by numeric ID, add a user, or save default
|
daemon, refresh a specific feed by numeric ID, add a user, or save default
|
||||||
configuration to a sample file.
|
configuration to a sample file.
|
||||||
USAGE_TEXT;
|
USAGE_TEXT;
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ class Conf {
|
||||||
public $serviceCurlUser = null;
|
public $serviceCurlUser = null;
|
||||||
/** @var string The password to use when performing feed updates using cURL */
|
/** @var string The password to use when performing feed updates using cURL */
|
||||||
public $serviceCurlPassword = null;
|
public $serviceCurlPassword = null;
|
||||||
|
|
||||||
/** @var integer Number of seconds to wait for data when fetching feeds from foreign servers */
|
/** @var integer Number of seconds to wait for data when fetching feeds from foreign servers */
|
||||||
public $fetchTimeout = 10;
|
public $fetchTimeout = 10;
|
||||||
/** @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 */
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Database {
|
||||||
const LIST_CONSERVATIVE = 1; // base metadata plus anything that is not potentially large text
|
const LIST_CONSERVATIVE = 1; // base metadata plus anything that is not potentially large text
|
||||||
const LIST_TYPICAL = 2; // conservative, with the addition of content
|
const LIST_TYPICAL = 2; // conservative, with the addition of content
|
||||||
const LIST_FULL = 3; // all possible fields
|
const LIST_FULL = 3; // all possible fields
|
||||||
|
|
||||||
/** @var Db\Driver */
|
/** @var Db\Driver */
|
||||||
public $db;
|
public $db;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class Database {
|
||||||
protected function caller(): string {
|
protected function caller(): string {
|
||||||
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
|
return debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3)[2]['function'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function driverList(): array {
|
public static function driverList(): array {
|
||||||
$sep = \DIRECTORY_SEPARATOR;
|
$sep = \DIRECTORY_SEPARATOR;
|
||||||
$path = __DIR__.$sep."Db".$sep;
|
$path = __DIR__.$sep."Db".$sep;
|
||||||
|
@ -102,7 +102,7 @@ class Database {
|
||||||
public function metaGet(string $key) {
|
public function metaGet(string $key) {
|
||||||
return $this->db->prepare("SELECT value from arsse_meta where key = ?", "str")->run($key)->getValue();
|
return $this->db->prepare("SELECT value from arsse_meta where key = ?", "str")->run($key)->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function metaSet(string $key, $value, string $type = "str"): bool {
|
public function metaSet(string $key, $value, string $type = "str"): bool {
|
||||||
$out = $this->db->prepare("UPDATE arsse_meta set value = ? where key = ?", $type, "str")->run($value, $key)->changes();
|
$out = $this->db->prepare("UPDATE arsse_meta set value = ? where key = ?", $type, "str")->run($value, $key)->changes();
|
||||||
if (!$out) {
|
if (!$out) {
|
||||||
|
@ -444,7 +444,7 @@ class Database {
|
||||||
target as (select ? as user, ? as source, ? as dest, ? as rename),
|
target as (select ? as user, ? as source, ? as dest, ? as rename),
|
||||||
folders as (SELECT id from arsse_folders join target on owner = user and coalesce(parent,0) = source union select arsse_folders.id as id from arsse_folders join folders on arsse_folders.parent=folders.id)
|
folders as (SELECT id from arsse_folders join target on owner = user and coalesce(parent,0) = source union select arsse_folders.id as id from arsse_folders join folders on arsse_folders.parent=folders.id)
|
||||||
".
|
".
|
||||||
"SELECT
|
"SELECT
|
||||||
((select dest from target) is null or exists(select id from arsse_folders join target on owner = user and coalesce(id,0) = coalesce(dest,0))) as extant,
|
((select dest from target) is null or exists(select id from arsse_folders join target on owner = user and coalesce(id,0) = coalesce(dest,0))) as extant,
|
||||||
not exists(select id from folders where id = coalesce((select dest from target),0)) as valid,
|
not exists(select id from folders where id = coalesce((select dest from target),0)) as valid,
|
||||||
not exists(select id from arsse_folders join target on coalesce(parent,0) = coalesce(dest,0) and name = coalesce((select rename from target),(select name from arsse_folders join target on id = source))) as available
|
not exists(select id from arsse_folders join target on coalesce(parent,0) = coalesce(dest,0) and name = coalesce((select rename from target),(select name from arsse_folders join target on id = source))) as available
|
||||||
|
@ -524,16 +524,16 @@ class Database {
|
||||||
$folder = $this->folderValidateId($user, $folder)['id'];
|
$folder = $this->folderValidateId($user, $folder)['id'];
|
||||||
// create a complex query
|
// create a complex query
|
||||||
$q = new Query(
|
$q = new Query(
|
||||||
"SELECT
|
"SELECT
|
||||||
arsse_subscriptions.id as id,
|
arsse_subscriptions.id as id,
|
||||||
feed,url,favicon,source,folder,pinned,err_count,err_msg,order_type,added,
|
feed,url,favicon,source,folder,pinned,err_count,err_msg,order_type,added,
|
||||||
arsse_feeds.updated as updated,
|
arsse_feeds.updated as updated,
|
||||||
topmost.top as top_folder,
|
topmost.top as top_folder,
|
||||||
coalesce(arsse_subscriptions.title, arsse_feeds.title) as title,
|
coalesce(arsse_subscriptions.title, arsse_feeds.title) as title,
|
||||||
(SELECT count(*) from arsse_articles where feed = arsse_subscriptions.feed) - (SELECT count(*) from arsse_marks where subscription = arsse_subscriptions.id and read = 1) as unread
|
(SELECT count(*) from arsse_articles where feed = arsse_subscriptions.feed) - (SELECT count(*) from arsse_marks where subscription = arsse_subscriptions.id and read = 1) as unread
|
||||||
from arsse_subscriptions
|
from arsse_subscriptions
|
||||||
join user on user = owner
|
join user on user = owner
|
||||||
join arsse_feeds on feed = arsse_feeds.id
|
join arsse_feeds on feed = arsse_feeds.id
|
||||||
left join topmost on folder=f_id"
|
left join topmost on folder=f_id"
|
||||||
);
|
);
|
||||||
$q->setOrder("pinned desc, title collate nocase");
|
$q->setOrder("pinned desc, title collate nocase");
|
||||||
|
@ -673,7 +673,7 @@ class Database {
|
||||||
$feeds = $this->db->query("SELECT id from arsse_feeds where next_fetch <= CURRENT_TIMESTAMP")->getAll();
|
$feeds = $this->db->query("SELECT id from arsse_feeds where next_fetch <= CURRENT_TIMESTAMP")->getAll();
|
||||||
return array_column($feeds, 'id');
|
return array_column($feeds, 'id');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function feedUpdate($feedID, bool $throwError = false): bool {
|
public function feedUpdate($feedID, bool $throwError = false): bool {
|
||||||
// check to make sure the feed exists
|
// check to make sure the feed exists
|
||||||
if (!ValueInfo::id($feedID)) {
|
if (!ValueInfo::id($feedID)) {
|
||||||
|
@ -874,13 +874,13 @@ class Database {
|
||||||
$extraColumns .= ",";
|
$extraColumns .= ",";
|
||||||
}
|
}
|
||||||
$q = new Query(
|
$q = new Query(
|
||||||
"SELECT
|
"SELECT
|
||||||
$extraColumns
|
$extraColumns
|
||||||
arsse_articles.id as id,
|
arsse_articles.id as id,
|
||||||
arsse_articles.feed as feed,
|
arsse_articles.feed as feed,
|
||||||
arsse_articles.modified as modified_date,
|
arsse_articles.modified as modified_date,
|
||||||
max(
|
max(
|
||||||
arsse_articles.modified,
|
arsse_articles.modified,
|
||||||
coalesce((select modified from arsse_marks where article = arsse_articles.id and subscription in (select sub from subscribed_feeds)),''),
|
coalesce((select modified from arsse_marks where article = arsse_articles.id and subscription in (select sub from subscribed_feeds)),''),
|
||||||
coalesce((select modified from arsse_label_members where article = arsse_articles.id and subscription in (select sub from subscribed_feeds)),'')
|
coalesce((select modified from arsse_label_members where article = arsse_articles.id and subscription in (select sub from subscribed_feeds)),'')
|
||||||
) as marked_date,
|
) as marked_date,
|
||||||
|
@ -1137,17 +1137,17 @@ class Database {
|
||||||
];
|
];
|
||||||
// the two queries we want to execute to make the requested changes
|
// the two queries we want to execute to make the requested changes
|
||||||
$queries = [
|
$queries = [
|
||||||
"UPDATE arsse_marks
|
"UPDATE arsse_marks
|
||||||
set
|
set
|
||||||
read = case when (select honour_read from target_articles where target_articles.id = article) = 1 then (select read from target_values) else read end,
|
read = case when (select honour_read from target_articles where target_articles.id = article) = 1 then (select read from target_values) else read end,
|
||||||
starred = coalesce((select starred from target_values),starred),
|
starred = coalesce((select starred from target_values),starred),
|
||||||
note = coalesce((select note from target_values),note),
|
note = coalesce((select note from target_values),note),
|
||||||
modified = CURRENT_TIMESTAMP
|
modified = CURRENT_TIMESTAMP
|
||||||
WHERE
|
WHERE
|
||||||
subscription in (select sub from subscribed_feeds)
|
subscription in (select sub from subscribed_feeds)
|
||||||
and article in (select id from target_articles where to_insert = 0 and (honour_read = 1 or honour_star = 1 or (select note from target_values) is not null))",
|
and article in (select id from target_articles where to_insert = 0 and (honour_read = 1 or honour_star = 1 or (select note from target_values) is not null))",
|
||||||
"INSERT INTO arsse_marks(subscription,article,read,starred,note)
|
"INSERT INTO arsse_marks(subscription,article,read,starred,note)
|
||||||
select
|
select
|
||||||
(select id from arsse_subscriptions join user on user = owner where arsse_subscriptions.feed = target_articles.feed),
|
(select id from arsse_subscriptions join user on user = owner where arsse_subscriptions.feed = target_articles.feed),
|
||||||
id,
|
id,
|
||||||
coalesce((select read from target_values) * honour_read,0),
|
coalesce((select read from target_values) * honour_read,0),
|
||||||
|
@ -1238,18 +1238,18 @@ class Database {
|
||||||
public function articleCleanup(): bool {
|
public function articleCleanup(): bool {
|
||||||
$query = $this->db->prepare(
|
$query = $this->db->prepare(
|
||||||
"WITH target_feed(id,subs) as (".
|
"WITH target_feed(id,subs) as (".
|
||||||
"SELECT
|
"SELECT
|
||||||
id, (select count(*) from arsse_subscriptions where feed = arsse_feeds.id) as subs
|
id, (select count(*) from arsse_subscriptions where feed = arsse_feeds.id) as subs
|
||||||
from arsse_feeds where id = ?".
|
from arsse_feeds where id = ?".
|
||||||
"), excepted_articles(id,edition) as (".
|
"), excepted_articles(id,edition) as (".
|
||||||
"SELECT
|
"SELECT
|
||||||
arsse_articles.id, (select max(id) from arsse_editions where article = arsse_articles.id) as edition
|
arsse_articles.id, (select max(id) from arsse_editions where article = arsse_articles.id) as edition
|
||||||
from arsse_articles
|
from arsse_articles
|
||||||
join target_feed on arsse_articles.feed = target_feed.id
|
join target_feed on arsse_articles.feed = target_feed.id
|
||||||
order by edition desc limit ?".
|
order by edition desc limit ?".
|
||||||
") ".
|
") ".
|
||||||
"DELETE from arsse_articles where
|
"DELETE from arsse_articles where
|
||||||
feed = (select max(id) from target_feed)
|
feed = (select max(id) from target_feed)
|
||||||
and id not in (select id from excepted_articles)
|
and id not in (select id from excepted_articles)
|
||||||
and (select count(*) from arsse_marks where article = arsse_articles.id and starred = 1) = 0
|
and (select count(*) from arsse_marks where article = arsse_articles.id and starred = 1) = 0
|
||||||
and (
|
and (
|
||||||
|
@ -1282,13 +1282,13 @@ class Database {
|
||||||
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "article", 'type' => "int > 0"]); // @codeCoverageIgnore
|
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "article", 'type' => "int > 0"]); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
$out = $this->db->prepare(
|
$out = $this->db->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
arsse_articles.id as article,
|
arsse_articles.id as article,
|
||||||
(select max(id) from arsse_editions where article = arsse_articles.id) as edition
|
(select max(id) from arsse_editions where article = arsse_articles.id) as edition
|
||||||
FROM arsse_articles
|
FROM arsse_articles
|
||||||
join arsse_feeds on arsse_feeds.id = arsse_articles.feed
|
join arsse_feeds on arsse_feeds.id = arsse_articles.feed
|
||||||
join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id
|
join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id
|
||||||
WHERE
|
WHERE
|
||||||
arsse_articles.id = ? and arsse_subscriptions.owner = ?",
|
arsse_articles.id = ? and arsse_subscriptions.owner = ?",
|
||||||
"int",
|
"int",
|
||||||
"str"
|
"str"
|
||||||
|
@ -1304,15 +1304,15 @@ class Database {
|
||||||
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "edition", 'type' => "int > 0"]); // @codeCoverageIgnore
|
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "edition", 'type' => "int > 0"]); // @codeCoverageIgnore
|
||||||
}
|
}
|
||||||
$out = $this->db->prepare(
|
$out = $this->db->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
arsse_editions.id as edition,
|
arsse_editions.id as edition,
|
||||||
arsse_editions.article as article,
|
arsse_editions.article as article,
|
||||||
(arsse_editions.id = (select max(id) from arsse_editions where article = arsse_editions.article)) as current
|
(arsse_editions.id = (select max(id) from arsse_editions where article = arsse_editions.article)) as current
|
||||||
FROM arsse_editions
|
FROM arsse_editions
|
||||||
join arsse_articles on arsse_editions.article = arsse_articles.id
|
join arsse_articles on arsse_editions.article = arsse_articles.id
|
||||||
join arsse_feeds on arsse_feeds.id = arsse_articles.feed
|
join arsse_feeds on arsse_feeds.id = arsse_articles.feed
|
||||||
join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id
|
join arsse_subscriptions on arsse_subscriptions.feed = arsse_feeds.id
|
||||||
WHERE
|
WHERE
|
||||||
edition = ? and arsse_subscriptions.owner = ?",
|
edition = ? and arsse_subscriptions.owner = ?",
|
||||||
"int",
|
"int",
|
||||||
"str"
|
"str"
|
||||||
|
@ -1359,10 +1359,10 @@ class Database {
|
||||||
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
throw new User\ExceptionAuthz("notAuthorized", ["action" => __FUNCTION__, "user" => $user]);
|
||||||
}
|
}
|
||||||
return $this->db->prepare(
|
return $this->db->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
id,name,
|
id,name,
|
||||||
(select count(*) from arsse_label_members where label = id and assigned = 1) as articles,
|
(select count(*) from arsse_label_members where label = id and assigned = 1) as articles,
|
||||||
(select count(*) from arsse_label_members
|
(select count(*) from arsse_label_members
|
||||||
join arsse_marks on arsse_label_members.article = arsse_marks.article and arsse_label_members.subscription = arsse_marks.subscription
|
join arsse_marks on arsse_label_members.article = arsse_marks.article and arsse_label_members.subscription = arsse_marks.subscription
|
||||||
where label = id and assigned = 1 and read = 1
|
where label = id and assigned = 1 and read = 1
|
||||||
) as read
|
) as read
|
||||||
|
@ -1395,10 +1395,10 @@ class Database {
|
||||||
$field = $byName ? "name" : "id";
|
$field = $byName ? "name" : "id";
|
||||||
$type = $byName ? "str" : "int";
|
$type = $byName ? "str" : "int";
|
||||||
$out = $this->db->prepare(
|
$out = $this->db->prepare(
|
||||||
"SELECT
|
"SELECT
|
||||||
id,name,
|
id,name,
|
||||||
(select count(*) from arsse_label_members where label = id and assigned = 1) as articles,
|
(select count(*) from arsse_label_members where label = id and assigned = 1) as articles,
|
||||||
(select count(*) from arsse_label_members
|
(select count(*) from arsse_label_members
|
||||||
join arsse_marks on arsse_label_members.article = arsse_marks.article and arsse_label_members.subscription = arsse_marks.subscription
|
join arsse_marks on arsse_label_members.article = arsse_marks.article and arsse_label_members.subscription = arsse_marks.subscription
|
||||||
where label = id and assigned = 1 and read = 1
|
where label = id and assigned = 1 and read = 1
|
||||||
) as read
|
) as read
|
||||||
|
@ -1484,11 +1484,11 @@ class Database {
|
||||||
$q->setWhere("not exists(select article from arsse_label_members where label = ? and article = arsse_articles.id)", "int", $id);
|
$q->setWhere("not exists(select article from arsse_label_members where label = ? and article = arsse_articles.id)", "int", $id);
|
||||||
$q->pushCTE("target_articles");
|
$q->pushCTE("target_articles");
|
||||||
$q->setBody(
|
$q->setBody(
|
||||||
"INSERT INTO
|
"INSERT INTO
|
||||||
arsse_label_members(label,article,subscription)
|
arsse_label_members(label,article,subscription)
|
||||||
SELECT
|
SELECT
|
||||||
?,id,
|
?,id,
|
||||||
(select id from arsse_subscriptions join user on user = owner where arsse_subscriptions.feed = target_articles.feed)
|
(select id from arsse_subscriptions join user on user = owner where arsse_subscriptions.feed = target_articles.feed)
|
||||||
FROM target_articles",
|
FROM target_articles",
|
||||||
"int",
|
"int",
|
||||||
$id
|
$id
|
||||||
|
|
|
@ -76,7 +76,7 @@ abstract class AbstractDriver implements Driver {
|
||||||
public function begin(bool $lock = false): Transaction {
|
public function begin(bool $lock = false): Transaction {
|
||||||
return new Transaction($this, $lock);
|
return new Transaction($this, $lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function savepointCreate(bool $lock = false): int {
|
public function savepointCreate(bool $lock = false): int {
|
||||||
if ($lock && !$this->transDepth) {
|
if ($lock && !$this->transDepth) {
|
||||||
$this->lock();
|
$this->lock();
|
||||||
|
|
|
@ -12,7 +12,7 @@ interface Driver {
|
||||||
const TR_ROLLBACK = 2;
|
const TR_ROLLBACK = 2;
|
||||||
const TR_PEND_COMMIT = -1;
|
const TR_PEND_COMMIT = -1;
|
||||||
const TR_PEND_ROLLBACK = -2;
|
const TR_PEND_ROLLBACK = -2;
|
||||||
|
|
||||||
public static function create(): Driver;
|
public static function create(): Driver;
|
||||||
// returns a human-friendly name for the driver (for display in installer, for example)
|
// returns a human-friendly name for the driver (for display in installer, for example)
|
||||||
public static function driverName(): string;
|
public static function driverName(): string;
|
||||||
|
|
|
@ -44,7 +44,7 @@ class Feed {
|
||||||
libxml_use_internal_errors(false);
|
libxml_use_internal_errors(false);
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct(int $feedID = null, string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = '', bool $scrape = false) {
|
public function __construct(int $feedID = null, string $url, string $lastModified = '', string $etag = '', string $username = '', string $password = '', bool $scrape = false) {
|
||||||
// fetch the feed
|
// fetch the feed
|
||||||
$this->resource = self::download($url, $lastModified, $etag, $username, $password);
|
$this->resource = self::download($url, $lastModified, $etag, $username, $password);
|
||||||
|
|
|
@ -58,79 +58,79 @@ class Context {
|
||||||
}
|
}
|
||||||
return array_values(array_filter($spec));
|
return array_values(array_filter($spec));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function reverse(bool $spec = null) {
|
public function reverse(bool $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function limit(int $spec = null) {
|
public function limit(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function offset(int $spec = null) {
|
public function offset(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function folder(int $spec = null) {
|
public function folder(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function folderShallow(int $spec = null) {
|
public function folderShallow(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function subscription(int $spec = null) {
|
public function subscription(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function latestArticle(int $spec = null) {
|
public function latestArticle(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function oldestArticle(int $spec = null) {
|
public function oldestArticle(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function latestEdition(int $spec = null) {
|
public function latestEdition(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function oldestEdition(int $spec = null) {
|
public function oldestEdition(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function unread(bool $spec = null) {
|
public function unread(bool $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function starred(bool $spec = null) {
|
public function starred(bool $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function modifiedSince($spec = null) {
|
public function modifiedSince($spec = null) {
|
||||||
$spec = Date::normalize($spec);
|
$spec = Date::normalize($spec);
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notModifiedSince($spec = null) {
|
public function notModifiedSince($spec = null) {
|
||||||
$spec = Date::normalize($spec);
|
$spec = Date::normalize($spec);
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function markedSince($spec = null) {
|
public function markedSince($spec = null) {
|
||||||
$spec = Date::normalize($spec);
|
$spec = Date::normalize($spec);
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function notMarkedSince($spec = null) {
|
public function notMarkedSince($spec = null) {
|
||||||
$spec = Date::normalize($spec);
|
$spec = Date::normalize($spec);
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edition(int $spec = null) {
|
public function edition(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function article(int $spec = null) {
|
public function article(int $spec = null) {
|
||||||
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
return $this->act(__FUNCTION__, func_num_args(), $spec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ abstract class AbstractHandler implements Handler {
|
||||||
}
|
}
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function fieldMapTypes(array $data, array $map, string $dateFormat = "sql"): array {
|
protected function fieldMapTypes(array $data, array $map, string $dateFormat = "sql"): array {
|
||||||
foreach ($map as $key => $type) {
|
foreach ($map as $key => $type) {
|
||||||
if (array_key_exists($key, $data)) {
|
if (array_key_exists($key, $data)) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
'/status' => ['GET' => "serverStatus"],
|
'/status' => ['GET' => "serverStatus"],
|
||||||
'/user' => ['GET' => "userStatus"],
|
'/user' => ['GET' => "userStatus"],
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$target->query = "";
|
$target->query = "";
|
||||||
return (string) $target;
|
return (string) $target;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function chooseCall(string $url, string $method): string {
|
protected function chooseCall(string $url, string $method): string {
|
||||||
// // normalize the URL path: change any IDs to 1 for easier comparison
|
// // normalize the URL path: change any IDs to 1 for easier comparison
|
||||||
$url = $this->normalizePathIds($url);
|
$url = $this->normalizePathIds($url);
|
||||||
|
@ -282,7 +282,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
return new EmptyResponse(404);
|
return new EmptyResponse(404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// list folders
|
// list folders
|
||||||
protected function folderList(array $url, array $data): ResponseInterface {
|
protected function folderList(array $url, array $data): ResponseInterface {
|
||||||
$folders = [];
|
$folders = [];
|
||||||
|
@ -362,7 +362,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
return new EmptyResponse(204);
|
return new EmptyResponse(204);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return list of feeds which should be refreshed
|
// return list of feeds which should be refreshed
|
||||||
protected function feedListStale(array $url, array $data): ResponseInterface {
|
protected function feedListStale(array $url, array $data): ResponseInterface {
|
||||||
// function requires admin rights per spec
|
// function requires admin rights per spec
|
||||||
|
@ -378,7 +378,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
return new Response(['feeds' => $out]);
|
return new Response(['feeds' => $out]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// refresh a feed
|
// refresh a feed
|
||||||
protected function feedUpdate(array $url, array $data): ResponseInterface {
|
protected function feedUpdate(array $url, array $data): ResponseInterface {
|
||||||
// function requires admin rights per spec
|
// function requires admin rights per spec
|
||||||
|
@ -431,7 +431,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
}
|
}
|
||||||
return new Response($out);
|
return new Response($out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// return list of feeds for the logged-in user
|
// return list of feeds for the logged-in user
|
||||||
protected function subscriptionList(array $url, array $data): ResponseInterface {
|
protected function subscriptionList(array $url, array $data): ResponseInterface {
|
||||||
$subs = Arsse::$db->subscriptionList(Arsse::$user->id);
|
$subs = Arsse::$db->subscriptionList(Arsse::$user->id);
|
||||||
|
|
|
@ -14,7 +14,7 @@ class Target {
|
||||||
public $path = [];
|
public $path = [];
|
||||||
public $query = "";
|
public $query = "";
|
||||||
public $fragment = "";
|
public $fragment = "";
|
||||||
|
|
||||||
public function __construct(string $target) {
|
public function __construct(string $target) {
|
||||||
$target = $this->parseFragment($target);
|
$target = $this->parseFragment($target);
|
||||||
$target = $this->parseQuery($target);
|
$target = $this->parseQuery($target);
|
||||||
|
|
|
@ -87,7 +87,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
'status' => 1,
|
'status' => 1,
|
||||||
'content' => ['error' => "MALFORMED_INPUT"],
|
'content' => ['error' => "MALFORMED_INPUT"],
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
public function opGetApiLevel(array $data): array {
|
public function opGetApiLevel(array $data): array {
|
||||||
return ['level' => self::LEVEL];
|
return ['level' => self::LEVEL];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function opGetVersion(array $data): array {
|
public function opGetVersion(array $data): array {
|
||||||
return [
|
return [
|
||||||
'version' => self::VERSION,
|
'version' => self::VERSION,
|
||||||
|
@ -186,7 +186,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
$user = $data['user'] ?? "";
|
$user = $data['user'] ?? "";
|
||||||
$pass = $data['password'] ?? "";
|
$pass = $data['password'] ?? "";
|
||||||
if (!Arsse::$conf->userSessionEnforced && isset(Arsse::$user->id)) {
|
if (!Arsse::$conf->userSessionEnforced && isset(Arsse::$user->id)) {
|
||||||
// if HTTP authentication was previously successful and sessions
|
// if HTTP authentication was previously successful and sessions
|
||||||
// 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);
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace JKingWeb\Arsse\REST\TinyTinyRSS;
|
||||||
|
|
||||||
class Exception extends \Exception {
|
class Exception extends \Exception {
|
||||||
protected $data = [];
|
protected $data = [];
|
||||||
|
|
||||||
public function __construct($msg = "UNSPECIFIED_ERROR", $data = [], $e = null) {
|
public function __construct($msg = "UNSPECIFIED_ERROR", $data = [], $e = null) {
|
||||||
$this->data = $data;
|
$this->data = $data;
|
||||||
parent::__construct($msg, 0, $e);
|
parent::__construct($msg, 0, $e);
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace JKingWeb\Arsse;
|
||||||
use JKingWeb\Arsse\Misc\Date;
|
use JKingWeb\Arsse\Misc\Date;
|
||||||
|
|
||||||
class Service {
|
class Service {
|
||||||
|
|
||||||
/** @var Service\Driver */
|
/** @var Service\Driver */
|
||||||
protected $drv;
|
protected $drv;
|
||||||
/** @var \DateInterval */
|
/** @var \DateInterval */
|
||||||
|
@ -26,7 +26,7 @@ class Service {
|
||||||
}
|
}
|
||||||
return $classes;
|
return $classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function interval(): \DateInterval {
|
public static function interval(): \DateInterval {
|
||||||
try {
|
try {
|
||||||
return new \DateInterval(Arsse::$conf->serviceFrequency);
|
return new \DateInterval(Arsse::$conf->serviceFrequency);
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
protected $options = [];
|
protected $options = [];
|
||||||
protected $queue;
|
protected $queue;
|
||||||
protected $handles = [];
|
protected $handles = [];
|
||||||
|
|
||||||
public static function driverName(): string {
|
public static function driverName(): string {
|
||||||
return Arsse::$lang->msg("Driver.Service.Curl.Name");
|
return Arsse::$lang->msg("Driver.Service.Curl.Name");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use JKingWeb\Arsse\Arsse;
|
||||||
|
|
||||||
class Driver implements \JKingWeb\Arsse\Service\Driver {
|
class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
protected $queue = [];
|
protected $queue = [];
|
||||||
|
|
||||||
public static function driverName(): string {
|
public static function driverName(): string {
|
||||||
return Arsse::$lang->msg("Driver.Service.Forking.Name");
|
return Arsse::$lang->msg("Driver.Service.Forking.Name");
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
public static function requirementsMet(): bool {
|
public static function requirementsMet(): bool {
|
||||||
return function_exists("popen");
|
return function_exists("popen");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use JKingWeb\Arsse\Arsse;
|
||||||
|
|
||||||
class Driver implements \JKingWeb\Arsse\Service\Driver {
|
class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
protected $queue = [];
|
protected $queue = [];
|
||||||
|
|
||||||
public static function driverName(): string {
|
public static function driverName(): string {
|
||||||
return Arsse::$lang->msg("Driver.Service.Internal.Name");
|
return Arsse::$lang->msg("Driver.Service.Internal.Name");
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ class Driver implements \JKingWeb\Arsse\Service\Driver {
|
||||||
// this driver has no requirements
|
// this driver has no requirements
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'API.TTRSS.Category.Uncategorized' => 'Uncategorized',
|
'API.TTRSS.Category.Uncategorized' => 'Uncategorized',
|
||||||
'API.TTRSS.Category.Special' => 'Special',
|
'API.TTRSS.Category.Special' => 'Special',
|
||||||
'API.TTRSS.Category.Labels' => 'Labels',
|
'API.TTRSS.Category.Labels' => 'Labels',
|
||||||
'API.TTRSS.Feed.All' => 'All articles',
|
'API.TTRSS.Feed.All' => 'All articles',
|
||||||
'API.TTRSS.Feed.Fresh' => 'Fresh articles',
|
'API.TTRSS.Feed.Fresh' => 'Fresh articles',
|
||||||
|
@ -181,4 +181,4 @@ return [
|
||||||
'Exception.JKingWeb/Arsse/Feed/Exception.xmlEntity' => 'Refused to parse feed "{url}" because it contains an XXE attack',
|
'Exception.JKingWeb/Arsse/Feed/Exception.xmlEntity' => 'Refused to parse feed "{url}" because it contains an XXE attack',
|
||||||
'Exception.JKingWeb/Arsse/Feed/Exception.subscriptionNotFound' => 'Unable to find a feed at location "{url}"',
|
'Exception.JKingWeb/Arsse/Feed/Exception.subscriptionNotFound' => 'Unable to find a feed at location "{url}"',
|
||||||
'Exception.JKingWeb/Arsse/Feed/Exception.unsupportedFeedFormat' => 'Feed "{url}" is of an unsupported format',
|
'Exception.JKingWeb/Arsse/Feed/Exception.unsupportedFeedFormat' => 'Feed "{url}" is of an unsupported format',
|
||||||
];
|
];
|
||||||
|
|
|
@ -105,7 +105,7 @@ create table arsse_marks(
|
||||||
subscription integer not null references arsse_subscriptions(id) on delete cascade on update cascade,
|
subscription integer not null references arsse_subscriptions(id) on delete cascade on update cascade,
|
||||||
read boolean not null default 0,
|
read boolean not null default 0,
|
||||||
starred boolean not null default 0,
|
starred boolean not null default 0,
|
||||||
modified text not null default CURRENT_TIMESTAMP,
|
modified text not null default CURRENT_TIMESTAMP,
|
||||||
primary key(article,subscription)
|
primary key(article,subscription)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -124,4 +124,4 @@ create table arsse_categories(
|
||||||
|
|
||||||
-- set version marker
|
-- set version marker
|
||||||
pragma user_version = 1;
|
pragma user_version = 1;
|
||||||
insert into arsse_meta(key,value) values('schema_version','1');
|
insert into arsse_meta(key,value) values('schema_version','1');
|
||||||
|
|
|
@ -49,7 +49,7 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$typeStr = "'".str_replace("'", "''", $type)."'";
|
$typeStr = "'".str_replace("'", "''", $type)."'";
|
||||||
$nativeStatement = $this->c->prepare(
|
$nativeStatement = $this->c->prepare(
|
||||||
"SELECT (
|
"SELECT (
|
||||||
(CASE WHEN substr($typeStr, 0, 7) <> 'strict ' then null else 1 end) is null
|
(CASE WHEN substr($typeStr, 0, 7) <> 'strict ' then null else 1 end) is null
|
||||||
and ? is null
|
and ? is null
|
||||||
) or (
|
) or (
|
||||||
$exp = ?
|
$exp = ?
|
||||||
|
@ -250,7 +250,7 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[$dateImmutable, "strict boolean", "1"],
|
[$dateImmutable, "strict boolean", "1"],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testConstructStatement() {
|
public function testConstructStatement() {
|
||||||
$nativeStatement = $this->c->prepare("SELECT ? as value");
|
$nativeStatement = $this->c->prepare("SELECT ? as value");
|
||||||
$this->assertInstanceOf(Statement::class, new \JKingWeb\Arsse\Db\SQLite3\Statement($this->c, $nativeStatement));
|
$this->assertInstanceOf(Statement::class, new \JKingWeb\Arsse\Db\SQLite3\Statement($this->c, $nativeStatement));
|
||||||
|
|
|
@ -50,7 +50,7 @@ class TestStatement extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$typeStr = "'".str_replace("'", "''", $type)."'";
|
$typeStr = "'".str_replace("'", "''", $type)."'";
|
||||||
$nativeStatement = $this->c->prepare(
|
$nativeStatement = $this->c->prepare(
|
||||||
"SELECT (
|
"SELECT (
|
||||||
(CASE WHEN substr($typeStr, 0, 7) <> 'strict ' then null else 1 end) is null
|
(CASE WHEN substr($typeStr, 0, 7) <> 'strict ' then null else 1 end) is null
|
||||||
and ? is null
|
and ? is null
|
||||||
) or (
|
) or (
|
||||||
$exp = ?
|
$exp = ?
|
||||||
|
|
|
@ -172,7 +172,7 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->assertException("malformedXml", "Feed");
|
$this->assertException("malformedXml", "Feed");
|
||||||
new Feed(null, $this->base."Parsing/Malformed");
|
new Feed(null, $this->base."Parsing/Malformed");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testDeduplicateFeedItems() {
|
public function testDeduplicateFeedItems() {
|
||||||
// duplicates with dates lead to the newest match being kept
|
// duplicates with dates lead to the newest match being kept
|
||||||
$t = strtotime("2002-05-19T15:21:36Z");
|
$t = strtotime("2002-05-19T15:21:36Z");
|
||||||
|
@ -245,7 +245,7 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$f = new Feed(null, $this->base."Caching/200None");
|
$f = new Feed(null, $this->base."Caching/200None");
|
||||||
$this->assertTime($t, $f->lastModified);
|
$this->assertTime($t, $f->lastModified);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testComputeNextFetchOnError() {
|
public function testComputeNextFetchOnError() {
|
||||||
for ($a = 0; $a < 100; $a++) {
|
for ($a = 0; $a < 100; $a++) {
|
||||||
if ($a < 3) {
|
if ($a < 3) {
|
||||||
|
@ -257,7 +257,7 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testComputeNextFetchFrom304() {
|
public function testComputeNextFetchFrom304() {
|
||||||
// if less than half an hour, check in 15 minutes
|
// if less than half an hour, check in 15 minutes
|
||||||
$t = strtotime("now");
|
$t = strtotime("now");
|
||||||
|
@ -305,7 +305,7 @@ class TestFeed extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$exp = strtotime("now + 3 hours");
|
$exp = strtotime("now + 3 hours");
|
||||||
$this->assertTime($exp, $f->nextFetch);
|
$this->assertTime($exp, $f->nextFetch);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testComputeNextFetchFrom200() {
|
public function testComputeNextFetchFrom200() {
|
||||||
// if less than half an hour, check in 15 minutes
|
// if less than half an hour, check in 15 minutes
|
||||||
$f = new Feed(null, $this->base."NextFetch/30m");
|
$f = new Feed(null, $this->base."NextFetch/30m");
|
||||||
|
|
|
@ -16,7 +16,7 @@ class TestValueInfo extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
$this->clearData();
|
$this->clearData();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetIntegerInfo() {
|
public function testGetIntegerInfo() {
|
||||||
$tests = [
|
$tests = [
|
||||||
[null, I::NULL],
|
[null, I::NULL],
|
||||||
|
|
|
@ -934,7 +934,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$exp = new EmptyResponse(403);
|
$exp = new EmptyResponse(403);
|
||||||
$this->assertMessage($exp, $this->req("GET", "/cleanup/before-update"));
|
$this->assertMessage($exp, $this->req("GET", "/cleanup/before-update"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCleanUpAfterUpdate() {
|
public function testCleanUpAfterUpdate() {
|
||||||
Phake::when(Arsse::$db)->articleCleanup()->thenReturn(true);
|
Phake::when(Arsse::$db)->articleCleanup()->thenReturn(true);
|
||||||
$exp = new EmptyResponse(204);
|
$exp = new EmptyResponse(204);
|
||||||
|
|
|
@ -60,7 +60,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
[$fake, "/full/url-not", []],
|
[$fake, "/full/url-not", []],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider provideAuthenticableRequests */
|
/** @dataProvider provideAuthenticableRequests */
|
||||||
public function testAuthenticateRequests(array $serverParams, array $expAttr) {
|
public function testAuthenticateRequests(array $serverParams, array $expAttr) {
|
||||||
$r = new REST();
|
$r = new REST();
|
||||||
|
@ -105,7 +105,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$act = $r->challenge($in);
|
$act = $r->challenge($in);
|
||||||
$this->assertMessage($exp, $act);
|
$this->assertMessage($exp, $act);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @dataProvider provideUnnormalizedOrigins */
|
/** @dataProvider provideUnnormalizedOrigins */
|
||||||
public function testNormalizeOrigins(string $origin, string $exp, array $ports = null) {
|
public function testNormalizeOrigins(string $origin, string $exp, array $ports = null) {
|
||||||
$r = new REST();
|
$r = new REST();
|
||||||
|
|
|
@ -105,21 +105,21 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
protected $richContent = <<<LONG_STRING
|
protected $richContent = <<<LONG_STRING
|
||||||
<section>
|
<section>
|
||||||
<p>
|
<p>
|
||||||
<b>Pour</b> vous faire mieux
|
<b>Pour</b> vous faire mieux
|
||||||
connaitre d’ou\u{300} vient
|
connaitre d’ou\u{300} vient
|
||||||
l’erreur de ceux qui
|
l’erreur de ceux qui
|
||||||
bla\u{302}ment la
|
bla\u{302}ment la
|
||||||
volupte\u{301}, et qui louent
|
volupte\u{301}, et qui louent
|
||||||
en quelque sorte la douleur,
|
en quelque sorte la douleur,
|
||||||
je vais entrer dans une
|
je vais entrer dans une
|
||||||
explication plus
|
explication plus
|
||||||
e\u{301}tendue, et vous faire
|
e\u{301}tendue, et vous faire
|
||||||
voir tout ce qui a
|
voir tout ce qui a
|
||||||
e\u{301}te\u{301} dit
|
e\u{301}te\u{301} dit
|
||||||
la\u{300}-dessus par
|
la\u{300}-dessus par
|
||||||
l’inventeur de la
|
l’inventeur de la
|
||||||
ve\u{301}rite\u{301}, et, pour
|
ve\u{301}rite\u{301}, et, pour
|
||||||
ainsi dire, par l’architecte
|
ainsi dire, par l’architecte
|
||||||
de la vie heureuse.
|
de la vie heureuse.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
@ -157,7 +157,7 @@ LONG_STRING;
|
||||||
protected function reqAuth($data, $user) {
|
protected function reqAuth($data, $user) {
|
||||||
return $this->req($data, "POST", "", null, $user);
|
return $this->req($data, "POST", "", null, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -1551,7 +1551,7 @@ LONG_STRING;
|
||||||
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 0, 'mode' => 1],
|
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 0, 'mode' => 1],
|
||||||
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 0, 'mode' => 2],
|
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 0, 'mode' => 2],
|
||||||
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 0, 'mode' => 3], // invalid mode
|
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 0, 'mode' => 3], // invalid mode
|
||||||
|
|
||||||
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 1], // Published feed' no-op
|
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 1], // Published feed' no-op
|
||||||
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 1, 'mode' => 0],
|
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 1, 'mode' => 0],
|
||||||
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 1, 'mode' => 1],
|
['op' => "updateArticle", 'sid' => "PriestsOfSyrinx", 'article_ids' => "42, 2112, -1", 'field' => 1, 'mode' => 1],
|
||||||
|
|
|
@ -83,7 +83,7 @@ class TestAuthorization extends \JKingWeb\Arsse\Test\AbstractTest {
|
||||||
$this->assertFalse(Arsse::$user->authorizationEnabled(true));
|
$this->assertFalse(Arsse::$user->authorizationEnabled(true));
|
||||||
$this->assertTrue(Arsse::$user->authorizationEnabled(true));
|
$this->assertTrue(Arsse::$user->authorizationEnabled(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSelfActionLogic() {
|
public function testSelfActionLogic() {
|
||||||
foreach (array_keys(self::USERS) as $user) {
|
foreach (array_keys(self::USERS) as $user) {
|
||||||
Arsse::$user->auth($user, "");
|
Arsse::$user->auth($user, "");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
usleep(1.05 * 1000000);
|
usleep(1.05 * 1000000);
|
||||||
return [
|
return [
|
||||||
'code' => 404,
|
'code' => 404,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
$item = '
|
$item = '
|
||||||
<item>
|
<item>
|
||||||
<description>'.str_repeat("0", 1024).'</description>
|
<description>'.str_repeat("0", 1024).'</description>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
if (array_key_exists("t", $_GET)) {
|
if (array_key_exists("t", $_GET)) {
|
||||||
return [
|
return [
|
||||||
'code' => 304,
|
'code' => 304,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<?php return [
|
<?php return [
|
||||||
'mime' => "application/rss+xml",
|
'mime' => "application/rss+xml",
|
||||||
'content' => <<<MESSAGE_BODY
|
'content' => <<<MESSAGE_BODY
|
||||||
<!DOCTYPE test [
|
<!DOCTYPE test [
|
||||||
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
||||||
]>
|
]>
|
||||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||||
<channel>
|
<channel>
|
||||||
|
|
|
@ -157,7 +157,7 @@ trait SeriesCleanup {
|
||||||
}
|
}
|
||||||
$this->compareExpectations($state);
|
$this->compareExpectations($state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCleanUpOldArticlesWithUnlimitedReadRetention() {
|
public function testCleanUpOldArticlesWithUnlimitedReadRetention() {
|
||||||
Arsse::$conf->purgeArticlesRead = "";
|
Arsse::$conf->purgeArticlesRead = "";
|
||||||
Arsse::$db->articleCleanup();
|
Arsse::$db->articleCleanup();
|
||||||
|
@ -169,7 +169,7 @@ trait SeriesCleanup {
|
||||||
}
|
}
|
||||||
$this->compareExpectations($state);
|
$this->compareExpectations($state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testCleanUpOldArticlesWithUnlimitedUnreadRetention() {
|
public function testCleanUpOldArticlesWithUnlimitedUnreadRetention() {
|
||||||
Arsse::$conf->purgeArticlesUnread = "";
|
Arsse::$conf->purgeArticlesUnread = "";
|
||||||
Arsse::$db->articleCleanup();
|
Arsse::$db->articleCleanup();
|
||||||
|
|
|
@ -30,7 +30,7 @@ trait SeriesFeed {
|
||||||
'title_content_hash' => '43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
'title_content_hash' => '43b970ac6ec5f8a9647b2c7e4eed8b1d7f62e154a95eed748b0294c1256764ba',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
public function setUpSeries() {
|
public function setUpSeries() {
|
||||||
// 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"));
|
||||||
|
|
|
@ -58,7 +58,7 @@ trait SeriesUser {
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
Arsse::$db->userPasswordGet("admin@example.net");
|
Arsse::$db->userPasswordGet("admin@example.net");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAddANewUser() {
|
public function testAddANewUser() {
|
||||||
$this->assertSame("", Arsse::$db->userAdd("john.doe@example.org", ""));
|
$this->assertSame("", Arsse::$db->userAdd("john.doe@example.org", ""));
|
||||||
Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userAdd");
|
Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userAdd");
|
||||||
|
@ -99,7 +99,7 @@ trait SeriesUser {
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
Arsse::$db->userAdd("john.doe@example.org", "");
|
Arsse::$db->userAdd("john.doe@example.org", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAUser() {
|
public function testRemoveAUser() {
|
||||||
$this->assertTrue(Arsse::$db->userRemove("admin@example.net"));
|
$this->assertTrue(Arsse::$db->userRemove("admin@example.net"));
|
||||||
Phake::verify(Arsse::$user)->authorize("admin@example.net", "userRemove");
|
Phake::verify(Arsse::$user)->authorize("admin@example.net", "userRemove");
|
||||||
|
@ -112,7 +112,7 @@ trait SeriesUser {
|
||||||
$this->assertException("doesNotExist", "User");
|
$this->assertException("doesNotExist", "User");
|
||||||
Arsse::$db->userRemove("john.doe@example.org");
|
Arsse::$db->userRemove("john.doe@example.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRemoveAUserWithoutAuthority() {
|
public function testRemoveAUserWithoutAuthority() {
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
@ -130,13 +130,13 @@ trait SeriesUser {
|
||||||
$this->assertSame($users, Arsse::$db->userList("example.com"));
|
$this->assertSame($users, Arsse::$db->userList("example.com"));
|
||||||
Phake::verify(Arsse::$user)->authorize("@example.com", "userList");
|
Phake::verify(Arsse::$user)->authorize("@example.com", "userList");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListAllUsersWithoutAuthority() {
|
public function testListAllUsersWithoutAuthority() {
|
||||||
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->userList();
|
Arsse::$db->userList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListUsersOnADomainWithoutAuthority() {
|
public function testListUsersOnADomainWithoutAuthority() {
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
@ -166,7 +166,7 @@ trait SeriesUser {
|
||||||
$this->assertException("doesNotExist", "User");
|
$this->assertException("doesNotExist", "User");
|
||||||
Arsse::$db->userPasswordSet("john.doe@example.org", "secret");
|
Arsse::$db->userPasswordSet("john.doe@example.org", "secret");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetAPasswordWithoutAuthority() {
|
public function testSetAPasswordWithoutAuthority() {
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
@ -188,7 +188,7 @@ trait SeriesUser {
|
||||||
$this->assertException("doesNotExist", "User");
|
$this->assertException("doesNotExist", "User");
|
||||||
Arsse::$db->userPropertiesGet("john.doe@example.org");
|
Arsse::$db->userPropertiesGet("john.doe@example.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetUserPropertiesWithoutAuthority() {
|
public function testGetUserPropertiesWithoutAuthority() {
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
@ -223,7 +223,7 @@ trait SeriesUser {
|
||||||
$this->assertException("doesNotExist", "User");
|
$this->assertException("doesNotExist", "User");
|
||||||
Arsse::$db->userPropertiesSet("john.doe@example.org", $try);
|
Arsse::$db->userPropertiesSet("john.doe@example.org", $try);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetUserPropertiesWithoutAuthority() {
|
public function testSetUserPropertiesWithoutAuthority() {
|
||||||
$try = ['name' => 'John Doe'];
|
$try = ['name' => 'John Doe'];
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
|
@ -244,7 +244,7 @@ trait SeriesUser {
|
||||||
$this->assertSame(UserDriver::RIGHTS_NONE, Arsse::$db->userRightsGet("john.doe@example.org"));
|
$this->assertSame(UserDriver::RIGHTS_NONE, Arsse::$db->userRightsGet("john.doe@example.org"));
|
||||||
Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userRightsGet");
|
Phake::verify(Arsse::$user)->authorize("john.doe@example.org", "userRightsGet");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetUserRightsWithoutAuthority() {
|
public function testGetUserRightsWithoutAuthority() {
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
$this->assertException("notAuthorized", "User", "ExceptionAuthz");
|
||||||
|
@ -266,7 +266,7 @@ trait SeriesUser {
|
||||||
$this->assertException("doesNotExist", "User");
|
$this->assertException("doesNotExist", "User");
|
||||||
Arsse::$db->userRightsSet("john.doe@example.org", $rights);
|
Arsse::$db->userRightsSet("john.doe@example.org", $rights);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSetUserRightsWithoutAuthority() {
|
public function testSetUserRightsWithoutAuthority() {
|
||||||
$rights = UserDriver::RIGHTS_GLOBAL_ADMIN;
|
$rights = UserDriver::RIGHTS_GLOBAL_ADMIN;
|
||||||
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
Phake::when(Arsse::$user)->authorize->thenReturn(false);
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
Silk icon set v1.3
|
Silk icon set v1.3
|
||||||
Copyright 2006, Mark James
|
Copyright 2006, Mark James
|
||||||
http://www.famfamfam.com/lab/icons/silk/
|
http://www.famfamfam.com/lab/icons/silk/
|
||||||
|
|
||||||
Used under license:
|
Used under license:
|
||||||
http://creativecommons.org/licenses/by/2.5/
|
http://creativecommons.org/licenses/by/2.5/
|
||||||
|
|
||||||
A minimal subset of the Silk icon set used by Tiny Tiny RSS is included here
|
A minimal subset of the Silk icon set used by Tiny Tiny RSS is included here
|
||||||
to provide consistent results with certain API functions.
|
to provide consistent results with certain API functions.
|
||||||
|
|
||||||
Note that TT-RSS renames some of the icons, and we use the modified names,
|
Note that TT-RSS renames some of the icons, and we use the modified names,
|
||||||
again for consistency. Below is a table listing the source file names:
|
again for consistency. Below is a table listing the source file names:
|
||||||
|
|
||||||
Modified Original
|
Modified Original
|
||||||
|
|
Loading…
Reference in a new issue